import { create } from 'zustand'; import { devtools } from 'zustand/middleware'; import dayjs from 'dayjs' import { fetchJSON, postForm, postJSON } from '@/utils/request'; import { HT_HOST } from '@/config'; import { groupBy, generateId, isEmpty } from '@/utils/commons'; export const searchAgencyAction = async (param) => { const { errcode, result } = await fetchJSON(`${HT_HOST}/Service_BaseInfoWeb/products_search`, param); return errcode !== 0 ? [] : result; }; /** * 搜索所有产品, 返回产品列表 * ! 只有审核通过, 已发布的 * @param {object} params { keyword, use_year, product_types, travel_agency_id, city } */ export const searchPublishedProductsAction = async (param) => { const { errcode, result } = await fetchJSON(`${HT_HOST}/Service_BaseInfoWeb/web_products_search`, param); return errcode !== 0 ? [] : result; }; export const copyAgencyDataAction = async (postbody) => { const formData = new FormData(); Object.keys(postbody).forEach((key) => { formData.append(key, postbody[key]); }); const { errcode, result } = await postForm(`${HT_HOST}/Service_BaseInfoWeb/agency_products_copy`, formData); return errcode === 0 ? true : false; }; export const getAgencyProductsAction = async (param) => { const _param = { ...param, use_year: String(param.use_year || '').replace('all', ''), audit_state: String(param.audit_state || '').replace('all', '') }; const { errcode, result } = await fetchJSON(`${HT_HOST}/Service_BaseInfoWeb/travel_agency_products`, _param); return errcode !== 0 ? { agency: {}, products: [] } : result; }; /** * @param {object} body { id, travel_agency_id, extras: [{id, title, code}] } */ export const addProductExtraAction = async (body) => { // console.log('addProductExtraAction', body); // return true; // test: 先不更新到HT const { errcode, result } = await postJSON(`${HT_HOST}/Service_BaseInfoWeb/products_extras_add`, body); return errcode === 0 ? true : false; }; /** * */ export const delProductExtrasAction = async (body) => { // return true; // test: 先不更新到HT const { errcode, result } = await postJSON(`${HT_HOST}/Service_BaseInfoWeb/products_extras_del`, body); return errcode === 0 ? true : false; }; /** * 获取指定产品的附加项目 * @param {object} param { id, travel_agency_id, use_year } */ export const getAgencyProductExtrasAction = async (param) => { const _param = { ...param, use_year: (param.use_year || '').replace('all', '') }; const { errcode, result } = await fetchJSON(`${HT_HOST}/Service_BaseInfoWeb/products_extras`, _param); return errcode !== 0 ? [] : result; }; /** * 审核一条价格 */ export const postProductsQuoteAuditAction = async (auditState, quoteRow) => { const postbody = { audit_state: auditState, id: quoteRow.id, travel_agency_id: quoteRow.travel_agency_id, }; const formData = new FormData(); Object.keys(postbody).forEach((key) => { formData.append(key, postbody[key]); }); const json = await postForm(`${HT_HOST}/Service_BaseInfoWeb/quotation_audit`, formData); return json; // return errcode !== 0 ? {} : result; }; /** * 供应商提交审核 */ export const postAgencyAuditAction = async (travel_agency_id, use_year) => { const postbody = { use_year, travel_agency_id, }; const formData = new FormData(); Object.keys(postbody).forEach((key) => { formData.append(key, postbody[key]); }); const { errcode, result } = await postForm(`${HT_HOST}/Service_BaseInfoWeb/agency_submit`, formData); return { errcode, result, success: errcode === 0 }; // const { errcode, result } = json; // return errcode !== 0 ? {} : result; }; /** * 保存一个产品 */ export const postProductsSaveAction = async (products) => { const { errcode, result } = await postJSON(`${HT_HOST}/Service_BaseInfoWeb/agency_product_save`, products); return { errcode, result, success: errcode === 0 }; } /** * 删除产品报价 */ export const deleteQuotationAction = async (id) => { const { errcode, result } = await fetchJSON(`${HT_HOST}/Service_BaseInfoWeb/agency_product_quotation_delete`, {id}); return { errcode, result, success: errcode === 0 }; } const initialState = { loading: false, searchValues: {}, // 客服首页: 搜索条件 agencyList: [], // 客服首页: 搜索结果 activeAgency: {}, // 审核/编辑 页: 当前的供应商 activeAgencyState: null, agencyProducts: {}, // 审核/编辑 页: 供应商产品列表 editingProduct: {}, // 编辑页: 当前编辑的产品 quotationList: [], // 编辑页: 当前产品报价列表 editing: false, switchParams: {}, // 头部切换参数 }; export const useProductsStore = create( devtools((set, get) => ({ // 初始化状态 ...initialState, // state actions setLoading: (loading) => set({ loading }), setSearchValues: (searchValues) => set({ searchValues }), setAgencyList: (agencyList) => set({ agencyList }), setActiveAgency: (activeAgency) => set({ activeAgency }), setActiveAgencyState: (activeAgencyState) => set({ activeAgencyState }), setAgencyProducts: (agencyProducts) => set({ agencyProducts }), setEditingProduct: (product) => { set(() => ({ editingProduct: product, quotationList: (product?.quotation??[]).map(q => { return { ...q, key: generateId(), fresh: false } }) })) }, setEditing: (editing) => set({ editing }), setSwitchParams: (switchParams) => set({ switchParams }), appendNewProduct: (productItem) => { const { setActiveAgency, agencyProducts, setAgencyProducts } = get(); const typeGroup = agencyProducts[productItem.info.product_type_id] || []; const newIndex = typeGroup.findIndex((item) => item.info.id === productItem.info.id); if (newIndex !== -1) { typeGroup.splice(newIndex, 1, productItem); } else { typeGroup.unshift(productItem); } return set({ agencyProducts: { ...agencyProducts, [productItem.info.product_type_id]: typeGroup }, }); }, reset: () => set(initialState), newEmptyQuotation: () => ({ id: null, adult_cost: 0, child_cost: 0, currency: 'RMB', unit_id: '0', group_size_min: 1, group_size_max: 10, use_dates: [ dayjs().startOf('M'), dayjs().endOf('M') ], weekdayList: [], fresh: true // 标识是否是新记录,新记录才用添加列表 }), appendQuotationList: (defList) => { const { activeAgency, editingProduct, quotationList } = get() const generatedList = [] defList.forEach(definition => { // 增加多个有效日期批量设置: const mappedPriceList = definition?.priceList.map(price => { return { id: null, adult_cost: price.priceInput.audultPrice, child_cost: price.priceInput.childrenPrice, group_size_min: price.priceInput.numberStart, group_size_max: price.priceInput.numberEnd, currency: definition.currency, unit_id: definition.unitId, // 保持和 API 返回格式一致,日期要转换为字符串 use_dates_start: definition.useDate[0].format('YYYY-MM-DD'), use_dates_end: definition.useDate[1].format('YYYY-MM-DD'), weekdays: definition.weekend.join(','), WPI_SN: editingProduct.info.id, WPP_VEI_SN: activeAgency.travel_agency_id, lastedit_changed: '', audit_state_id: -1, key: generateId(), fresh: false } }) generatedList.push(...mappedPriceList) }) const mergedList = [...quotationList,...generatedList] set(() => ({ quotationList: mergedList })) return mergedList }, saveOrUpdateQuotation: (formValues) => { const { activeAgency, editingProduct, quotationList } = get() let mergedList = [] formValues.WPI_SN = editingProduct.info.id formValues.WPP_VEI_SN = activeAgency.travel_agency_id formValues.use_dates_start = formValues.use_dates[0].format('YYYY-MM-DD') formValues.use_dates_end = formValues.use_dates[1].format('YYYY-MM-DD') formValues.weekdays = formValues.weekdayList.join(',') if (formValues.fresh) { formValues.key = generateId() formValues.lastedit_changed = '' formValues.audit_state_id = -1 // 新增, formValues.fresh = false // 添加到列表后就不是新纪录,保存要修改原来记录 mergedList = [...quotationList,...[formValues]] } else { mergedList = quotationList.map(prevQuotation => { if (prevQuotation.key === formValues.key) { const changedList = [] for (const [key, value] of Object.entries(formValues)) { if (key === 'use_dates' || key === 'id' || key === 'key') continue const preValue = prevQuotation[key] const hasChanged = preValue !== value if (hasChanged) { changedList.push({ [key]: preValue, }) } } return { ...prevQuotation, adult_cost: formValues.adult_cost, child_cost: formValues.child_cost, currency: formValues.currency, unit_id: formValues.unit_id, group_size_min: formValues.group_size_min, group_size_max: formValues.group_size_max, use_dates_start: formValues.use_dates_start, use_dates_end: formValues.use_dates_end, weekdays: formValues.weekdays, lastedit_changed: JSON.stringify(changedList, null, 2) } } else { return prevQuotation } }) } set(() => ({ quotationList: mergedList })) return mergedList }, deleteQuotation: async(quotation) => { const { editingProduct, quotationList, agencyProducts } = get() const productTypeId = editingProduct.info.product_type_id; const quotationId = quotation.id const newList = quotationList.filter(q => { return q.key != quotation.key }) set({ agencyProducts: { ...agencyProducts, [productTypeId]: [{ ...editingProduct, quotation: newList }] }, quotationList: newList }) if (isEmpty(quotationId)) { return Promise.resolve(newList) } else { const { result, success } = await deleteQuotationAction(quotationId) if (success) { return Promise.resolve(result) } else { return Promise.reject(result) } } }, // side effects searchAgency: async (param) => { const { setLoading, setAgencyList } = get(); setLoading(true); const res = await searchAgencyAction(param); setAgencyList(res); setLoading(false); }, getAgencyProducts: async (param) => { const { setLoading, setActiveAgency, setActiveAgencyState, setAgencyProducts, editingProduct, setEditingProduct } = get(); setLoading(true); setAgencyProducts({}); // setEditingProduct({}); const res = await getAgencyProductsAction(param); const productsData = groupBy(res.products, (row) => row.info.product_type_id); setAgencyProducts(productsData); setActiveAgency(res.agency); setActiveAgencyState(res.agency.audit_state_id); if (editingProduct?.info?.id) { const item = (productsData[editingProduct.info.product_type_id] || []).find((item) => item.info.id === editingProduct.info.id); setEditingProduct(item); } else { setEditingProduct({}); } setLoading(false); }, getAgencyProductExtras: async (param) => { const res = await getAgencyProductExtrasAction(param); // todo: }, }), { name: 'productStore' }) ); export default useProductsStore;