diff --git a/doc/价格管理平台.bmpr b/doc/价格管理平台.bmpr
index 2e3bd02..eb1a8d6 100644
Binary files a/doc/价格管理平台.bmpr and b/doc/价格管理平台.bmpr differ
diff --git a/package.json b/package.json
index 7b26815..dd39be7 100644
--- a/package.json
+++ b/package.json
@@ -15,8 +15,6 @@
"i18next": "^23.11.5",
"i18next-browser-languagedetector": "^8.0.0",
"i18next-http-backend": "^2.5.2",
- "mobx": "^6.9.0",
- "mobx-react": "^7.6.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-i18next": "^14.1.2",
diff --git a/public/locales/en/common.json b/public/locales/en/common.json
index 0810454..b113807 100644
--- a/public/locales/en/common.json
+++ b/public/locales/en/common.json
@@ -21,6 +21,13 @@
"preview": "Preview",
"Total": "Total",
"Action": "Action",
+ "Import": "Import",
+ "Export": "Export",
+ "Copy": "Copy",
+
+ "Table": {
+ "Total": "Total {{total}} items"
+ },
"Login": "Login",
"Username": "Username",
diff --git a/public/locales/en/products.json b/public/locales/en/products.json
index 6e50c59..0ccfecf 100644
--- a/public/locales/en/products.json
+++ b/public/locales/en/products.json
@@ -7,15 +7,26 @@
"Attractions": "Attractions",
"Meals": "Meals",
"Extras": "Extras",
+ "Overtravel": "超公里",
"Special": "Special"
},
"auditState": {
"New": "New",
"Pending": "Pending",
- "Approve": "Approve",
+ "Approved": "Approved",
"Rejected": "Rejected",
"Published": "Published"
},
+ "auditStateAction": {
+ "New": "New",
+ "Pending": "Pending",
+ "Approved": "Approve",
+ "Rejected": "Reject",
+ "Published": "Publish"
+ },
+ "Status": "Status",
+ "State": "State",
+
"Title": "Title",
"Vendor": "Vendor",
"AuState": "Audit State",
@@ -24,7 +35,6 @@
"AuditedBy": "Audited By",
"AuditDate": "Audit Date",
-
"productProject": "Product project",
"Code": "Code",
"City": "City",
diff --git a/public/locales/zh/common.json b/public/locales/zh/common.json
index 4ef0694..e3239a1 100644
--- a/public/locales/zh/common.json
+++ b/public/locales/zh/common.json
@@ -21,6 +21,13 @@
"preview": "预览",
"Total": "总数",
"Action": "操作",
+ "Import": "导入",
+ "Export": "导出",
+ "Copy": "复制",
+
+ "Table": {
+ "Total": "共 {{total}} 条"
+ },
"Login": "登录",
"Username": "账号",
diff --git a/public/locales/zh/products.json b/public/locales/zh/products.json
index 87b9914..3abea44 100644
--- a/public/locales/zh/products.json
+++ b/public/locales/zh/products.json
@@ -6,21 +6,53 @@
"Package": "包价线路",
"Attractions": "景点",
"Meals": "餐费",
- "Extras": "附加",
+ "Extras": "附加项目",
+ "Overtravel": "超公里",
"Special": "特殊项目"
},
"auditState": {
"New": "新增",
"Pending": "待审核",
- "Approve": "已通过",
+ "Approved": "已通过",
"Rejected": "已拒绝",
"Published": "已发布"
},
+ "auditStateAction": {
+ "New": "新增",
+ "Pending": "待审核",
+ "Approved": "审核通过",
+ "Rejected": "审核拒绝",
+ "Published": "审核发布"
+ },
+ "Status": "状态",
+ "State": "状态",
+
"Title": "名称",
"Vendor": "供应商",
"AuState": "审核状态",
"CreatedBy": "提交人员",
"CreateDate": "提交时间",
+
+
+ "AuditedBy": "审核人员",
+ "AuditDate": "审核时间",
+
+ "Quotation": "报价",
+ "Offer": "报价",
+ "Unit": "单位",
+ "GroupSize": "人等",
+ "UseDates": "使用日期",
+ "Weekdays": "有效日/周X",
+
+ "UseYear": "年份",
+
+ "AgeType": {
+ "Type": "人群",
+ "Adult": "成人",
+ "Child": "儿童"
+ },
+
+ "#": "#"
"Auditors": "审核人员",
"AuditDate": "审核时间",
diff --git a/src/components/AuditStateSelector.jsx b/src/components/AuditStateSelector.jsx
new file mode 100644
index 0000000..db4c77d
--- /dev/null
+++ b/src/components/AuditStateSelector.jsx
@@ -0,0 +1,12 @@
+import { Select } from 'antd';
+import { useProductsAuditStates } from '@/hooks/useProductsSets';
+
+const AuditStateSelector = ({ ...props }) => {
+ const states = useProductsAuditStates();
+ return (
+ <>
+
+ >
+ );
+};
+export default AuditStateSelector;
diff --git a/src/components/ErrorPage.jsx b/src/components/ErrorPage.jsx
index 49b8f9d..9c779d0 100644
--- a/src/components/ErrorPage.jsx
+++ b/src/components/ErrorPage.jsx
@@ -1,12 +1,12 @@
-import { useRouteError } from "react-router-dom"
+import { useRouteError } from 'react-router-dom'
import { Result } from 'antd'
export default function ErrorPage() {
const errorResponse = useRouteError()
return (
)
diff --git a/src/components/RequireAuth.jsx b/src/components/RequireAuth.jsx
new file mode 100644
index 0000000..cabef0b
--- /dev/null
+++ b/src/components/RequireAuth.jsx
@@ -0,0 +1,22 @@
+import { Result } from 'antd'
+import { usingStorage } from '@/hooks/usingStorage'
+import useAuthStore from '@/stores/Auth'
+
+export default function RequireAuth({ children, ...props }) {
+
+ const isPermitted = useAuthStore((state) => state.isPermitted)
+ const { userId } = usingStorage()
+
+ if (isPermitted(props.subject)) {
+ // if (props.subject === '/account/management1') {
+ return children
+ } else if (props.result) {
+ return (
+
+ )
+ }
+}
\ No newline at end of file
diff --git a/src/components/SearchForm.jsx b/src/components/SearchForm.jsx
index 97ca443..979a6fc 100644
--- a/src/components/SearchForm.jsx
+++ b/src/components/SearchForm.jsx
@@ -3,24 +3,27 @@ import { Form, Input, Row, Col, Select, DatePicker, Space, Button } from 'antd';
import { objectMapper, at } from '@/utils/commons';
import { DATE_FORMAT, SMALL_DATETIME_FORMAT } from '@/config';
import useFormStore from '@/stores/Form';
-import usePresets from '@/hooks/usePresets';
+import useDatePresets from '@/hooks/useDatePresets';
import { useTranslation } from 'react-i18next';
-import SearchInput from './SearchInput';
+
import { fetchJSON } from '@/utils/request';
import { HT_HOST } from '@/config';
+import SearchInput from './SearchInput';
+import AuditStateSelector from './AuditStateSelector';
+
//供应商列表
-export const fetchVendorList = async () => {
- const { errcode, Result } = await fetchJSON(`${HT_HOST}/service-cusservice/PTGetHWVendorList`)
- return errcode !== 0 ? [] : Result
+export const fetchVendorList = async (q) => {
+ const { errcode, result } = await fetchJSON(`${HT_HOST}/Service_BaseInfoWeb/VendorList`, { q })
+ return errcode !== 0 ? [] : result
}
const { RangePicker } = DatePicker;
const SearchForm = ({ initialValue, onSubmit, onReset, ...props }) => {
const { t } = useTranslation();
- const presets = usePresets();
+ const presets = useDatePresets();
const [formValues, setFormValues] = useFormStore((state) => [state.formValues, state.setFormValues]);
const [formValuesToSub, setFormValuesToSub] = useFormStore((state) => [state.formValuesToSub, state.setFormValuesToSub]);
const [form] = Form.useForm();
@@ -47,13 +50,16 @@ const SearchForm = ({ initialValue, onSubmit, onReset, ...props }) => {
{ key: 'endtime', transform: (arrVal) => (arrVal ? arrVal[1].format(SMALL_DATETIME_FORMAT) : '') },
],
'invoiceStatus': { key: 'invoiceStatus', transform: (value) => value?.value || value?.key || '', default: '' },
- 'auditState': { key: 'auditState', transform: (value) => value?.value || value?.key || '', default: '' },
+ 'audit_state': { key: 'audit_state', transform: (value) => value?.value || value?.key || '', default: '' },
'agency': {
key: 'agency',
transform: (value) => {
return Array.isArray(value) ? value.map((ele) => ele.key).join(',') : value ? value.value : '';
},
},
+ 'year': [
+ { key: 'year', transform: (arrVal) => (arrVal ? arrVal.format('YYYY') : '') },
+ ],
};
let dest = {};
const { dates, ...omittedValue } = values;
@@ -162,15 +168,15 @@ function getFields(props) {
'referenceNo',
99,
-
+
,
fieldProps?.referenceNo?.col || 6
),
item(
'PNR',
99,
-
-
+
+
,
fieldProps?.PNR?.col || 4
),
@@ -202,37 +208,56 @@ function getFields(props) {
,
fieldProps?.dates?.col || midCol
),
+ item(
+ 'username',
+ 3,
+
+
+ ,
+ fieldProps?.username?.col || 4
+ ),
+ item(
+ 'realname',
+ 4,
+
+
+ ,
+ fieldProps?.realname?.col || 4
+ ),
/**
*
*/
+ item(
+ 'year',
+ 99,
+
+
+ ,
+ fieldProps?.year?.col || 3
+ ),
item(
'agency',
99,
-
+
,
fieldProps?.agency?.col || 6
),
item(
- 'auditState',
+ 'audit_state',
99,
-
-
+
+
,
- fieldProps?.auditState?.col || 3
+ fieldProps?.audit_state?.col || 3
),
-
];
baseChildren = baseChildren
.map((x) => {
diff --git a/src/components/SearchInput.jsx b/src/components/SearchInput.jsx
index d816647..dcf2657 100644
--- a/src/components/SearchInput.jsx
+++ b/src/components/SearchInput.jsx
@@ -31,6 +31,7 @@ function DebounceSelect({ fetchOptions, debounceTimeout = 800, ...props }) {
showSearch
allowClear
maxTagCount={1}
+ dropdownStyle={{width: '16rem'}}
{...props}
onSearch={debounceFetcher}
notFoundContent={fetching ? : null}
diff --git a/src/components/SecondHeaderWrapper.jsx b/src/components/SecondHeaderWrapper.jsx
index 2b2ffca..097b0d4 100644
--- a/src/components/SecondHeaderWrapper.jsx
+++ b/src/components/SecondHeaderWrapper.jsx
@@ -14,7 +14,7 @@ const HeaderWrapper = ({ children, header, ...props }) => {
{/* {header} */}
- {header}
+ {header}
diff --git a/src/config.js b/src/config.js
index 58e13a2..03d67fd 100644
--- a/src/config.js
+++ b/src/config.js
@@ -6,6 +6,35 @@ export const HT_HOST = import.meta.env.PROD ? "https://p9axztuwd7x8a7.mycht.cn"
export const DATE_FORMAT = "YYYY-MM-DD";
export const DATE_FORMAT_MONTH = "YYYY-MM";
export const SMALL_DATETIME_FORMAT = "YYYY-MM-DD 23:59";
+export const OFFICEWEBVIEWERURL = "https://view.officeapps.live.com/op/embed.aspx?wdPrint=1&wdHideGridlines=0&wdHideComments=1&wdEmbedCode=0&src=";
const __BUILD_VERSION__ = `__BUILD_VERSION__`.replace(/"/g, '')
export const BUILD_VERSION = import.meta.env.PROD ? __BUILD_VERSION__ : import.meta.env.MODE;
+
+// 权限常量定义
+// 账号、权限管理
+// category: system
+export const PERM_ACCOUNT_MANAGEMENT = '/account/management'
+export const PERM_ACCOUNT_NEW = '/account/new'
+export const PERM_ACCOUNT_DISABLE = '/account/disable'
+export const PERM_ACCOUNT_RESET_PASSWORD = '/account/reset-password'
+export const PERM_ROLE_NEW = '/account/role/new'
+
+// 海外供应商
+// category: oversea
+export const PERM_OVERSEA = '/oversea/all'
+
+// 国内供应商
+// category: domestic
+export const PERM_DOMESTIC = '/domestic/all'
+
+// 机票供应商
+// category: air-ticket
+export const PERM_AIR_TICKET = '/air-ticket/all'
+
+// 价格管理
+export const PERM_PRODUCTS_MANAGEMENT = '/products/*'; // 管理
+export const PERM_PRODUCTS_INFO_AUDIT = '/products/info/audit'; // 信息.审核
+export const PERM_PRODUCTS_INFO_PUT = '/products/info/put'; // 信息.录入
+export const PERM_PRODUCTS_OFFER_AUDIT = '/products/offer/audit'; // 价格.审核
+export const PERM_PRODUCTS_OFFER_PUT = '/products/offer/put'; // 价格.录入
diff --git a/src/hooks/usePresets.js b/src/hooks/useDatePresets.js
similarity index 91%
rename from src/hooks/usePresets.js
rename to src/hooks/useDatePresets.js
index aa046e6..87397b9 100644
--- a/src/hooks/usePresets.js
+++ b/src/hooks/useDatePresets.js
@@ -2,7 +2,7 @@ import { useEffect, useState } from 'react';
import dayjs from "dayjs";
import { useTranslation } from 'react-i18next';
-const usePresets = () => {
+const useDatePresets = () => {
const [presets, setPresets] = useState([]);
const { t, i18n } = useTranslation();
@@ -39,4 +39,4 @@ const usePresets = () => {
return presets;
}
-export default usePresets;
+export default useDatePresets;
diff --git a/src/hooks/useHTLanguageSets.js b/src/hooks/useHTLanguageSets.js
new file mode 100644
index 0000000..73b827e
--- /dev/null
+++ b/src/hooks/useHTLanguageSets.js
@@ -0,0 +1,14 @@
+export const useHTLanguageSets = () => {
+ const newData = [
+ { key: '1', value: '1', label: 'English' },
+ { key: '2', value: '2', label: 'Chinese (中文)' },
+ { key: '3', value: '3', label: 'Japanese (日本語)' },
+ { key: '4', value: '4', label: 'German (Deutsch)' },
+ { key: '5', value: '5', label: 'French (Français)' },
+ { key: '6', value: '6', label: 'Spanish (Español)' },
+ { key: '7', value: '7', label: 'Russian (Русский)' },
+ { key: '8', value: '8', label: 'Italian (Italiano)' },
+ ];
+
+ return newData;
+};
diff --git a/src/hooks/useProductsSets.js b/src/hooks/useProductsSets.js
index 4545d91..6749ede 100644
--- a/src/hooks/useProductsSets.js
+++ b/src/hooks/useProductsSets.js
@@ -3,6 +3,40 @@ import { useTranslation } from 'react-i18next';
/**
* 产品管理 相关的预设数据
+ * 项目类型
+酒店预定 1
+火车 2
+飞机票务 3
+游船 4
+快巴 5
+旅行社(综费) 6
+景点 7
+特殊项目 8
+其他 9
+酒店 A
+超公里 B
+餐费 C
+小包价 D
+站 X
+购物 S
+餐 R
+娱乐 E
+精华线路 T
+客人testimonial F
+线路订单 O
+省 P
+信息 I
+国家 G
+城市 K
+图片 H
+地图 M
+包价线路 L
+节日节庆 V
+火车站 N
+手机租赁 Z
+ * * webht 类型, 20240624 新增HT类型
+Q 导游
+J 车费
*/
export const useProductsTypes = () => {
@@ -11,14 +45,15 @@ export const useProductsTypes = () => {
useEffect(() => {
const newData = [
- { label: t('products:type.Experience'), value: 'Experience', key: 'Experience' },
- { label: t('products:type.Car'), value: 'Car', key: 'Car' },
- { label: t('products:type.Guide'), value: 'Guide', key: 'Guide' },
- { label: t('products:type.Package'), value: 'Package', key: 'Package' },
- { label: t('products:type.Attractions'), value: 'Attractions', key: 'Attractions' },
- { label: t('products:type.Meals'), value: 'Meals', key: 'Meals' },
- { label: t('products:type.Extras'), value: 'Extras', key: 'Extras' },
- { label: t('products:type.Special'), value: 'Special', key: 'Special' },
+ { label: t('products:type.Experience'), value: '6', key: '6' },
+ { label: t('products:type.Overtravel'), value: 'B', key: 'B' },
+ { label: t('products:type.Car'), value: 'J', key: 'J' },
+ { label: t('products:type.Guide'), value: 'Q', key: 'Q' },
+ { label: t('products:type.Package'), value: 'D', key: 'D' },
+ { label: t('products:type.Attractions'), value: '7', key: '7' },
+ { label: t('products:type.Meals'), value: 'C', key: 'C' },
+ { label: t('products:type.Extras'), value: '8', key: '8' },
+ // { label: t('products:type.Special'), value: 'Special', key: 'Special' },
];
setTypes(newData);
}, [i18n.language]);
@@ -26,21 +61,45 @@ export const useProductsTypes = () => {
return types;
};
-
-export const useProductsAuditStatus = () => {
+export const useProductsAuditStates = () => {
const [types, setTypes] = useState([]);
const { t, i18n } = useTranslation();
useEffect(() => {
const newData = [
- { value: '0', label: 'New' },
- { value: '1', label: 'Pending' },
- { value: '2', label: 'Approve' },
- { value: '3', label: 'Rejected' },
- { value: '4', label: 'Published' },
+ { key: '-1', value: '-1', label: t('products:auditState.New') },
+ { key: '0', value: '0', label: t('products:auditState.Pending') },
+ { key: '2', value: '2', label: t('products:auditState.Approved') },
+ { key: '3', value: '3', label: t('products:auditState.Rejected') },
+ { key: '1', value: '1', label: t('products:auditState.Published') },
+ // ELSE 未知
];
setTypes(newData);
}, [i18n.language]);
return types;
};
+
+export const useProductsAuditStatesMapVal = (value) => {
+ const stateSets = useProductsAuditStates();
+ const stateMapVal = stateSets.reduce((r, c) => ({ ...r, [`${c.value}`]: c }), {});
+ return stateMapVal;
+};
+
+/**
+ * @ignore
+ */
+export const useProductsTypesFieldsets = (type, role) => {
+ const infoDefault = ['code', 'title'];
+ const infoAdmin = ['remarks', 'dept', 'display_to_c'];
+ const infoTypesMap = {
+ '6': [],
+ 'B': ['city_id', 'km'],
+ 'J': ['description', 'city_id', 'recommends_rate', 'duration', 'display_to_c'],
+ 'Q': ['description', 'city_id', 'duration', ],
+ 'D': ['description', 'city_id', 'recommends_rate','duration',],
+ '7': ['description', 'city_id', 'recommends_rate', 'duration', 'display_to_c', 'open_weekdays'], // todo: 怎么是2个图
+ 'C': ['description', 'city_id',],
+ '8': [], // todo: ?
+ };
+};
diff --git a/src/i18n/LanguageSwitcher.jsx b/src/i18n/LanguageSwitcher.jsx
index ac1f009..dd1a743 100644
--- a/src/i18n/LanguageSwitcher.jsx
+++ b/src/i18n/LanguageSwitcher.jsx
@@ -1,6 +1,17 @@
-import React, { useState } from 'react';
-import { Dropdown, Menu } from 'antd';
+import { useState, useEffect } from 'react';
+import { Dropdown } from 'antd';
import { useTranslation } from 'react-i18next';
+import { appendRequestParams } from '@/utils/request';
+
+const i18n_to_htcode = {
+ 'zh': 2,
+ 'en': 1,
+};
+
+export const useLanguage = () => {
+ const { i18n } = useTranslation();
+ return { language: i18n.language, };
+};
/**
* 语言选择组件
@@ -8,6 +19,13 @@ import { useTranslation } from 'react-i18next';
const Language = () => {
const { t, i18n } = useTranslation();
const [selectedKeys, setSelectedKeys] = useState([i18n.language]);
+
+ useEffect(() => {
+ appendRequestParams('lgc', i18n_to_htcode[i18n.language]);
+
+ return () => {};
+ }, [i18n.language]);
+
// 切换语言事件
const handleChangeLanguage = ({ key }) => {
setSelectedKeys([key]);
diff --git a/src/main.jsx b/src/main.jsx
index 3ed3c89..138e237 100644
--- a/src/main.jsx
+++ b/src/main.jsx
@@ -1,12 +1,9 @@
import React from "react";
-import { configure } from "mobx";
import ReactDOM from "react-dom/client";
import {
createBrowserRouter,
RouterProvider,
} from "react-router-dom";
-import RootStore from "@/stores/Root";
-import { StoreContext } from '@/stores/StoreContext';
import "@/assets/global.css";
import App from "@/views/App";
import Standlone from "@/views/Standlone";
@@ -14,11 +11,13 @@ import Login from "@/views/Login";
import Logout from "@/views/Logout";
import Index from "@/views/index";
import ErrorPage from "@/components/ErrorPage";
+import RequireAuth from '@/components/RequireAuth'
import ReservationNewest from "@/views/reservation/Newest";
import ReservationDetail from "@/views/reservation/Detail";
import ChangePassword from "@/views/account/ChangePassword";
import AccountProfile from "@/views/account/Profile";
import AccountManagement from "@/views/account/Management";
+import RoleList from "@/views/account/RoleList";
import FeedbackIndex from "@/views/feedback/Index";
import FeedbackDetail from "@/views/feedback/Detail";
import FeedbackCustomerDetail from "@/views/feedback/CustomerDetail";
@@ -30,19 +29,15 @@ import InvoiceDetail from "@/views/invoice/Detail";
import InvoicePaid from "@/views/invoice/Paid";
import InvoicePaidDetail from "@/views/invoice/PaidDetail";
import Airticket from "@/views/airticket/Index";
+import AirticketPlan from "@/views/airticket/Plan";
+import { ThemeContext } from '@/stores/ThemeContext'
+
import ProductsIndex from '@/views/products/Index';
import ProductsDetail from '@/views/products/Detail';
import ProductsAudit from '@/views/products/Audit';
-import './i18n';
+import { PERM_ACCOUNT_MANAGEMENT, PERM_ROLE_NEW, PERM_OVERSEA, PERM_AIR_TICKET } from '@/config'
-configure({
- useProxies: "ifavailable",
- enforceActions: "observed",
- computedRequiresReaction: true,
- observableRequiresReaction: false,
- reactionRequiresObservable: true,
- disableErrorBoundaries: process.env.NODE_ENV == "production"
-});
+import './i18n';
const router = createBrowserRouter([
{
@@ -51,25 +46,27 @@ const router = createBrowserRouter([
errorElement: ,
children: [
{ index: true, element: },
- { path: "reservation/newest", element: },
- { path: "reservation/:reservationId", element: },
{ path: "account/change-password", element: },
{ path: "account/profile", element: },
- { path: "account/management", element: },
- { path: "feedback", element: },
- { path: "feedback/:GRI_SN/:CII_SN/:RefNo", element: },
- { path: "feedback/:GRI_SN/:RefNo", element: },
- { path: "report", element: },
- { path: "notice", element: },
- { path: "notice/:CCP_BLID", element: },
- { path: "invoice",element:},
- { path: "invoice/detail/:GMDSN/:GSN",element:},
- { path: "invoice/paid",element:},
- { path: "invoice/paid/detail/:flid",element:},
- { path: "airticket",element:},
+ { path: "account/management", element: },
+ { path: "account/role-list", element: },
+ { path: "reservation/newest", element: },
+ { path: "reservation/:reservationId", element: },
+ { path: "feedback", element: },
+ { path: "feedback/:GRI_SN/:CII_SN/:RefNo", element: },
+ { path: "feedback/:GRI_SN/:RefNo", element: },
+ { path: "report", element: },
+ { path: "notice", element: },
+ { path: "notice/:CCP_BLID", element: },
+ { path: "invoice",element:},
+ { path: "invoice/detail/:GMDSN/:GSN",element:},
+ { path: "invoice/paid",element:},
+ { path: "invoice/paid/detail/:flid", element: },
+ { path: "airticket",element: },
+ { path: "airticket/plan/:coli_sn",element:},
{ path: "products",element:},
- { path: "products/:travel_agency_id/audit",element:},
- { path: "products/:travel_agency_id",element:},
+ { path: "products/:travel_agency_id/:use_year/:audit_state/audit",element:},
+ { path: "products/:travel_agency_id/:use_year/:audit_state/edit",element:},
]
},
{
@@ -81,15 +78,14 @@ const router = createBrowserRouter([
}
]);
-const rootStore = new RootStore();
ReactDOM.createRoot(document.getElementById("root")).render(
//
-
- Loading...
}
- />
-
+
+ Loading...
}
+ />
+
//
);
diff --git a/src/stores/Account.js b/src/stores/Account.js
new file mode 100644
index 0000000..6c6410e
--- /dev/null
+++ b/src/stores/Account.js
@@ -0,0 +1,141 @@
+import { create } from 'zustand'
+import { fetchJSON, postForm } from '@/utils/request'
+import { HT_HOST } from "@/config"
+import { usingStorage } from '@/hooks/usingStorage'
+
+export const postAccountStatus = async (formData) => {
+
+ const { errcode, result } = await postForm(
+ `${HT_HOST}/service-CooperateSOA/set_account_status`, formData)
+ return errcode !== 0 ? {} : result
+}
+
+export const postAccountPassword = async (formData) => {
+
+ const { errcode, result } = await postForm(
+ `${HT_HOST}/service-CooperateSOA/reset_account_password`, formData)
+ return errcode !== 0 ? {} : result
+}
+
+export const fetchAccountList = async (params) => {
+
+ const { errcode, result } = await fetchJSON(
+ `${HT_HOST}/service-CooperateSOA/search_account`, params)
+ return errcode !== 0 ? {} : result
+}
+
+export const postAccountForm = async (formData) => {
+
+ const { errcode, result } = await postForm(
+ `${HT_HOST}/service-CooperateSOA/new_or_update_account`, formData)
+ return errcode !== 0 ? {} : result
+}
+
+export const postRoleForm = async (formData) => {
+
+ const { errcode, result } = await postForm(
+ `${HT_HOST}/service-CooperateSOA/new_or_update_role`, formData)
+ return errcode !== 0 ? {} : result
+}
+
+export const fetchRoleList = async () => {
+
+ const { errcode, result } = await fetchJSON(
+ `${HT_HOST}/service-CooperateSOA/get_role_list`)
+ return errcode !== 0 ? {} : result
+}
+
+const useAccountStore = create((set, get) => ({
+
+ accountList: [],
+
+ disableAccount: async (accountId) => {
+
+ const formData = new FormData()
+ formData.append('wu_id', accountId)
+ // enable disable
+ formData.append('account_status', 'disable')
+
+ const result = await postAccountStatus(formData)
+
+ console.info(result)
+ },
+
+ resetAccountPassword: async (accountId, password) => {
+
+ const formData = new FormData()
+ formData.append('wu_id', accountId)
+ formData.append('newPassword', password)
+
+ return postAccountPassword(formData)
+ },
+
+ newRole: () => {
+ return {
+ role_id: null,
+ role_name: '',
+ role_ids: ''
+ }
+ },
+
+ saveOrUpdateRole: async (formValues) => {
+ const formData = new FormData()
+ formData.append('role_id', formValues.role_id)
+ formData.append('role_name', formValues.role_name)
+ formData.append('res_ids', '2,3')
+
+ return postRoleForm(formData)
+ },
+
+ saveOrUpdateAccount: async (formValues) => {
+ const { userId } = usingStorage()
+ const formData = new FormData()
+ formData.append('wu_id', formValues.userId)
+ formData.append('lmi_sn', formValues.lmi_sn)
+ formData.append('lmi2_sn', formValues.lmi2_sn)
+ formData.append('user_name', formValues.username)
+ formData.append('real_name', formValues.realname)
+ formData.append('email', formValues.email)
+
+ formData.append('travel_agency_id', formValues.travelAgencyId)
+ formData.append('roles', formValues.roleId)
+
+ formData.append('opi_sn', userId)
+
+ return postAccountForm(formData)
+ },
+
+ searchAccountByCriteria: async (formValues) => {
+
+ const searchParams = {
+ username: formValues.username,
+ realname: formValues.realname,
+ lgc: 2
+ }
+
+ const resultArray = await fetchAccountList(searchParams)
+
+ const mapAccoutList = resultArray.map((r) => {
+ return {
+ userId: r.wu_id,
+ lmi_sn: r.lmi_sn,
+ lmi2_sn: r.lmi2_sn,
+ username: r.user_name,
+ realname: r.real_name,
+ email: r.email,
+ lastLogin: r.wu_lastlogindate,
+ travelAgency: r.travel_agency_name,
+ travelAgencyId: r.travel_agency_id,
+ // 数据库支持逗号分隔多角色(5,6,7),目前界面只需单个。
+ roleId: parseInt(r.roles),
+ role: r.roles_name,
+ }
+ })
+
+ set(() => ({
+ accountList: mapAccoutList
+ }))
+ },
+}))
+
+export default useAccountStore
\ No newline at end of file
diff --git a/src/stores/Airticket.js b/src/stores/Airticket.js
index 1ddc720..6a393b9 100644
--- a/src/stores/Airticket.js
+++ b/src/stores/Airticket.js
@@ -8,8 +8,10 @@ const airTicketStore = create((set, get) => ({
loading: false,
setLoading: loading => set({ loading }),
setPlanList: planList => set({ planList }),
+ setPlanDetail: planDetail => set({ planDetail }),
+ setGuestList: guestList => set({ guestList }),
- async getPlanList(vei_sn, GRI_Name, PNR, TimeStart, TimeEnd) {
+ async getPlanList(vei_sn, GRI_Name, TimeStart, TimeEnd) {
const { setLoading, setPlanList } = get();
setLoading(true);
const searchParams = {
@@ -17,7 +19,6 @@ const airTicketStore = create((set, get) => ({
FlightDate1: TimeStart,
FlightDate2: TimeEnd,
GRI_Name: GRI_Name,
- PNR: PNR,
};
const { errcode, result } = await fetchJSON(`${HT_HOST}/Service_BaseInfoWeb/GetFlightPlan`, searchParams);
@@ -25,6 +26,27 @@ const airTicketStore = create((set, get) => ({
setPlanList(_result);
setLoading(false);
},
+
+ async getPlanDetail(vei_sn, gri_sn) {
+ const { setPlanDetail } = get();
+ const searchParams = {
+ vei_sn: 6376, //vei_sn,
+ gri_sn: 369040, //gri_sn
+ };
+ const { errcode, result } = await fetchJSON(`${HT_HOST}/Service_BaseInfoWeb/GetFlightPlanDetail`, searchParams);
+ const _result = errcode !== 0 ? [] : result;
+ setPlanDetail(_result);
+ },
+ async getGuestList(coli_sn) {
+ const { setGuestList } = get();
+ const searchParams = {
+ COLI_SN: 1097829, //coli_sn,
+ };
+ const { errcode, result } = await fetchJSON(`${HT_HOST}/Service_BaseInfoWeb/GetFlightGuestInfo`, searchParams);
+ const _result = errcode !== 0 ? [] : result;
+ setGuestList(_result);
+ },
+
}));
export default airTicketStore;
diff --git a/src/stores/Auth.js b/src/stores/Auth.js
index f7f31f3..c82a3c5 100644
--- a/src/stores/Auth.js
+++ b/src/stores/Auth.js
@@ -55,13 +55,13 @@ const useAuthStore = create((set, get) => ({
// 以下是权限列表从数据库读取后使用的方法
// return this.permissionList.some((value, key, arry) => {
// if (value.indexOf(WILDCARD_TOKEN) > -1) {
- // return true;
+ // return true
// }
// if (value === perm) {
- // return true;
+ // return true
// }
- // return false;
- // });
+ // return false
+ // })
},
@@ -88,6 +88,7 @@ const useAuthStore = create((set, get) => ({
setStorage(KEY_TRAVEL_AGENCY_ID, userDetail.LMI_VEI_SN)
setStorage(KEY_USER_DETAIL, {username: userDetail.LoginName, travelAgencyName: userDetail.VName})
appendRequestParams('token', loginToken)
+ appendRequestParams('wu_id', userDetail.LMI_SN)
// loadPageSpy(`${json.Result.VName}-${json.Result.LoginName}`)
startTokenInterval()
},
@@ -154,19 +155,4 @@ const useAuthStore = create((set, get) => ({
},
}))
-export default useAuthStore
-
-export class Auth {
- // TODO: 等待所有获取用户信息修改完后删除
- login = {
- token: '',
- userId: 0, // LMI_SN
- username: '0',
- travelAgencyId: 0, // VEI_SN
- travelAgencyName: '',
- telephone: '',
- emailAddress: '',
- cityId: 0,
- timeout: false
- }
-}
+export default useAuthStore
\ No newline at end of file
diff --git a/src/stores/Feedback.js b/src/stores/Feedback.js
index dd3feb1..9b2356e 100644
--- a/src/stores/Feedback.js
+++ b/src/stores/Feedback.js
@@ -1,4 +1,3 @@
-import { makeAutoObservable, runInAction } from 'mobx';
import { fetchJSON, postForm } from '@/utils/request';
import { groupBy } from '@/utils/commons';
import * as config from '@/config';
diff --git a/src/stores/Invoice.js b/src/stores/Invoice.js
index 814e69f..09ac0f2 100644
--- a/src/stores/Invoice.js
+++ b/src/stores/Invoice.js
@@ -1,10 +1,5 @@
-import { makeAutoObservable, runInAction } from "mobx";
import { fetchJSON, postForm } from "@/utils/request";
-import { prepareUrl, isNotEmpty, objectMapper } from "@/utils/commons";
import { HT_HOST } from "@/config";
-import { json } from "react-router-dom";
-import * as config from "@/config";
-import dayjs from "dayjs";
import { create } from 'zustand';
import { devtools } from 'zustand/middleware';
@@ -138,366 +133,3 @@ const useInvoiceStore = create(
);
export default useInvoiceStore;
-
-export class Invoice {
- constructor(root) {
- makeAutoObservable(this, { rootStore: false });
- this.root = root;
- }
-
- invoiceList = []; //账单列表
- invoicekImages = []; //图片列表
- invoiceGroupInfo = {}; //账单详细
- invoiceProductList = []; //账单细项
- invoiceZDDetail = []; //报账信息
- invoiceCurrencyList = []; //币种
- invoicePicList = []; //多账单图片列表数组
- invoiceFormData = { info_money: 0, info_Currency: "", info_date: "" }; //存储form数据
-
- invoicePaid = [] ; //支付账单列表
- invoicePaidDetail = []; //每期账单详细
-
- loading = false;
- search_date_start = dayjs().subtract(2, "M").startOf("M");
- search_date_end = dayjs().endOf("M");
-
- onDateRangeChange = dates => {
- console.log(dates);
- this.search_date_start = dates==null? null: dates[0];
- this.search_date_end = dates==null? null: dates[1];
- };
-
- fetchInvoiceList(VEI_SN, GroupNo, DateStart, DateEnd,OrderType) {
- this.loading = true;
- const fetchUrl = prepareUrl(HT_HOST + "/service-cusservice/PTSearchGMBPageList")
- .append("VEI_SN", VEI_SN)
- .append("OrderType", 0)
- .append("GroupNo", GroupNo.trim())
- .append("DateStart", DateStart)
- .append("DateEnd", DateEnd)
- .append("Orderbytype", 1)
- .append("TimeType", 0)
- .append("limitmarket", "")
- .append("mddgroup", "")
- .append("SecuryGroup", "")
- .append("TotalNum", 0)
- .append("PageSize", 2000)
- .append("PageIndex", 1)
- .append("PayState",OrderType)
- .append("token",this.root.authStore.login.token)
- .build();
-
- return fetchJSON(fetchUrl).then(json => {
- runInAction(() => {
- this.loading = false;
- if (json.errcode == 0) {
- if (isNotEmpty(json.Result)) {
- this.invoiceList = json.Result.map((data, index) => {
- return {
- key: data.GMDSN,
- gmd_gri_sn: data.GMD_GRI_SN,
- gmd_vei_sn: data.GMD_VEI_SN,
- GetGDate: data.GetGDate,
- GMD_FillWorkers_SN: data.GMD_FillWorkers_SN,
- GMD_FWks_LastEditTime: data.GMD_FWks_LastEditTime,
- GMD_VerifyUser_SN: data.GMD_VerifyUser_SN,
- GMD_Dealed: data.GMD_Dealed,
- GMD_VRequestVerify: data.GMD_VRequestVerify,
- LeftGDate: data.LeftGDate,
- GMD_FillWorkers_Name: data.GMD_FillWorkers_Name,
- GroupName: data.GroupName,
- AllMoney: data.AllMoney,
- PersonNum: data.PersonNum,
- GMD_Currency: data.GMD_Currency,
- VName: data.VName,
- FKState: data.FKState,
- };
- });
- } else {
- this.invoiceList = [];
- }
- } else {
- throw new Error(json.errmsg + ": " + json.errcode);
- }
- });
- });
- }
-
- fetchInvoiceDetail(GMDSN, GSN) {
- const fetchUrl = prepareUrl(HT_HOST + "/service-cusservice/PTGetZDDetail")
- .append("VEI_SN", this.root.authStore.login.travelAgencyId)
- .append("GRI_SN", GSN)
- .append("GMD_SN", GMDSN)
- .append("LGC", 1)
- .append("Bill", 1)
- .append("token",this.root.authStore.login.token)
- .build();
-
- return fetchJSON(fetchUrl).then(json => {
- runInAction(() => {
- if (json.errcode == 0) {
- this.invoiceGroupInfo = json.GroupInfo[0];
- this.invoiceProductList = json.ProductList;
- this.invoiceCurrencyList = json.CurrencyList;
- this.invoiceZDDetail = json.ZDDetail;
- } else {
- throw new Error(json.errmsg + ": " + json.errcode);
- }
- });
- return json;
- });
- }
-
- //获取供应商提交的图片
- getInvoicekImages(VEI_SN, GRI_SN) {
- let url = `/service-fileServer/ListFile`;
- url += `?GRI_SN=${GRI_SN}&VEI_SN=${VEI_SN}&FilePathName=invoice`;
- url += `&token=${this.root.authStore.login.token}`;
- fetch(config.HT_HOST + url)
- .then(response => response.json())
- .then(json => {
- console.log(json);
- runInAction(() => {
- this.invoicekImages = json.result.map((data, index) => {
- return {
- uid: -index, //用负数,防止添加删除的时候错误
- name: data.file_name,
- status: "done",
- url: data.file_url,
- };
- });
- });
- })
- .catch(error => {
- console.log("fetch data failed", error);
- });
- }
-
- //从数据库获取图片列表
- getInvoicekImages_fromData(jsonData) {
- let arrLen = jsonData.length;
- let arrPicList = jsonData.map((data, index) => {
- const GMD_Pic = data.GMD_Pic;
- let picList = [];
- if (isNotEmpty(GMD_Pic)) {
- let js_Pic = JSON.parse(GMD_Pic);
- picList = js_Pic.map((picData, pic_Index) => {
- return {
- uid: -pic_Index, //用负数,防止添加删除的时候错误
- name: "",
- status: "done",
- url: picData.url,
- };
- });
- }
- if (data.GMD_Dealed == false && arrLen == index + 1) {
- this.invoicekImages = picList;
- }
- return picList;
- });
-
- runInAction(() => {
- this.invoicePicList = arrPicList;
- });
- }
-
- //获取数据库的表单默认数据回填。
- getFormData(jsonData) {
- let arrLen = jsonData.length;
- return jsonData.map((data, index) => {
- if (data.GMD_Dealed == false && arrLen == index + 1) {
- //只有最后一条账单未审核通过才显示
- runInAction(() => {
- this.invoiceFormData = { info_money: data.GMD_Cost, info_Currency: data.GMD_Currency, info_date: isNotEmpty(data.GMD_PayDate) ? dayjs(data.GMD_PayDate) : "" };
- });
- }
- });
- }
-
- removeFeedbackImages(fileurl) {
- let url = `/service-fileServer/FileDelete`;
- url += `?fileurl=${fileurl}`;
- url += `&token=${this.root.authStore.login.token}`;
- return fetch(config.HT_HOST + url)
- .then(response => response.json())
- .then(json => {
- console.log(json);
- return json.Result;
- })
- .catch(error => {
- console.log("fetch data failed", error);
- });
- }
-
- postEditInvoiceDetail(GMD_SN, Currency, Cost, PayDate, Pic, Memo) {
- let postUrl = HT_HOST + "/service-cusservice/EditSupplierFK";
- let formData = new FormData();
- formData.append("LMI_SN", this.root.authStore.login.userId);
- formData.append("GMD_SN", GMD_SN);
- formData.append("Currency", Currency);
- formData.append("Cost", Cost);
- formData.append("PayDate", isNotEmpty(PayDate) ? PayDate : "");
- formData.append("Pic", Pic);
- formData.append("Memo", Memo);
- formData.append("token",this.root.authStore.login.token);
-
- return postForm(postUrl, formData).then(json => {
- console.info(json);
- return json;
- });
- }
-
- postAddInvoice(GRI_SN, Currency, Cost, PayDate, Pic, Memo) {
- let postUrl = HT_HOST + "/service-cusservice/AddSupplierFK";
- let formData = new FormData();
- formData.append("LMI_SN", this.root.authStore.login.userId);
- formData.append("VEI_SN", this.root.authStore.login.travelAgencyId);
- formData.append("GRI_SN", GRI_SN);
- formData.append("Currency", Currency);
- formData.append("Cost", Cost);
- formData.append("PayDate", isNotEmpty(PayDate) ? PayDate : "");
- formData.append("Pic", Pic);
- formData.append("Memo", Memo);
- formData.append("token",this.root.authStore.login.token);
- return postForm(postUrl, formData).then(json => {
- console.info(json);
- return json;
- });
- }
-
- //账单状态
- invoiceStatus(FKState) {
- switch (FKState - 1) {
- case 1:
- return "Submitted";
- break;
- case 2:
- return "Travel Advisor";
- break;
- case 3:
- return "Finance Dept";
- break;
- case 4:
- return "Paid";
- break;
- default:
- return "";
- break;
- }
- }
-
- fetchInvoicePaid(VEI_SN, GroupNo, DateStart, DateEnd) {
- this.loading = true;
- const fetchUrl = prepareUrl(HT_HOST + "/service-Cooperate/Cooperate/GetInvoicePaid")
- .append("VEI_SN", VEI_SN)
- .append("GroupNo", GroupNo)
- .append("DateStart", DateStart)
- .append("DateEnd", DateEnd)
- .append("token",this.root.authStore.login.token)
- .build();
-
- return fetchJSON(fetchUrl).then(json => {
- runInAction(() => {
- this.loading = false;
- if (json.errcode == 0) {
- if (isNotEmpty(json.Result)) {
- this.invoicePaid = json.Result.map((data, index) => {
- return {
- key: data.fl_id,
- fl_finaceNo: data.fl_finaceNo,
- fl_vei_sn: data.fl_vei_sn,
- fl_year: data.fl_year,
- fl_month: data.fl_month,
- fl_memo: data.fl_memo,
- fl_adddate: data.fl_adddate,
- fl_addUserSn: data.fl_addUserSn,
- fl_updateUserSn: data.fl_updateUserSn,
- fl_updatetime: data.fl_updatetime,
- fl_state: data.fl_state,
- fl_paid: data.fl_paid,
- fl_pic: data.fl_pic,
- fcount: data.fcount,
- pSum: data.pSum,
- };
- });
- } else {
- this.invoicePaid = [];
- }
- } else {
- throw new Error(json.errmsg + ": " + json.errcode);
- }
- });
- });
-
- }
-
-
- fetchInvoicePaidDetail(VEI_SN,FLID){
- this.loading = true;
- const fetchUrl = prepareUrl(HT_HOST + "/service-Cooperate/Cooperate/GetInvoicePaidDetail")
- .append("VEI_SN", VEI_SN)
- .append("fl_id", FLID)
- .append("token",this.root.authStore.login.token)
- .build();
-
- return fetchJSON(fetchUrl).then(json => {
- runInAction(() => {
- this.loading = false;
- if (json.errcode == 0) {
- if (isNotEmpty(json.Result)) {
- this.invoicePaidDetail = json.Result.map((data, index) => {
- return {
- key: data.fl2_id,
- fl2_fl_id: data.fl2_fl_id,
- fl2_GroupName: data.fl2_GroupName,
- fl2_gri_sn: data.fl2_gri_sn,
- fl2_gmd_sn: data.fl2_gmd_sn,
- fl2_wl: data.fl2_wl,
- fl2_ArriveDate: data.fl2_ArriveDate,
- fl2_price: data.fl2_price,
- fl2_state: data.fl2_state,
- fl2_updatetime: data.fl2_updatetime,
- fl2_updateUserSn: data.fl2_updateUserSn,
- fl2_memo: data.fl2_memo,
- fl2_memo2: data.fl2_memo2,
- fl2_paid: data.fl2_paid,
- fl2_pic: data.fl2_pic,
- };
- });
- } else {
- this.invoicePaidDetail = [];
- }
- } else {
- throw new Error(json.errmsg + ": " + json.errcode);
- }
- });
- });
- }
-
- /* 测试数据 */
- //账单列表范例数据
- testData = [
- {
- GSMSN: 449865,
- gmd_gri_sn: 334233,
- gmd_vei_sn: 628,
- GetDate: "2023-04-2 00:33:33",
- GMD_FillWorkers_SN: 8617,
- GMD_FWks_LastEditTime: "2023-04-26 12:33:33",
- GMD_VerifyUser_SN: 8928,
- GMD_Dealed: 1,
- GMD_VRequestVerify: 1,
- TotalCount: 22,
- LeftGDate: "2023-03-30 00:00:00",
- GMD_FillWorkers_Name: "",
- GroupName: " 中华游230501-CA230402033",
- AllMoney: 3539,
- FKState: 1,
- GMD_Currency: "",
- PersonNum: "1大1小",
- VName: "",
- },
- ];
-}
-
-// export default Invoice;
diff --git a/src/stores/Products/Index.js b/src/stores/Products/Index.js
index 872bec9..a18f098 100644
--- a/src/stores/Products/Index.js
+++ b/src/stores/Products/Index.js
@@ -1,23 +1,57 @@
import { create } from 'zustand';
import { devtools } from 'zustand/middleware';
-import { fetchJSON } from '@/utils/request';
+import { fetchJSON, postForm } from '@/utils/request';
import { HT_HOST } from '@/config';
+import { groupBy } from '@/utils/commons';
+
+export const searchAgencyAction = async (param) => {
+ const { errcode, result } = await fetchJSON(`${HT_HOST}/Service_BaseInfoWeb/products_search`, param);
+ return errcode !== 0 ? [] : result;
+};
+export const getAgencyProductsAction = async (param) => {
+ const _param = { ...param, use_year: (param.use_year || '').replace('all', ''), audit_state: (param.audit_state || '').replace('all', '') };
+ const { errcode, result } = await fetchJSON(`${HT_HOST}/Service_BaseInfoWeb/travel_agency_products`, _param);
+ return errcode !== 0 ? { agency: {}, products: [] } : result;
+};
+
+export const postProductsQuoteAudit = async (auditState, quoteRow) => {
+ const postbody = {
+ audit_state: auditState,
+ id: quoteRow.id,
+ travel_agency_id: quoteRow.travel_agency_id,
+ };
+ const formData = new FormData();
+ Object.keys(postbody).forEach((key) => {
+ formData.append(key, postbody[key]);
+ });
+ const json = await postForm(`${HT_HOST}/Service_BaseInfoWeb/quotation_audit`, formData);
+ return json;
+ // return errcode !== 0 ? {} : result;
+};
+
+export const postProductsAudit = async (auditState, infoRow) => {
+ const postbody = {
+ audit_state: auditState,
+ id: infoRow.id,
+ travel_agency_id: infoRow.travel_agency_id,
+ };
+ const formData = new FormData();
+ Object.keys(postbody).forEach((key) => {
+ formData.append(key, postbody[key]);
+ });
+ const json = await postForm(`${HT_HOST}/Service_BaseInfoWeb/travel-agency-products-audit`, formData);
+ return json;
+ // const { errcode, result } = json;
+ // return errcode !== 0 ? {} : result;
+};
const initialState = {
loading: false,
- productsList: [
- {
- 'audit_date': '2001-03-03',
- 'travel_agency_name': '新油低外',
- 'travel_agency_id': '650000200301029585',
- 'created_by': '冯丽',
- 'create_date': '1989-06-20',
- 'lastedit_memo': 'nostrud ad eu',
- 'audited_by': '黎静',
- 'audit_state': '1',
- },
- ],
+ searchValues: {},
+ agencyList: [],
+ activeAgency: {},
+ agencyProducts: {},
};
export const useProductsStore = create(
devtools((set, get) => ({
@@ -25,11 +59,33 @@ export const useProductsStore = create(
...initialState,
// state actions
- setProductsList: (productsList) => set({ productsList }),
+ setLoading: loading => set({ loading }),
+ setSearchValues: searchValues => set({ searchValues }),
+ setAgencyList: (agencyList) => set({ agencyList }),
+ setActiveAgency: activeAgency => set({ activeAgency }),
+ setAgencyProducts: agencyProducts => set({ agencyProducts }),
reset: () => set(initialState),
// side effects
+ searchAgency: async (param) => {
+ const { setLoading, setAgencyList } = get();
+ setLoading(true);
+ const res = await searchAgencyAction(param);
+ setAgencyList(res);
+ setLoading(false);
+ },
+
+ getAgencyProducts: async (param) => {
+ const { setLoading, setActiveAgency, setAgencyProducts } = get();
+ setLoading(true);
+ const res = await getAgencyProductsAction(param);
+ const productsData = groupBy(res.products, row => row.info.product_type_id);
+ setAgencyProducts(productsData);
+ setActiveAgency(res.agency);
+ setLoading(false);
+ },
+
}))
);
export default useProductsStore;
diff --git a/src/stores/Root.js b/src/stores/Root.js
deleted file mode 100644
index a24bd54..0000000
--- a/src/stores/Root.js
+++ /dev/null
@@ -1,39 +0,0 @@
-import { makeAutoObservable } from "mobx";
-import { Auth } from "./Auth";
-
-class Root {
- constructor() {
- this.authStore = new Auth(this);
- makeAutoObservable(this);
- }
-
- clearSession() {
- if (window.sessionStorage) {
- const sessionStorage = window.sessionStorage;
- sessionStorage.clear();
- } else {
- console.error('browser not support sessionStorage!');
- }
- }
-
- getSession(key) {
- if (window.sessionStorage) {
- const sessionStorage = window.sessionStorage;
- return sessionStorage.getItem(key);
- } else {
- console.error('browser not support sessionStorage!');
- return null;
- }
- }
-
- putSession(key, value) {
- if (window.sessionStorage) {
- const sessionStorage = window.sessionStorage;
- return sessionStorage.setItem(key, value);
- } else {
- console.error('browser not support sessionStorage!');
- }
- }
-}
-
-export default Root;
diff --git a/src/stores/StoreContext.js b/src/stores/StoreContext.js
deleted file mode 100644
index aca4a62..0000000
--- a/src/stores/StoreContext.js
+++ /dev/null
@@ -1,7 +0,0 @@
-import { createContext, useContext } from "react";
-
-export const StoreContext = createContext();
-
-export function useStore() {
- return useContext(StoreContext);
-}
\ No newline at end of file
diff --git a/src/stores/ThemeContext.js b/src/stores/ThemeContext.js
new file mode 100644
index 0000000..f4f7aa7
--- /dev/null
+++ b/src/stores/ThemeContext.js
@@ -0,0 +1,7 @@
+import { createContext, useContext } from 'react'
+
+export const ThemeContext = createContext({})
+
+export function useThemeContext() {
+ return useContext(ThemeContext)
+}
\ No newline at end of file
diff --git a/src/utils/commons.js b/src/utils/commons.js
index c5508ca..2e83226 100644
--- a/src/utils/commons.js
+++ b/src/utils/commons.js
@@ -129,7 +129,7 @@ export function escape2Html(str) {
var output = temp.innerText || temp.textContent;
temp = null;
return output;
- }
+}
export function formatPrice(price) {
return Math.ceil(price).toLocaleString();
@@ -139,7 +139,6 @@ export function formatPercent(number) {
return Math.round(number * 100) + "%";
}
-
/**
* ! 不支持计算 Set 或 Map
* @param {*} val
@@ -148,23 +147,23 @@ export function formatPercent(number) {
* false if: 'false', 'undefined'
*/
export function isEmpty(val) {
- // return val === undefined || val === null || val === "";
- return [Object, Array].includes((val || {}).constructor) && !Object.entries(val || {}).length;
+ // return val === undefined || val === null || val === "";
+ return [Object, Array].includes((val || {}).constructor) && !Object.entries(val || {}).length;
}
/**
* 数组排序
*/
-export const sortBy = (key) => {
- return (a, b) => (a[key] > b[key] ? 1 : b[key] > a[key] ? -1 : 0);
+export const sortBy = key => {
+ return (a, b) => (a[key] > b[key] ? 1 : b[key] > a[key] ? -1 : 0);
};
/**
* Object排序keys
*/
-export const sortKeys = (obj) =>
- Object.keys(obj)
- .sort()
- .reduce((a, k2) => ({ ...a, [k2]: obj[k2] }), {});
+export const sortKeys = obj =>
+ Object.keys(obj)
+ .sort()
+ .reduce((a, k2) => ({ ...a, [k2]: obj[k2] }), {});
/**
* 数组排序, 给定排序数组
@@ -174,41 +173,41 @@ export const sortKeys = (obj) =>
* @returns
*/
export const sortArrayByOrder = (items, keyName, keyOrder) => {
- return items.sort((a, b) => {
- return keyOrder.indexOf(a[keyName]) - keyOrder.indexOf(b[keyName]);
- });
+ return items.sort((a, b) => {
+ return keyOrder.indexOf(a[keyName]) - keyOrder.indexOf(b[keyName]);
+ });
};
/**
* 合并Object, 递归地
*/
export function merge(...objects) {
- const isDeep = objects.some((obj) => obj !== null && typeof obj === 'object');
+ const isDeep = objects.some(obj => obj !== null && typeof obj === "object");
- const result = objects[0] || (isDeep ? {} : objects[0]);
+ const result = objects[0] || (isDeep ? {} : objects[0]);
- for (let i = 1; i < objects.length; i++) {
- const obj = objects[i];
+ for (let i = 1; i < objects.length; i++) {
+ const obj = objects[i];
- if (!obj) continue;
+ if (!obj) continue;
- Object.keys(obj).forEach((key) => {
- const val = obj[key];
+ Object.keys(obj).forEach(key => {
+ const val = obj[key];
- if (isDeep) {
- if (Array.isArray(val)) {
- result[key] = [].concat(Array.isArray(result[key]) ? result[key] : [result[key]], val);
- } else if (typeof val === 'object') {
- result[key] = merge(result[key], val);
- } else {
- result[key] = val;
- }
- } else {
- result[key] = typeof val === 'boolean' ? val : result[key];
- }
- });
- }
+ if (isDeep) {
+ if (Array.isArray(val)) {
+ result[key] = [].concat(Array.isArray(result[key]) ? result[key] : [result[key]], val);
+ } else if (typeof val === "object") {
+ result[key] = merge(result[key], val);
+ } else {
+ result[key] = val;
+ }
+ } else {
+ result[key] = typeof val === "boolean" ? val : result[key];
+ }
+ });
+ }
- return result;
+ return result;
}
/**
@@ -217,16 +216,16 @@ export function merge(...objects) {
* @see https://www.lodashjs.com/docs/lodash.groupBy#_groupbycollection-iteratee_identity
*/
export function groupBy(array = [], callback) {
- return array.reduce((groups, item) => {
- const key = typeof callback === 'function' ? callback(item) : item[callback];
+ return array.reduce((groups, item) => {
+ const key = typeof callback === "function" ? callback(item) : item[callback];
- if (!groups[key]) {
- groups[key] = [];
- }
+ if (!groups[key]) {
+ groups[key] = [];
+ }
- groups[key].push(item);
- return groups;
- }, {});
+ groups[key].push(item);
+ return groups;
+ }, {});
}
/**
@@ -235,12 +234,12 @@ export function groupBy(array = [], callback) {
* @param {array} keys
*/
export function pick(object, keys) {
- return keys.reduce((obj, key) => {
- if (object && Object.prototype.hasOwnProperty.call(object, key)) {
- obj[key] = object[key];
- }
- return obj;
- }, {});
+ return keys.reduce((obj, key) => {
+ if (object && Object.prototype.hasOwnProperty.call(object, key)) {
+ obj[key] = object[key];
+ }
+ return obj;
+ }, {});
}
/**
@@ -250,44 +249,44 @@ export function pick(object, keys) {
* @returns
*/
export function omit(object, keysToOmit) {
- return Object.fromEntries(Object.entries(object).filter(([key]) => !keysToOmit.includes(key)));
+ return Object.fromEntries(Object.entries(object).filter(([key]) => !keysToOmit.includes(key)));
}
/**
* 深拷贝
*/
export function cloneDeep(value) {
- // return structuredClone(value);
- if (typeof value !== 'object' || value === null) {
- return value;
- }
+ // return structuredClone(value);
+ if (typeof value !== "object" || value === null) {
+ return value;
+ }
- const result = Array.isArray(value) ? [] : {};
+ const result = Array.isArray(value) ? [] : {};
- for (const key in value) {
- if (Object.prototype.hasOwnProperty.call(value, key)) {
- result[key] = cloneDeep(value[key]);
- }
- }
+ for (const key in value) {
+ if (Object.prototype.hasOwnProperty.call(value, key)) {
+ result[key] = cloneDeep(value[key]);
+ }
+ }
- return result;
+ return result;
}
/**
* 向零四舍五入, 固定精度设置
*/
function curriedFix(precision = 0) {
- return function (number) {
- // Shift number by precision places
- const shift = Math.pow(10, precision);
- const shiftedNumber = number * shift;
+ return function (number) {
+ // Shift number by precision places
+ const shift = Math.pow(10, precision);
+ const shiftedNumber = number * shift;
- // Round to nearest integer
- const roundedNumber = Math.round(shiftedNumber);
+ // Round to nearest integer
+ const roundedNumber = Math.round(shiftedNumber);
- // Shift back decimal place
- return roundedNumber / shift;
- };
+ // Shift back decimal place
+ return roundedNumber / shift;
+ };
}
/**
* 向零四舍五入, 保留2位小数
@@ -313,106 +312,106 @@ export const fixToInt = curriedFix(0);
*
*/
export function objectMapper(input, keyMap) {
- // Loop through array mapping
- if (Array.isArray(input)) {
- return input.map((obj) => objectMapper(obj, keyMap));
- }
-
- if (typeof input === 'object') {
- const mappedObj = {};
-
- Object.keys(input).forEach((key) => {
- // Keep original keys not in keyMap
- if (!keyMap[key]) {
- mappedObj[key] = input[key];
- }
- // Handle array of maps
- if (Array.isArray(keyMap[key])) {
- keyMap[key].forEach((map) => {
- let value = input[key];
- if (map.transform) value = map.transform(value);
- mappedObj[map.key] = value;
- });
-
- // Handle single map
- } else {
- const map = keyMap[key];
- if (map) {
- let value = input[key];
- if (map.transform) value = map.transform(value);
- mappedObj[map.key || map] = value;
- }
- }
- });
-
- return mappedObj;
- }
-
- return input;
+ // Loop through array mapping
+ if (Array.isArray(input)) {
+ return input.map(obj => objectMapper(obj, keyMap));
+ }
+
+ if (typeof input === "object") {
+ const mappedObj = {};
+
+ Object.keys(input).forEach(key => {
+ // Keep original keys not in keyMap
+ if (!keyMap[key]) {
+ mappedObj[key] = input[key];
+ }
+ // Handle array of maps
+ if (Array.isArray(keyMap[key])) {
+ keyMap[key].forEach(map => {
+ let value = input[key];
+ if (map.transform) value = map.transform(value);
+ mappedObj[map.key] = value;
+ });
+
+ // Handle single map
+ } else {
+ const map = keyMap[key];
+ if (map) {
+ let value = input[key];
+ if (map.transform) value = map.transform(value);
+ mappedObj[map.key || map] = value;
+ }
+ }
+ });
+
+ return mappedObj;
+ }
+
+ return input;
}
/**
* 创建一个对应于对象路径的值数组
*/
export function at(obj, path) {
- let result;
- if (Array.isArray(obj)) {
- // array case
- const indexes = path.split('.').map((i) => parseInt(i));
- result = [];
- for (let i = 0; i < indexes.length; i++) {
- result.push(obj[indexes[i]]);
- }
- } else {
- // object case
- const indexes = path.split('.').map((i) => i);
- result = [obj];
- for (let i = 0; i < indexes.length; i++) {
- result = [result[0][indexes[i]]];
- }
- }
- return result;
+ let result;
+ if (Array.isArray(obj)) {
+ // array case
+ const indexes = path.split(".").map(i => parseInt(i));
+ result = [];
+ for (let i = 0; i < indexes.length; i++) {
+ result.push(obj[indexes[i]]);
+ }
+ } else {
+ // object case
+ const indexes = path.split(".").map(i => i);
+ result = [obj];
+ for (let i = 0; i < indexes.length; i++) {
+ result = [result[0][indexes[i]]];
+ }
+ }
+ return result;
}
/**
* 删除 null/undefined
*/
export function flush(collection) {
- let result, len, i;
- if (!collection) {
- return undefined;
- }
- if (Array.isArray(collection)) {
- result = [];
- len = collection.length;
- for (i = 0; i < len; i++) {
- const elem = collection[i];
- if (elem != null) {
- result.push(elem);
- }
- }
- return result;
- }
- if (typeof collection === 'object') {
- result = {};
- const keys = Object.keys(collection);
- len = keys.length;
- for (i = 0; i < len; i++) {
- const key = keys[i];
- const value = collection[key];
- if (value != null) {
- result[key] = value;
- }
- }
- return result;
- }
- return undefined;
+ let result, len, i;
+ if (!collection) {
+ return undefined;
+ }
+ if (Array.isArray(collection)) {
+ result = [];
+ len = collection.length;
+ for (i = 0; i < len; i++) {
+ const elem = collection[i];
+ if (elem != null) {
+ result.push(elem);
+ }
+ }
+ return result;
+ }
+ if (typeof collection === "object") {
+ result = {};
+ const keys = Object.keys(collection);
+ len = keys.length;
+ for (i = 0; i < len; i++) {
+ const key = keys[i];
+ const value = collection[key];
+ if (value != null) {
+ result[key] = value;
+ }
+ }
+ return result;
+ }
+ return undefined;
}
/**
* 千分位 格式化数字
*/
-export const numberFormatter = (number) => {
- return new Intl.NumberFormat().format(number);
+export const numberFormatter = number => {
+ return new Intl.NumberFormat().format(number);
};
/**
@@ -422,193 +421,195 @@ export const numberFormatter = (number) => {
* getNestedValue(obj, keyArr); // Returns: 'c'
*/
export const getNestedValue = (obj, keyArr) => {
- return keyArr.reduce((acc, curr) => {
- return acc && Object.prototype.hasOwnProperty.call(acc, curr) ? acc[curr] : undefined;
- // return acc && acc[curr];
- }, obj);
+ return keyArr.reduce((acc, curr) => {
+ return acc && Object.prototype.hasOwnProperty.call(acc, curr) ? acc[curr] : undefined;
+ // return acc && acc[curr];
+ }, obj);
};
/**
* 计算笛卡尔积
*/
-export const cartesianProductArray = (arr, sep = '_', index = 0, prefix = '') => {
- let result = [];
- if (index === arr.length) {
- return [prefix];
- }
- arr[index].forEach((item) => {
- result = result.concat(cartesianProductArray(arr, sep, index + 1, prefix ? `${prefix}${sep}${item}` : `${item}`));
- });
- return result;
+export const cartesianProductArray = (arr, sep = "_", index = 0, prefix = "") => {
+ let result = [];
+ if (index === arr.length) {
+ return [prefix];
+ }
+ arr[index].forEach(item => {
+ result = result.concat(cartesianProductArray(arr, sep, index + 1, prefix ? `${prefix}${sep}${item}` : `${item}`));
+ });
+ return result;
};
-export const stringToColour = (str) => {
- var hash = 0
- for (let i = 0; i < str.length; i++) {
- hash = str.charCodeAt(i) + ((hash << 5) - hash)
- }
- var colour = '#'
- for (let i = 0; i < 3; i++) {
- var value = (hash >> (i * 8)) & 0xff
- value = (value % 150) + 50
- colour += ('00' + value.toString(16)).substr(-2)
- }
- return colour
-}
+export const stringToColour = str => {
+ var hash = 0;
+ for (let i = 0; i < str.length; i++) {
+ hash = str.charCodeAt(i) + ((hash << 5) - hash);
+ }
+ var colour = "#";
+ for (let i = 0; i < 3; i++) {
+ var value = (hash >> (i * 8)) & 0xff;
+ value = (value % 150) + 50;
+ colour += ("00" + value.toString(16)).substr(-2);
+ }
+ return colour;
+};
export const debounce = (func, wait, immediate) => {
- var timeout;
- return function () {
- var context = this,
- args = arguments;
- clearTimeout(timeout);
- if (immediate && !timeout) func.apply(context, args);
- timeout = setTimeout(function () {
- timeout = null;
- if (!immediate) func.apply(context, args);
- }, wait);
- };
-}
+ var timeout;
+ return function () {
+ var context = this,
+ args = arguments;
+ clearTimeout(timeout);
+ if (immediate && !timeout) func.apply(context, args);
+ timeout = setTimeout(function () {
+ timeout = null;
+ if (!immediate) func.apply(context, args);
+ }, wait);
+ };
+};
-export const removeFormattingChars = (str) => {
- const regex = /[\r\n\t\v\f]/g;
- str = str.replace(regex, ' ');
- // Replace more than four consecutive spaces with a single space
- str = str.replace(/\s{4,}/g, ' ');
- return str;
-}
+export const removeFormattingChars = str => {
+ const regex = /[\r\n\t\v\f]/g;
+ str = str.replace(regex, " ");
+ // Replace more than four consecutive spaces with a single space
+ str = str.replace(/\s{4,}/g, " ");
+ return str;
+};
export const olog = (text, ...args) => {
- console.log(
- `%c ${text} `,
- 'background:#fb923c ; padding: 1px; border-radius: 3px; color: #fff',...args
- );
+ console.log(`%c ${text} `, "background:#fb923c ; padding: 1px; border-radius: 3px; color: #fff", ...args);
};
-export const sanitizeFilename = (str) => {
- // Remove whitespace and replace with hyphens
- str = str.replace(/\s+/g, '-');
- // Remove invalid characters and replace with hyphens
- str = str.replace(/[^a-zA-Z0-9.-]/g, '-');
- // Replace consecutive hyphens with a single hyphen
- str = str.replace(/-+/g, '-');
- // Trim leading and trailing hyphens
- str = str.replace(/^-+|-+$/g, '');
- return str;
-}
+export const sanitizeFilename = str => {
+ // Remove whitespace and replace with hyphens
+ str = str.replace(/\s+/g, "-");
+ // Remove invalid characters and replace with hyphens
+ str = str.replace(/[^a-zA-Z0-9.-]/g, "-");
+ // Replace consecutive hyphens with a single hyphen
+ str = str.replace(/-+/g, "-");
+ // Trim leading and trailing hyphens
+ str = str.replace(/^-+|-+$/g, "");
+ return str;
+};
export const formatBytes = (bytes, decimals = 2) => {
- if (bytes === 0) return '';
+ if (bytes === 0) return "";
- const k = 1024;
- const dm = decimals < 0 ? 0 : decimals;
- const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
+ const k = 1024;
+ const dm = decimals < 0 ? 0 : decimals;
+ const sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
- const i = Math.floor(Math.log(bytes) / Math.log(k));
- return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + " " + sizes[i];
};
export const calcCacheSizes = async () => {
- try {
- let swCacheSize = 0;
- let diskCacheSize = 0;
- let indexedDBSize = 0;
-
- // 1. Get the service worker cache size
- if ('caches' in window) {
- const cacheNames = await caches.keys();
- for (const name of cacheNames) {
- const cache = await caches.open(name);
- const requests = await cache.keys();
- for (const request of requests) {
- const response = await cache.match(request);
- swCacheSize += Number(response.headers.get('Content-Length')) || 0;
- }
- }
- }
-
- // 2. Get the disk cache size
- // const diskCacheName = 'disk-cache';
- // const diskCache = await caches.open(diskCacheName);
- // const diskCacheKeys = await diskCache.keys();
- // for (const request of diskCacheKeys) {
- // const response = await diskCache.match(request);
- // diskCacheSize += Number(response.headers.get('Content-Length')) || 0;
- // }
-
- // 3. Get the IndexedDB cache size
- // const indexedDBNames = await window.indexedDB.databases();
- // for (const dbName of indexedDBNames) {
- // const db = await window.indexedDB.open(dbName.name);
- // const objectStoreNames = db.objectStoreNames;
-
- // if (objectStoreNames !== undefined) {
- // const objectStores = Array.from(objectStoreNames).map((storeName) => db.transaction([storeName], 'readonly').objectStore(storeName));
-
- // for (const objectStore of objectStores) {
- // const request = objectStore.count();
- // request.onsuccess = () => {
- // indexedDBSize += request.result;
- // };
- // }
- // }
- // }
-
- return { swCacheSize, diskCacheSize, indexedDBSize, totalSize: Number(swCacheSize) + Number(diskCacheSize) + indexedDBSize };
- } catch (error) {
- console.error('Error getting cache sizes:', error);
- }
+ try {
+ let swCacheSize = 0;
+ let diskCacheSize = 0;
+ let indexedDBSize = 0;
+
+ // 1. Get the service worker cache size
+ if ("caches" in window) {
+ const cacheNames = await caches.keys();
+ for (const name of cacheNames) {
+ const cache = await caches.open(name);
+ const requests = await cache.keys();
+ for (const request of requests) {
+ const response = await cache.match(request);
+ swCacheSize += Number(response.headers.get("Content-Length")) || 0;
+ }
+ }
+ }
+
+ // 2. Get the disk cache size
+ // const diskCacheName = 'disk-cache';
+ // const diskCache = await caches.open(diskCacheName);
+ // const diskCacheKeys = await diskCache.keys();
+ // for (const request of diskCacheKeys) {
+ // const response = await diskCache.match(request);
+ // diskCacheSize += Number(response.headers.get('Content-Length')) || 0;
+ // }
+
+ // 3. Get the IndexedDB cache size
+ // const indexedDBNames = await window.indexedDB.databases();
+ // for (const dbName of indexedDBNames) {
+ // const db = await window.indexedDB.open(dbName.name);
+ // const objectStoreNames = db.objectStoreNames;
+
+ // if (objectStoreNames !== undefined) {
+ // const objectStores = Array.from(objectStoreNames).map((storeName) => db.transaction([storeName], 'readonly').objectStore(storeName));
+
+ // for (const objectStore of objectStores) {
+ // const request = objectStore.count();
+ // request.onsuccess = () => {
+ // indexedDBSize += request.result;
+ // };
+ // }
+ // }
+ // }
+
+ return { swCacheSize, diskCacheSize, indexedDBSize, totalSize: Number(swCacheSize) + Number(diskCacheSize) + indexedDBSize };
+ } catch (error) {
+ console.error("Error getting cache sizes:", error);
+ }
};
-export const clearAllCaches = async (cb) => {
- try {
- // 1. Clear the service worker cache
- if ('caches' in window) {
- // if (navigator.serviceWorker) {
- const cacheNames = await caches.keys();
- await Promise.all(cacheNames.map((name) => caches.delete(name)));
- }
-
- // 2. Clear the disk cache (HTTP cache)
- // const diskCacheName = 'disk-cache';
- // await window.caches.delete(diskCacheName);
- // const diskCache = await window.caches.open(diskCacheName);
- // const diskCacheKeys = await diskCache.keys();
- // await Promise.all(diskCacheKeys.map((request) => diskCache.delete(request)));
-
- // 3. Clear the IndexedDB cache
- const indexedDBNames = await window.indexedDB.databases();
- await Promise.all(indexedDBNames.map((dbName) => window.indexedDB.deleteDatabase(dbName.name)));
-
- // Unregister the service worker
- const registration = await navigator.serviceWorker.getRegistration();
- if (registration) {
- await registration.unregister();
- console.log('Service worker unregistered');
- } else {
- console.log('No service worker registered');
- }
- if (typeof cb === 'function' ) {
- cb();
- }
-
- } catch (error) {
- console.error('Error clearing caches or unregistering service worker:', error);
- }
+export const clearAllCaches = async cb => {
+ try {
+ // 1. Clear the service worker cache
+ if ("caches" in window) {
+ // if (navigator.serviceWorker) {
+ const cacheNames = await caches.keys();
+ await Promise.all(cacheNames.map(name => caches.delete(name)));
+ }
+
+ // 2. Clear the disk cache (HTTP cache)
+ // const diskCacheName = 'disk-cache';
+ // await window.caches.delete(diskCacheName);
+ // const diskCache = await window.caches.open(diskCacheName);
+ // const diskCacheKeys = await diskCache.keys();
+ // await Promise.all(diskCacheKeys.map((request) => diskCache.delete(request)));
+
+ // 3. Clear the IndexedDB cache
+ const indexedDBNames = await window.indexedDB.databases();
+ await Promise.all(indexedDBNames.map(dbName => window.indexedDB.deleteDatabase(dbName.name)));
+
+ // Unregister the service worker
+ const registration = await navigator.serviceWorker.getRegistration();
+ if (registration) {
+ await registration.unregister();
+ console.log("Service worker unregistered");
+ } else {
+ console.log("No service worker registered");
+ }
+ if (typeof cb === "function") {
+ cb();
+ }
+ } catch (error) {
+ console.error("Error clearing caches or unregistering service worker:", error);
+ }
};
-export const loadScript = (src) => {
- return new Promise((resolve, reject) => {
- const script = document.createElement('script');
- script.type = 'text/javascript';
- script.onload = resolve;
- script.onerror = reject;
- script.crossOrigin = 'anonymous';
- script.src = src;
- if (document.head.append) {
- document.head.append(script);
- } else {
- document.getElementsByTagName('head')[0].appendChild(script);
- }
- });
+export const loadScript = src => {
+ return new Promise((resolve, reject) => {
+ const script = document.createElement("script");
+ script.type = "text/javascript";
+ script.onload = resolve;
+ script.onerror = reject;
+ script.crossOrigin = "anonymous";
+ script.src = src;
+ if (document.head.append) {
+ document.head.append(script);
+ } else {
+ document.getElementsByTagName("head")[0].appendChild(script);
+ }
+ });
};
+//格式化为冒号时间,2010转为20:10
+export const formatColonTime = text => {
+ const hours = text.substring(0, 2);
+ const minutes = text.substring(2);
+ return `${hours}:${minutes}`;
+};
diff --git a/src/utils/request.js b/src/utils/request.js
index 68d80a6..ac97803 100644
--- a/src/utils/request.js
+++ b/src/utils/request.js
@@ -106,6 +106,7 @@ export function postForm(url, data) {
}
}).then(checkStatus)
.then(response => response.json())
+ .then(checkBizCode)
.catch(error => {
throw error
})
diff --git a/src/views/App.jsx b/src/views/App.jsx
index cbb2949..190067b 100644
--- a/src/views/App.jsx
+++ b/src/views/App.jsx
@@ -28,7 +28,7 @@ function App() {
const [validateUserPassword, tokenTimeout] = useAuthStore(
(state) => [state.validateUserPassword, state.tokenTimeout])
- const { loginToken, userDetail } = usingStorage()
+ const { loginToken, userDetail, userId } = usingStorage()
const noticeUnRead = useNoticeStore((state) => state.noticeUnRead)
const href = useHref()
@@ -40,6 +40,7 @@ function App() {
if (!needToLogin) {
appendRequestParams('token', loginToken)
+ appendRequestParams('wu_id', userId)
}
useEffect(() => {
@@ -150,9 +151,9 @@ function App() {
{ label: {t('ChangePassword')}, key: '0' },
{ label: {t('Profile')}, key: '1' },
{ label: {t('account:management.tile')}, key: '3' },
+ { label: {t('account:management.roleList')}, key: '4' },
{ type: 'divider' },
- { label: {t('Logout')}, key: '4' },
- { label: {t('ChangeVendor')}, key: 'change-vendor' },
+ { label: {t('Logout')}, key: '99' },
],
{ type: 'divider' },
{ label: <>v{BUILD_VERSION}>, key: 'BUILD_VERSION' },
diff --git a/src/views/account/Management.jsx b/src/views/account/Management.jsx
index 4f028ea..6c2c323 100644
--- a/src/views/account/Management.jsx
+++ b/src/views/account/Management.jsx
@@ -3,72 +3,18 @@ import { Row, Col, Space, Button, Table, Select, TreeSelect, Typography, Modal,
import { ExclamationCircleFilled } from '@ant-design/icons'
import { useTranslation } from 'react-i18next'
import useFormStore from '@/stores/Form'
-import useReservationStore from '@/stores/Reservation'
+import useAuthStore from '@/stores/Auth'
+import useAccountStore from '@/stores/Account'
+import { fetchRoleList } from '@/stores/Account'
import SearchForm from '@/components/SearchForm'
+import RequireAuth from '@/components/RequireAuth'
+import { PERM_ROLE_NEW } from '@/config'
const { Title } = Typography
-const permissionData = [
- {
- title: '机票管理',
- value: '0-0',
- key: '0-0',
- children: [
- {
- title: '录入机票价格',
- value: '0-0-0',
- key: '0-0-0',
- },
- ],
- },
- {
- title: '产品管理',
- value: '0-1',
- key: '0-1',
- children: [
- {
- title: '录入产品价格',
- value: '0-1-0',
- key: '0-1-0',
- },
- {
- title: '新增产品描述',
- value: '0-1-1',
- key: '0-1-1',
- },
- {
- title: '复制供应商产品信息',
- value: '0-1-2',
- key: '0-1-2',
- },
- ],
- },
- {
- title: '账号管理',
- value: '2-1',
- key: '2-1',
- children: [
- {
- title: '重置账号密码',
- value: '2-1-0',
- key: '2-1-0',
- },
- {
- title: '禁用账号',
- value: '2-1-1',
- key: '2-1-1',
- },
- {
- title: '分配账号角色',
- value: '2-1-2',
- key: '2-1-2',
- },
- ],
- },
-];
-
function Management() {
const { t } = useTranslation()
+
const accountListColumns = [
{
title: t('account:username'),
@@ -79,14 +25,17 @@ function Management() {
title: t('account:realname'),
dataIndex: 'realname',
},
+ {
+ title: t('account:travelAgency'),
+ dataIndex: 'travelAgency',
+ },
{
title: t('account:email'),
dataIndex: 'email',
},
{
title: t('account:role'),
- dataIndex: 'role',
- render: roleRender
+ dataIndex: 'role'
},
{
title: t('account:lastLogin'),
@@ -99,139 +48,95 @@ function Management() {
},
]
- function accountRender(text) {
- return (
-
- )
- }
-
- function roleRender(text) {
+ function accountRender(text, account) {
return (
-
+
)
}
- function actionRender() {
+ function actionRender(text, account) {
return (
-
-
+
+
)
}
- const onPermissionChange = (newValue) => {
- console.log('onChange ', newValue);
- setPermissionValue(newValue);
- }
-
- const [permissionValue, setPermissionValue] = useState(['0-0-0'])
const [isAccountModalOpen, setAccountModalOpen] = useState(false)
- const [isRoleModalOpen, setRoleModalOpen] = useState(false)
const [dataLoading, setDataLoading] = useState(false)
- const [accountList, setaccountList] = useState([
- {
- key: 1,
- username: 'bjyiran',
- realname: '怡小芳',
- email: 'xiaofang@yiran.com',
- role: '国内供应商',
- lastLogin: '2024-06-12 13:53'
- },
- {
- key: 2,
- username: 'int-robin',
- realname: 'Robin',
- email: 'robin@int.com',
- role: '海外供应商',
- lastLogin: '2024-06-12 13:53'
- },
- {
- key: 3,
- username: 'betty-wu',
- realname: '吴雪',
- email: 'betty@hainatravel.com',
- role: '客服组',
- lastLogin: '2024-06-12 13:53'
- },
- {
- key: 4,
- username: 'lancy',
- realname: '吴金倩',
- email: 'lancy@hainatravel.com',
- role: '产品组',
- lastLogin: '2024-06-12 13:53'
- },
- {
- key: 5,
- username: 'LYJ',
- realname: '廖一军',
- email: 'lyj@hainatravel.com',
- role: 'Web 开发组,海外测试供应商',
- lastLogin: '2024-06-12 13:53'
- }
- ])
-
- const formValuesToSub = useFormStore((state) => state.formValuesToSub)
+ const [roleAllList, setRoleAllList] = useState([])
- const [editAccountForm, editRoleForm] = Form.useForm()
- const [fetchReservationList] =
- useReservationStore((state) =>
- [state.fetchAllGuideList, state.fetchReservationList, state.reservationList, state.reservationPage, state.cityList, state.selectReservation, state.getCityListByReservationId])
+ const [accountForm] = Form.useForm()
+ const [searchAccountByCriteria, accountList, disableAccount, saveOrUpdateAccount, resetAccountPassword] =
+ useAccountStore((state) =>
+ [state.searchAccountByCriteria, state.accountList, state.disableAccount, state.saveOrUpdateAccount, state.resetAccountPassword])
const { notification, modal } = App.useApp()
- const handleAccountOk = () => {
+ const onAccountSeleted = async (account) => {
+ accountForm.setFieldsValue(account)
+ const roleList = await fetchRoleList()
+ setRoleAllList(roleList.map(r => {
+ return {
+ value: r.role_id,
+ label: r.role_name,
+ disabled: r.role_id === 1
+ }
+ }))
+ setAccountModalOpen(true)
}
- const handleAccountCancel = () => {
- setAccountModalOpen(false)
- }
-
- const handleRoleOk = () => {
- }
-
- const handleRoleCancel = () => {
- setRoleModalOpen(false)
- }
-
- const onFinish = (values) => {
+ const onAccountFinish = (values) => {
console.log(values)
+ saveOrUpdateAccount(values)
+ .catch(ex => {
+ notification.error({
+ message: 'Notification',
+ description: ex.message,
+ placement: 'top',
+ duration: 4,
+ })
+ })
}
- const onFinishFailed = (error) => {
+ const onAccountFailed = (error) => {
console.log('Failed:', error)
// form.resetFields()
}
- // 默认重新搜索第一页,所有状态的计划
- const onSearchClick = (current = 1, status = null) => {
- }
-
- const showDisableConfirm = () => {
+ const showDisableConfirm = (account) => {
modal.confirm({
title: 'Do you want to disable this account?',
icon: ,
- content: 'Username: Ivy, Realname: 怡小芳',
+ content: `Username: ${account.username}, Realname: ${account.realname}`,
onOk() {
- console.log('OK')
+ disableAccount(account.userId)
},
onCancel() {
- console.log('Cancel')
},
})
}
- const showResetPasswordConfirm = () => {
+ const showResetPasswordConfirm = (account) => {
+ const randomPassword = account.username + (Math.floor(Math.random() * 900) + 100)
modal.confirm({
title: 'Do you want to reset password?',
icon: ,
- content: 'Username: Ivy, Realname: 怡小芳',
+ content: `Username: ${account.username}, Realname: ${account.realname}`,
onOk() {
- console.log('OK')
+ resetAccountPassword(account.userId, randomPassword)
+ .then(() => {
+ notification.info({
+ message: '新密码:' + randomPassword,
+ description: `请复制密码给 [${account.realname}]`,
+ placement: 'top',
+ duration: 60,
+ })
+ })
+ console.log('ResetPassword')
},
onCancel() {
- console.log('Cancel')
},
})
}
@@ -240,137 +145,109 @@ function Management() {
<>
- {t('account:management.newAccount')}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {/* Role Edit */}
-
+ )}
>
-
+
+
+
- {t('account:management.newRole')}
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{t('account:management.tile')}
{
+ onSubmit={(err, formValues, filedsVal) => {
+ console.info(formValues)
setDataLoading(true)
- fetchReservationList(formVal)
+ searchAccountByCriteria(formValues)
.catch(ex => {
notification.error({
message: 'Notification',
@@ -388,7 +265,6 @@ function Management() {
-
@@ -397,6 +273,7 @@ function Management() {
1) {
+ return (
+
+ )
+ }
+ }
+
+ const onPermissionChange = (newValue) => {
+ console.log('onChange ', newValue)
+ setPermissionValue(newValue)
+ }
+
+ useEffect (() => {
+ setDataLoading(true)
+ fetchRoleList()
+ .then(r => {
+ setRoleAllList(r)
+ })
+ .finally(() => {
+ setDataLoading(false)
+ })
+ }, [])
+
+ const [permissionValue, setPermissionValue] = useState(['0-0-0'])
+ const [isRoleModalOpen, setRoleModalOpen] = useState(false)
+ const [dataLoading, setDataLoading] = useState(false)
+ const [roleAllList, setRoleAllList] = useState([])
+
+ const [roleForm] = Form.useForm()
+ const [saveOrUpdateRole, newRole] =
+ useAccountStore((state) =>
+ [state.saveOrUpdateRole, state.newRole])
+
+ const { notification, modal } = App.useApp()
+
+ const onRoleSeleted = (role) => {
+ roleForm.setFieldsValue(role)
+ setRoleModalOpen(true)
+ }
+
+ const onNewRole = () => {
+ const role = newRole()
+ roleForm.setFieldsValue(role)
+ setRoleModalOpen(true)
+ }
+
+ const onRoleFinish = (values) => {
+ console.log(values)
+ saveOrUpdateRole(values)
+ .catch(ex => {
+ console.info(ex.message)
+ notification.error({
+ message: 'Notification',
+ description: ex.message,
+ placement: 'top',
+ duration: 4,
+ })
+ })
+ }
+
+ const onRoleFailed = (error) => {
+ console.log('Failed:', error)
+ // form.resetFields()
+ }
+
+ return (
+ <>
+ setRoleModalOpen(false)} onCancel={() => setRoleModalOpen(false)}
+ destroyOnClose={true}
+ clearOnDestroy={true}
+ modalRender={(dom) => (
+
+ )}
+ >
+
+
+
+
+
+
+
+
+
+ {t('account:management.roleList')}
+
+
+
+
+
+
+
+
+
+
+
+ { return t('Total') + `:${total}` }
+ }}
+ onChange={(pagination) => { onSearchClick(pagination.current) }}
+ columns={roleListColumns} dataSource={roleAllList}
+ />
+
+
+
+ >
+ )
+}
+
+export default RoleList
diff --git a/src/views/airticket/Index.jsx b/src/views/airticket/Index.jsx
index 06cbb02..32a84a5 100644
--- a/src/views/airticket/Index.jsx
+++ b/src/views/airticket/Index.jsx
@@ -1,8 +1,8 @@
import { useState, useEffect } from "react";
import { Grid, Divider, Layout, Spin, Input, Col, Row, Space, List, Table } from "antd";
import { PhoneOutlined, CustomerServiceOutlined, AudioOutlined } from "@ant-design/icons";
-import { useParams, useHref, useNavigate } from "react-router-dom";
-import { isEmpty } from "@/utils/commons";
+import { useParams, useHref, useNavigate, NavLink } from "react-router-dom";
+import { isEmpty, formatColonTime } from "@/utils/commons";
import dayjs from "dayjs";
import SearchForm from "@/components/SearchForm";
@@ -29,6 +29,11 @@ const planListColumns = [
title: "出发日期",
key: "StartDate",
dataIndex: "StartDate",
+ sorter: (a, b) => {
+ const dateA = new Date(a.StartDate);
+ const dateB = new Date(b.StartDate);
+ return dateB.getTime() - dateA.getTime();
+ },
},
{
title: "出发城市",
@@ -49,16 +54,25 @@ const planListColumns = [
title: "起飞时间",
key: "FlightTimeStart",
dataIndex: "FlightTimeStart",
+ render: text => formatColonTime(text),
},
{
title: "落地时间",
key: "FlightTimeEnd",
dataIndex: "FlightTimeEnd",
+ render: text => formatColonTime(text),
},
{
- title: "PNR 暂时用FlightInfo",
+ title: "是否出票",
+ key: "COLD_PlanVEI_SN",
+ dataIndex: "COLD_PlanVEI_SN",
+ render: (text, record) => "否",
+ },
+ {
+ title: "操作",
key: "FlightInfo",
dataIndex: "FlightInfo",
+ render: (text, record) => {"编辑"},
},
];
@@ -66,7 +80,7 @@ const Airticket = props => {
const href = useHref();
const navigate = useNavigate();
const { phonenumber } = useParams();
- const {travelAgencyId, } = usingStorage();
+ const { travelAgencyId } = usingStorage();
const [getPlanList, planList, loading] = airTicketStore(state => [state.getPlanList, state.planList, state.loading]);
const [phone_number, setPhone_number] = useState(phonenumber);
const showTotal = total => `合计 ${total} `;
@@ -82,14 +96,14 @@ const Airticket = props => {
dates: [dayjs().startOf("M"), dayjs().endOf("M")],
}}
fieldsConfig={{
- shows: ["referenceNo", "PNR", "dates"],
+ shows: ["referenceNo", "dates"],
fieldProps: {
referenceNo: { label: "搜索计划" },
dates: { label: "出发日期" },
},
}}
onSubmit={(err, formVal, filedsVal) => {
- getPlanList(travelAgencyId, formVal.referenceNo, formVal.PNR, formVal.startdate, formVal.endtime);
+ getPlanList(travelAgencyId, formVal.referenceNo, formVal.startdate, formVal.endtime);
}}
/>
diff --git a/src/views/airticket/Plan.jsx b/src/views/airticket/Plan.jsx
new file mode 100644
index 0000000..29ba956
--- /dev/null
+++ b/src/views/airticket/Plan.jsx
@@ -0,0 +1,196 @@
+import { useState, useEffect } from "react";
+import { Grid, Divider, Layout, Form, Input, Col, Row, Space, Collapse, Table, Button } from "antd";
+import { PhoneOutlined, CustomerServiceOutlined, AudioOutlined, ArrowUpOutlined, ArrowDownOutlined } from "@ant-design/icons";
+import { useParams, useHref, useNavigate, NavLink } from "react-router-dom";
+import { isEmpty, formatColonTime } from "@/utils/commons";
+import { OFFICEWEBVIEWERURL } from "@/config";
+
+import airTicketStore from "@/stores/Airticket";
+import { usingStorage } from "@/hooks/usingStorage";
+
+const AirticketPlan = props => {
+ const { coli_sn } = useParams();
+ const { travelAgencyId, loginToken } = usingStorage();
+ const [getPlanDetail, planDetail, getGuestList, guestList, loading] = airTicketStore(state => [state.getPlanDetail, state.planDetail, state.getGuestList, state.guestList, state.loading]);
+ const reservationUrl = `https://p9axztuwd7x8a7.mycht.cn/Service_BaseInfoWeb/FlightPlanDocx?GRI_SN=${coli_sn}&VEI_SN=${travelAgencyId}`;
+ const reservationPreviewUrl = OFFICEWEBVIEWERURL + encodeURIComponent(reservationUrl);
+
+ console.log(reservationPreviewUrl);
+
+ const Airticket_form = props => {
+ const aitInfo = props.airInfo;
+ return (
+ <>
+
+
+
+
+
+
+ } value={aitInfo.FromCity} />
+ } value={aitInfo.ToCity} />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/*
+
+ */}
+
+
+
+ >
+ );
+ };
+
+ const detail_items = () => {
+ return planDetail
+ ? planDetail.map(item => {
+ return {
+ key: item.id,
+ label: `${item.StartDate} 计划: ${item.FlightInfo}`,
+ children: ,
+ };
+ })
+ : [];
+ };
+
+ const guestListColumns = [
+ {
+ title: "姓名",
+ key: "MEI_Name",
+ dataIndex: "MEI_Name",
+ },
+ {
+ title: "证件类型",
+ key: "MEI_PassportType",
+ dataIndex: "MEI_PassportType",
+ },
+ {
+ title: "证件号",
+ key: "MEI_PassportNo",
+ dataIndex: "MEI_PassportNo",
+ },
+ {
+ title: "证件有效期",
+ key: "MEI_PassportValidDate",
+ dataIndex: "MEI_PassportValidDate",
+ },
+ {
+ title: "性别",
+ key: "MEI_Gender",
+ dataIndex: "MEI_Gender",
+ },
+ {
+ title: "年龄",
+ key: "MEI_age",
+ dataIndex: "MEI_age",
+ },
+ {
+ title: "国籍",
+ key: "MEI_Country",
+ dataIndex: "MEI_Country",
+ },
+ {
+ title: "票号",
+ key: "MEI_SN",
+ dataIndex: "MEI_SN",
+ },
+ {
+ title: "PNR",
+ key: "MEI_SN",
+ dataIndex: "MEI_SN",
+ },
+ {
+ title: "机票费用(RMB)含基建和税",
+ key: "MEI_SN",
+ dataIndex: "MEI_SN",
+ },
+ {
+ title: "折扣",
+ key: "MEI_SN",
+ dataIndex: "MEI_SN",
+ },
+ {
+ title: "手续费",
+ key: "MEI_SN",
+ dataIndex: "MEI_SN",
+ },
+ {
+ title: "机票类型(成人/儿童/婴儿)",
+ key: "MEI_SN",
+ dataIndex: "MEI_SN",
+ },
+ ];
+
+ useEffect(() => {
+ getPlanDetail(travelAgencyId, coli_sn);
+ getGuestList(travelAgencyId, coli_sn);
+ console.log(detail_items());
+ }, []);
+
+ return (
+
+
+
+ {/* */}
+
+
+ 出票信息
+
+
+
+
+
+ );
+};
+export default AirticketPlan;
diff --git a/src/views/invoice/Index.jsx b/src/views/invoice/Index.jsx
index 17a9603..559a718 100644
--- a/src/views/invoice/Index.jsx
+++ b/src/views/invoice/Index.jsx
@@ -1,6 +1,4 @@
import { NavLink, useNavigate } from "react-router-dom";
-import { useState } from "react";
-import { toJS } from "mobx";
import { Row, Col, Space, Button, Table, App, Steps } from "antd";
import { formatDate, isNotEmpty } from "@/utils/commons";
import { AuditOutlined, SmileOutlined, SolutionOutlined, EditOutlined } from "@ant-design/icons";
@@ -103,7 +101,7 @@ function Index() {
-
+
diff --git a/src/views/products/Audit.jsx b/src/views/products/Audit.jsx
index f4187a2..e055cc3 100644
--- a/src/views/products/Audit.jsx
+++ b/src/views/products/Audit.jsx
@@ -1,30 +1,182 @@
-import { createContext, useContext, useEffect, useState } from 'react';
-import { Button, Table, Tabs } from 'antd';
-import { useProductsTypes } from '@/hooks/useProductsSets';
+import { useEffect, useState } from 'react';
+import { useParams, } from 'react-router-dom';
+import { App, Button, Collapse, Table, Space, } from 'antd';
+import { useProductsTypes, useProductsAuditStatesMapVal } from '@/hooks/useProductsSets';
import SecondHeaderWrapper from '@/components/SecondHeaderWrapper';
+import { useTranslation } from 'react-i18next';
+import useProductsStore, { postProductsQuoteAudit } from '@/stores/Products/Index';
+import { isEmpty } from '@/utils/commons';
-const Header = () => {
+const Header = ({ title, agency, refresh, ...props}) => {
+ const { t } = useTranslation();
+ const [activeAgency, ] = useProductsStore((state) => [state.activeAgency, ]);
+ const { message, notification } = App.useApp();
+ const handleAuditItem = (state, row) => {
+ postProductsQuoteAudit(state, {id: row.id, travel_agency_id: activeAgency.travel_agency_id})
+ .then((json) => {
+ if (json.errcode === 0) {
+ message.success(json.errmsg);
+ if (typeof refresh === 'function') {
+ refresh();
+ }
+ }
+ })
+ .catch((ex) => {
+ notification.error({
+ message: 'Notification',
+ description: ex.message,
+ placement: 'top',
+ duration: 4,
+ });
+ });
+ };
return (
-
-
-
-
+
+
+
{title}
+
+ {/*
*/}
+ {/*
*/}
+
+ {/*
*/}
+
+ {/* todo: export */}
+
);
};
-const TypesTabs = () => {
+const PriceTable = ({dataSource,refresh}) => {
+ const { t } = useTranslation('products');
+ const [loading, activeAgency, ] = useProductsStore((state) => [state.loading, state.activeAgency, ]);
+ const { message, notification } = App.useApp();
+ const stateMapVal = useProductsAuditStatesMapVal();
+
+ const handleAuditPriceItem = (state, row) => {
+ postProductsQuoteAudit(state, {id: row.id, travel_agency_id: activeAgency.travel_agency_id})
+ .then((json) => {
+ if (json.errcode === 0) {
+ message.success(json.errmsg);
+ if (typeof refresh === 'function') {
+ refresh();
+ }
+ }
+ })
+ .catch((ex) => {
+ notification.error({
+ message: 'Notification',
+ description: ex.message,
+ placement: 'top',
+ duration: 4,
+ });
+ });
+ };
+
+ const columns = [
+ { key: 'title', dataIndex: ['info', 'title'], title: t('Title'), onCell: (r, index) => ({ rowSpan: r.rowSpan }) },
+ { key: 'adult', title: t('AgeType.Adult'), render: (_, { value, currency, unit_name }) => `${value} ${currency} / ${unit_name}` },
+ { key: 'child', title: t('AgeType.Child'), render: (_, { value, currency, unit_name }) => `${value} ${currency} / ${unit_name}` },
+ // {key: 'price', title: t('Currency'), },
+ // {key: 'currency', title: t('Currency'), },
+ // {key: 'unit', title: t('Unit'), },
+ {
+ key: 'groupSize',
+ dataIndex: ['group_size_min'],
+ title: t('GroupSize'),
+ render: (_, { group_size_min, group_size_max }) => `${group_size_min} - ${group_size_max}`,
+ },
+ {
+ key: 'useDates',
+ dataIndex: ['use_dates_start'],
+ title: t('UseDates'),
+ render: (_, { use_dates_start, use_dates_end }) => `${use_dates_start} ~ ${use_dates_end}`,
+ },
+ { key: 'weekdays', dataIndex: ['weekdays'], title: t('Weekdays') },
+ {
+ key: 'state',
+ title: t('State'),
+ render: (_, r) => {
+ return stateMapVal[`${r.audit_state_id}`]?.label;
+ },
+ },
+ {
+ title: '价格审核',
+ key: 'action',
+ render: (_, r) => r.audit_state_id <= 0 ?(
+
+
+
+
+ ) : null,
+ },
+ ];
+ return
r.id} />;
+}
+
+/**
+ *
+ */
+const TypesPanels = (props) => {
+ const [loading, agencyProducts, ] = useProductsStore((state) => [state.loading, state.agencyProducts]);
+ // console.log(agencyProducts);
const productsTypes = useProductsTypes();
+ const [activeKey, setActiveKey] = useState([]);
+ const [showTypes, setShowTypes] = useState([]);
+ useEffect(() => {
+ // 只显示有产品的类型; 展开产品的价格表, 合并名称列
+ const hasDataTypes = Object.keys(agencyProducts);
+ const _show = productsTypes
+ .filter((kk) => hasDataTypes.includes(kk.value))
+ .map((ele) => ({
+ ...ele,
+ children: (
+ r.concat(c.quotation.map((q, i) => ({ ...q, info: c.info, rowSpan: i === 0 ? c.quotation.length : 0 }))), [])}
+ refresh={props.refresh}
+ />
+ ),
+ }));
+ setShowTypes(_show);
+
+ setActiveKey(isEmpty(_show) ? [] : [_show[0].key]);
+
+ return () => {};
+ }, [productsTypes, agencyProducts]);
+
+ const onCollapseChange = (_activeKey) => {
+ setActiveKey(_activeKey)
+ }
return (
-
+
)
}
const Audit = ({ ...props }) => {
+ const { travel_agency_id, use_year, audit_state } = useParams();
+ const [activeAgency, getAgencyProducts] = useProductsStore((state) => [state.activeAgency, state.getAgencyProducts]);
+
+ const handleGetAgencyProducts = () => {
+ getAgencyProducts({ travel_agency_id, use_year, audit_state });
+ }
+
+ useEffect(() => {
+ handleGetAgencyProducts();
+
+ return () => {};
+ }, [travel_agency_id])
+
return (
<>
- }>
-
+ }>
+
+
>
);
diff --git a/src/views/products/Index.jsx b/src/views/products/Index.jsx
index b793b2f..d1b1495 100644
--- a/src/views/products/Index.jsx
+++ b/src/views/products/Index.jsx
@@ -1,22 +1,32 @@
-import { useEffect, useState } from 'react';
+import { useEffect } from 'react';
import { Link } from 'react-router-dom';
-import { Row, Col, Space, Typography, Table, Button } from 'antd';
-import useProductsStore from '@/stores/Products/Index';
-import { usingStorage } from '@/hooks/usingStorage';
+import { Row, Col, Space, Table } from 'antd';
import SearchForm from '@/components/SearchForm';
import dayjs from 'dayjs';
import { useTranslation } from 'react-i18next';
-import { useProductsTypes } from '@/hooks/useProductsSets';
+import useProductsStore from '@/stores/Products/Index';
+import useFormStore from '@/stores/Form';
+import { objectMapper } from '@/utils/commons';
function Index() {
const { t } = useTranslation();
- const { userId } = usingStorage();
- const [loading, productsList] = useProductsStore((state) => [state.loading, state.productsList]);
+ const [loading, agencyList, searchAgency] = useProductsStore((state) => [state.loading, state.agencyList, state.searchAgency]);
+ const [searchValues, setSearchValues] = useProductsStore((state) => [state.searchValues, state.setSearchValues]);
+ const formValuesToSub = useFormStore(state => state.formValuesToSub);
+
+ const handleSearchAgency = (formVal = undefined) => {
+ const { starttime, endtime, ...param } = formVal || formValuesToSub;
+ const searchParam = objectMapper(param, { agency: 'travel_agency_ids', startdate: 'edit_date1', enddate: 'edit_date2' });
+ setSearchValues(searchParam);
+ searchAgency(searchParam);
+ }
- const [noticeList, setNoticeList] = useState([]);
- useEffect(() => {}, []);
+ useEffect(() => {
+ // handleSearchAgency();
+ }, []);
+
+ const showTotal = (total) => t('Table.Total', { total });
- const showTotal = (total) => `Total ${total} items`;
const columns = [
{ title: t('products:Vendor'), key: 'vendor', dataIndex: 'travel_agency_name' },
{ title: t('products:CreatedBy'), key: 'created_by', dataIndex: 'created_by' },
@@ -29,8 +39,8 @@ function Index() {
key: 'action',
render: (_, r) => (
- {t('Edit')}
- {t('Audit')}
+ {t('Edit')}
+ {t('Audit')}
),
},
@@ -38,23 +48,37 @@ function Index() {
return (
{
+ handleSearchAgency(formVal);
}}
/>
-
+