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/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 a669294..979a6fc 100644
--- a/src/components/SearchForm.jsx
+++ b/src/components/SearchForm.jsx
@@ -208,6 +208,22 @@ function getFields(props) {
,
fieldProps?.dates?.col || midCol
),
+ item(
+ 'username',
+ 3,
+
+
+ ,
+ fieldProps?.username?.col || 4
+ ),
+ item(
+ 'realname',
+ 4,
+
+
+ ,
+ fieldProps?.realname?.col || 4
+ ),
/**
*
*/
diff --git a/src/config.js b/src/config.js
index 58e13a2..fc69f82 100644
--- a/src/config.js
+++ b/src/config.js
@@ -6,6 +6,28 @@ 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'
diff --git a/src/main.jsx b/src/main.jsx
index dae7d6e..d78954e 100644
--- a/src/main.jsx
+++ b/src/main.jsx
@@ -5,8 +5,6 @@ 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 +12,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,10 +30,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 Gysgl from "@/views/gysgl/Index"
+import { PERM_ACCOUNT_MANAGEMENT, PERM_ROLE_NEW, PERM_OVERSEA, PERM_AIR_TICKET } from '@/config'
+
import './i18n';
configure({
@@ -52,22 +57,24 @@ 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/:use_year/:audit_state/audit",element:},
{ path: "products/:travel_agency_id/:use_year/:audit_state/edit",element:},
@@ -83,15 +90,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 5511e6b..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
+ // })
},
@@ -155,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/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 928911d..b1eb9ca 100644
--- a/src/views/App.jsx
+++ b/src/views/App.jsx
@@ -152,8 +152,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('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;