售价:{{
item.buy_price != null && item.buy_price !== ''
- ? `${item.price} 元/g`
+ ? `${item.price} 元/${item.drug?.unit?.name || item.unit?.name || 'g'}`
: '—'
}}
@@ -436,7 +436,7 @@ function prescriptionStatusColor() {
{{ item.drug_name }}
-
规格: {{ item.drug.specification || 'g' }}
+
规格: {{ item.drug.specification || item.drug?.unit?.name || 'g' }}
数量: {{ item.number }}
单价: {{ item.price }} 元
diff --git a/apps/web-antd/src/views/business/order/product-order/config/table.ts b/apps/web-antd/src/views/business/order/product-order/config/table.ts
index d0e597ea..61e73107 100644
--- a/apps/web-antd/src/views/business/order/product-order/config/table.ts
+++ b/apps/web-antd/src/views/business/order/product-order/config/table.ts
@@ -17,7 +17,7 @@ export const gridOptions: VxeGridProps = {
},
columns: [
{ type: 'expand', width: 80, slots: { content: 'expand-content' } },
- { field: 'id', align: 'left', title: 'ID', width: 100 },
+ { field: 'id', align: 'left', title: 'ID', width: 50 },
{
field: 'order_no',
align: 'left',
diff --git a/apps/web-antd/src/views/business/order/product-order/index.vue b/apps/web-antd/src/views/business/order/product-order/index.vue
index 7cf6a92c..87ea2b35 100644
--- a/apps/web-antd/src/views/business/order/product-order/index.vue
+++ b/apps/web-antd/src/views/business/order/product-order/index.vue
@@ -1394,14 +1394,14 @@ const openOrderAmountVerify = () => {
供货价:{{
item.buy_price != null && item.buy_price !== ''
- ? `${item.buy_price} 元/g`
+ ? `${item.buy_price} 元/${item.drug?.unit?.name || item.unit?.name || 'g'}`
: '—'
}}
售价:{{
item.buy_price != null && item.buy_price !== ''
- ? `${item.price} 元/g`
+ ? `${item.price} 元/${item.drug?.unit?.name || item.unit?.name || 'g'}`
: '—'
}}
diff --git a/apps/web-antd/src/views/business/patient-call-log-dict/api/index.ts b/apps/web-antd/src/views/business/patient-call-log-dict/api/index.ts
new file mode 100644
index 00000000..82d51e7f
--- /dev/null
+++ b/apps/web-antd/src/views/business/patient-call-log-dict/api/index.ts
@@ -0,0 +1,34 @@
+import { requestClient } from '#/api/request';
+
+// 后端路由前缀:patient-call-log-dict(routes/admin.php 中 cc_auto_route_register 注册)
+const prefix = 'patient-call-log-dict/';
+
+/** 列表(分页 + 搜索 name/type/status) */
+export async function getPatientCallLogDictList(data: any) {
+ return requestClient.get(`${prefix}list`, { params: data });
+}
+
+/** 下拉:可选 type 过滤(type=1 结果 / type=2 标签) */
+export async function getPatientCallLogDictOption(data?: any) {
+ return requestClient.get(`${prefix}option`, { params: data });
+}
+
+/** 详情 */
+export async function getPatientCallLogDictInfo(id: number) {
+ return requestClient.get(`${prefix}detail`, { params: { id } });
+}
+
+/** 新增 */
+export async function createPatientCallLogDict(data: Record) {
+ return requestClient.post(`${prefix}create`, data);
+}
+
+/** 更新 */
+export async function updatePatientCallLogDict(data: Record) {
+ return requestClient.post(`${prefix}update`, data);
+}
+
+/** 删除(软删;ids 数组) */
+export async function deletePatientCallLogDict(data: Record) {
+ return requestClient.post(`${prefix}delete`, data);
+}
diff --git a/apps/web-antd/src/views/business/patient-call-log-dict/components/modal.vue b/apps/web-antd/src/views/business/patient-call-log-dict/components/modal.vue
new file mode 100644
index 00000000..dd412f61
--- /dev/null
+++ b/apps/web-antd/src/views/business/patient-call-log-dict/components/modal.vue
@@ -0,0 +1,88 @@
+
+
+
+
+
+
diff --git a/apps/web-antd/src/views/business/patient-call-log-dict/config/form.ts b/apps/web-antd/src/views/business/patient-call-log-dict/config/form.ts
new file mode 100644
index 00000000..470b642d
--- /dev/null
+++ b/apps/web-antd/src/views/business/patient-call-log-dict/config/form.ts
@@ -0,0 +1,96 @@
+import type { VbenFormProps } from '#/adapter/form';
+
+export const modalFormProps: VbenFormProps = {
+ wrapperClass: 'grid-cols-12',
+ commonConfig: {
+ formItemClass: 'col-span-12',
+ componentProps: {
+ class: 'w-full',
+ },
+ },
+ layout: 'horizontal',
+ schema: [
+ {
+ component: 'VbenInput',
+ fieldName: 'id',
+ label: 'ID',
+ formItemClass: 'col-span-6',
+ defaultValue: '',
+ dependencies: {
+ show: false,
+ triggerFields: ['id'],
+ },
+ },
+ {
+ // 1 回访结果 / 2 回访标签;区分后续列表渲染
+ component: 'VbenSelect',
+ componentProps: {
+ placeholder: '请选择类型',
+ options: [
+ { label: '回访结果', value: 1 },
+ { label: '回访标签', value: 2 },
+ ],
+ },
+ fieldName: 'type',
+ label: '类型',
+ rules: 'required',
+ defaultValue: 1,
+ },
+ {
+ component: 'VbenInput',
+ componentProps: {
+ placeholder: '请输入展示名(如 接通/关怀)',
+ },
+ fieldName: 'name',
+ label: '名称',
+ rules: 'required',
+ defaultValue: '',
+ },
+ {
+ // 小程序存储的英文/拼音 value;与历史记录匹配
+ component: 'VbenInput',
+ componentProps: {
+ placeholder: '请输入存储值(如 connected/care)',
+ },
+ fieldName: 'value',
+ label: '存储值',
+ rules: 'required',
+ defaultValue: '',
+ },
+ {
+ // hex 颜色,用于小程序彩色 tag
+ component: 'VbenInput',
+ componentProps: {
+ placeholder: '请输入 hex 颜色,如 #6acdbb',
+ },
+ fieldName: 'color',
+ label: '颜色',
+ defaultValue: '#6acdbb',
+ },
+ {
+ component: 'VbenInputNumber',
+ componentProps: {
+ min: 0,
+ precision: 0,
+ },
+ fieldName: 'sort',
+ label: '排序',
+ defaultValue: 0,
+ },
+ {
+ component: 'VbenSelect',
+ componentProps: {
+ placeholder: '请选择状态',
+ options: [
+ { label: '启用', value: 1 },
+ { label: '禁用', value: 0 },
+ ],
+ },
+ fieldName: 'status',
+ label: '状态',
+ formItemClass: 'col-span-6',
+ defaultValue: 1,
+ },
+ ],
+ showDefaultActions: false,
+};
diff --git a/apps/web-antd/src/views/business/patient-call-log-dict/config/search.ts b/apps/web-antd/src/views/business/patient-call-log-dict/config/search.ts
new file mode 100644
index 00000000..aaf2b136
--- /dev/null
+++ b/apps/web-antd/src/views/business/patient-call-log-dict/config/search.ts
@@ -0,0 +1,45 @@
+import type { VbenFormProps } from '@vben/common-ui';
+
+// 列表搜索:按名称模糊、类型精确、状态精确
+export const formOptions: VbenFormProps = {
+ layout: 'inline',
+ showResetButton: true,
+ showSubmitButton: true,
+ schemas: [
+ {
+ fieldName: 'name',
+ component: 'Input',
+ label: '名称',
+ componentProps: {
+ placeholder: '请输入名称',
+ allowClear: true,
+ },
+ },
+ {
+ fieldName: 'type',
+ component: 'Select',
+ label: '类型',
+ componentProps: {
+ placeholder: '请选择类型',
+ allowClear: true,
+ options: [
+ { label: '回访结果', value: 1 },
+ { label: '回访标签', value: 2 },
+ ],
+ },
+ },
+ {
+ fieldName: 'status',
+ component: 'Select',
+ label: '状态',
+ componentProps: {
+ placeholder: '请选择状态',
+ allowClear: true,
+ options: [
+ { label: '启用', value: 1 },
+ { label: '禁用', value: 0 },
+ ],
+ },
+ },
+ ],
+};
diff --git a/apps/web-antd/src/views/business/patient-call-log-dict/config/table.ts b/apps/web-antd/src/views/business/patient-call-log-dict/config/table.ts
new file mode 100644
index 00000000..2c75f699
--- /dev/null
+++ b/apps/web-antd/src/views/business/patient-call-log-dict/config/table.ts
@@ -0,0 +1,79 @@
+import type { VxeGridProps } from '#/adapter/vxe-table';
+
+import { getPatientCallLogDictList } from '../api';
+
+interface RowType {
+ id: number;
+ type: number;
+ type_txt: string;
+ name: string;
+ value: string;
+ color: string;
+ sort: number;
+ status: number;
+ status_txt: string;
+ created_at: string;
+ updated_at: string;
+}
+
+export const gridOptions: VxeGridProps = {
+ checkboxConfig: {
+ highlight: true,
+ labelField: '',
+ },
+ columnConfig: {
+ useKey: true,
+ },
+ rowConfig: {
+ useKey: true,
+ isHover: true,
+ isCurrent: true,
+ },
+ columns: [
+ { type: 'checkbox', width: 60 },
+ { field: 'id', align: 'left', title: 'ID', width: 80 },
+ { field: 'type_txt', align: 'left', title: '类型', width: 110 },
+ { field: 'name', align: 'left', title: '名称', minWidth: 140 },
+ { field: 'value', align: 'left', title: '存储值', minWidth: 140 },
+ {
+ field: 'color',
+ align: 'left',
+ title: '颜色',
+ width: 120,
+ // 用色块+hex 直观预览,避免放函数调用导致渲染异常
+ slots: { default: 'color' },
+ },
+ { field: 'sort', align: 'left', title: '排序', width: 90 },
+ { field: 'status_txt', align: 'left', title: '状态', width: 90 },
+ { field: 'created_at', title: '创建时间', width: 180 },
+ { type: 'html', title: '操作', slots: { default: 'action' }, width: 160 },
+ ],
+ keepSource: true,
+ pagerConfig: {},
+ proxyConfig: {
+ ajax: {
+ query: async ({ page }, formValues) => {
+ return await getPatientCallLogDictList({
+ page: page.currentPage,
+ pageSize: page.pageSize,
+ ...formValues,
+ });
+ },
+ },
+ },
+ border: false,
+ toolbarConfig: {
+ search: true,
+ refresh: true,
+ print: false,
+ export: false,
+ zoom: true,
+ slots: {
+ buttons: 'toolbar-buttons',
+ },
+ custom: {
+ icon: 'vxe-icon-menu',
+ },
+ },
+ showOverflow: false,
+};
diff --git a/apps/web-antd/src/views/business/patient-call-log-dict/index.vue b/apps/web-antd/src/views/business/patient-call-log-dict/index.vue
new file mode 100644
index 00000000..01d1ade6
--- /dev/null
+++ b/apps/web-antd/src/views/business/patient-call-log-dict/index.vue
@@ -0,0 +1,124 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ row.color }}
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/web-antd/src/views/business/special-prescription/components/ChineseDrugEditor.vue b/apps/web-antd/src/views/business/special-prescription/components/ChineseDrugEditor.vue
index 5600a99a..6edf1e6f 100644
--- a/apps/web-antd/src/views/business/special-prescription/components/ChineseDrugEditor.vue
+++ b/apps/web-antd/src/views/business/special-prescription/components/ChineseDrugEditor.vue
@@ -33,6 +33,8 @@ export interface ChineseDrugItem {
price: number;
buy_price?: number;
way_id: number;
+ unit_id?: number;
+ unit?: { id: number; name: string } | null;
}
const props = withDefaults(
@@ -123,6 +125,8 @@ const newDrugInfo = ref<{
number?: number;
price?: number;
way_id?: number;
+ unit_id?: number;
+ unit?: { id: number; name: string } | null;
}>({});
onMounted(async () => {
@@ -180,6 +184,10 @@ function selectNewDrug(drugId: number) {
newDrugInfo.value.name = selectedItem.drug?.drug_name || '';
newDrugInfo.value.price = selectedItem.price || 0;
newDrugInfo.value.way_id = 0;
+ newDrugInfo.value.unit =
+ selectedItem.drug?.unit || selectedItem.unit || null;
+ newDrugInfo.value.unit_id =
+ selectedItem.drug?.unit_id || selectedItem.unit_id || 0;
nextTick(() => {
const numberInput = document.querySelector('.new-chinese-number input') as HTMLInputElement;
numberInput?.focus();
@@ -204,6 +212,8 @@ function addChineseDrug() {
number: newDrugInfo.value.number,
price: newDrugInfo.value.price || 0,
way_id: newDrugInfo.value.way_id || 0,
+ unit_id: newDrugInfo.value.unit_id || 0,
+ unit: newDrugInfo.value.unit || null,
});
newDrugInfo.value = {};
chineseSearchResults.value = [];
@@ -244,6 +254,8 @@ function changeChineseDrug(index: number, drugId: number) {
drug.drug_id = drugId;
drug.drug_name = selectedItem.drug?.drug_name || '';
drug.price = selectedItem.price || 0;
+ drug.unit = selectedItem.drug?.unit || selectedItem.unit || null;
+ drug.unit_id = selectedItem.drug?.unit_id || selectedItem.unit_id || 0;
syncToParent();
nextTick(() => {
const numberInput = document.querySelector(`.chinese-number-${index} input`) as HTMLInputElement;
@@ -287,6 +299,8 @@ function loadDrugs(recipes: any[], dosage?: number, dayDosage?: number, drugPric
price: zeroPrice ? 0 : (configured?.sell_price ?? recipe.price ?? 0),
buy_price: zeroPrice ? 0 : (configured?.buy_price ?? recipe.buy_price ?? 0),
way_id: recipe.way_id || 0,
+ unit_id: recipe.unit_id || 0,
+ unit: recipe.unit || null,
};
});
if (dosage !== undefined) dosageLocal.value = dosage;
@@ -404,7 +418,7 @@ defineExpose({
{{ drug.drug_name }}
,
- {{ drug.number }}g
+ {{ drug.number }}{{ drug.unit?.name || 'g' }}
,
{{ getWayName(drug.way_id) }}
@@ -439,7 +453,7 @@ defineExpose({
style="width: 60px"
@change="onDrugNumberChange"
/>
- g
+ {{ drug.unit?.name || 'g' }}
,
方法:
diff --git a/apps/web-antd/src/views/doctor/doctor-reception/components/WesternModal.vue b/apps/web-antd/src/views/doctor/doctor-reception/components/WesternModal.vue
index c6daa068..3fa9922e 100644
--- a/apps/web-antd/src/views/doctor/doctor-reception/components/WesternModal.vue
+++ b/apps/web-antd/src/views/doctor/doctor-reception/components/WesternModal.vue
@@ -122,6 +122,13 @@ const getDrugListByWesternModal = debounce(async (searchText = '') => {
drugList.value = res.map((item) => {
const matched = selectList.value.find((v) => v.index_id === item.id);
+ const unitId = matched?.unit_id || item.drug?.unit_id;
+ // 优先接口返回的 unit,再回退本地字典,保证中药网格展示真实单位
+ const unitObj =
+ matched?.unit ||
+ item.drug?.unit ||
+ item.unit ||
+ drugUnit.value.find((u) => u.id === unitId);
return {
...item,
select_number: matched?.select_number || 0,
@@ -133,7 +140,8 @@ const getDrugListByWesternModal = debounce(async (searchText = '') => {
frequency_id: matched?.frequency_id || item.drug.frequency_id,
type_id: matched?.type_id || item.drug.type_id,
time_id: matched?.time_id || item.drug.time_id,
- unit_id: matched?.unit_id || item.drug.unit_id,
+ unit_id: unitId,
+ unit: unitObj,
},
};
});
@@ -190,8 +198,10 @@ function addProducts(data) {
use_frequency: drugUseFrequency.value.find(
(item) => item.id === data.drug.frequency_id,
),
- // 药品单位信息
- unit: drugUnit.value.find((item) => item.id === data.drug.unit_id),
+ // 药品单位:优先用选药接口返回的 unit,再回退本地字典
+ unit:
+ data.drug?.unit ||
+ drugUnit.value.find((item) => item.id === data.drug.unit_id),
// 药品价格
price: data.price,
// 药品使用方式ID
@@ -751,7 +761,7 @@ function updateProductNumber(id, number) {