Merge branch 'feature/price_manager' of github.com:hainatravel/GHHub into feature/price_manager

feature/price_manager
黄文强@HWQ-PC 1 year ago
commit 40e8d97aa8

@ -26,8 +26,9 @@
"Export": "Export", "Export": "Export",
"Copy": "Copy", "Copy": "Copy",
"sureCancel": "Sure you want to cancel?", "sureCancel": "Are you sure to cancel?",
"sureDelete":"Sure you want to delete?", "sureDelete":"Are you sure to delete?",
"Yes": "Yes",
"Success": "Success", "Success": "Success",
"Failed": "Failed", "Failed": "Failed",

@ -1,4 +1,5 @@
{ {
"ProductType": "Product Type",
"type": { "type": {
"Experience": "Experience", "Experience": "Experience",
"Car": "Transport Services", "Car": "Transport Services",
@ -7,8 +8,7 @@
"Attractions": "Attractions", "Attractions": "Attractions",
"Meals": "Meals", "Meals": "Meals",
"Extras": "Extras", "Extras": "Extras",
"Overtravel": "超公里", "UltraService": "Ultra Service"
"Special": "Special"
}, },
"EditComponents": { "EditComponents": {
"info": "Product Information", "info": "Product Information",
@ -29,6 +29,11 @@
"Rejected": "Reject", "Rejected": "Reject",
"Published": "Publish" "Published": "Publish"
}, },
"PriceUnit": {
"0": "Person",
"1": "Group",
"title": "Price Unit"
},
"Status": "Status", "Status": "Status",
"State": "State", "State": "State",
@ -39,6 +44,13 @@
"CreateDate": "Create Date", "CreateDate": "Create Date",
"AuditedBy": "Audited By", "AuditedBy": "Audited By",
"AuditDate": "Audit Date", "AuditDate": "Audit Date",
"OpenHours": "Open Hours",
"Duration": "Duration",
"KM": "KM",
"RecommendsRate": "RecommendsRate",
"OpenWeekdays": "Open Weekdays",
"DisplayToC": "DisplayToC",
"Dept": "Dept",
"productProject": "Product project", "productProject": "Product project",
"Code": "Code", "Code": "Code",

@ -8,5 +8,24 @@
"CurrentPassword": "请输入密码。", "CurrentPassword": "请输入密码。",
"NewPassword": "请输入新密码。", "NewPassword": "请输入新密码。",
"ReenterPassword": "请重复输入密码。" "ReenterPassword": "请重复输入密码。"
} },
"createdOn": "创建时间",
"action": "操作",
"action.edit": "编辑",
"action.disable": "禁用",
"action.resetPassword": "重置密码",
"accountList": "管理账号",
"newAccount": "新增账号",
"detail": "详细信息",
"username": "用户名",
"realname": "姓名",
"travelAgencyName": "供应商名称",
"email": "邮箱地址",
"lastLogin": "最后登陆时间",
"roleList": "管理角色",
"newRole": "新增角色",
"roleName": "角色名称",
"permission": "权限"
} }

@ -28,6 +28,7 @@
"sureCancel": "确定取消?", "sureCancel": "确定取消?",
"sureDelete":"确定删除?", "sureDelete":"确定删除?",
"Yes": "是",
"Success": "成功", "Success": "成功",
"Failed": "失败", "Failed": "失败",
@ -62,13 +63,13 @@
"thisYear": "今年" "thisYear": "今年"
}, },
"weekdays": { "weekdays": {
"1": "一", "1": "一",
"2": "二", "2": "二",
"3": "三", "3": "三",
"4": "四", "4": "四",
"5": "五", "5": "五",
"6": "六", "6": "六",
"7": "日" "7": "日"
}, },
"weekdaysShort": { "weekdaysShort": {
"1": "一", "1": "一",

@ -1,14 +1,14 @@
{ {
"ProductType": "项目类型",
"type": { "type": {
"Experience": "综费", "Experience": "综费",
"Car": "车费", "Car": "车费",
"Guide": "导", "Guide": "导",
"Package": "包价线路", "Package": "包价线路",
"Attractions": "景点", "Attractions": "景点",
"Meals": "餐费", "Meals": "餐费",
"Extras": "附加项目", "Extras": "附加项目",
"Overtravel": "超公里", "UltraService": "超公里"
"Special": "特殊项目"
}, },
"EditComponents": { "EditComponents": {
"info": "产品信息", "info": "产品信息",
@ -29,6 +29,11 @@
"Rejected": "审核拒绝", "Rejected": "审核拒绝",
"Published": "审核发布" "Published": "审核发布"
}, },
"PriceUnit": {
"0": "每人",
"1": "每团",
"title": "报价单位"
},
"Status": "状态", "Status": "状态",
"State": "状态", "State": "状态",
@ -37,11 +42,18 @@
"AuState": "审核状态", "AuState": "审核状态",
"CreatedBy": "提交人员", "CreatedBy": "提交人员",
"CreateDate": "提交时间", "CreateDate": "提交时间",
"AuditedBy": "审核人员", "AuditedBy": "审核人员",
"AuditDate": "审核时间", "AuditDate": "审核时间",
"OpenHours": "游览时间",
"Duration": "游览时长",
"KM": "公里数",
"RecommendsRate": "推荐指数",
"OpenWeekdays": "周开放日",
"DisplayToC": "报价信显示",
"Dept": "小组",
"productProject": "产品项目", "productProject": "产品项目",
"Code": "简码", "Code": "简码",
"City": "城市", "City": "城市",
@ -71,7 +83,7 @@
"GroupSize": "人等", "GroupSize": "人等",
"UseDates": "使用日期", "UseDates": "使用日期",
"Weekdays": "有效日/周X", "Weekdays": "周末",
"OnWeekdays": "周: ", "OnWeekdays": "周: ",
"Unlimited": "不限", "Unlimited": "不限",

@ -3,7 +3,7 @@ import { Form, Input, Row, Col, Select, DatePicker, Space, Button } from 'antd';
import { objectMapper, at } from '@/utils/commons'; import { objectMapper, at } from '@/utils/commons';
import { DATE_FORMAT, SMALL_DATETIME_FORMAT } from '@/config'; import { DATE_FORMAT, SMALL_DATETIME_FORMAT } from '@/config';
import useFormStore from '@/stores/Form'; import useFormStore from '@/stores/Form';
import useDatePresets from '@/hooks/useDatePresets'; import {useDatePresets} from '@/hooks/useDatePresets';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { fetchJSON } from '@/utils/request'; import { fetchJSON } from '@/utils/request';
@ -209,7 +209,7 @@ function getFields(props) {
), ),
item( item(
'username', 'username',
3, 99,
<Form.Item name='username' label={t('account:username')} {...fieldProps.username}> <Form.Item name='username' label={t('account:username')} {...fieldProps.username}>
<Input placeholder={t('account:username')} allowClear /> <Input placeholder={t('account:username')} allowClear />
</Form.Item>, </Form.Item>,
@ -217,7 +217,7 @@ function getFields(props) {
), ),
item( item(
'realname', 'realname',
4, 99,
<Form.Item name='realname' label={t('account:realname')} {...fieldProps.realname}> <Form.Item name='realname' label={t('account:realname')} {...fieldProps.realname}>
<Input placeholder={t('account:realname')} allowClear /> <Input placeholder={t('account:realname')} allowClear />
</Form.Item>, </Form.Item>,

@ -1,8 +1,9 @@
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import dayjs from "dayjs"; import dayjs from "dayjs";
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import i18n from '@/i18n';
const useDatePresets = () => { export const useDatePresets = () => {
const [presets, setPresets] = useState([]); const [presets, setPresets] = useState([]);
const { t, i18n } = useTranslation(); const { t, i18n } = useTranslation();
@ -39,4 +40,21 @@ const useDatePresets = () => {
return presets; return presets;
} }
export default useDatePresets; export const useWeekdays = () => {
const [data, setData] = useState([]);
const { t, i18n } = useTranslation();
useEffect(() => {
const newData = [
{ value: '1', label: t('weekdays.1') },
{ value: '2', label: t('weekdays.2') },
{ value: '3', label: t('weekdays.3') },
{ value: '4', label: t('weekdays.4') },
{ value: '5', label: t('weekdays.5') },
{ value: '6', label: t('weekdays.6') },
{ value: '7', label: t('weekdays.7') },
];
setData(newData);
return () => {};
}, [i18n.language]);
return data;
};

@ -1,42 +1,44 @@
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import useAuthStore from '@/stores/Auth';
import { PERM_OVERSEA, PERM_AIR_TICKET, PERM_PRODUCTS_MANAGEMENT } from '@/config';
/** /**
* 产品管理 相关的预设数据 * 产品管理 相关的预设数据
* 项目类型 * 项目类型
酒店预定 1 * * 酒店预定 1
火车 2 * * 火车 2
飞机票务 3 * * 飞机票务 3
游船 4 * * 游船 4
快巴 5 * * 快巴 5
旅行社(综费) 6 * * 旅行社(综费) 6
景点 7 * * 景点 7
特殊项目 8 * * 特殊项目 8
其他 9 * * 其他 9
酒店 A * * 酒店 A
超公里 B * * 超公里 B
餐费 C * * 餐费 C
小包价 D * * 小包价 D
X * * X
购物 S * * 购物 S
R * * R (餐厅)
娱乐 E * * 娱乐 E
精华线路 T * * 精华线路 T
客人testimonial F * * 客人testimonial F
线路订单 O * * 线路订单 O
P * * P
信息 I * * 信息 I
国家 G * * 国家 G
城市 K * * 城市 K
图片 H * * 图片 H
地图 M * * 地图 M
包价线路 L * * 包价线路 L (已废弃)
节日节庆 V * * 节日节庆 V
火车站 N * * 火车站 N
手机租赁 Z * * 手机租赁 Z
* * webht 类型, 20240624 新增HT类型 * * ---- webht 类型, 20240624 新增HT类型 ----
Q 导游 * * 导游 Q
J 车费 * * 车费 J
*/ */
export const useProductsTypes = () => { export const useProductsTypes = () => {
@ -46,20 +48,24 @@ export const useProductsTypes = () => {
useEffect(() => { useEffect(() => {
const newData = [ const newData = [
{ label: t('products:type.Experience'), value: '6', key: '6' }, { label: t('products:type.Experience'), value: '6', key: '6' },
{ label: t('products:type.Overtravel'), value: 'B', key: 'B' }, { label: t('products:type.UltraService'), value: 'B', key: 'B' },
{ label: t('products:type.Car'), value: 'J', key: 'J' }, { label: t('products:type.Car'), value: 'J', key: 'J' },
{ label: t('products:type.Guide'), value: 'Q', key: 'Q' }, { label: t('products:type.Guide'), value: 'Q', key: 'Q' },
{ label: t('products:type.Package'), value: 'D', key: 'D' }, // 包价线路 { label: t('products:type.Package'), value: 'D', key: 'D' }, // 包价线路
{ label: t('products:type.Attractions'), value: '7', key: '7' }, { label: t('products:type.Attractions'), value: '7', key: '7' },
{ label: t('products:type.Meals'), value: 'C', key: 'C' }, { label: t('products:type.Meals'), value: 'R', key: 'R' },
{ label: t('products:type.Extras'), value: '8', key: '8' }, { label: t('products:type.Extras'), value: '8', key: '8' },
// { label: t('products:type.Special'), value: 'Special', key: 'Special' },
]; ];
setTypes(newData); setTypes(newData);
}, [i18n.language]); }, [i18n.language]);
return types; return types;
}; };
export const useProductsTypesMapVal = (value) => {
const stateSets = useProductsTypes();
const stateMapVal = stateSets.reduce((r, c) => ({ ...r, [`${c.value}`]: c }), {});
return stateMapVal;
};
export const useProductsAuditStates = () => { export const useProductsAuditStates = () => {
const [types, setTypes] = useState([]); const [types, setTypes] = useState([]);
@ -89,17 +95,26 @@ export const useProductsAuditStatesMapVal = (value) => {
/** /**
* @ignore * @ignore
*/ */
export const useProductsTypesFieldsets = (type, role) => { export const useProductsTypesFieldsets = (type) => {
const infoDefault = ['code', 'title']; const [isPermitted] = useAuthStore((state) => [state.isPermitted]);
const infoDefault = [['code'], ['title']];
const infoAdmin = ['remarks', 'dept', 'display_to_c']; const infoAdmin = ['remarks', 'dept', 'display_to_c'];
const infoTypesMap = { const infoTypesMap = {
'6': [], '6': [[],[]],
'B': ['city_id', 'km'], 'B': [['city_id', 'km'], []],
'J': ['description', 'city_id', 'recommends_rate', 'duration', 'display_to_c'], 'J': [['city_id', 'recommends_rate', 'duration', 'display_to_c'], ['description',]],
'Q': ['description', 'city_id', 'duration', ], 'Q': [['city_id', 'duration', ], ['description',]],
'D': ['description', 'city_id', 'recommends_rate','duration',], 'D': [['city_id', 'recommends_rate','duration',], ['description',]],
'7': ['description', 'city_id', 'recommends_rate', 'duration', 'display_to_c', 'open_weekdays'], // todo: 怎么是2个图 '7': [['city_id', 'recommends_rate', 'duration', 'display_to_c', 'open_weekdays'], ['description',]], // todo: 怎么是2个图
'C': ['description', 'city_id',], 'R': [['city_id',], ['description',]],
'8': [], // todo: ? '8': [[],[]], // todo: ?
}; };
}; const thisTypeFieldset = (_type) => {
const adminSet = isPermitted(PERM_PRODUCTS_MANAGEMENT) ? infoAdmin : [];
return [
[...infoDefault[0], ...infoTypesMap[_type][0], ...adminSet],
[...infoDefault[1], ...infoTypesMap[_type][1]]
];
};
return thisTypeFieldset(type);
}

@ -8,16 +8,15 @@ const i18n_to_htcode = {
'en': 1, 'en': 1,
}; };
export const useLanguage = () => { export const useDefaultLgc = () => {
const { i18n } = useTranslation(); const { i18n } = useTranslation();
return { language: i18n.language, }; return { language: i18n_to_htcode[i18n.language], };
}; };
/** /**
* 语言选择组件 * 语言选择组件
*/ */
const Language = () => { const Language = () => {
const { t, i18n } = useTranslation(); const { t, i18n } = useTranslation();
const [selectedKeys, setSelectedKeys] = useState([i18n.language]); const [selectedKeys, setSelectedKeys] = useState([i18n.language]);
useEffect(() => { useEffect(() => {

@ -9,7 +9,6 @@ import App from "@/views/App";
import Standlone from "@/views/Standlone"; import Standlone from "@/views/Standlone";
import Login from "@/views/Login"; import Login from "@/views/Login";
import Logout from "@/views/Logout"; import Logout from "@/views/Logout";
import Index from "@/views/index";
import ErrorPage from "@/components/ErrorPage"; import ErrorPage from "@/components/ErrorPage";
import RequireAuth from '@/components/RequireAuth' import RequireAuth from '@/components/RequireAuth'
import ReservationNewest from "@/views/reservation/Newest"; import ReservationNewest from "@/views/reservation/Newest";
@ -49,10 +48,12 @@ const initAppliction = async () => {
if (isNotEmpty(loginToken)) { if (isNotEmpty(loginToken)) {
appendRequestParams('token', loginToken) appendRequestParams('token', loginToken)
appendRequestParams('lmi_sn', userId)
} }
if (isNotEmpty(userId)) { if (isNotEmpty(userId)) {
appendRequestParams('wu_id', userId) appendRequestParams('lmi_sn', userId)
await fireAuth() await fireAuth()
} }
} }
@ -65,7 +66,7 @@ const router = createBrowserRouter([
element: <App />, element: <App />,
errorElement: <ErrorPage />, errorElement: <ErrorPage />,
children: [ children: [
{ index: true, element: <Index /> }, { index: true, element: <NoticeIndex /> },
{ path: "account/change-password", element: <ChangePassword />}, { path: "account/change-password", element: <ChangePassword />},
{ path: "account/profile", element: <AccountProfile />}, { path: "account/profile", element: <AccountProfile />},
{ path: "account/management", element: <RequireAuth subject={PERM_ACCOUNT_MANAGEMENT} result={true}><AccountManagement /></RequireAuth>}, { path: "account/management", element: <RequireAuth subject={PERM_ACCOUNT_MANAGEMENT} result={true}><AccountManagement /></RequireAuth>},
@ -76,14 +77,14 @@ const router = createBrowserRouter([
{ path: "feedback/:GRI_SN/:CII_SN/:RefNo", element: <RequireAuth subject={PERM_OVERSEA} result={true}><FeedbackCustomerDetail /></RequireAuth>}, { path: "feedback/:GRI_SN/:CII_SN/:RefNo", element: <RequireAuth subject={PERM_OVERSEA} result={true}><FeedbackCustomerDetail /></RequireAuth>},
{ path: "feedback/:GRI_SN/:RefNo", element: <RequireAuth subject={PERM_OVERSEA} result={true}><FeedbackDetail /></RequireAuth>}, { path: "feedback/:GRI_SN/:RefNo", element: <RequireAuth subject={PERM_OVERSEA} result={true}><FeedbackDetail /></RequireAuth>},
{ path: "report", element: <RequireAuth subject={PERM_OVERSEA} result={true}><ReportIndex /></RequireAuth>}, { path: "report", element: <RequireAuth subject={PERM_OVERSEA} result={true}><ReportIndex /></RequireAuth>},
{ path: "notice", element: <RequireAuth subject={PERM_OVERSEA} result={true}><NoticeIndex /></RequireAuth>}, { path: "notice", element: <NoticeIndex />},
{ path: "notice/:CCP_BLID", element: <RequireAuth subject={PERM_OVERSEA} result={true}><NoticeDetail /></RequireAuth>}, { path: "notice/:CCP_BLID", element: <NoticeDetail />},
{ path: "invoice",element:<RequireAuth subject={PERM_OVERSEA} result={true}><InvoiceIndex /></RequireAuth>}, { path: "invoice",element:<RequireAuth subject={PERM_OVERSEA} result={true}><InvoiceIndex /></RequireAuth>},
{ path: "invoice/detail/:GMDSN/:GSN",element:<RequireAuth subject={PERM_OVERSEA} result={true}><InvoiceDetail /></RequireAuth>}, { path: "invoice/detail/:GMDSN/:GSN",element:<RequireAuth subject={PERM_OVERSEA} result={true}><InvoiceDetail /></RequireAuth>},
{ path: "invoice/paid",element:<RequireAuth subject={PERM_OVERSEA} result={true}><InvoicePaid /></RequireAuth>}, { path: "invoice/paid",element:<RequireAuth subject={PERM_OVERSEA} result={true}><InvoicePaid /></RequireAuth>},
{ path: "invoice/paid/detail/:flid", element: <RequireAuth subject={PERM_OVERSEA} result={true}><InvoicePaidDetail /></RequireAuth>}, { path: "invoice/paid/detail/:flid", element: <RequireAuth subject={PERM_OVERSEA} result={true}><InvoicePaidDetail /></RequireAuth>},
{ path: "airticket",element: <RequireAuth subject={PERM_AIR_TICKET} result={true}><Airticket /></RequireAuth>}, { path: "airticket",element: <RequireAuth subject={PERM_AIR_TICKET} result={true}><Airticket /></RequireAuth>},
{ path: "airticket/plan/:coli_sn",element:<AirticketPlan />}, { path: "airticket/plan/:coli_sn",element:<RequireAuth subject={PERM_AIR_TICKET} result={true}><AirticketPlan /></RequireAuth>},
{ path: "products",element: <RequireAuth subject={PERM_PRODUCTS_MANAGEMENT} result={true}><ProductsManage /></RequireAuth>}, { path: "products",element: <RequireAuth subject={PERM_PRODUCTS_MANAGEMENT} result={true}><ProductsManage /></RequireAuth>},
{ path: "products/:travel_agency_id/:use_year/:audit_state/audit",element:<RequireAuth subject={PERM_PRODUCTS_MANAGEMENT} result={true}><ProductsAudit /></RequireAuth>}, { path: "products/:travel_agency_id/:use_year/:audit_state/audit",element:<RequireAuth subject={PERM_PRODUCTS_MANAGEMENT} result={true}><ProductsAudit /></RequireAuth>},
{ path: "products/:travel_agency_id/:use_year/:audit_state/edit",element:<ProductsDetail />}, { path: "products/:travel_agency_id/:use_year/:audit_state/edit",element:<ProductsDetail />},

@ -70,11 +70,11 @@ const useAccountStore = create((set, get) => ({
accountList: [], accountList: [],
disableAccount: async (accountId) => { disableAccount: async (userId) => {
const formData = new FormData() const formData = new FormData()
formData.append('wu_id', accountId) formData.append('lmi_sn', userId)
// enable disable // enable | disable
formData.append('account_status', 'disable') formData.append('account_status', 'disable')
const result = await postAccountStatus(formData) const result = await postAccountStatus(formData)
@ -82,10 +82,10 @@ const useAccountStore = create((set, get) => ({
console.info(result) console.info(result)
}, },
resetAccountPassword: async (accountId, password) => { resetAccountPassword: async (userId, password) => {
const formData = new FormData() const formData = new FormData()
formData.append('wu_id', accountId) formData.append('lmi_sn', userId)
formData.append('newPassword', password) formData.append('newPassword', password)
return postAccountPassword(formData) return postAccountPassword(formData)
@ -111,8 +111,8 @@ const useAccountStore = create((set, get) => ({
saveOrUpdateAccount: async (formValues) => { saveOrUpdateAccount: async (formValues) => {
const { userId } = usingStorage() const { userId } = usingStorage()
const formData = new FormData() const formData = new FormData()
formData.append('wu_id', formValues.userId) formData.append('wu_id', formValues.accountId)
formData.append('lmi_sn', formValues.lmi_sn) formData.append('lmi_sn', formValues.userId)
formData.append('lmi2_sn', formValues.lmi2_sn) formData.append('lmi2_sn', formValues.lmi2_sn)
formData.append('user_name', formValues.username) formData.append('user_name', formValues.username)
formData.append('real_name', formValues.realname) formData.append('real_name', formValues.realname)
@ -138,8 +138,8 @@ const useAccountStore = create((set, get) => ({
const mapAccoutList = resultArray.map((r) => { const mapAccoutList = resultArray.map((r) => {
return { return {
userId: r.wu_id, accountId: r.wu_id,
lmi_sn: r.lmi_sn, userId: r.lmi_sn,
lmi2_sn: r.lmi2_sn, lmi2_sn: r.lmi2_sn,
username: r.user_name, username: r.user_name,
realname: r.real_name, realname: r.real_name,

@ -36,7 +36,7 @@ export const fetchUserDetail = async (loginToken) => {
export const fetchPermissionListByUserId = async (userId) => { export const fetchPermissionListByUserId = async (userId) => {
const { errcode, result } = await fetchJSON( const { errcode, result } = await fetchJSON(
`${HT_HOST}/service-CooperateSOA/get_account_permission_list`, { wu_id: userId}) `${HT_HOST}/service-CooperateSOA/get_account_permission_list`, { lmi_sn: userId})
return errcode !== 0 ? {} : result return errcode !== 0 ? {} : result
} }
@ -71,7 +71,7 @@ const useAuthStore = create(obervseLifecycle((set, get) => ({
// 以上是 Hardcode 判断 // 以上是 Hardcode 判断
// 以下是权限列表从数据库读取后使用的方法 // 以下是权限列表从数据库读取后使用的方法
return permissionList.some((value) => { return permissionList.some((value) => {
if (value.indexOf(WILDCARD_TOKEN) > -1) { if (value.indexOf(WILDCARD_TOKEN) == 0) {
return true return true
} }
if (value === perm) { if (value === perm) {
@ -85,9 +85,9 @@ const useAuthStore = create(obervseLifecycle((set, get) => ({
const { startTokenInterval, loadUserPermission } = get() const { startTokenInterval, loadUserPermission } = get()
const { setStorage } = usingStorage() const { setStorage } = usingStorage()
const { token: loginToken, WU_ID: userId } = await fetchLoginToken(usr, pwd) const { token: loginToken } = await fetchLoginToken(usr, pwd)
const userDetail = await fetchUserDetail(loginToken) const userDetail = await fetchUserDetail(loginToken)
await loadUserPermission(userId) await loadUserPermission(userDetail.LMI_SN)
set(() => ({ set(() => ({
tokenTimeout: false, tokenTimeout: false,
@ -95,10 +95,10 @@ const useAuthStore = create(obervseLifecycle((set, get) => ({
})) }))
setStorage(KEY_LOGIN_TOKEN, loginToken) setStorage(KEY_LOGIN_TOKEN, loginToken)
setStorage(KEY_USER_ID, userId) setStorage(KEY_USER_ID, userDetail.LMI_SN)
setStorage(KEY_TRAVEL_AGENCY_ID, userDetail.LMI_VEI_SN) setStorage(KEY_TRAVEL_AGENCY_ID, userDetail.LMI_VEI_SN)
appendRequestParams('token', loginToken) appendRequestParams('token', loginToken)
appendRequestParams('wu_id', userDetail.LMI_SN) appendRequestParams('lmi_sn', userDetail.LMI_SN)
// loadPageSpy(`${json.Result.VName}-${json.Result.LoginName}`) // loadPageSpy(`${json.Result.VName}-${json.Result.LoginName}`)
startTokenInterval() startTokenInterval()
}, },
@ -131,7 +131,7 @@ const useAuthStore = create(obervseLifecycle((set, get) => ({
const now = new Date() const now = new Date()
const diffTime = now.getTime() - lastReqDate.getTime() const diffTime = now.getTime() - lastReqDate.getTime()
const diffHours = diffTime/1000/60/60 const diffHours = diffTime/1000/60/60
if (diffHours > 4) { if (diffHours > 1) {
loginTimeout() loginTimeout()
} }
} }
@ -144,7 +144,8 @@ const useAuthStore = create(obervseLifecycle((set, get) => ({
loginTimeout: () => { loginTimeout: () => {
const { tokenInterval } = get() const { tokenInterval } = get()
// TODO: 这里没有清理 token刷新后可以正常使用系统 const { clearStorage } = usingStorage()
clearStorage()
clearInterval(tokenInterval) clearInterval(tokenInterval)
set(() => ({ set(() => ({
tokenTimeout: true tokenTimeout: true

@ -4,7 +4,7 @@ import { Layout, Menu, ConfigProvider, theme, Dropdown, Space, Row, Col, Badge,
import { DownOutlined } from '@ant-design/icons'; import { DownOutlined } from '@ant-design/icons';
import 'antd/dist/reset.css'; import 'antd/dist/reset.css';
import AppLogo from '@/assets/logo-gh.png'; import AppLogo from '@/assets/logo-gh.png';
import { isEmpty } from '@/utils/commons'; import { isEmpty, isNotEmpty } from '@/utils/commons';
import Language from '../i18n/LanguageSwitcher'; import Language from '../i18n/LanguageSwitcher';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import zhLocale from 'antd/locale/zh_CN'; import zhLocale from 'antd/locale/zh_CN';
@ -43,6 +43,7 @@ function App() {
const needToLogin = href !== '/login' && isEmpty(loginToken) const needToLogin = href !== '/login' && isEmpty(loginToken)
useEffect(() => { useEffect(() => {
if (isNotEmpty(loginToken)) {
fetchUserDetail(loginToken) fetchUserDetail(loginToken)
.then(u => { .then(u => {
setUserDetail({ setUserDetail({
@ -50,6 +51,7 @@ function App() {
travelAgencyName: u.VName, travelAgencyName: u.VName,
}) })
}) })
}
}, [loginToken]) }, [loginToken])
useEffect(() => { useEffect(() => {
@ -58,10 +60,6 @@ function App() {
} }
}, [href]) }, [href])
useEffect(() => {
window.gtag('event', 'page_view', { page_location: window.location.href });
}, [location])
const onSubmit = () => { const onSubmit = () => {
validateUserPassword(userDetail?.username, password) validateUserPassword(userDetail?.username, password)
.catch(ex => { .catch(ex => {
@ -69,23 +67,24 @@ function App() {
alert(t('Validation.LoginFailed')) alert(t('Validation.LoginFailed'))
}) })
setPassword('') setPassword('')
}; }
const splitPath = href.split('/'); const splitPath = href.split('/')
let defaultPath = 'reservation'; let defaultPath = 'notice'
if (splitPath.length > 1) { if (splitPath.length > 1) {
defaultPath = splitPath[1]; defaultPath = splitPath[1]
} }
const { const {
token: { colorBgContainer }, token: { colorBgContainer },
} = theme.useToken(); } = theme.useToken()
const [antdLng, setAntdLng] = useState(enLocale); const [antdLng, setAntdLng] = useState(enLocale);
useEffect(() => { useEffect(() => {
setAntdLng(i18n.language === 'en' ? enLocale : zhLocale); setAntdLng(i18n.language === 'en' ? enLocale : zhLocale);
}, [i18n.language]); }, [i18n.language])
return ( return (
<ConfigProvider locale={antdLng} <ConfigProvider locale={antdLng}
theme={{ theme={{
@ -159,8 +158,9 @@ function App() {
items: [...[ items: [...[
{ label: <Link to='/account/change-password'>{t('ChangePassword')}</Link>, key: '0' }, { label: <Link to='/account/change-password'>{t('ChangePassword')}</Link>, key: '0' },
{ label: <Link to='/account/profile'>{t('Profile')}</Link>, key: '1' }, { label: <Link to='/account/profile'>{t('Profile')}</Link>, key: '1' },
isPermitted(PERM_ACCOUNT_MANAGEMENT) ? { label: <Link to='/account/management'>{t('account:management.tile')}</Link>, key: '3' } : null, { type: 'divider' },
isPermitted(PERM_ROLE_NEW) ? { label: <Link to='/account/role-list'>{t('account:management.roleList')}</Link>, key: '4' } : null, isPermitted(PERM_ACCOUNT_MANAGEMENT) ? { label: <Link to='/account/management'>{t('account:accountList')}</Link>, key: '3' } : null,
isPermitted(PERM_ROLE_NEW) ? { label: <Link to='/account/role-list'>{t('account:roleList')}</Link>, key: '4' } : null,
{ type: 'divider' }, { type: 'divider' },
{ label: <Link to='/logout'>{t('Logout')}</Link>, key: '99' }, { label: <Link to='/logout'>{t('Logout')}</Link>, key: '99' },
] ]
@ -195,7 +195,7 @@ function App() {
</ErrorBoundary> </ErrorBoundary>
</AntApp> </AntApp>
</ConfigProvider> </ConfigProvider>
); )
} }
export default App export default App

@ -1,13 +0,0 @@
export default function Index() {
return (
<p id="zero-state">
Global Highlights Hub
<br />
Check out{" "}
<a href="https://www.chinahighlights.com">
the docs at chinahighlights.com
</a>
.
</p>
);
}

@ -17,7 +17,7 @@ function Login() {
useEffect (() => { useEffect (() => {
if (loginStatus === 302) { if (loginStatus === 302) {
navigate('/reservation/newest') navigate('/')
} }
}, [loginStatus]) }, [loginStatus])

@ -1,14 +1,12 @@
import { useState, useEffect } from 'react' import SearchForm from '@/components/SearchForm'
import { Row, Col, Space, Button, Table, Select, TreeSelect, Typography, Modal, App, Form, Input } from 'antd' import useAccountStore, { fetchRoleList, fetchTravelAgencyByName } from '@/stores/Account'
import useFormStore from '@/stores/Form'
import { isEmpty } from '@/utils/commons'
import { ExclamationCircleFilled } from '@ant-design/icons' import { ExclamationCircleFilled } from '@ant-design/icons'
import { useTranslation } from 'react-i18next' import { App, Button, Col, Form, Input, Modal, Row, Select, Space, Table, Typography } from 'antd'
import { fetchTravelAgencyByName } from '@/stores/Account'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { isEmpty } from '@/utils/commons' import { useEffect, useState } from 'react'
import useAccountStore from '@/stores/Account' import { useTranslation } from 'react-i18next'
import useFormStore from '@/stores/Form'
import { fetchRoleList } from '@/stores/Account'
import SearchForm from '@/components/SearchForm'
const { Title } = Typography const { Title } = Typography
@ -26,7 +24,7 @@ function Management() {
dataIndex: 'realname', dataIndex: 'realname',
}, },
{ {
title: t('account:travelAgency'), title: t('account:travelAgencyName'),
dataIndex: 'travelAgencyName', dataIndex: 'travelAgencyName',
}, },
{ {
@ -34,7 +32,7 @@ function Management() {
dataIndex: 'email', dataIndex: 'email',
}, },
{ {
title: t('account:role'), title: t('account:roleName'),
dataIndex: 'role' dataIndex: 'role'
}, },
{ {
@ -43,7 +41,7 @@ function Management() {
render: (text) => (isEmpty(text) ? '' : dayjs(text).format('YYYY-MM-DD HH:mm:ss')) render: (text) => (isEmpty(text) ? '' : dayjs(text).format('YYYY-MM-DD HH:mm:ss'))
}, },
{ {
title: t('account:action'), title: t('account:action.edit'),
dataIndex: 'account:action', dataIndex: 'account:action',
render: actionRender render: actionRender
}, },
@ -78,7 +76,7 @@ function Management() {
const formValues = useFormStore(state => state.formValues) const formValues = useFormStore(state => state.formValues)
const { notification, modal } = App.useApp() const { notification, modal } = App.useApp()
useEffect (() => { useEffect(() => {
fetchRoleList() fetchRoleList()
.then((roleList) => { .then((roleList) => {
setRoleAllList(roleList.map(r => { setRoleAllList(roleList.map(r => {
@ -108,7 +106,6 @@ function Management() {
} }
const onAccountSeleted = async (account) => { const onAccountSeleted = async (account) => {
console.info(account)
setTravelAgencyList([{ setTravelAgencyList([{
label: account.travelAgencyName, label: account.travelAgencyName,
value: account.travelAgencyId value: account.travelAgencyId
@ -156,7 +153,6 @@ function Management() {
} }
const handleTravelAgencyChange = (newValue) => { const handleTravelAgencyChange = (newValue) => {
console.info(newValue)
setCurrentTravelAgency(newValue) setCurrentTravelAgency(newValue)
} }
@ -189,7 +185,6 @@ function Management() {
duration: 60, duration: 60,
}) })
}) })
console.log('ResetPassword')
}, },
onCancel() { onCancel() {
}, },
@ -204,7 +199,7 @@ function Management() {
autoFocus: true, autoFocus: true,
htmlType: 'submit', htmlType: 'submit',
}} }}
title={t('account:management.newAccount')} title={t('account:detail')}
open={isAccountModalOpen} onOk={() => setAccountModalOpen(false)} onCancel={() => setAccountModalOpen(false)} open={isAccountModalOpen} onOk={() => setAccountModalOpen(false)} onCancel={() => setAccountModalOpen(false)}
destroyOnClose={true} destroyOnClose={true}
clearOnDestroy={true} clearOnDestroy={true}
@ -225,11 +220,11 @@ function Management() {
</Form> </Form>
)} )}
> >
<Form.Item name='accountId' className='hidden' ><Input /></Form.Item>
<Form.Item name='userId' className='hidden' ><Input /></Form.Item> <Form.Item name='userId' className='hidden' ><Input /></Form.Item>
<Form.Item name='lmi_sn' className='hidden' ><Input /></Form.Item>
<Form.Item name='lmi2_sn' className='hidden' ><Input /></Form.Item> <Form.Item name='lmi2_sn' className='hidden' ><Input /></Form.Item>
<Form.Item <Form.Item
label={t('account:management.username')} label={t('account:username')}
name='username' name='username'
rules={[ rules={[
{ {
@ -241,7 +236,7 @@ function Management() {
<Input /> <Input />
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label={t('account:management.realname')} label={t('account:realname')}
name='realname' name='realname'
rules={[ rules={[
{ {
@ -253,7 +248,7 @@ function Management() {
<Input /> <Input />
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label={t('account:management.email')} label={t('account:email')}
name='email' name='email'
rules={[ rules={[
{ {
@ -265,7 +260,7 @@ function Management() {
<Input /> <Input />
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label={t('account:management.travelAgency')} label={t('account:travelAgencyName')}
name='travelAgencyId' name='travelAgencyId'
rules={[ rules={[
{ {
@ -287,7 +282,7 @@ function Management() {
</Select> </Select>
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label={t('account:management.role')} label={t('account:roleName')}
name='roleId' name='roleId'
rules={[ rules={[
{ {
@ -296,18 +291,24 @@ function Management() {
}, },
]} ]}
> >
<Select options={roleAllList}> <Select
options={roleAllList}
filterOption={false}
notFoundContent={null}
>
</Select> </Select>
</Form.Item> </Form.Item>
</Modal> </Modal>
<Space direction='vertical' style={{ width: '100%' }}> <Space direction='vertical' style={{ width: '100%' }}>
<Title level={3}>{t('account:management.tile')}</Title> <Title level={3}>{t('account:accountList')}</Title>
<SearchForm <SearchForm
fieldsConfig={{ fieldsConfig={{
shows: ['username', 'realname', 'dates'], shows: ['username', 'realname'],
fieldProps: { fieldProps: {
dates: { label: t('group:ArrivalDate') }, username: { label: t('account:username') },
realname: { label: t('account:realname') },
}, },
sort: { username: 1, realname: 2, dates: 3},
}} }}
onSubmit={() => { onSubmit={() => {
handelAccountSearch() handelAccountSearch()
@ -316,7 +317,7 @@ function Management() {
<Row> <Row>
<Col span={24}> <Col span={24}>
<Space> <Space>
<Button onClick={() => setAccountModalOpen(true)}>{t('account:management.newAccount')}</Button> <Button onClick={() => setAccountModalOpen(true)}>{t('account:newAccount')}</Button>
</Space> </Space>
</Col> </Col>
</Row> </Row>

@ -1,12 +1,14 @@
import { useState, useEffect } from 'react'
import { Row, Col, Space, Button, Table, TreeSelect, Typography, Modal, App, Form, Input } from 'antd'
import { useTranslation } from 'react-i18next'
import useAccountStore from '@/stores/Account'
import { fetchRoleList, fetchPermissionList, fetchPermissionListByRoleId } from '@/stores/Account'
import dayjs from 'dayjs'
import { isEmpty } from '@/utils/commons'
import RequireAuth from '@/components/RequireAuth' import RequireAuth from '@/components/RequireAuth'
import { PERM_ROLE_NEW } from '@/config' import { PERM_ROLE_NEW } from '@/config'
import useAccountStore, { fetchPermissionList, fetchPermissionListByRoleId, fetchRoleList } from '@/stores/Account'
import { isEmpty } from '@/utils/commons'
import {
SyncOutlined,
} from '@ant-design/icons'
import { App, Button, Col, Form, Input, Modal, Row, Space, Table, Tag, TreeSelect, Typography } from 'antd'
import dayjs from 'dayjs'
import { useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
const { Title } = Typography const { Title } = Typography
@ -15,7 +17,7 @@ function RoleList() {
const roleListColumns = [ const roleListColumns = [
{ {
title: t('account:rolename'), title: t('account:roleName'),
dataIndex: 'role_name', dataIndex: 'role_name',
}, },
{ {
@ -30,8 +32,10 @@ function RoleList() {
}, },
] ]
function actionRender(text, role) { function actionRender(_, role) {
if (role.role_id > 1) { if (role.role_id == 1) {
return (<Tag icon={<SyncOutlined spin />} color='warning'>不能修改</Tag>)
} else {
return ( return (
<Button type='link' key='edit' onClick={() => onRoleSeleted(role)}>{t('account:action.edit')}</Button> <Button type='link' key='edit' onClick={() => onRoleSeleted(role)}>{t('account:action.edit')}</Button>
) )
@ -49,7 +53,7 @@ function RoleList() {
}, {}) }, {})
} }
useEffect (() => { useEffect(() => {
setDataLoading(true) setDataLoading(true)
fetchRoleList() fetchRoleList()
.then(r => { .then(r => {
@ -110,7 +114,7 @@ function RoleList() {
const { notification, modal } = App.useApp() const { notification, modal } = App.useApp()
const onRoleSeleted = (role) => { const onRoleSeleted = (role) => {
fetchPermissionListByRoleId({role_id: role.role_id}) fetchPermissionListByRoleId({ role_id: role.role_id })
.then(result => { .then(result => {
role.res_array = result.map(r => r.res_id) role.res_array = result.map(r => r.res_id)
roleForm.setFieldsValue(role) roleForm.setFieldsValue(role)
@ -154,7 +158,7 @@ function RoleList() {
autoFocus: true, autoFocus: true,
htmlType: 'submit', htmlType: 'submit',
}} }}
title={t('account:management.newRole')} title={t('account:detail')}
open={isRoleModalOpen} onOk={() => setRoleModalOpen(false)} onCancel={() => setRoleModalOpen(false)} open={isRoleModalOpen} onOk={() => setRoleModalOpen(false)} onCancel={() => setRoleModalOpen(false)}
destroyOnClose={true} destroyOnClose={true}
clearOnDestroy={true} clearOnDestroy={true}
@ -177,7 +181,7 @@ function RoleList() {
> >
<Form.Item name='role_id' className='hidden' ><Input /></Form.Item> <Form.Item name='role_id' className='hidden' ><Input /></Form.Item>
<Form.Item <Form.Item
label={t('account:management.roleName')} label={t('account:roleName')}
name='role_name' name='role_name'
rules={[ rules={[
{ {
@ -189,7 +193,7 @@ function RoleList() {
<Input /> <Input />
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label={t('account:management.permission')} label={t('account:permission')}
name='res_array' name='res_array'
> >
<TreeSelect treeData={permissionTreeData} value={permissionValue} <TreeSelect treeData={permissionTreeData} value={permissionValue}
@ -213,12 +217,12 @@ function RoleList() {
</Form.Item> </Form.Item>
</Modal> </Modal>
<Space direction='vertical' style={{ width: '100%' }}> <Space direction='vertical' style={{ width: '100%' }}>
<Title level={3}>{t('account:management.roleList')}</Title> <Title level={3}>{t('account:roleList')}</Title>
<Row> <Row>
<Col span={24}> <Col span={24}>
<Space> <Space>
<RequireAuth subject={PERM_ROLE_NEW}> <RequireAuth subject={PERM_ROLE_NEW}>
<Button onClick={() => onNewRole()}>{t('account:management.newRole')}</Button> <Button onClick={() => onNewRole()}>{t('account:newRole')}</Button>
</RequireAuth> </RequireAuth>
</Space> </Space>
</Col> </Col>
@ -230,6 +234,7 @@ function RoleList() {
loading={dataLoading} loading={dataLoading}
rowKey='role_id' rowKey='role_id'
pagination={{ pagination={{
pageSize: 20,
showQuickJumper: true, showQuickJumper: true,
showLessItems: true, showLessItems: true,
showSizeChanger: true, showSizeChanger: true,

@ -62,6 +62,8 @@ const PriceTable = ({ dataSource, refresh }) => {
const { message, notification } = App.useApp(); const { message, notification } = App.useApp();
const stateMapVal = useProductsAuditStatesMapVal(); const stateMapVal = useProductsAuditStatesMapVal();
// console.log(dataSource);
const handleAuditPriceItem = (state, row) => { const handleAuditPriceItem = (state, row) => {
postProductsQuoteAuditAction(state, { id: row.id, travel_agency_id: activeAgency.travel_agency_id }) postProductsQuoteAuditAction(state, { id: row.id, travel_agency_id: activeAgency.travel_agency_id })
.then((json) => { .then((json) => {
@ -83,11 +85,9 @@ const PriceTable = ({ dataSource, refresh }) => {
}; };
const columns = [ const columns = [
{ key: 'title', dataIndex: ['info', 'title'], width: '16rem', title: t('Title'), onCell: (r, index) => ({ rowSpan: r.rowSpan }) }, { key: 'title', dataIndex: ['info', 'title'], width: '16rem', title: t('Title'), onCell: (r, index) => ({ rowSpan: r.rowSpan }), render: (text, r) => text || r.lgc_details?.['2']?.title || r.lgc_details?.['1']?.title || '' },
{ key: 'adult', title: t('AgeType.Adult'), render: (_, { value, currency, unit_name }) => `${value} ${currency} / ${unit_name}` }, { key: 'adult', title: t('AgeType.Adult'), render: (_, { adult_cost, currency, unit_id, unit_name }) => `${adult_cost} ${currency} / ${t(`PriceUnit.${unit_id}`)}` },
{ key: 'child', title: t('AgeType.Child'), render: (_, { value, currency, unit_name }) => `${value} ${currency} / ${unit_name}` }, { key: 'child', title: t('AgeType.Child'), render: (_, { child_cost, currency, unit_id, unit_name }) => `${child_cost} ${currency} / ${t(`PriceUnit.${unit_id}`)}` },
// {key: 'price', title: t('Currency'), },
// {key: 'currency', title: t('Currency'), },
// {key: 'unit', title: t('Unit'), }, // {key: 'unit', title: t('Unit'), },
{ {
key: 'groupSize', key: 'groupSize',
@ -135,16 +135,33 @@ const TypesPanels = (props) => {
const [activeKey, setActiveKey] = useState([]); const [activeKey, setActiveKey] = useState([]);
const [showTypes, setShowTypes] = useState([]); const [showTypes, setShowTypes] = useState([]);
useEffect(() => { useEffect(() => {
// ; , // ; , ; ,
const hasDataTypes = Object.keys(agencyProducts); const hasDataTypes = Object.keys(agencyProducts);
const _show = productsTypes const _show = productsTypes
.filter((kk) => hasDataTypes.includes(kk.value)) .filter((kk) => hasDataTypes.includes(kk.value))
.map((ele) => ({ .map((ele) => ({
...ele, ...ele,
extra: t('Table.Total', { total: agencyProducts[ele.value].length }),
children: ( children: (
<PriceTable <PriceTable
// loading={loading} // loading={loading}
dataSource={agencyProducts[ele.value].reduce((r, c) => r.concat(c.quotation.map((q, i) => ({ ...q, weekdays: q.weekdays.split(',').filter(Boolean).map(w => t(`weekdaysShort.${w}`)).join(', '), info: c.info, rowSpan: i === 0 ? c.quotation.length : 0 }))), [])} dataSource={agencyProducts[ele.value].reduce(
(r, c) =>
r.concat(
c.quotation.map((q, i) => ({
...q,
weekdays: q.weekdays
.split(',')
.filter(Boolean)
.map((w) => t(`weekdaysShort.${w}`))
.join(', '),
info: c.info,
lgc_details: c.lgc_details.reduce((rlgc, clgc) => ({...r, [clgc.lgc]: clgc}), {}),
rowSpan: i === 0 ? c.quotation.length : 0,
}))
),
[]
)}
refresh={props.refresh} refresh={props.refresh}
/> />
), ),

@ -1,19 +1,22 @@
import { createContext, useContext, useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { useParams } from 'react-router-dom'; import { useParams } from 'react-router-dom';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { App, Table, Button, Modal, Popconfirm } from 'antd'; import { App, Table, Button, Modal, Popconfirm } from 'antd';
import useProductsStore, { getAgencyProductExtrasAction, getAgencyProductsAction, addProductExtraAction, delProductExtrasAction } from '@/stores/Products/Index'; import { getAgencyProductExtrasAction, getAgencyProductsAction, addProductExtraAction, delProductExtrasAction } from '@/stores/Products/Index';
import { isEmpty, cloneDeep } from '@/utils/commons'; import { cloneDeep } from '@/utils/commons';
import SearchForm from '@/components/SearchForm'; import SearchForm from '@/components/SearchForm';
import RequireAuth from '@/components/RequireAuth'; import RequireAuth from '@/components/RequireAuth';
import { PERM_PRODUCTS_MANAGEMENT } from '@/config'; import { PERM_PRODUCTS_MANAGEMENT } from '@/config';
import { useProductsTypesMapVal } from '@/hooks/useProductsSets';
const NewAddonModal = ({ onPick, ...props }) => { const NewAddonModal = ({ onPick, ...props }) => {
const { travel_agency_id, use_year } = useParams(); const { travel_agency_id, use_year } = useParams();
const { t } = useTranslation(); const { t } = useTranslation();
const { notification, message } = App.useApp(); const { notification, message } = App.useApp();
const productsTypesMapVal = useProductsTypesMapVal();
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const [loading, setLoading] = useState(false); // bind loading const [loading, setLoading] = useState(false); // bind loading
const [searchLoading, setSearchLoading] = useState(false); const [searchLoading, setSearchLoading] = useState(false);
@ -24,27 +27,26 @@ const NewAddonModal = ({ onPick, ...props }) => {
const { starttime, endtime, ...param } = copyObject; const { starttime, endtime, ...param } = copyObject;
setSearchLoading(true); setSearchLoading(true);
setSearchResult([]); setSearchResult([]);
const result = await getAgencyProductsAction({ ...param, audit_state: '1', travel_agency_id, use_year }); // debug: audit_state: '1',
const result = await getAgencyProductsAction({ ...param, audit_state: '0', travel_agency_id, use_year });
setSearchResult(result?.products || []); setSearchResult(result?.products || []);
setSearchLoading(false); setSearchLoading(false);
}; };
const handleAddExtras = async (item) => { const handleAddExtras = async (item) => {
// const success = await fetchBindOrder({ coli_sn, conversationid: currentConversationID });
// success ? message.success('') : message.error('');
// setOpen(false);
if (typeof onPick === 'function') { if (typeof onPick === 'function') {
onPick(item); onPick(item);
} }
}; };
// todo: // todo:
const searchResultColumns = [ const searchResultColumns = [
{ key: 'ptype', dataIndex: ['info', 'product_type_id'], width: '6rem', title: t('products:ProductType'), render: (text, r) => productsTypesMapVal[text].label },
{ key: 'title', dataIndex: ['info', 'title'], width: '16rem', title: t('products:Title') }, { key: 'title', dataIndex: ['info', 'title'], width: '16rem', title: t('products:Title') },
{ {
title: t('products:price'), title: t('products:price'),
dataIndex: ['quotation', '0', 'value'], dataIndex: ['quotation', '0', 'adult_cost'],
width: '10rem', width: '10rem',
render: (_, { quotation }) => `${quotation[0].value} ${quotation[0].currency} / ${quotation[0].unit_name}`, // todo: render: (_, { quotation }) => `${quotation[0].adult_cost} ${quotation[0].currency} / ${quotation[0].unit_name}`, // todo:
}, },
{ {
key: 'action', key: 'action',
@ -63,7 +65,7 @@ const NewAddonModal = ({ onPick, ...props }) => {
return ( return (
<> <>
<Button type='primary' onClick={() => setOpen(true)} className='mt-2'> <Button type='primary' onClick={() => setOpen(true)} className='mt-2'>
{t('New')} {t('New')} {t('products:EditComponents.Extras')}
</Button> </Button>
<Modal width={'95%'} style={{ top: 20 }} open={open} title={'添加附加'} footer={false} onCancel={() => setOpen(false)} destroyOnClose> <Modal width={'95%'} style={{ top: 20 }} open={open} title={'添加附加'} footer={false} onCancel={() => setOpen(false)} destroyOnClose>
@ -119,14 +121,14 @@ const Extras = ({ productId, onChange, ...props }) => {
setExtrasData(prev => [].concat(prev, [item])); setExtrasData(prev => [].concat(prev, [item]));
// todo: ; // todo: ;
const newSuccess = await addProductExtraAction({ travel_agency_id, id: productId, extras: [2] }); const newSuccess = await addProductExtraAction({ travel_agency_id, id: productId, extras: [2] });
newSuccess ? message.success(t('Success')) : message.error(t('Failed')); newSuccess ? message.success(t('Action')+t('Success')) : message.error(t('Action')+t('Failed'));
await handleGetAgencyProductExtras(); await handleGetAgencyProductExtras();
} }
const handleDelAddon = async (item) => { const handleDelAddon = async (item) => {
// todo: // todo:
const delSuccess = await delProductExtrasAction({ travel_agency_id, id: productId, extras: [2] }); const delSuccess = await delProductExtrasAction({ travel_agency_id, id: productId, extras: [2] });
delSuccess ? message.success(t('Success')) : message.error(t('Failed')); delSuccess ? message.success(t('Action')+t('Success')) : message.error(t('Action')+t('Failed'));
await handleGetAgencyProductExtras(); await handleGetAgencyProductExtras();
}; };
@ -143,7 +145,7 @@ const Extras = ({ productId, onChange, ...props }) => {
dataIndex: ['quotation', '0', 'value'], dataIndex: ['quotation', '0', 'value'],
width: '10rem', width: '10rem',
render: (_, { quotation }) => `${quotation[0].value} ${quotation[0].currency} / ${quotation[0].unit_name}`, // todo: render: (_, { quotation }) => `${quotation[0].adult_cost} ${quotation[0].currency} / ${quotation[0].unit_name}`, // todo:
}, },
// { title: t('products:Types'), dataIndex: 'age_type', width: '40%', }, // { title: t('products:Types'), dataIndex: 'age_type', width: '40%', },
{ {
@ -151,7 +153,7 @@ const Extras = ({ productId, onChange, ...props }) => {
dataIndex: 'operation', dataIndex: 'operation',
width: '4rem', width: '4rem',
render: (_, r) => ( render: (_, r) => (
<Popconfirm title={t('products:sureDelete')} onConfirm={(e) => handleDelAddon(r)} > <Popconfirm title={t('sureDelete')} onConfirm={(e) => handleDelAddon(r)} okText={t('Yes')} >
<Button size='small' type='link' danger> <Button size='small' type='link' danger>
{t('Delete')} {t('Delete')}
</Button> </Button>

@ -49,10 +49,10 @@ function Index() {
const columns = [ const columns = [
{ title: t('products:Vendor'), key: 'vendor', dataIndex: 'travel_agency_name' }, { title: t('products:Vendor'), key: 'vendor', dataIndex: 'travel_agency_name' },
{ title: t('products:CreatedBy'), key: 'created_by', dataIndex: 'created_by' }, { title: t('products:CreatedBy'), key: 'created_by', dataIndex: 'created_by_name' },
{ title: t('products:CreateDate'), key: 'create_date', dataIndex: 'create_date' }, { title: t('products:CreateDate'), key: 'create_date', dataIndex: 'create_date' },
{ title: t('products:AuState'), key: 'audit_state', dataIndex: 'audit_state' }, { title: t('products:AuState'), key: 'audit_state', dataIndex: 'audit_state' },
{ title: t('products:AuditedBy'), key: 'audited_by', dataIndex: 'audited_by' }, { title: t('products:AuditedBy'), key: 'audited_by', dataIndex: 'audited_by_name' },
{ title: t('products:AuditDate'), key: 'audit_date', dataIndex: 'audit_date' }, { title: t('products:AuditDate'), key: 'audit_date', dataIndex: 'audit_date' },
{ {
title: '', title: '',

Loading…
Cancel
Save