From f2d73179827a981c021b517aad7667c1fd6d4264 Mon Sep 17 00:00:00 2001 From: lq Date: Fri, 19 Dec 2025 15:58:31 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E6=94=B9=E8=A6=81=E8=AF=8A?= =?UTF-8?q?=E6=89=80=E4=BE=9B=E8=B4=A7=E4=BB=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/views/system/store/api/index.ts | 26 ++ .../store/components/DrugPriceModal.vue | 171 +++++++++ .../system/store/config/drug-price-table.ts | 336 ++++++++++++++++++ .../src/views/system/store/config/search.ts | 22 ++ .../web-antd/src/views/system/store/index.vue | 34 +- 5 files changed, 588 insertions(+), 1 deletion(-) create mode 100644 apps/web-antd/src/views/system/store/components/DrugPriceModal.vue create mode 100644 apps/web-antd/src/views/system/store/config/drug-price-table.ts diff --git a/apps/web-antd/src/views/system/store/api/index.ts b/apps/web-antd/src/views/system/store/api/index.ts index 53f8ef17..8900b39e 100644 --- a/apps/web-antd/src/views/system/store/api/index.ts +++ b/apps/web-antd/src/views/system/store/api/index.ts @@ -83,3 +83,29 @@ export async function updateStoreShippingFree(data: { id: number }) { export async function updateStoreSubscribeStatus(data: { id: number }) { return requestClient.post(`${prefix}update-subscribe-status`, data); } + +/** + * 获取诊所药品列表(按类型) + * @param storeId 诊所ID + * @param type 药品类型(1=中药,2=西药) + */ +export async function getStoreDrugsByTypeApi(storeId: number, type: number) { + return requestClient.get(`${prefix}get-store-drugs-by-type`, { + params: { store_id: storeId, type }, + }); +} + +/** + * 批量更新诊所药品价格(平台管理员专用) + * @param data + */ +export async function updateStoreDrugPricesApi(data: { + store_id: number; + drugs: Array<{ + id: number; + price: number; + buy_price: number; + }>; +}) { + return requestClient.post(`${prefix}update-store-drug-prices`, data); +} diff --git a/apps/web-antd/src/views/system/store/components/DrugPriceModal.vue b/apps/web-antd/src/views/system/store/components/DrugPriceModal.vue new file mode 100644 index 00000000..e9b73554 --- /dev/null +++ b/apps/web-antd/src/views/system/store/components/DrugPriceModal.vue @@ -0,0 +1,171 @@ + + + + + diff --git a/apps/web-antd/src/views/system/store/config/drug-price-table.ts b/apps/web-antd/src/views/system/store/config/drug-price-table.ts new file mode 100644 index 00000000..7db20033 --- /dev/null +++ b/apps/web-antd/src/views/system/store/config/drug-price-table.ts @@ -0,0 +1,336 @@ +import type { VxeGridProps } from '#/adapter/vxe-table'; + +import { message } from 'ant-design-vue'; + +import { + getStoreDrugsByTypeApi, + updateStoreDrugPricesApi, +} from '../api'; + +export interface DrugItem { + id: number; + drug_id: number; + drug_name: string; + image?: string; + price: number; + buy_price: number; +} + +/** + * 单行保存函数 + * @param row 当前行数据 + * @param storeId 诊所ID + * @param gridApi 表格API实例 + */ +export const handleSaveRow = async ( + row: DrugItem, + storeId: number, + gridApi: any, +) => { + if (!storeId) { + message.error('诊所ID不能为空'); + return; + } + + try { + // 获取当前行的最新数据(从表格中获取,包含编辑后的值) + const tableData = gridApi?.grid?.getTableData?.(); + const fullData = tableData?.fullData || []; + const currentRow = fullData.find((item: DrugItem) => item.id === row.id); + + if (!currentRow) { + message.error('未找到该行数据'); + return; + } + + // 构建提交数据(只提交当前行) + const drugs = [ + { + id: currentRow.id, + price: parseFloat(String(currentRow.price)) || 0, + buy_price: parseFloat(String(currentRow.buy_price)) || 0, + }, + ]; + + // 验证数据 + for (const drug of drugs) { + if (drug.price < 0 || drug.buy_price < 0) { + message.error('价格不能为负数'); + return; + } + if (isNaN(drug.price) || isNaN(drug.buy_price)) { + message.error('价格格式不正确'); + return; + } + } + + await updateStoreDrugPricesApi({ + store_id: storeId, + drugs, + }); + + message.success('保存成功'); + // 刷新表格数据 + gridApi?.reload?.(); + } catch (error: any) { + message.error(error?.message || '保存失败'); + } +}; + +/** + * 批量保存函数(只保存修改的数据) + * @param gridApi 表格API实例 + * @param storeId 诊所ID + */ +export const handleBatchSave = async ( + gridApi: any, + storeId: number, +) => { + if (!storeId) { + message.error('诊所ID不能为空'); + return; + } + + try { + // 使用getRecordset获取修改的记录 + const recordset = gridApi?.grid?.getRecordset?.(); + const updateRecords = recordset?.updateRecords || []; + + // 如果getRecordset没有返回修改记录,尝试获取所有数据 + if (updateRecords.length === 0) { + const tableData = gridApi?.grid?.getTableData?.(); + const fullData = tableData?.fullData || []; + + if (fullData.length === 0) { + message.warning('没有可保存的数据'); + return; + } + + // 如果没有修改记录,提交所有数据 + const drugs = fullData.map((row: DrugItem) => ({ + id: row.id, + price: parseFloat(String(row.price)) || 0, + buy_price: parseFloat(String(row.buy_price)) || 0, + })); + + // 验证数据 + for (const drug of drugs) { + if (drug.price < 0 || drug.buy_price < 0) { + message.error('价格不能为负数'); + return; + } + if (isNaN(drug.price) || isNaN(drug.buy_price)) { + message.error('价格格式不正确'); + return; + } + } + + await updateStoreDrugPricesApi({ + store_id: storeId, + drugs, + }); + + message.success('保存成功'); + gridApi?.reload?.(); + return; + } + + // 构建提交数据(只提交修改过的数据) + const dataToSave = updateRecords; + + // 构建提交数据 + const drugs = dataToSave.map((row: DrugItem) => ({ + id: row.id, + price: parseFloat(String(row.price)) || 0, + buy_price: parseFloat(String(row.buy_price)) || 0, + })); + + // 验证数据 + for (const drug of drugs) { + if (drug.price < 0 || drug.buy_price < 0) { + message.error('价格不能为负数'); + return; + } + if (isNaN(drug.price) || isNaN(drug.buy_price)) { + message.error('价格格式不正确'); + return; + } + } + + await updateStoreDrugPricesApi({ + store_id: storeId, + drugs, + }); + + message.success('保存成功'); + // 刷新表格数据 + gridApi?.reload?.(); + } catch (error: any) { + message.error(error?.message || '保存失败'); + } +}; + +/** + * 获取中药表格配置 + * @param storeId 诊所ID + * @param onSaveRow 单行保存回调函数 + * @returns 表格配置对象 + */ +export const getChinaMedicineGridOptions = ( + storeId: number, + onSaveRow: (row: DrugItem) => Promise, +): VxeGridProps => ({ + columns: [ + { type: 'seq', width: 60, title: '序号' }, + { field: 'drug_name', title: '药品名称' }, + { + field: 'price', + title: '零售价', + editRender: { name: 'input', props: { type: 'number', step: 0.01, min: 0 } }, + formatter: ({ cellValue }) => { + if (cellValue === null || cellValue === undefined || cellValue === '') { + return '0.00'; + } + const num = parseFloat(String(cellValue)); + return isNaN(num) ? '0.00' : num.toFixed(2); + }, + }, + { + field: 'buy_price', + title: '供货价', + editRender: { name: 'input', props: { type: 'number', step: 0.01, min: 0 } }, + formatter: ({ cellValue }) => { + if (cellValue === null || cellValue === undefined || cellValue === '') { + return '0.00'; + } + const num = parseFloat(String(cellValue)); + return isNaN(num) ? '0.00' : num.toFixed(2); + }, + }, + { + title: '操作', + slots: { default: 'china-action' }, + }, + ], + editConfig: { + mode: 'cell', + trigger: 'click', + showStatus: true, + }, + proxyConfig: { + ajax: { + query: async ({ page }, formValues) => { + if (!storeId) { + return { items: [], total: 0 }; + } + const res = await getStoreDrugsByTypeApi(storeId, 1); + let items = res || []; + + // 如果有关键词搜索,进行过滤 + if (formValues?.drug_name) { + const keyword = String(formValues.drug_name).toLowerCase(); + items = items.filter((item: DrugItem) => + item.drug_name?.toLowerCase().includes(keyword), + ); + } + + return { items, total: items.length }; + }, + }, + }, + toolbarConfig: { + search: true, + refresh: true, + zoom: true, + slots: { + buttons: 'toolbar-buttons', + }, + }, + height: 500, + showOverflow: true, +}); + +/** + * 获取西药表格配置 + * @param storeId 诊所ID + * @param onSaveRow 单行保存回调函数 + * @returns 表格配置对象 + */ +export const getWesternMedicineGridOptions = ( + storeId: number, + onSaveRow: (row: DrugItem) => Promise, +): VxeGridProps => ({ + columns: [ + { type: 'seq', width: 60, title: '序号' }, + { field: 'drug_name', title: '药品名称' }, + { + field: 'image', + title: '图片', + slots: { default: 'western-image' }, + }, + { + field: 'price', + title: '零售价', + editRender: { name: 'input', props: { type: 'number', step: 0.01, min: 0 } }, + formatter: ({ cellValue }) => { + if (cellValue === null || cellValue === undefined || cellValue === '') { + return '0.00'; + } + const num = parseFloat(String(cellValue)); + return isNaN(num) ? '0.00' : num.toFixed(2); + }, + }, + { + field: 'buy_price', + title: '供货价', + editRender: { name: 'input', props: { type: 'number', step: 0.01, min: 0 } }, + formatter: ({ cellValue }) => { + if (cellValue === null || cellValue === undefined || cellValue === '') { + return '0.00'; + } + const num = parseFloat(String(cellValue)); + return isNaN(num) ? '0.00' : num.toFixed(2); + }, + }, + { + title: '操作', + slots: { default: 'western-action' }, + }, + ], + editConfig: { + mode: 'cell', + trigger: 'click', + showStatus: true, + }, + proxyConfig: { + ajax: { + query: async ({ page }, formValues) => { + if (!storeId) { + return { items: [], total: 0 }; + } + const res = await getStoreDrugsByTypeApi(storeId, 2); + let items = res || []; + + // 如果有关键词搜索,进行过滤 + if (formValues?.drug_name) { + const keyword = String(formValues.drug_name).toLowerCase(); + items = items.filter((item: DrugItem) => + item.drug_name?.toLowerCase().includes(keyword), + ); + } + + return { items, total: items.length }; + }, + }, + }, + toolbarConfig: { + search: true, + refresh: true, + zoom: true, + slots: { + buttons: 'toolbar-buttons', + }, + }, + height: 500, + showOverflow: true, +}); diff --git a/apps/web-antd/src/views/system/store/config/search.ts b/apps/web-antd/src/views/system/store/config/search.ts index d3dc7417..b5ed68ad 100644 --- a/apps/web-antd/src/views/system/store/config/search.ts +++ b/apps/web-antd/src/views/system/store/config/search.ts @@ -57,3 +57,25 @@ export const formOptions: VbenFormProps = { // 按下回车时是否提交表单 submitOnEnter: false, }; + +// 药品价格编辑搜索表单配置 +export const drugPriceFormOptions: VbenFormProps = { + collapsed: false, + schema: [ + { + component: 'VbenInput', + componentProps: { + placeholder: '输入药品名称', + }, + defaultValue: '', + fieldName: 'drug_name', + label: '药品名称', + }, + ], + showCollapseButton: true, + submitButtonOptions: { + content: '查询', + }, + submitOnChange: true, + submitOnEnter: false, +}; diff --git a/apps/web-antd/src/views/system/store/index.vue b/apps/web-antd/src/views/system/store/index.vue index abd4ecf1..e2a07bb7 100644 --- a/apps/web-antd/src/views/system/store/index.vue +++ b/apps/web-antd/src/views/system/store/index.vue @@ -1,9 +1,10 @@