feat: 111
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
# title
|
# title
|
||||||
VITE_GLOB_APP_TITLE = SimpleAdmin
|
VITE_GLOB_APP_TITLE = 未病局管理系统
|
||||||
|
|
||||||
# 本地运行端口号
|
# 本地运行端口号
|
||||||
VITE_PORT = 8848
|
VITE_PORT = 8848
|
||||||
|
|||||||
+2
-2
@@ -25,10 +25,10 @@ VITE_PWA = true
|
|||||||
VITE_HTTP_PROXY = true
|
VITE_HTTP_PROXY = true
|
||||||
|
|
||||||
# 线上环境接口地址
|
# 线上环境接口地址
|
||||||
VITE_API_URL = http://127.0.0.1:5566
|
VITE_API_URL = http://medical.23544.com:7106/
|
||||||
|
|
||||||
# 开发环境跨域代理,支持配置多个
|
# 开发环境跨域代理,支持配置多个
|
||||||
VITE_PROXY = [["/api","http://127.0.0.1:5566"]]
|
VITE_PROXY = [["/api","http://medical.23544.com:7106/"]]
|
||||||
|
|
||||||
#是否启用mqtt
|
#是否启用mqtt
|
||||||
VITE_MQTT = false
|
VITE_MQTT = false
|
||||||
|
|||||||
+29
-31
@@ -20,42 +20,40 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
// 继承某些已有的规则
|
// 继承某些已有的规则
|
||||||
extends: ["plugin:vue/vue3-recommended", "plugin:@typescript-eslint/recommended", "plugin:prettier/recommended"],
|
extends: ["plugin:vue/vue3-recommended", "plugin:@typescript-eslint/recommended"],
|
||||||
/**
|
/**
|
||||||
* "off" 或 0 ==> 关闭规则
|
* "off" 或 0 ==> 关闭规则
|
||||||
* "warn" 或 1 ==> 打开的规则作为警告(不影响代码执行)
|
* "warn" 或 1 ==> 打开的规则作为警告(不影响代码执行)
|
||||||
* "error" 或 2 ==> 规则作为一个错误(代码不能执行,界面报错)
|
* "error" 或 2 ==> 规则作为一个错误(代码不能执行,界面报错)
|
||||||
*/
|
*/
|
||||||
rules: {
|
rules: {
|
||||||
// eslint (http://eslint.cn/docs/rules)
|
// // eslint (http://eslint.cn/docs/rules)
|
||||||
"no-var": "error", // 要求使用 let 或 const 而不是 var
|
// "no-var": "error", // 要求使用 let 或 const 而不是 var
|
||||||
"no-multiple-empty-lines": ["error", { max: 1 }], // 不允许多个空行
|
// "no-multiple-empty-lines": ["error", { max: 1 }], // 不允许多个空行
|
||||||
"prefer-const": "off", // 使用 let 关键字声明但在初始分配后从未重新分配的变量,要求使用 const
|
// "prefer-const": "off", // 使用 let 关键字声明但在初始分配后从未重新分配的变量,要求使用 const
|
||||||
"no-use-before-define": "off", // 禁止在 函数/类/变量 定义之前使用它们
|
// "no-use-before-define": "off", // 禁止在 函数/类/变量 定义之前使用它们
|
||||||
|
// // typeScript (https://typescript-eslint.io/rules)
|
||||||
// typeScript (https://typescript-eslint.io/rules)
|
// "@typescript-eslint/no-unused-vars": "error", // 禁止定义未使用的变量
|
||||||
"@typescript-eslint/no-unused-vars": "error", // 禁止定义未使用的变量
|
// "@typescript-eslint/prefer-ts-expect-error": "error", // 禁止使用 @ts-ignore
|
||||||
"@typescript-eslint/prefer-ts-expect-error": "error", // 禁止使用 @ts-ignore
|
// "@typescript-eslint/no-empty-function": "error", // 禁止空函数
|
||||||
"@typescript-eslint/no-empty-function": "error", // 禁止空函数
|
// "@typescript-eslint/ban-ts-comment": "error", // 禁止 @ts-<directive> 使用注释或要求在指令后进行描述
|
||||||
"@typescript-eslint/ban-ts-comment": "error", // 禁止 @ts-<directive> 使用注释或要求在指令后进行描述
|
// "@typescript-eslint/no-inferrable-types": "off", // 可以轻松推断的显式类型可能会增加不必要的冗长
|
||||||
"@typescript-eslint/no-inferrable-types": "off", // 可以轻松推断的显式类型可能会增加不必要的冗长
|
// "@typescript-eslint/no-namespace": "off", // 禁止使用自定义 TypeScript 模块和命名空间
|
||||||
"@typescript-eslint/no-namespace": "off", // 禁止使用自定义 TypeScript 模块和命名空间
|
"@typescript-eslint/no-explicit-any": "off" // 禁止使用 any 类型
|
||||||
"@typescript-eslint/no-explicit-any": "off", // 禁止使用 any 类型
|
// "@typescript-eslint/ban-types": "off", // 禁止使用特定类型
|
||||||
"@typescript-eslint/ban-types": "off", // 禁止使用特定类型
|
// "@typescript-eslint/no-var-requires": "off", // 允许使用 require() 函数导入模块
|
||||||
"@typescript-eslint/no-var-requires": "off", // 允许使用 require() 函数导入模块
|
// "@typescript-eslint/no-non-null-assertion": "off", // 不允许使用后缀运算符的非空断言(!)
|
||||||
"@typescript-eslint/no-non-null-assertion": "off", // 不允许使用后缀运算符的非空断言(!)
|
// // vue (https://eslint.vuejs.org/rules)
|
||||||
|
// "vue/script-setup-uses-vars": "error", // 防止<script setup>使用的变量<template>被标记为未使用,此规则仅在启用该no-unused-vars规则时有效
|
||||||
// vue (https://eslint.vuejs.org/rules)
|
// "vue/v-slot-style": "error", // 强制执行 v-slot 指令样式
|
||||||
"vue/script-setup-uses-vars": "error", // 防止<script setup>使用的变量<template>被标记为未使用,此规则仅在启用该no-unused-vars规则时有效
|
// "vue/no-mutating-props": "error", // 不允许改变组件 prop
|
||||||
"vue/v-slot-style": "error", // 强制执行 v-slot 指令样式
|
// "vue/custom-event-name-casing": "error", // 为自定义事件名称强制使用特定大小写
|
||||||
"vue/no-mutating-props": "error", // 不允许改变组件 prop
|
// "vue/html-closing-bracket-newline": "error", // 在标签的右括号之前要求或禁止换行
|
||||||
"vue/custom-event-name-casing": "error", // 为自定义事件名称强制使用特定大小写
|
// "vue/attribute-hyphenation": "error", // 对模板中的自定义组件强制执行属性命名样式:my-prop="prop"
|
||||||
"vue/html-closing-bracket-newline": "error", // 在标签的右括号之前要求或禁止换行
|
// "vue/attributes-order": "off", // vue api使用顺序,强制执行属性顺序
|
||||||
"vue/attribute-hyphenation": "error", // 对模板中的自定义组件强制执行属性命名样式:my-prop="prop"
|
// "vue/no-v-html": "off", // 禁止使用 v-html
|
||||||
"vue/attributes-order": "off", // vue api使用顺序,强制执行属性顺序
|
// "vue/require-default-prop": "off", // 此规则要求为每个 prop 为必填时,必须提供默认值
|
||||||
"vue/no-v-html": "off", // 禁止使用 v-html
|
// "vue/multi-word-component-names": "off", // 要求组件名称始终为 “-” 链接的单词
|
||||||
"vue/require-default-prop": "off", // 此规则要求为每个 prop 为必填时,必须提供默认值
|
// "vue/no-setup-props-destructure": "off" // 禁止解构 props 传递给 setup
|
||||||
"vue/multi-word-component-names": "off", // 要求组件名称始终为 “-” 链接的单词
|
|
||||||
"vue/no-setup-props-destructure": "off" // 禁止解构 props 传递给 setup
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
#!/usr/bin/env sh
|
|
||||||
. "$(dirname -- "$0")/_/husky.sh"
|
|
||||||
|
|
||||||
npx --no-install commitlint --edit $1
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
#!/usr/bin/env sh
|
|
||||||
. "$(dirname -- "$0")/_/husky.sh"
|
|
||||||
|
|
||||||
npm run lint:lint-staged
|
|
||||||
Vendored
+1
-1
@@ -13,7 +13,7 @@
|
|||||||
"files.eol": "\n",
|
"files.eol": "\n",
|
||||||
"typescript.tsdk": "node_modules/typescript/lib",
|
"typescript.tsdk": "node_modules/typescript/lib",
|
||||||
"[vue]": {
|
"[vue]": {
|
||||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
"editor.defaultFormatter": "Vue.volar"
|
||||||
},
|
},
|
||||||
"[typescript]": {
|
"[typescript]": {
|
||||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||||
|
|||||||
+2
-2
@@ -6,7 +6,7 @@ import { createSvgIconsPlugin } from "vite-plugin-svg-icons";
|
|||||||
import { createHtmlPlugin } from "vite-plugin-html";
|
import { createHtmlPlugin } from "vite-plugin-html";
|
||||||
import vue from "@vitejs/plugin-vue";
|
import vue from "@vitejs/plugin-vue";
|
||||||
import vueJsx from "@vitejs/plugin-vue-jsx";
|
import vueJsx from "@vitejs/plugin-vue-jsx";
|
||||||
import eslintPlugin from "vite-plugin-eslint";
|
// import eslintPlugin from "vite-plugin-eslint";
|
||||||
import viteCompression from "vite-plugin-compression";
|
import viteCompression from "vite-plugin-compression";
|
||||||
import vueSetupExtend from "unplugin-vue-setup-extend-plus/vite";
|
import vueSetupExtend from "unplugin-vue-setup-extend-plus/vite";
|
||||||
import UnoCSS from "unocss/vite";
|
import UnoCSS from "unocss/vite";
|
||||||
@@ -31,7 +31,7 @@ export const createVitePlugins = (viteEnv: ViteEnv): (PluginOption | PluginOptio
|
|||||||
// vue 可以使用 jsx/tsx 语法
|
// vue 可以使用 jsx/tsx 语法
|
||||||
vueJsx(),
|
vueJsx(),
|
||||||
// esLint 报错信息显示在浏览器界面上
|
// esLint 报错信息显示在浏览器界面上
|
||||||
eslintPlugin(),
|
// eslintPlugin(),
|
||||||
// name 可以写在 script 标签上
|
// name 可以写在 script 标签上
|
||||||
vueSetupExtend({}),
|
vueSetupExtend({}),
|
||||||
// 创建打包压缩配置
|
// 创建打包压缩配置
|
||||||
|
|||||||
Vendored
-48
@@ -18,67 +18,22 @@ declare module 'vue' {
|
|||||||
CropUpload: typeof import('./src/components/CropUpload/index.vue')['default']
|
CropUpload: typeof import('./src/components/CropUpload/index.vue')['default']
|
||||||
DatePicker: typeof import('./src/components/Form/DatePicker/index.vue')['default']
|
DatePicker: typeof import('./src/components/Form/DatePicker/index.vue')['default']
|
||||||
ECharts: typeof import('./src/components/ECharts/index.vue')['default']
|
ECharts: typeof import('./src/components/ECharts/index.vue')['default']
|
||||||
ElAlert: typeof import('element-plus/es')['ElAlert']
|
|
||||||
ElAside: typeof import('element-plus/es')['ElAside']
|
|
||||||
ElAvatar: typeof import('element-plus/es')['ElAvatar']
|
|
||||||
ElBadge: typeof import('element-plus/es')['ElBadge']
|
|
||||||
ElBreadcrumb: typeof import('element-plus/es')['ElBreadcrumb']
|
|
||||||
ElBreadcrumbItem: typeof import('element-plus/es')['ElBreadcrumbItem']
|
|
||||||
ElButton: typeof import('element-plus/es')['ElButton']
|
ElButton: typeof import('element-plus/es')['ElButton']
|
||||||
ElCard: typeof import('element-plus/es')['ElCard']
|
|
||||||
ElCascader: typeof import('element-plus/es')['ElCascader']
|
|
||||||
ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
|
ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
|
||||||
ElCol: typeof import('element-plus/es')['ElCol']
|
|
||||||
ElColorPicker: typeof import('element-plus/es')['ElColorPicker']
|
|
||||||
ElContainer: typeof import('element-plus/es')['ElContainer']
|
|
||||||
ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
|
|
||||||
ElDescriptions: typeof import('element-plus/es')['ElDescriptions']
|
|
||||||
ElDescriptionsItem: typeof import('element-plus/es')['ElDescriptionsItem']
|
|
||||||
ElDialog: typeof import('element-plus/es')['ElDialog']
|
ElDialog: typeof import('element-plus/es')['ElDialog']
|
||||||
ElDivider: typeof import('element-plus/es')['ElDivider']
|
|
||||||
ElDrawer: typeof import('element-plus/es')['ElDrawer']
|
|
||||||
ElDropdown: typeof import('element-plus/es')['ElDropdown']
|
|
||||||
ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
|
|
||||||
ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu']
|
|
||||||
ElEmpty: typeof import('element-plus/es')['ElEmpty']
|
ElEmpty: typeof import('element-plus/es')['ElEmpty']
|
||||||
ElFooter: typeof import('element-plus/es')['ElFooter']
|
|
||||||
ElForm: typeof import('element-plus/es')['ElForm']
|
ElForm: typeof import('element-plus/es')['ElForm']
|
||||||
ElFormItem: typeof import('element-plus/es')['ElFormItem']
|
ElFormItem: typeof import('element-plus/es')['ElFormItem']
|
||||||
ElHeader: typeof import('element-plus/es')['ElHeader']
|
|
||||||
ElIcon: typeof import('element-plus/es')['ElIcon']
|
ElIcon: typeof import('element-plus/es')['ElIcon']
|
||||||
ElImage: typeof import('element-plus/es')['ElImage']
|
|
||||||
ElImageViewer: typeof import('element-plus/es')['ElImageViewer']
|
|
||||||
ElInput: typeof import('element-plus/es')['ElInput']
|
ElInput: typeof import('element-plus/es')['ElInput']
|
||||||
ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
|
|
||||||
ElLink: typeof import('element-plus/es')['ElLink']
|
|
||||||
ElMain: typeof import('element-plus/es')['ElMain']
|
|
||||||
ElMenu: typeof import('element-plus/es')['ElMenu']
|
|
||||||
ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
|
|
||||||
ElOption: typeof import('element-plus/es')['ElOption']
|
ElOption: typeof import('element-plus/es')['ElOption']
|
||||||
ElPageHeader: typeof import('element-plus/es')['ElPageHeader']
|
|
||||||
ElPagination: typeof import('element-plus/es')['ElPagination']
|
|
||||||
ElPopover: typeof import('element-plus/es')['ElPopover']
|
ElPopover: typeof import('element-plus/es')['ElPopover']
|
||||||
ElRadio: typeof import('element-plus/es')['ElRadio']
|
|
||||||
ElRadioButton: typeof import('element-plus/es')['ElRadioButton']
|
|
||||||
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
|
|
||||||
ElRow: typeof import('element-plus/es')['ElRow']
|
|
||||||
ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
|
|
||||||
ElSelect: typeof import('element-plus/es')['ElSelect']
|
ElSelect: typeof import('element-plus/es')['ElSelect']
|
||||||
ElSlider: typeof import('element-plus/es')['ElSlider']
|
|
||||||
ElSpace: typeof import('element-plus/es')['ElSpace']
|
ElSpace: typeof import('element-plus/es')['ElSpace']
|
||||||
ElStep: typeof import('element-plus/es')['ElStep']
|
|
||||||
ElSteps: typeof import('element-plus/es')['ElSteps']
|
|
||||||
ElSubMenu: typeof import('element-plus/es')['ElSubMenu']
|
|
||||||
ElSwitch: typeof import('element-plus/es')['ElSwitch']
|
ElSwitch: typeof import('element-plus/es')['ElSwitch']
|
||||||
ElTable: typeof import('element-plus/es')['ElTable']
|
|
||||||
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
|
|
||||||
ElTabPane: typeof import('element-plus/es')['ElTabPane']
|
ElTabPane: typeof import('element-plus/es')['ElTabPane']
|
||||||
ElTabs: typeof import('element-plus/es')['ElTabs']
|
ElTabs: typeof import('element-plus/es')['ElTabs']
|
||||||
ElTag: typeof import('element-plus/es')['ElTag']
|
|
||||||
ElTooltip: typeof import('element-plus/es')['ElTooltip']
|
ElTooltip: typeof import('element-plus/es')['ElTooltip']
|
||||||
ElTreeSelect: typeof import('element-plus/es')['ElTreeSelect']
|
|
||||||
ElUpload: typeof import('element-plus/es')['ElUpload']
|
|
||||||
ElWatermark: typeof import('element-plus/es')['ElWatermark']
|
|
||||||
ESign: typeof import('./src/components/ESign/index.vue')['default']
|
ESign: typeof import('./src/components/ESign/index.vue')['default']
|
||||||
FormContainer: typeof import('./src/components/Form/FormContainer/index.vue')['default']
|
FormContainer: typeof import('./src/components/Form/FormContainer/index.vue')['default']
|
||||||
Grid: typeof import('./src/components/Grid/index.vue')['default']
|
Grid: typeof import('./src/components/Grid/index.vue')['default']
|
||||||
@@ -112,7 +67,4 @@ declare module 'vue' {
|
|||||||
UploadImgs: typeof import('./src/components/Upload/UploadImgs.vue')['default']
|
UploadImgs: typeof import('./src/components/Upload/UploadImgs.vue')['default']
|
||||||
UserSelector: typeof import('./src/components/Selectors/UserSelector/index.vue')['default']
|
UserSelector: typeof import('./src/components/Selectors/UserSelector/index.vue')['default']
|
||||||
}
|
}
|
||||||
export interface ComponentCustomProperties {
|
|
||||||
vLoading: typeof import('element-plus/es')['ElLoadingDirective']
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -23,7 +23,7 @@
|
|||||||
"serve": "vite",
|
"serve": "vite",
|
||||||
"build:dev": "vue-tsc && vite build --mode development",
|
"build:dev": "vue-tsc && vite build --mode development",
|
||||||
"build:test": "vue-tsc && vite build --mode test",
|
"build:test": "vue-tsc && vite build --mode test",
|
||||||
"build:pro": "vue-tsc && vite build --mode production",
|
"build:pro": "vite build --mode production",
|
||||||
"type:check": "vue-tsc --noEmit --skipLibCheck",
|
"type:check": "vue-tsc --noEmit --skipLibCheck",
|
||||||
"preview": "pnpm run build:dev && vite preview",
|
"preview": "pnpm run build:dev && vite preview",
|
||||||
"lint:eslint": "eslint --fix --ext .js,.ts,.vue ./src",
|
"lint:eslint": "eslint --fix --ext .js,.ts,.vue ./src",
|
||||||
|
|||||||
@@ -23,14 +23,14 @@ const medicinalApi = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
/** 获取药材消耗记录 */
|
/** 获取药材消耗记录 */
|
||||||
getConsumptionRecords(id: number) {
|
getConsumptionRecords(params: { id: number; pageNum?: number; pageSize?: number }) {
|
||||||
return http.get<any>(`${id}/consumption-records`);
|
console.log("获取添加记录,请求参数=", params);
|
||||||
|
return http.get<ResPage<any>>(`consumption-records`, params); // 透传分页参数
|
||||||
},
|
},
|
||||||
|
|
||||||
/** 获取药材添加记录 */
|
/** 获取药材添加记录 */
|
||||||
getAdditionRecords(id: number, params?: { pageNum?: number; pageSize?: number }) {
|
getAdditionRecords(params: { id: number; pageNum?: number; pageSize?: number }) {
|
||||||
// 注意:这里把 id 放到路径里,分页走 params
|
return http.get<ResPage<any>>(`addition-records`, params);
|
||||||
return http.get<any>(`/${id}/addition-records`, { params });
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/** 添加药材 */
|
/** 添加药材 */
|
||||||
@@ -39,13 +39,13 @@ const medicinalApi = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
/** 修改药材添加记录 */
|
/** 修改药材添加记录 */
|
||||||
updateAdditionRecord(id: number, params: UpdateMedicinalAddLogInput) {
|
updateAdditionRecord(params: UpdateMedicinalAddLogInput) {
|
||||||
return http.put(`addition-records/${id}`, params);
|
return http.post(`addition-records`, params);
|
||||||
},
|
},
|
||||||
|
|
||||||
/** 删除药材添加记录 */
|
/** 删除药材添加记录 */
|
||||||
deleteAdditionRecord(id: number) {
|
deleteAdditionRecord(params: { id: number }) {
|
||||||
return http.delete(`addition-records/${id}`);
|
return http.post(`addition-delete`, params);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -62,14 +62,15 @@ export interface MedicinalInfo {
|
|||||||
export interface AddMedicinalInput {
|
export interface AddMedicinalInput {
|
||||||
medicinalTypeId: number;
|
medicinalTypeId: number;
|
||||||
addWeight: number;
|
addWeight: number;
|
||||||
unitPrice: number;
|
totalPrice: number;
|
||||||
medicinalName: string;
|
medicinalName: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 修改添加记录 */
|
/** 修改添加记录 */
|
||||||
export interface UpdateMedicinalAddLogInput {
|
export interface UpdateMedicinalAddLogInput {
|
||||||
|
id: number;
|
||||||
addWeight: number;
|
addWeight: number;
|
||||||
unitPrice: number;
|
totalPrice: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export { medicinalApi };
|
export { medicinalApi };
|
||||||
|
|||||||
@@ -1,41 +1,149 @@
|
|||||||
import { moduleRequest } from "@/api/request";
|
import { moduleRequest } from "@/api/request";
|
||||||
|
import { ResPage } from "@/api/interface";
|
||||||
|
|
||||||
const http = moduleRequest("/biz/weibingju/prescription/");
|
const http = moduleRequest("/biz/weibingju/prescription/");
|
||||||
|
|
||||||
|
// -----------------------------
|
||||||
|
// 类型定义(对应后端 DTO)
|
||||||
|
// -----------------------------
|
||||||
|
|
||||||
|
/** 人员类型 */
|
||||||
|
export enum PersonType {
|
||||||
|
Employee = 1,
|
||||||
|
Relative = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 处方列表 DTO */
|
||||||
|
export interface PrescriptionDto {
|
||||||
|
id: number;
|
||||||
|
personId: number;
|
||||||
|
personName: string;
|
||||||
|
personType: PersonType;
|
||||||
|
employeeName?: string;
|
||||||
|
visitDate?: string;
|
||||||
|
canEdit: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 处方药材 DTO */
|
||||||
|
export interface PrescriptionHerbDto {
|
||||||
|
Id: number;
|
||||||
|
medicinalName: string;
|
||||||
|
amountG: number;
|
||||||
|
note?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 人员详情 DTO */
|
||||||
|
export interface PersonDetailDto {
|
||||||
|
id?: number;
|
||||||
|
name: string;
|
||||||
|
age?: number;
|
||||||
|
weight?: number;
|
||||||
|
height?: number;
|
||||||
|
isEmployee: boolean;
|
||||||
|
employeeId?: number;
|
||||||
|
employeeName?: string;
|
||||||
|
relationShip?: number;
|
||||||
|
relationShipName?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 处方详情 DTO */
|
||||||
|
export interface PrescriptionDetailDto {
|
||||||
|
id: number;
|
||||||
|
person: PersonDetailDto;
|
||||||
|
diagnosisResult: string;
|
||||||
|
userMedicinaAdvice: string;
|
||||||
|
visitDate?: string;
|
||||||
|
herbs: PrescriptionHerbDto[];
|
||||||
|
canEdit: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 保存处方输入 DTO */
|
||||||
|
export interface SavePrescriptionInput {
|
||||||
|
id?: number;
|
||||||
|
person: PersonInputDto;
|
||||||
|
diagnosisResult: string;
|
||||||
|
userMedicinaAdvice: string;
|
||||||
|
visitDate?: string;
|
||||||
|
herbs: PrescriptionHerbInputDto[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 人员输入 DTO */
|
||||||
|
export interface PersonInputDto {
|
||||||
|
id?: number;
|
||||||
|
name: string;
|
||||||
|
age?: number;
|
||||||
|
weight?: number;
|
||||||
|
height?: number;
|
||||||
|
isEmployee: boolean;
|
||||||
|
employeeId?: number;
|
||||||
|
relationShip?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 处方药材输入 DTO */
|
||||||
|
export interface PrescriptionHerbInputDto {
|
||||||
|
Id: number;
|
||||||
|
amountG: number;
|
||||||
|
note?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 人员 DTO(列表用) */
|
||||||
|
export interface PersonDto {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
age?: number;
|
||||||
|
employeeId?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 添加人员输入 DTO */
|
||||||
|
export interface AddPersonInput {
|
||||||
|
name: string;
|
||||||
|
age?: number;
|
||||||
|
weight?: number;
|
||||||
|
height?: number;
|
||||||
|
isEmployee: boolean;
|
||||||
|
employeeId?: number;
|
||||||
|
relationShip?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 关系类型 DTO */
|
||||||
|
export interface RelationTypeDto {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------
|
||||||
|
// API 方法(对应后端接口)
|
||||||
|
// -----------------------------
|
||||||
|
|
||||||
const prescriptionApi = {
|
const prescriptionApi = {
|
||||||
/** 获取处方列表(分页) */
|
/** 获取处方列表 */
|
||||||
getList(params: any) {
|
getList(params: any) {
|
||||||
return http.get<any>("list", params);
|
return http.get<ResPage<PrescriptionDto>>("list", params);
|
||||||
},
|
},
|
||||||
|
|
||||||
/** 获取处方详情 */
|
/** 获取处方详情 */
|
||||||
getDetail(params: any) {
|
getDetail(id: number) {
|
||||||
return http.get<any>("detail", params);
|
return http.get<PrescriptionDetailDto>(`getprescriptiondetile?id=${id}`);
|
||||||
},
|
},
|
||||||
|
|
||||||
/** 保存处方(新增/编辑) */
|
/** 保存处方(新增/编辑) */
|
||||||
save(params: any) {
|
save(params: SavePrescriptionInput) {
|
||||||
const url = params.id ? "edit" : "add";
|
return http.post<number>("add", params);
|
||||||
return http.post<any>(url, params);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/** 获取人员列表 */
|
/** 获取人员列表 */
|
||||||
getPersonList(params: any) {
|
getPersonList(params: { type?: PersonType; employeeId?: number }) {
|
||||||
return http.get<any>("persons", params, { loading: false });
|
return http.get<PersonDto[]>("persons", params);
|
||||||
},
|
},
|
||||||
|
|
||||||
/** 新增人员 */
|
/** 添加人员 */
|
||||||
addPerson(params: any) {
|
addPerson(params: AddPersonInput) {
|
||||||
return http.post<any>("addpersons", params);
|
return http.post<number>("addpersons", params);
|
||||||
},
|
},
|
||||||
|
|
||||||
/** 获取亲属关系列表 */
|
/** 获取关系类型 */
|
||||||
getRelationTypes() {
|
getRelationTypes() {
|
||||||
return http.get<any>("relation-types", {}, { loading: false });
|
return http.get<RelationTypeDto[]>("relation-types");
|
||||||
},
|
|
||||||
|
|
||||||
/** 搜索药材 */
|
|
||||||
searchMedicinals(params: any) {
|
|
||||||
return http.get<any>("medicinals/search", params, { loading: false });
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -15,5 +15,5 @@
|
|||||||
|
|
||||||
export * from "./organization";
|
export * from "./organization";
|
||||||
export * from "./ops";
|
export * from "./ops";
|
||||||
export * from "./WeiBingJu/medicinal";
|
export * from "./weibingju/medicinal";
|
||||||
export * from "./WeiBingJu/prescription";
|
export * from "./weibingju/prescription";
|
||||||
|
|||||||
@@ -134,10 +134,12 @@ export default class RequestHttp {
|
|||||||
this.apiNameArray.forEach(apiName => {
|
this.apiNameArray.forEach(apiName => {
|
||||||
let responseApiArray = responseUrl.split("/"); //分割
|
let responseApiArray = responseUrl.split("/"); //分割
|
||||||
let method = responseApiArray[responseApiArray.length - 1]; //取最后一个
|
let method = responseApiArray[responseApiArray.length - 1]; //取最后一个
|
||||||
|
console.log("method=", method);
|
||||||
|
console.log("noMessageApiNameArray=", this.noMessageApiNameArray);
|
||||||
let result = this.noMessageApiNameArray.includes(method); //判断是否在不提示的数组中
|
let result = this.noMessageApiNameArray.includes(method); //判断是否在不提示的数组中
|
||||||
if (!result && responseUrl.includes(apiName)) {
|
if (!result && responseUrl.includes(apiName)) {
|
||||||
//如果不在不提示的数组中并且请求地址包含指定的方法
|
//如果不在不提示的数组中并且请求地址包含指定的方法
|
||||||
ElMessage.success(data.msg);
|
// ElMessage.success(data.msg);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+65
-80
@@ -6,88 +6,73 @@
|
|||||||
// biome-ignore lint: disable
|
// biome-ignore lint: disable
|
||||||
export {}
|
export {}
|
||||||
declare global {
|
declare global {
|
||||||
const EffectScope: (typeof import("vue"))["EffectScope"];
|
const EffectScope: typeof import('vue')['EffectScope']
|
||||||
const ElMessage: (typeof import("element-plus/es"))["ElMessage"];
|
const ElMessage: typeof import('element-plus/es')['ElMessage']
|
||||||
const ElMessageBox: (typeof import("element-plus/es"))["ElMessageBox"];
|
const ElMessageBox: (typeof import("element-plus/es"))["ElMessageBox"]
|
||||||
const computed: (typeof import("vue"))["computed"];
|
const computed: typeof import('vue')['computed']
|
||||||
const createApp: (typeof import("vue"))["createApp"];
|
const createApp: typeof import('vue')['createApp']
|
||||||
const customRef: (typeof import("vue"))["customRef"];
|
const customRef: typeof import('vue')['customRef']
|
||||||
const defineAsyncComponent: (typeof import("vue"))["defineAsyncComponent"];
|
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
|
||||||
const defineComponent: (typeof import("vue"))["defineComponent"];
|
const defineComponent: typeof import('vue')['defineComponent']
|
||||||
const effectScope: (typeof import("vue"))["effectScope"];
|
const effectScope: typeof import('vue')['effectScope']
|
||||||
const getCurrentInstance: (typeof import("vue"))["getCurrentInstance"];
|
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
|
||||||
const getCurrentScope: (typeof import("vue"))["getCurrentScope"];
|
const getCurrentScope: typeof import('vue')['getCurrentScope']
|
||||||
const h: (typeof import("vue"))["h"];
|
const h: typeof import('vue')['h']
|
||||||
const inject: (typeof import("vue"))["inject"];
|
const inject: typeof import('vue')['inject']
|
||||||
const isProxy: (typeof import("vue"))["isProxy"];
|
const isProxy: typeof import('vue')['isProxy']
|
||||||
const isReactive: (typeof import("vue"))["isReactive"];
|
const isReactive: typeof import('vue')['isReactive']
|
||||||
const isReadonly: (typeof import("vue"))["isReadonly"];
|
const isReadonly: typeof import('vue')['isReadonly']
|
||||||
const isRef: (typeof import("vue"))["isRef"];
|
const isRef: typeof import('vue')['isRef']
|
||||||
const markRaw: (typeof import("vue"))["markRaw"];
|
const markRaw: typeof import('vue')['markRaw']
|
||||||
const nextTick: (typeof import("vue"))["nextTick"];
|
const nextTick: typeof import('vue')['nextTick']
|
||||||
const onActivated: (typeof import("vue"))["onActivated"];
|
const onActivated: typeof import('vue')['onActivated']
|
||||||
const onBeforeMount: (typeof import("vue"))["onBeforeMount"];
|
const onBeforeMount: typeof import('vue')['onBeforeMount']
|
||||||
const onBeforeRouteLeave: (typeof import("vue-router"))["onBeforeRouteLeave"];
|
const onBeforeRouteLeave: typeof import('vue-router')['onBeforeRouteLeave']
|
||||||
const onBeforeRouteUpdate: (typeof import("vue-router"))["onBeforeRouteUpdate"];
|
const onBeforeRouteUpdate: typeof import('vue-router')['onBeforeRouteUpdate']
|
||||||
const onBeforeUnmount: (typeof import("vue"))["onBeforeUnmount"];
|
const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
|
||||||
const onBeforeUpdate: (typeof import("vue"))["onBeforeUpdate"];
|
const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
|
||||||
const onDeactivated: (typeof import("vue"))["onDeactivated"];
|
const onDeactivated: typeof import('vue')['onDeactivated']
|
||||||
const onErrorCaptured: (typeof import("vue"))["onErrorCaptured"];
|
const onErrorCaptured: typeof import('vue')['onErrorCaptured']
|
||||||
const onMounted: (typeof import("vue"))["onMounted"];
|
const onMounted: typeof import('vue')['onMounted']
|
||||||
const onRenderTracked: (typeof import("vue"))["onRenderTracked"];
|
const onRenderTracked: typeof import('vue')['onRenderTracked']
|
||||||
const onRenderTriggered: (typeof import("vue"))["onRenderTriggered"];
|
const onRenderTriggered: typeof import('vue')['onRenderTriggered']
|
||||||
const onScopeDispose: (typeof import("vue"))["onScopeDispose"];
|
const onScopeDispose: typeof import('vue')['onScopeDispose']
|
||||||
const onServerPrefetch: (typeof import("vue"))["onServerPrefetch"];
|
const onServerPrefetch: typeof import('vue')['onServerPrefetch']
|
||||||
const onUnmounted: (typeof import("vue"))["onUnmounted"];
|
const onUnmounted: typeof import('vue')['onUnmounted']
|
||||||
const onUpdated: (typeof import("vue"))["onUpdated"];
|
const onUpdated: typeof import('vue')['onUpdated']
|
||||||
const onWatcherCleanup: (typeof import("vue"))["onWatcherCleanup"];
|
const onWatcherCleanup: typeof import('vue')['onWatcherCleanup']
|
||||||
const provide: (typeof import("vue"))["provide"];
|
const provide: typeof import('vue')['provide']
|
||||||
const reactive: (typeof import("vue"))["reactive"];
|
const reactive: typeof import('vue')['reactive']
|
||||||
const readonly: (typeof import("vue"))["readonly"];
|
const readonly: typeof import('vue')['readonly']
|
||||||
const ref: (typeof import("vue"))["ref"];
|
const ref: typeof import('vue')['ref']
|
||||||
const resolveComponent: (typeof import("vue"))["resolveComponent"];
|
const resolveComponent: typeof import('vue')['resolveComponent']
|
||||||
const shallowReactive: (typeof import("vue"))["shallowReactive"];
|
const shallowReactive: typeof import('vue')['shallowReactive']
|
||||||
const shallowReadonly: (typeof import("vue"))["shallowReadonly"];
|
const shallowReadonly: typeof import('vue')['shallowReadonly']
|
||||||
const shallowRef: (typeof import("vue"))["shallowRef"];
|
const shallowRef: typeof import('vue')['shallowRef']
|
||||||
const toRaw: (typeof import("vue"))["toRaw"];
|
const toRaw: typeof import('vue')['toRaw']
|
||||||
const toRef: (typeof import("vue"))["toRef"];
|
const toRef: typeof import('vue')['toRef']
|
||||||
const toRefs: (typeof import("vue"))["toRefs"];
|
const toRefs: typeof import('vue')['toRefs']
|
||||||
const toValue: (typeof import("vue"))["toValue"];
|
const toValue: typeof import('vue')['toValue']
|
||||||
const triggerRef: (typeof import("vue"))["triggerRef"];
|
const triggerRef: typeof import('vue')['triggerRef']
|
||||||
const unref: (typeof import("vue"))["unref"];
|
const unref: typeof import('vue')['unref']
|
||||||
const useAttrs: (typeof import("vue"))["useAttrs"];
|
const useAttrs: typeof import('vue')['useAttrs']
|
||||||
const useCssModule: (typeof import("vue"))["useCssModule"];
|
const useCssModule: typeof import('vue')['useCssModule']
|
||||||
const useCssVars: (typeof import("vue"))["useCssVars"];
|
const useCssVars: typeof import('vue')['useCssVars']
|
||||||
const useId: (typeof import("vue"))["useId"];
|
const useId: typeof import('vue')['useId']
|
||||||
const useLink: (typeof import("vue-router"))["useLink"];
|
const useLink: typeof import('vue-router')['useLink']
|
||||||
const useModel: (typeof import("vue"))["useModel"];
|
const useModel: typeof import('vue')['useModel']
|
||||||
const useRoute: (typeof import("vue-router"))["useRoute"];
|
const useRoute: typeof import('vue-router')['useRoute']
|
||||||
const useRouter: (typeof import("vue-router"))["useRouter"];
|
const useRouter: typeof import('vue-router')['useRouter']
|
||||||
const useSlots: (typeof import("vue"))["useSlots"];
|
const useSlots: typeof import('vue')['useSlots']
|
||||||
const useTemplateRef: (typeof import("vue"))["useTemplateRef"];
|
const useTemplateRef: typeof import('vue')['useTemplateRef']
|
||||||
const watch: (typeof import("vue"))["watch"];
|
const watch: typeof import('vue')['watch']
|
||||||
const watchEffect: (typeof import("vue"))["watchEffect"];
|
const watchEffect: typeof import('vue')['watchEffect']
|
||||||
const watchPostEffect: (typeof import("vue"))["watchPostEffect"];
|
const watchPostEffect: typeof import('vue')['watchPostEffect']
|
||||||
const watchSyncEffect: (typeof import("vue"))["watchSyncEffect"];
|
const watchSyncEffect: typeof import('vue')['watchSyncEffect']
|
||||||
}
|
}
|
||||||
// for type re-export
|
// for type re-export
|
||||||
declare global {
|
declare global {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
export type {
|
export type { Component, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
|
||||||
Component,
|
import('vue')
|
||||||
ComponentPublicInstance,
|
|
||||||
ComputedRef,
|
|
||||||
DirectiveBinding,
|
|
||||||
ExtractDefaultPropTypes,
|
|
||||||
ExtractPropTypes,
|
|
||||||
ExtractPublicPropTypes,
|
|
||||||
InjectionKey,
|
|
||||||
PropType,
|
|
||||||
Ref,
|
|
||||||
MaybeRef,
|
|
||||||
MaybeRefOrGetter,
|
|
||||||
VNode,
|
|
||||||
WritableComputedRef
|
|
||||||
} from "vue";
|
|
||||||
import("vue");
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,43 +2,36 @@
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<!-- 查询表单 -->
|
<!-- 查询表单 -->
|
||||||
<SearchForm v-show="isShowSearch" :search="_search" :reset="_reset" :columns="searchColumns" :search-param="searchParam" :search-col="searchCol" />
|
<SearchForm v-show="isShowSearch" :search="_search" :reset="_reset" :columns="searchColumns"
|
||||||
|
:search-param="searchParam" :search-col="searchCol" />
|
||||||
|
|
||||||
<!-- 表格主体 -->
|
<!-- 表格主体 -->
|
||||||
<div class="card table-main">
|
<div class="card table-main">
|
||||||
<!-- 表格头部 操作按钮 -->
|
<!-- 表格头部 操作按钮 -->
|
||||||
<div class="table-header">
|
<div class="table-header">
|
||||||
<div class="header-button-lf">
|
<div class="header-button-lf">
|
||||||
<slot name="tableHeader" :selected-list="selectedList" :selected-list-ids="selectedListIds" :is-selected="isSelected" />
|
<slot name="tableHeader" :selected-list="selectedList" :selected-list-ids="selectedListIds"
|
||||||
|
:is-selected="isSelected" />
|
||||||
</div>
|
</div>
|
||||||
<div v-if="toolButton" class="header-button-ri">
|
<div v-if="toolButton" class="header-button-ri">
|
||||||
<slot name="toolButton">
|
<slot name="toolButton">
|
||||||
<el-button v-if="showToolButton('refresh')" :icon="Refresh" circle @click="getTableList" />
|
<el-button v-if="showToolButton('refresh')" :icon="Refresh" circle @click="getTableList" />
|
||||||
<el-button v-if="showToolButton('setting') && columns.length" :icon="Operation" circle @click="openColSetting" />
|
<el-button v-if="showToolButton('setting') && columns.length" :icon="Operation" circle
|
||||||
<el-button v-if="showToolButton('search') && searchColumns?.length" :icon="Search" circle @click="isShowSearch = !isShowSearch" />
|
@click="openColSetting" />
|
||||||
|
<el-button v-if="showToolButton('search') && searchColumns?.length" :icon="Search" circle
|
||||||
|
@click="isShowSearch = !isShowSearch" />
|
||||||
</slot>
|
</slot>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- 表格主体 -->
|
<!-- 表格主体 -->
|
||||||
<el-table
|
<el-table ref="tableRef" v-bind="$attrs" :id="uuid" :data="processTableData" :border="border" :row-key="rowKey"
|
||||||
ref="tableRef"
|
@selection-change="selectionChange">
|
||||||
v-bind="$attrs"
|
|
||||||
:id="uuid"
|
|
||||||
:data="processTableData"
|
|
||||||
:border="border"
|
|
||||||
:row-key="rowKey"
|
|
||||||
@selection-change="selectionChange"
|
|
||||||
>
|
|
||||||
<!-- 默认插槽 -->
|
<!-- 默认插槽 -->
|
||||||
<slot />
|
<slot />
|
||||||
<template v-for="item in tableColumns" :key="item">
|
<template v-for="item in tableColumns" :key="item">
|
||||||
<!-- selection || radio || index || expand || sort -->
|
<!-- selection || radio || index || expand || sort -->
|
||||||
<el-table-column
|
<el-table-column v-if="item.type && columnTypes.includes(item.type)" v-bind="item"
|
||||||
v-if="item.type && columnTypes.includes(item.type)"
|
:align="item.align ?? 'center'" :reserve-selection="item.type == 'selection'">
|
||||||
v-bind="item"
|
|
||||||
:align="item.align ?? 'center'"
|
|
||||||
:reserve-selection="item.type == 'selection'"
|
|
||||||
>
|
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<!-- expand -->
|
<!-- expand -->
|
||||||
<template v-if="item.type == 'expand'">
|
<template v-if="item.type == 'expand'">
|
||||||
@@ -51,7 +44,9 @@
|
|||||||
</el-radio>
|
</el-radio>
|
||||||
<!-- sort -->
|
<!-- sort -->
|
||||||
<el-tag v-if="item.type == 'sort'" class="move">
|
<el-tag v-if="item.type == 'sort'" class="move">
|
||||||
<el-icon> <DCaret /></el-icon>
|
<el-icon>
|
||||||
|
<DCaret />
|
||||||
|
</el-icon>
|
||||||
</el-tag>
|
</el-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
@@ -78,13 +73,8 @@
|
|||||||
</el-table>
|
</el-table>
|
||||||
<!-- 分页组件 -->
|
<!-- 分页组件 -->
|
||||||
<slot name="pagination">
|
<slot name="pagination">
|
||||||
<Pagination
|
<Pagination v-if="pagination" :pageable="pageable" :pager-count="pagerCount"
|
||||||
v-if="pagination"
|
:handle-size-change="handleSizeChange" :handle-current-change="handleCurrentChange" />
|
||||||
:pageable="pageable"
|
|
||||||
:pager-count="pagerCount"
|
|
||||||
:handle-size-change="handleSizeChange"
|
|
||||||
:handle-current-change="handleCurrentChange"
|
|
||||||
/>
|
|
||||||
</slot>
|
</slot>
|
||||||
</div>
|
</div>
|
||||||
<!-- 列设置 -->
|
<!-- 列设置 -->
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<AssemblySize id="assemblySize" />
|
<AssemblySize id="assemblySize" />
|
||||||
<SearchMenu id="searchMenu" />
|
<SearchMenu id="searchMenu" />
|
||||||
<ThemeSetting id="themeSetting" />
|
<ThemeSetting id="themeSetting" />
|
||||||
<Message id="message" />
|
<!-- <Message id="message" /> -->
|
||||||
<Fullscreen id="fullscreen" />
|
<Fullscreen id="fullscreen" />
|
||||||
<ChangeModule id="changeModule" />
|
<ChangeModule id="changeModule" />
|
||||||
</div>
|
</div>
|
||||||
@@ -18,7 +18,7 @@ import { computed } from "vue";
|
|||||||
import { useUserStore } from "@/stores/modules/user";
|
import { useUserStore } from "@/stores/modules/user";
|
||||||
import AssemblySize from "./components/AssemblySize.vue";
|
import AssemblySize from "./components/AssemblySize.vue";
|
||||||
import ThemeSetting from "./components/ThemeSetting.vue";
|
import ThemeSetting from "./components/ThemeSetting.vue";
|
||||||
import Message from "./components/Message.vue";
|
// import Message from "./components/Message.vue";
|
||||||
import Fullscreen from "./components/Fullscreen.vue";
|
import Fullscreen from "./components/Fullscreen.vue";
|
||||||
import Avatar from "./components/Avatar.vue";
|
import Avatar from "./components/Avatar.vue";
|
||||||
import ChangeModule from "./components/ChangeModule.vue";
|
import ChangeModule from "./components/ChangeModule.vue";
|
||||||
@@ -34,14 +34,17 @@ const username = computed(() => userStore.userInfo?.name);
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
padding-right: 25px;
|
padding-right: 25px;
|
||||||
|
|
||||||
.header-icon {
|
.header-icon {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
&>* {
|
&>* {
|
||||||
margin-left: 21px;
|
margin-left: 21px;
|
||||||
color: var(--el-header-text-color);
|
color: var(--el-header-text-color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.username {
|
.username {
|
||||||
margin: 0 20px;
|
margin: 0 20px;
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
|
|||||||
@@ -14,20 +14,19 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<el-tabs v-model="activeName">
|
<el-tabs v-model="activeName">
|
||||||
<el-tab-pane
|
<el-tab-pane v-for="(tab, index) in messageTypeOptions" :key="index"
|
||||||
v-for="(tab, index) in messageTypeOptions"
|
:label="tab.label + `(${messageStore.getUnReadCount(tab.value)})`" :name="tab.value">
|
||||||
:key="index"
|
|
||||||
:label="tab.label + `(${messageStore.getUnReadCount(tab.value)})`"
|
|
||||||
:name="tab.value"
|
|
||||||
>
|
|
||||||
<div class="message-list">
|
<div class="message-list">
|
||||||
<div class="message-item" v-for="(msg, index2) in getNewUnRead(tab.value)" :key="index2">
|
<div class="message-item" v-for="(msg, index2) in getNewUnRead(tab.value)" :key="index2">
|
||||||
<img v-if="tab.value === MessageTypeDictEnum.INFORM" src="@/assets/images/msg01.png" alt="" class="message-icon" />
|
<img v-if="tab.value === MessageTypeDictEnum.INFORM" src="@/assets/images/msg01.png" alt=""
|
||||||
<img v-else-if="tab.value === MessageTypeDictEnum.NOTICE" src="@/assets/images/msg03.png" alt="" class="message-icon" />
|
class="message-icon" />
|
||||||
|
<img v-else-if="tab.value === MessageTypeDictEnum.NOTICE" src="@/assets/images/msg03.png" alt=""
|
||||||
|
class="message-icon" />
|
||||||
<img v-else src="@/assets/images/msg02.png" alt="" class="message-icon" />
|
<img v-else src="@/assets/images/msg02.png" alt="" class="message-icon" />
|
||||||
<div class="message-content">
|
<div class="message-content">
|
||||||
<!-- 如果未读class用message-title-black -->
|
<!-- 如果未读class用message-title-black -->
|
||||||
<span :class="{ 'message-title': msg.read, 'message-title-black': !msg.read }">{{ msg.subject }}</span>
|
<span :class="{ 'message-title': msg.read, 'message-title-black': !msg.read }">{{ msg.subject
|
||||||
|
}}</span>
|
||||||
<span class="message-date">{{ msg.sendTimeFormat }}</span>
|
<span class="message-date">{{ msg.sendTimeFormat }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -95,6 +94,7 @@ function toMessage() {
|
|||||||
.el-link {
|
.el-link {
|
||||||
margin-right: 8px;
|
margin-right: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.message-empty {
|
.message-empty {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@@ -103,32 +103,40 @@ function toMessage() {
|
|||||||
height: 260px;
|
height: 260px;
|
||||||
line-height: 45px;
|
line-height: 45px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.message-list {
|
.message-list {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
||||||
.message-item {
|
.message-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 15px 0;
|
padding: 15px 0;
|
||||||
border-bottom: 1px solid var(--el-border-color-light);
|
border-bottom: 1px solid var(--el-border-color-light);
|
||||||
|
|
||||||
&:last-child {
|
&:last-child {
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.message-icon {
|
.message-icon {
|
||||||
width: 40px;
|
width: 40px;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
margin: 0 20px 0 5px;
|
margin: 0 20px 0 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.message-content {
|
.message-content {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
||||||
.message-title {
|
.message-title {
|
||||||
margin-bottom: 2px;
|
margin-bottom: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.message-title-black {
|
.message-title-black {
|
||||||
margin-bottom: 2px;
|
margin-bottom: 2px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
.message-date {
|
.message-date {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: var(--el-text-color-secondary);
|
color: var(--el-text-color-secondary);
|
||||||
|
|||||||
+12
-19
@@ -1,14 +1,14 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-dialog :model-value="visible" @update:model-value="handleUpdateVisible" title="添加药材" width="600px" destroy-on-close>
|
<el-dialog :model-value="visible" @update:model-value="handleUpdateVisible" title="添加药材" width="600px"
|
||||||
|
destroy-on-close :close-on-click-modal="false">
|
||||||
<el-form :model="form" label-width="120px" ref="formRef" class="mt-2" :rules="formRules">
|
<el-form :model="form" label-width="120px" ref="formRef" class="mt-2" :rules="formRules">
|
||||||
<!-- 药材下拉 + 未找到按钮 -->
|
<!-- 药材下拉 + 未找到按钮 -->
|
||||||
<el-form-item v-if="!isAddingNew" label="药材名称" prop="medicinalTypeId" style="display: flex; align-items: center">
|
<el-form-item v-if="!isAddingNew" label="药材名称" prop="Id" style="display: flex; align-items: center">
|
||||||
<el-select v-model="form.medicinalTypeId" placeholder="请选择药材" filterable style="flex: 1; margin-right: 8px">
|
<el-select v-model="form.Id" placeholder="请选择药材" filterable style="flex: 1; margin-right: 8px">
|
||||||
<el-option v-for="item in medicinalList" :key="item.id" :label="item.dictLabel" :value="item.id" />
|
<el-option v-for="item in medicinalList" :key="item.id" :label="item.medicinalName" :value="item.id" />
|
||||||
</el-select>
|
</el-select>
|
||||||
<el-button type="text" @click="handleNotFound">未找到</el-button>
|
<el-button type="text" @click="handleNotFound">未找到</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<!-- 新药材输入框 -->
|
<!-- 新药材输入框 -->
|
||||||
<el-form-item label="新药材名称" v-if="isAddingNew" prop="medicinalName">
|
<el-form-item label="新药材名称" v-if="isAddingNew" prop="medicinalName">
|
||||||
<el-input v-model="form.medicinalName" placeholder="请输入新药材名称" />
|
<el-input v-model="form.medicinalName" placeholder="请输入新药材名称" />
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, reactive, watch, computed } from "vue";
|
import { ref, reactive, watch, computed } from "vue";
|
||||||
import { medicinalApi } from "@/api/modules/biz/WeiBingJu/medicinal";
|
import { medicinalApi } from "@/api/modules/biz/weibingju/medicinal";
|
||||||
import { ElMessage, ElForm, FormRules } from "element-plus";
|
import { ElMessage, ElForm, FormRules } from "element-plus";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@@ -46,7 +46,7 @@ const isAddingNew = ref(false);
|
|||||||
|
|
||||||
const formRef = ref<InstanceType<typeof ElForm>>();
|
const formRef = ref<InstanceType<typeof ElForm>>();
|
||||||
const form = reactive({
|
const form = reactive({
|
||||||
medicinalTypeId: null as number | null,
|
Id: null as number | null,
|
||||||
addWeight: 0,
|
addWeight: 0,
|
||||||
// 前端改为 totalPrice
|
// 前端改为 totalPrice
|
||||||
totalPrice: 0,
|
totalPrice: 0,
|
||||||
@@ -55,7 +55,7 @@ const form = reactive({
|
|||||||
|
|
||||||
// 动态表单校验(注意 totalPrice 字段)
|
// 动态表单校验(注意 totalPrice 字段)
|
||||||
const formRules = computed<FormRules>(() => ({
|
const formRules = computed<FormRules>(() => ({
|
||||||
medicinalTypeId: [{ required: !isAddingNew.value, message: "请选择药材", trigger: "change" }],
|
Id: [{ required: !isAddingNew.value, message: "请选择药材", trigger: "change" }],
|
||||||
medicinalName: [{ required: isAddingNew.value, message: "请输入新药材名称", trigger: "blur" }],
|
medicinalName: [{ required: isAddingNew.value, message: "请输入新药材名称", trigger: "blur" }],
|
||||||
addWeight: [
|
addWeight: [
|
||||||
{ required: true, message: "请输入添加量", trigger: "blur" },
|
{ required: true, message: "请输入添加量", trigger: "blur" },
|
||||||
@@ -72,7 +72,6 @@ const fetchMedicinalList = async () => {
|
|||||||
const res = await medicinalApi.getDictList();
|
const res = await medicinalApi.getDictList();
|
||||||
medicinalList.value = res.data || [];
|
medicinalList.value = res.data || [];
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
ElMessage.error("加载药材列表失败");
|
|
||||||
medicinalList.value = [];
|
medicinalList.value = [];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -96,7 +95,7 @@ const handleUpdateVisible = (newVisible: boolean) => {
|
|||||||
};
|
};
|
||||||
const handleCancel = () => emit("update:visible", false);
|
const handleCancel = () => emit("update:visible", false);
|
||||||
const handleResetForm = () => {
|
const handleResetForm = () => {
|
||||||
form.medicinalTypeId = null;
|
form.Id = null;
|
||||||
form.addWeight = 0;
|
form.addWeight = 0;
|
||||||
form.totalPrice = 0;
|
form.totalPrice = 0;
|
||||||
form.medicinalName = "";
|
form.medicinalName = "";
|
||||||
@@ -106,7 +105,7 @@ const handleResetForm = () => {
|
|||||||
|
|
||||||
const handleNotFound = () => {
|
const handleNotFound = () => {
|
||||||
isAddingNew.value = true;
|
isAddingNew.value = true;
|
||||||
form.medicinalTypeId = null;
|
form.Id = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
@@ -123,15 +122,10 @@ const handleSubmit = async () => {
|
|||||||
ElMessage.warning("添加量需大于 0");
|
ElMessage.warning("添加量需大于 0");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// unitPrice = totalPrice / addWeight,保留两位
|
|
||||||
const unitPrice = parseFloat((form.totalPrice / form.addWeight).toFixed(2));
|
|
||||||
|
|
||||||
// 构造后端期望的 payload(注意把 totalPrice 改为 unitPrice)
|
|
||||||
const payload: any = {
|
const payload: any = {
|
||||||
medicinalTypeId: form.medicinalTypeId,
|
Id: form.Id,
|
||||||
addWeight: form.addWeight,
|
addWeight: form.addWeight,
|
||||||
unitPrice: unitPrice,
|
totalPrice: form.totalPrice,
|
||||||
medicinalName: form.medicinalName
|
medicinalName: form.medicinalName
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -141,7 +135,6 @@ const handleSubmit = async () => {
|
|||||||
emit("update:visible", false);
|
emit("update:visible", false);
|
||||||
emit("refreshList");
|
emit("refreshList");
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
ElMessage.error(err.message || "添加失败");
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
+31
-37
@@ -1,17 +1,14 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-dialog
|
<el-dialog :model-value="props.visible" :title="`${props.medicinalName} - 添加记录`" width="1200px"
|
||||||
:model-value="props.visible"
|
@close="handleDialogClose" @update:model-value="handleUpdateVisible" append-to-body
|
||||||
:title="`${props.medicinalName} - 添加记录`"
|
:body-class="'el-dialog__body-new'" :close-on-click-modal="false">
|
||||||
width="1200px"
|
<ProTable ref="proTableRef" title="添加记录" :columns="columns" :request-api="getAdditionRecordsApi" :row-key="rowKey"
|
||||||
@close="handleDialogClose"
|
:border="true" :show-selection="false">
|
||||||
@update:model-value="handleUpdateVisible"
|
|
||||||
append-to-body
|
|
||||||
>
|
|
||||||
<ProTable ref="proTableRef" title="添加记录" :columns="columns" :request-api="getAdditionRecordsApi" :row-key="rowKey" :show-selection="false">
|
|
||||||
<!-- 行内列 slot:addWeight -->
|
<!-- 行内列 slot:addWeight -->
|
||||||
<template #addWeight="{ row }">
|
<template #addWeight="{ row }">
|
||||||
<template v-if="editingId === row.id">
|
<template v-if="editingId === row.id">
|
||||||
<el-input-number v-model.number="editModel.addWeight" :min="0.01" :step="0.01" controls-position="right" size="small" />
|
<el-input-number v-model.number="editModel.addWeight" :min="0.01" :step="0.01" controls-position="right"
|
||||||
|
size="small" />
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
{{ row.addWeight }}
|
{{ row.addWeight }}
|
||||||
@@ -26,17 +23,11 @@
|
|||||||
<!-- totalPrice 列:查看时显示合计,编辑时可以修改 -->
|
<!-- totalPrice 列:查看时显示合计,编辑时可以修改 -->
|
||||||
<template #totalPrice="{ row }">
|
<template #totalPrice="{ row }">
|
||||||
<template v-if="editingId === row.id">
|
<template v-if="editingId === row.id">
|
||||||
<el-input-number
|
<el-input-number v-model.number="editModel.totalPrice" :min="0" :step="0.01" controls-position="right"
|
||||||
v-model.number="editModel.totalPrice"
|
size="small" placeholder="输入总价(元)" />
|
||||||
:min="0"
|
|
||||||
:step="0.01"
|
|
||||||
controls-position="right"
|
|
||||||
size="small"
|
|
||||||
placeholder="输入总价(元)"
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
{{ ((row.addWeight ?? 0) * (row.unitPrice ?? 0)).toFixed(2) }}
|
{{ row.totalPrice }}
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -52,8 +43,11 @@
|
|||||||
<el-button size="small" @click="cancelRowEdit">取消</el-button>
|
<el-button size="small" @click="cancelRowEdit">取消</el-button>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<el-button type="text" size="small" @click="startRowEdit(row)"> 编辑 </el-button>
|
<el-button v-if="row.canEdit" type="text" size="small" @click="startRowEdit(row)">编辑</el-button>
|
||||||
<el-button type="text" size="small" text-color="#ff4d4f" @click="handleDeleteRecord(row.id)"> 删除 </el-button>
|
<el-button v-if="row.canEdit" type="text" size="small" style="color: #ff4d4f"
|
||||||
|
@click="handleDeleteRecord(row.id)">
|
||||||
|
删除
|
||||||
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
</ProTable>
|
</ProTable>
|
||||||
@@ -64,7 +58,6 @@
|
|||||||
/**
|
/**
|
||||||
* 单行行内编辑版本(总价 totalPrice 输入):
|
* 单行行内编辑版本(总价 totalPrice 输入):
|
||||||
* - 点击「编辑」:将该行复制到 editModel(editModel.addWeight & editModel.totalPrice),记录 editingId(只允许单行编辑)
|
* - 点击「编辑」:将该行复制到 editModel(editModel.addWeight & editModel.totalPrice),记录 editingId(只允许单行编辑)
|
||||||
* - 保存:计算 unitPrice = totalPrice / addWeight,发送 unitPrice 到后端
|
|
||||||
* - 取消:不调用后端,直接清除 editingId(恢复显示)
|
* - 取消:不调用后端,直接清除 editingId(恢复显示)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -75,7 +68,7 @@ import { ElMessage, ElMessageBox } from "element-plus";
|
|||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
visible: { type: Boolean, default: false },
|
visible: { type: Boolean, default: false },
|
||||||
medicinalId: { type: Number, required: true },
|
id: { type: Number, required: true },
|
||||||
medicinalName: { type: String, default: "药材" }
|
medicinalName: { type: String, default: "药材" }
|
||||||
});
|
});
|
||||||
const emit = defineEmits(["update:visible", "close", "refreshList"]);
|
const emit = defineEmits(["update:visible", "close", "refreshList"]);
|
||||||
@@ -86,7 +79,7 @@ const proTableRef = ref<any | null>(null);
|
|||||||
// 当前正在编辑的行 id(单行)
|
// 当前正在编辑的行 id(单行)
|
||||||
const editingId = ref<number | null>(null);
|
const editingId = ref<number | null>(null);
|
||||||
|
|
||||||
// 编辑模型(只存一行):注意 totalPrice 而不是 unitPrice
|
// 编辑模型(只存一行):注意 totalPrice
|
||||||
const editModel = reactive({
|
const editModel = reactive({
|
||||||
addWeight: 0,
|
addWeight: 0,
|
||||||
totalPrice: 0
|
totalPrice: 0
|
||||||
@@ -111,7 +104,8 @@ const rowKey = (row: any) => row.id;
|
|||||||
watch(
|
watch(
|
||||||
() => props.visible,
|
() => props.visible,
|
||||||
async val => {
|
async val => {
|
||||||
if (val && props.medicinalId) {
|
if (val && props.id) {
|
||||||
|
console.log("打开添加记录弹窗,药材ID=", props.id);
|
||||||
await nextTick();
|
await nextTick();
|
||||||
proTableRef.value?.refresh?.();
|
proTableRef.value?.refresh?.();
|
||||||
}
|
}
|
||||||
@@ -121,7 +115,10 @@ watch(
|
|||||||
|
|
||||||
// 将 ProTable 的请求透传到后端(ProTable 会带上 pageNum/pageSize 等)
|
// 将 ProTable 的请求透传到后端(ProTable 会带上 pageNum/pageSize 等)
|
||||||
const getAdditionRecordsApi = (params: any) => {
|
const getAdditionRecordsApi = (params: any) => {
|
||||||
return medicinalApi.getAdditionRecords(props.medicinalId, params);
|
return medicinalApi.getAdditionRecords({
|
||||||
|
id: props.id,
|
||||||
|
...params
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// 开始编辑:把当前行复制到 editModel(addWeight 和 totalPrice)
|
// 开始编辑:把当前行复制到 editModel(addWeight 和 totalPrice)
|
||||||
@@ -133,7 +130,7 @@ const startRowEdit = (row: any) => {
|
|||||||
editingId.value = row.id;
|
editingId.value = row.id;
|
||||||
editModel.addWeight = row.addWeight ?? 0;
|
editModel.addWeight = row.addWeight ?? 0;
|
||||||
// 后端返回的是 unitPrice,前端要显示/编辑 totalPrice = unitPrice * addWeight
|
// 后端返回的是 unitPrice,前端要显示/编辑 totalPrice = unitPrice * addWeight
|
||||||
editModel.totalPrice = Number(((row.unitPrice ?? 0) * (row.addWeight ?? 1)).toFixed(2));
|
editModel.totalPrice = row.totalPrice;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 取消编辑:清空 editingId(恢复显示)
|
// 取消编辑:清空 editingId(恢复显示)
|
||||||
@@ -157,12 +154,11 @@ const saveRowEdit = async (row: any) => {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
saving.value = true;
|
saving.value = true;
|
||||||
// 计算 unitPrice(保留两位)
|
|
||||||
const unitPrice = parseFloat((editModel.totalPrice / editModel.addWeight).toFixed(2));
|
|
||||||
|
|
||||||
await medicinalApi.updateAdditionRecord(row.id, {
|
await medicinalApi.updateAdditionRecord({
|
||||||
|
id: row.id,
|
||||||
addWeight: editModel.addWeight,
|
addWeight: editModel.addWeight,
|
||||||
unitPrice: unitPrice
|
totalPrice: editModel.totalPrice
|
||||||
});
|
});
|
||||||
|
|
||||||
ElMessage.success("保存成功");
|
ElMessage.success("保存成功");
|
||||||
@@ -171,7 +167,6 @@ const saveRowEdit = async (row: any) => {
|
|||||||
emit("refreshList");
|
emit("refreshList");
|
||||||
cancelRowEdit();
|
cancelRowEdit();
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
ElMessage.error(err?.message || "保存失败");
|
|
||||||
} finally {
|
} finally {
|
||||||
saving.value = false;
|
saving.value = false;
|
||||||
}
|
}
|
||||||
@@ -186,12 +181,11 @@ const handleDeleteRecord = async (id: number) => {
|
|||||||
})
|
})
|
||||||
.then(async () => {
|
.then(async () => {
|
||||||
try {
|
try {
|
||||||
await medicinalApi.deleteAdditionRecord(id);
|
await medicinalApi.deleteAdditionRecord({ id: id });
|
||||||
ElMessage.success("删除成功");
|
ElMessage.success("删除成功");
|
||||||
await proTableRef.value?.refresh?.();
|
await proTableRef.value?.refresh?.();
|
||||||
emit("refreshList");
|
emit("refreshList");
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
ElMessage.error(err?.message || "删除失败");
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
@@ -218,8 +212,8 @@ const handleUpdateVisible = (newVal: boolean) => {
|
|||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style lang="scss">
|
||||||
.mb-4 {
|
.el-dialog__body-new {
|
||||||
margin-bottom: 16px;
|
height: 550px !important;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog :model-value="props.visible" :title="`${props.medicinalName} - 消耗记录`" width="800px"
|
||||||
|
@close="handleDialogClose" @update:model-value="handleUpdateVisible" append-to-body
|
||||||
|
:body-class="'el-dialog__body-new'" :close-on-click-modal="false">
|
||||||
|
<!-- 统一使用ProTable实现列表(带分页),与AdditionRecordDialog风格保持一致 -->
|
||||||
|
<ProTable ref="proTableRef" title="消耗记录列表" :columns="columns" :request-api="getConsumptionRecordsApi"
|
||||||
|
:row-key="rowKey" :show-selection="false" :border="true">
|
||||||
|
<!-- 人员列:包含家属标记的自定义渲染 -->
|
||||||
|
<template #personName="{ row }">
|
||||||
|
<span>{{ row.personName }}</span>
|
||||||
|
<el-tag size="small" type="info" v-if="row.isRelative" style="margin-left: 8px">
|
||||||
|
家属({{ row.employeeName || "未知员工" }})
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 使用时间:格式化渲染 -->
|
||||||
|
<template #useTime="{ row }">
|
||||||
|
{{ row.useTime ? formatDate(row.useTime) : "-" }}
|
||||||
|
</template>
|
||||||
|
</ProTable>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { defineProps, defineEmits, ref, watch, nextTick } from "vue";
|
||||||
|
import ProTable from "@/components/ProTable/index.vue";
|
||||||
|
import { medicinalApi } from "@/api";
|
||||||
|
import { ElMessage, ElMessageBox } from "element-plus";
|
||||||
|
|
||||||
|
/** 1. 定义Props(与父组件传参匹配,参考AdditionRecordDialog) */
|
||||||
|
const props = defineProps({
|
||||||
|
visible: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
id: { // 对应父组件传的「currentMedicinalId」,与AdditionRecordDialog的id参数统一
|
||||||
|
type: Number,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
medicinalName: {
|
||||||
|
type: String,
|
||||||
|
default: "药材"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/** 2. 定义Emits(与AdditionRecordDialog事件机制统一) */
|
||||||
|
const emit = defineEmits(["update:visible", "close", "refreshList"]);
|
||||||
|
|
||||||
|
/** 3. 状态管理(ProTable引用 + 无编辑状态,仅列表) */
|
||||||
|
const proTableRef = ref<any | null>(null); // ProTable实例引用,用于刷新列表
|
||||||
|
|
||||||
|
/** 4. 列配置(与消耗记录字段匹配,仅保留展示列) */
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
prop: "amountG",
|
||||||
|
label: "使用量(g)",
|
||||||
|
minWidth: 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: "personName",
|
||||||
|
label: "使用人员",
|
||||||
|
minWidth: 250,
|
||||||
|
slotName: "personName" // 关联自定义模板
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: "useTime",
|
||||||
|
label: "使用时间",
|
||||||
|
minWidth: 150,
|
||||||
|
slotName: "useTime" // 关联时间格式化模板
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
/** 5. 行唯一标识(与后端返回的主键匹配) */
|
||||||
|
const rowKey = (row: any) => row.id;
|
||||||
|
|
||||||
|
/** 6. 接口请求(透传ProTable分页参数,与AdditionRecordDialog逻辑统一) */
|
||||||
|
const getConsumptionRecordsApi = (params: any) => {
|
||||||
|
// 调用药材消耗记录接口,携带「药材ID」和「分页参数」
|
||||||
|
return medicinalApi.getConsumptionRecords({
|
||||||
|
id: props.id, // 药材ID(必传)
|
||||||
|
...params // 分页参数(pageNum、pageSize等,从ProTable传入)
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 7. 时间格式化工具(与AdditionRecordDialog格式统一) */
|
||||||
|
const formatDate = (dateStr: string) => {
|
||||||
|
const d = new Date(String(dateStr).replace(" ", "T"));
|
||||||
|
return isNaN(d.getTime()) ? dateStr : d.toLocaleString();
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 8. 弹窗显示/隐藏监听(弹窗显示时刷新列表,与AdditionRecordDialog逻辑统一) */
|
||||||
|
watch(
|
||||||
|
() => props.visible,
|
||||||
|
async (isVisible) => {
|
||||||
|
if (isVisible && props.id) {
|
||||||
|
await nextTick(); // 等待ProTable渲染完成
|
||||||
|
proTableRef.value?.refresh?.(); // 刷新列表数据
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ immediate: true } // 初始加载时触发
|
||||||
|
);
|
||||||
|
|
||||||
|
/** 9. 弹窗关闭逻辑(与AdditionRecordDialog统一,清空状态+通知父组件) */
|
||||||
|
const handleDialogClose = () => {
|
||||||
|
emit("update:visible", false); // 通知父组件更新弹窗状态
|
||||||
|
emit("close"); // 触发关闭事件(可选)
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 10. 弹窗状态更新回调(与Element Plus Dialog事件匹配) */
|
||||||
|
const handleUpdateVisible = (newVal: boolean) => {
|
||||||
|
if (!newVal) { // 仅当弹窗关闭时执行清理逻辑
|
||||||
|
handleDialogClose();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style lang="scss">
|
||||||
|
.el-dialog__body-new {
|
||||||
|
height: 550px !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
+15
-30
@@ -1,6 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="table-box">
|
<div class="table-box">
|
||||||
<el-card class="mt-4">
|
|
||||||
<ProTable ref="proTable" title="药材列表" :columns="columns" :request-api="medicinalApi.page">
|
<ProTable ref="proTable" title="药材列表" :columns="columns" :request-api="medicinalApi.page">
|
||||||
<template #tableHeader>
|
<template #tableHeader>
|
||||||
<!-- 新增按钮:保持框架一致的 s-button 写法 -->
|
<!-- 新增按钮:保持框架一致的 s-button 写法 -->
|
||||||
@@ -8,23 +7,20 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #operation="scope">
|
<template #operation="scope">
|
||||||
<s-button link :opt="FormOptEnum.VIEW" size="small" @click="handleViewConsumption(scope.row)"> 查看消耗记录 </s-button>
|
<s-button link :opt="FormOptEnum.VIEW" size="small" @click="handleViewConsumption(scope.row)"> 查看消耗记录
|
||||||
<s-button link :opt="FormOptEnum.VIEW" size="small" class="ml-2" @click="handleViewAddition(scope.row)"> 查看添加记录 </s-button>
|
</s-button>
|
||||||
|
<s-button link :opt="FormOptEnum.VIEW" size="small" class="ml-2" @click="handleViewAddition(scope.row)">
|
||||||
|
查看添加记录 </s-button>
|
||||||
</template>
|
</template>
|
||||||
</ProTable>
|
</ProTable>
|
||||||
</el-card>
|
|
||||||
|
|
||||||
<!-- 消耗记录弹窗 -->
|
<!-- 消耗记录弹窗 -->
|
||||||
<consumption-record-dialog v-model:visible="showConsumptionDialog" :medicinal-id="currentMedicinalId" :medicinal-name="currentMedicinalName" />
|
<consumption-record-dialog v-model:visible="showConsumptionDialog" :id="currentMedicinalId"
|
||||||
|
:medicinal-name="currentMedicinalName" />
|
||||||
|
|
||||||
<!-- 添加记录弹窗 -->
|
<!-- 添加记录弹窗 -->
|
||||||
<addition-record-dialog
|
<addition-record-dialog :visible="showAdditionDialog" :id="currentMedicinalId"
|
||||||
:visible="showAdditionDialog"
|
:medicinal-name="currentMedicinalName" @update:visible="val => (showAdditionDialog = val)"
|
||||||
:medicinal-id="currentMedicinalId"
|
@refresh-list="handleRefresh" />
|
||||||
:medicinal-name="currentMedicinalName"
|
|
||||||
@update:visible="val => (showAdditionDialog = val)"
|
|
||||||
@refresh-list="handleRefresh"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<!-- 新增药材弹窗 -->
|
<!-- 新增药材弹窗 -->
|
||||||
<add-medicinal-dialog v-model:visible="showAddMedicinalDialog" @refresh-list="handleRefresh" />
|
<add-medicinal-dialog v-model:visible="showAddMedicinalDialog" @refresh-list="handleRefresh" />
|
||||||
@@ -40,7 +36,7 @@ import type { ColumnProps, ProTableInstance } from "@/components/ProTable/interf
|
|||||||
import { FormOptEnum } from "@/enums";
|
import { FormOptEnum } from "@/enums";
|
||||||
|
|
||||||
// 子组件
|
// 子组件
|
||||||
//import ConsumptionRecordDialog from "./components/ConsumptionRecordDialog.vue";
|
import ConsumptionRecordDialog from "./components/ConsumptionRecordDialog.vue";
|
||||||
import AdditionRecordDialog from "./components/AdditionRecordDialog.vue";
|
import AdditionRecordDialog from "./components/AdditionRecordDialog.vue";
|
||||||
import AddMedicinalDialog from "./components/AddMedicinalDialog.vue";
|
import AddMedicinalDialog from "./components/AddMedicinalDialog.vue";
|
||||||
|
|
||||||
@@ -56,9 +52,10 @@ const currentMedicinalName = ref<string>("");
|
|||||||
const columns: ColumnProps<MedicinalInfo>[] = [
|
const columns: ColumnProps<MedicinalInfo>[] = [
|
||||||
{ type: "selection", fixed: "left", width: 80 },
|
{ type: "selection", fixed: "left", width: 80 },
|
||||||
{ prop: "medicinalName", label: "药材名称", search: { el: "input" } },
|
{ prop: "medicinalName", label: "药材名称", search: { el: "input" } },
|
||||||
|
{ prop: "totalUsedWeight", label: "使用量(g)" },
|
||||||
{ prop: "stock", label: "药材库存(g)" },
|
{ prop: "stock", label: "药材库存(g)" },
|
||||||
{ prop: "usedCost", label: "使用成本" },
|
{ prop: "usedCost", label: "预估使用成本" },
|
||||||
{ prop: "remainingValue", label: "剩余价值" },
|
{ prop: "remainingValue", label: "预估剩余价值" },
|
||||||
{ prop: "operation", label: "操作", width: 240, fixed: "right" }
|
{ prop: "operation", label: "操作", width: 240, fixed: "right" }
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -69,7 +66,7 @@ function onOpenAdd() {
|
|||||||
|
|
||||||
// 查看消耗记录
|
// 查看消耗记录
|
||||||
function handleViewConsumption(row: MedicinalInfo) {
|
function handleViewConsumption(row: MedicinalInfo) {
|
||||||
currentMedicinalId.value = row.medicinalId ?? (row as any).id ?? null;
|
currentMedicinalId.value = row.Id ?? (row as any).id ?? null;
|
||||||
currentMedicinalName.value = row.medicinalName ?? "";
|
currentMedicinalName.value = row.medicinalName ?? "";
|
||||||
showConsumptionDialog.value = true;
|
showConsumptionDialog.value = true;
|
||||||
}
|
}
|
||||||
@@ -78,7 +75,7 @@ function handleViewConsumption(row: MedicinalInfo) {
|
|||||||
function handleViewAddition(row: MedicinalInfo) {
|
function handleViewAddition(row: MedicinalInfo) {
|
||||||
console.log("查看添加记录", row);
|
console.log("查看添加记录", row);
|
||||||
// 直接设置正确的ID和名称,然后显示弹窗
|
// 直接设置正确的ID和名称,然后显示弹窗
|
||||||
currentMedicinalId.value = row.medicinalId ?? (row as any).id ?? null;
|
currentMedicinalId.value = row.id ?? (row as any).id ?? null;
|
||||||
currentMedicinalName.value = row.medicinalName ?? "";
|
currentMedicinalName.value = row.medicinalName ?? "";
|
||||||
showAdditionDialog.value = true;
|
showAdditionDialog.value = true;
|
||||||
}
|
}
|
||||||
@@ -88,15 +85,3 @@ function handleRefresh() {
|
|||||||
proTable.value?.refresh?.();
|
proTable.value?.refresh?.();
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
|
||||||
.table-box {
|
|
||||||
padding-bottom: 24px;
|
|
||||||
}
|
|
||||||
.mt-4 {
|
|
||||||
margin-top: 16px;
|
|
||||||
}
|
|
||||||
.ml-2 {
|
|
||||||
margin-left: 8px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -0,0 +1,959 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog :model-value="visible" :title="dialogTitle" width="1000px" destroy-on-close @close="handleClose"
|
||||||
|
:body-class="'modal-class'" @update:model-value="handleVisibleChange" :close-on-click-modal="false">
|
||||||
|
<!-- 表单根节点:查看模式禁用,新增/编辑模式可交互 -->
|
||||||
|
<el-form ref="formRef" :model="formData" :rules="formRules" label-width="120px" class="prescription-form"
|
||||||
|
:disabled="isViewMode">
|
||||||
|
<!-- 1. 人员信息 -->
|
||||||
|
<el-card class="form-section" shadow="never">
|
||||||
|
<template #header>
|
||||||
|
<div class="section-title">人员信息</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 人员类型 -->
|
||||||
|
<el-form-item label="人员类型" prop="personType">
|
||||||
|
<el-radio-group v-model="formData.personType" @change="handlePersonTypeChange" :disabled="isViewMode">
|
||||||
|
<el-radio :label="1">公司员工</el-radio>
|
||||||
|
<el-radio :label="2">员工家属</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<!-- 公司员工模式 -->
|
||||||
|
<template v-if="formData.personType === 1">
|
||||||
|
<!-- 员工姓名 -->
|
||||||
|
<el-form-item label="员工姓名" prop="employeeInfo">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<el-select v-if="showEmployeeSelect" v-model="formData.employeeId" placeholder="请选择员工" filterable
|
||||||
|
:loading="employeeLoading" class="flex-1" @change="handleEmployeeChange" @clear="handleEmployeeClear"
|
||||||
|
:disabled="isViewMode">
|
||||||
|
<el-option v-for="item in employeeOptions" :key="item.id" :label="item.name" :value="item.id" />
|
||||||
|
</el-select>
|
||||||
|
<!-- 新增/编辑模式显示"新增员工"按钮 -->
|
||||||
|
<el-button v-if="!isViewMode" type="primary" size="small" @click="handleOpenAddEmployeeDialog">
|
||||||
|
新增员工
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
<el-input v-if="!showEmployeeSelect && !formData.employeeId" v-model="formData.newEmployeeName"
|
||||||
|
placeholder="请输入员工姓名" class="mt-2" :disabled="isViewMode" />
|
||||||
|
</el-form-item>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 员工家属模式 -->
|
||||||
|
<template v-if="formData.personType === 2">
|
||||||
|
<!-- 关联员工 -->
|
||||||
|
<el-form-item label="关联员工" prop="relatedEmployeeInfo">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<el-select v-if="showRelatedEmployeeSelect" v-model="formData.relatedEmployeeId" placeholder="请选择关联员工"
|
||||||
|
filterable :loading="employeeLoading" class="flex-1" @change="handleRelatedEmployeeChange"
|
||||||
|
@clear="handleRelatedEmployeeClear" :disabled="isViewMode">
|
||||||
|
<el-option v-for="item in employeeOptions" :key="item.id" :label="item.name" :value="item.id" />
|
||||||
|
</el-select>
|
||||||
|
<!-- 新增/编辑模式显示"新增关联员工"按钮 -->
|
||||||
|
<el-button v-if="!isViewMode" type="primary" size="small" @click="handleOpenAddRelatedEmployeeDialog">
|
||||||
|
新增员工
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
<el-input v-if="!showRelatedEmployeeSelect && !formData.relatedEmployeeId"
|
||||||
|
v-model="formData.newRelatedEmployeeName" placeholder="请输入关联员工姓名" class="mt-2" :disabled="isViewMode" />
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<!-- 家属姓名 -->
|
||||||
|
<el-form-item label="家属姓名" prop="relativeInfo">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<el-select v-if="showRelativeSelect && (formData.relatedEmployeeId || formData.newRelatedEmployeeName)"
|
||||||
|
v-model="formData.relativeId" placeholder="请选择家属" filterable :loading="relativeLoading" class="flex-1"
|
||||||
|
@change="handleRelativeChange" @clear="handleRelativeClear" :disabled="isViewMode">
|
||||||
|
<el-option v-for="item in relativeOptions" :key="item.id" :label="item.name" :value="item.id" />
|
||||||
|
</el-select>
|
||||||
|
<el-input v-else v-model="formData.newRelativeName" placeholder="请输入家属姓名" class="flex-1"
|
||||||
|
:disabled="!formData.relatedEmployeeId && !formData.newRelatedEmployeeName || isViewMode" />
|
||||||
|
<!-- 新增/编辑模式显示"新增家属"按钮 -->
|
||||||
|
<el-button
|
||||||
|
v-if="!isViewMode && showRelativeSelect && formData.relatedEmployeeId && !formData.newRelatedEmployeeName"
|
||||||
|
type="primary" size="small" @click="handleOpenAddRelativeDialog">
|
||||||
|
新增家属
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<!-- 亲属关系 -->
|
||||||
|
<el-form-item label="亲属关系" prop="relationShip">
|
||||||
|
<el-select v-model="formData.relationShip" placeholder="请选择亲属关系" :disabled="isViewMode">
|
||||||
|
<el-option v-for="item in relationTypes" :key="item.id" :label="item.name" :value="item.id" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 出生日期、体重、身高 -->
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item label="出生日期" prop="birthday">
|
||||||
|
<el-date-picker v-model="formData.birthday" type="date" placeholder="请选择出生日期" format="YYYY-MM-DD"
|
||||||
|
value-format="YYYY-MM-DD" class="w-full" :disabled="isViewMode" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item label="当前体重(kg)" prop="weight">
|
||||||
|
<el-input-number v-model="formData.weight" :min="0" :max="500" :precision="1" placeholder="请输入体重"
|
||||||
|
class="w-full" :disabled="isViewMode" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item label="身高(cm)" prop="height">
|
||||||
|
<el-input-number v-model="formData.height" :min="0" :max="300" :precision="1" placeholder="请输入身高"
|
||||||
|
class="w-full" :disabled="isViewMode" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<!-- 2. 药材消耗 -->
|
||||||
|
<el-card class="form-section" shadow="never">
|
||||||
|
<template #header>
|
||||||
|
<div class="section-title">
|
||||||
|
药材消耗
|
||||||
|
<!-- 新增/编辑模式显示"添加药材"按钮 -->
|
||||||
|
<el-button v-if="!isViewMode" type="primary" size="small" class="ml-4" @click="addHerb">
|
||||||
|
添加药材
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<el-table :data="formData.herbs" border>
|
||||||
|
<el-table-column label="药材名称--剩余量" width="200">
|
||||||
|
<template #default="{ row, $index }">
|
||||||
|
<el-select v-model="row.id" placeholder="请选择药材" filterable :loading="medicinalLoading"
|
||||||
|
@change="handleMedicinalChange($index)" :disabled="isViewMode">
|
||||||
|
<el-option v-for="item in medicinalOptions" :key="item.id"
|
||||||
|
:label="`${item.medicinalName}--${item.stock}g`" :value="item.id" />
|
||||||
|
</el-select>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="消耗(g)" width="200">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-input-number v-model="row.amountG" :min="0" :precision="2" placeholder="消耗量" class="w-full"
|
||||||
|
:disabled="isViewMode" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="备注" min-width="80">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-input v-model="row.note" placeholder="请输入备注" :disabled="isViewMode" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="操作" width="80">
|
||||||
|
<template #default="{ $index }">
|
||||||
|
<!-- 新增/编辑模式显示"移除"按钮 -->
|
||||||
|
<el-button v-if="!isViewMode" type="danger" size="small" @click="removeHerb($index)">
|
||||||
|
移除
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<!-- 3. 诊断信息 -->
|
||||||
|
<el-card class="form-section" shadow="never">
|
||||||
|
<template #header>
|
||||||
|
<div class="section-title">诊断信息</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<el-form-item label="诊断结果" prop="diagnosisResult">
|
||||||
|
<el-input v-model="formData.diagnosisResult" type="textarea" :rows="3" placeholder="请输入诊断结果"
|
||||||
|
:disabled="isViewMode" />
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="用药建议" prop="userMedicinaAdvice">
|
||||||
|
<el-input v-model="formData.userMedicinaAdvice" type="textarea" :rows="3" placeholder="请输入用药建议"
|
||||||
|
:disabled="isViewMode" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<!-- 4. 就诊信息 -->
|
||||||
|
<el-card class="form-section" shadow="never">
|
||||||
|
<template #header>
|
||||||
|
<div class="section-title">就诊信息</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<el-form-item label="就诊时间" prop="visitDate">
|
||||||
|
<el-date-picker v-model="formData.visitDate" type="datetime" placeholder="请选择就诊时间" format="YYYY-MM-DD HH:mm"
|
||||||
|
value-format="YYYY-MM-DD HH:mm:ss" class="w-full" :disabled="isViewMode" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-card>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<!-- 底部按钮 -->
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<el-button @click="handleClose">取消</el-button>
|
||||||
|
<!-- 新增/编辑模式显示提交按钮 -->
|
||||||
|
<el-button v-if="!isViewMode" type="primary" :loading="submitLoading" @click="handleSubmit">
|
||||||
|
{{ isEdit ? '更新' : '保存' }}
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 新增员工弹窗(仅在新增/编辑模式显示) -->
|
||||||
|
<el-dialog v-if="!isViewMode" v-model="showAddEmployeeDialog" title="新增员工" width="400px">
|
||||||
|
<el-form :model="newEmployeeForm" label-width="80px" ref="newEmployeeFormRef">
|
||||||
|
<el-form-item label="员工姓名" prop="name">
|
||||||
|
<el-input v-model="newEmployeeForm.name" placeholder="请输入员工姓名" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="showAddEmployeeDialog = false">取消</el-button>
|
||||||
|
<el-button type="primary" @click="confirmAddEmployee">确定</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
<!-- 新增关联员工弹窗(仅在新增/编辑模式显示) -->
|
||||||
|
<el-dialog v-if="!isViewMode" v-model="showAddRelatedEmployeeDialog" title="新增关联员工" width="400px">
|
||||||
|
<el-form :model="newRelatedEmployeeForm" label-width="80px" ref="newRelatedEmployeeFormRef">
|
||||||
|
<el-form-item label="员工姓名" prop="name">
|
||||||
|
<el-input v-model="newRelatedEmployeeForm.name" placeholder="请输入员工姓名" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="showAddRelatedEmployeeDialog = false">取消</el-button>
|
||||||
|
<el-button type="primary" @click="confirmAddRelatedEmployee">确定</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
<!-- 新增家属弹窗(仅在新增/编辑模式显示) -->
|
||||||
|
<el-dialog v-if="!isViewMode" v-model="showAddRelativeDialog" title="新增家属" width="400px">
|
||||||
|
<el-form :model="newRelativeForm" label-width="80px" ref="newRelativeFormRef">
|
||||||
|
<el-form-item label="家属姓名" prop="name">
|
||||||
|
<el-input v-model="newRelativeForm.name" placeholder="请输入家属姓名" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="showAddRelativeDialog = false">取消</el-button>
|
||||||
|
<el-button type="primary" @click="confirmAddRelative">确定</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, computed, watch } from 'vue'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import type { FormInstance, FormRules } from 'element-plus'
|
||||||
|
|
||||||
|
import { prescriptionApi } from '@/api'
|
||||||
|
import { medicinalApi } from '@/api/modules/biz/weibingju/medicinal'
|
||||||
|
|
||||||
|
// 接口定义
|
||||||
|
interface Employee {
|
||||||
|
id: string | number;
|
||||||
|
name: string;
|
||||||
|
birthday?: string;
|
||||||
|
height?: number;
|
||||||
|
}
|
||||||
|
interface Relative {
|
||||||
|
id: string | number;
|
||||||
|
name: string;
|
||||||
|
employeeId?: string | number;
|
||||||
|
birthday?: string;
|
||||||
|
height?: number;
|
||||||
|
relationShip?: number;
|
||||||
|
}
|
||||||
|
interface Medicinal { id: number | string; medicinalName: string; stock: number }
|
||||||
|
interface Herb { id?: number | string; medicinalName: string; amountG: number; note: string }
|
||||||
|
|
||||||
|
// Props定义:区分新增(无id)、编辑(有id且isEdit=true)、查看(有id且isEdit=false)
|
||||||
|
interface Props {
|
||||||
|
visible: boolean;
|
||||||
|
prescriptionId?: number;
|
||||||
|
isEdit: boolean
|
||||||
|
}
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
visible: false,
|
||||||
|
prescriptionId: undefined,
|
||||||
|
isEdit: false
|
||||||
|
})
|
||||||
|
const emit = defineEmits<{
|
||||||
|
"update:visible": [value: boolean];
|
||||||
|
"refresh-list": [];
|
||||||
|
}>()
|
||||||
|
|
||||||
|
// 核心模式判断:查看模式 = 有处方ID且非编辑
|
||||||
|
const isViewMode = computed(() => !!props.prescriptionId && !props.isEdit)
|
||||||
|
// 弹窗标题:根据模式动态显示
|
||||||
|
const dialogTitle = computed(() => {
|
||||||
|
if (isViewMode.value) return '查看就诊处方'
|
||||||
|
return props.isEdit ? '编辑就诊处方' : '新增就诊处方'
|
||||||
|
})
|
||||||
|
|
||||||
|
// 表单引用 & 状态
|
||||||
|
const formRef = ref<FormInstance>()
|
||||||
|
const newEmployeeFormRef = ref<FormInstance>()
|
||||||
|
const newRelatedEmployeeFormRef = ref<FormInstance>()
|
||||||
|
const newRelativeFormRef = ref<FormInstance>()
|
||||||
|
const submitLoading = ref(false)
|
||||||
|
const isEdit = computed(() => props.isEdit)
|
||||||
|
|
||||||
|
// 表单数据
|
||||||
|
const formData = ref({
|
||||||
|
personType: 1,
|
||||||
|
employeeId: undefined as string | number | undefined,
|
||||||
|
newEmployeeName: '',
|
||||||
|
relatedEmployeeId: undefined as string | number | undefined,
|
||||||
|
newRelatedEmployeeName: '',
|
||||||
|
relativeId: undefined as string | number | undefined,
|
||||||
|
newRelativeName: '',
|
||||||
|
relationShip: undefined as number | undefined,
|
||||||
|
birthday: undefined as string | undefined,
|
||||||
|
weight: undefined as number | undefined,
|
||||||
|
height: undefined as number | undefined,
|
||||||
|
herbs: [] as Herb[],
|
||||||
|
diagnosisResult: '',
|
||||||
|
userMedicinaAdvice: '',
|
||||||
|
visitDate: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
// 表单校验规则
|
||||||
|
const formRules: FormRules = {
|
||||||
|
personType: [{ required: true, message: '请选择人员类型', trigger: 'change' }],
|
||||||
|
employeeInfo: [{
|
||||||
|
required: true,
|
||||||
|
validator: (rule, value, callback) => {
|
||||||
|
if (formData.value.personType === 1) {
|
||||||
|
if (!formData.value.employeeId && !formData.value.newEmployeeName) {
|
||||||
|
callback(new Error('请选择或输入员工姓名'))
|
||||||
|
} else {
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
trigger: ['change', 'blur']
|
||||||
|
}],
|
||||||
|
relatedEmployeeInfo: [{
|
||||||
|
required: true,
|
||||||
|
validator: (rule, value, callback) => {
|
||||||
|
if (formData.value.personType === 2) {
|
||||||
|
if (!formData.value.relatedEmployeeId && !formData.value.newRelatedEmployeeName) {
|
||||||
|
callback(new Error('请选择或输入关联员工姓名'))
|
||||||
|
} else {
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
trigger: ['change', 'blur']
|
||||||
|
}],
|
||||||
|
relativeInfo: [{
|
||||||
|
required: true,
|
||||||
|
validator: (rule, value, callback) => {
|
||||||
|
if (formData.value.personType === 2) {
|
||||||
|
if (!formData.value.relativeId && !formData.value.newRelativeName) {
|
||||||
|
callback(new Error('请选择或输入家属姓名'))
|
||||||
|
} else {
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
trigger: ['change', 'blur']
|
||||||
|
}],
|
||||||
|
relationShip: [{
|
||||||
|
required: formData.value.personType === 2,
|
||||||
|
message: '请选择亲属关系',
|
||||||
|
trigger: 'change'
|
||||||
|
}],
|
||||||
|
visitDate: [{ required: true, message: '请选择就诊时间', trigger: 'change' }],
|
||||||
|
diagnosisResult: [{ required: true, message: '请输入诊断结果', trigger: 'blur' }]
|
||||||
|
}
|
||||||
|
|
||||||
|
// 数据源 & 弹窗状态
|
||||||
|
const employeeOptions = ref<Employee[]>([])
|
||||||
|
const employeeLoading = ref(false)
|
||||||
|
const showEmployeeSelect = ref(true)
|
||||||
|
const showRelatedEmployeeSelect = ref(true)
|
||||||
|
|
||||||
|
const relativeOptions = ref<Relative[]>([])
|
||||||
|
const relativeLoading = ref(false)
|
||||||
|
const showRelativeSelect = ref(true)
|
||||||
|
|
||||||
|
const relationTypes = ref<{ id: number; name: string }[]>([])
|
||||||
|
const medicinalOptions = ref<Medicinal[]>([])
|
||||||
|
const medicinalLoading = ref(false)
|
||||||
|
|
||||||
|
const showAddEmployeeDialog = ref(false)
|
||||||
|
const showAddRelatedEmployeeDialog = ref(false)
|
||||||
|
const showAddRelativeDialog = ref(false)
|
||||||
|
const newEmployeeForm = ref({ name: '' })
|
||||||
|
const newRelatedEmployeeForm = ref({ name: '' })
|
||||||
|
const newRelativeForm = ref({ name: '' })
|
||||||
|
|
||||||
|
// 本地临时人员集合
|
||||||
|
const localCreatedPersons = ref<Array<{
|
||||||
|
tempId: string
|
||||||
|
name: string
|
||||||
|
isEmployee: boolean
|
||||||
|
employeeTempId?: string
|
||||||
|
employeeId?: number
|
||||||
|
relationShip?: number
|
||||||
|
}>>([])
|
||||||
|
|
||||||
|
// 生成临时ID
|
||||||
|
const genTempId = (prefix = 'tmp') => `${prefix}_${Date.now()}_${Math.floor(Math.random() * 1000)}`
|
||||||
|
|
||||||
|
// 检查名称重复
|
||||||
|
const checkNameDuplicate = (name: string, isEmployee: boolean) => {
|
||||||
|
const normalizedName = name.trim()
|
||||||
|
if (isEmployee) {
|
||||||
|
return employeeOptions.value.some(item =>
|
||||||
|
(item.name || '').trim() === normalizedName ||
|
||||||
|
localCreatedPersons.value.some(p => p.isEmployee && p.name.trim() === normalizedName)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
return relativeOptions.value.some(item =>
|
||||||
|
(item.name || '').trim() === normalizedName ||
|
||||||
|
localCreatedPersons.value.some(p => !p.isEmployee && p.name.trim() === normalizedName)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加载数据接口
|
||||||
|
const fetchEmployees = async (keyword?: string) => {
|
||||||
|
try {
|
||||||
|
employeeLoading.value = true
|
||||||
|
const params: any = { type: 1 }
|
||||||
|
if (keyword) params.keyword = keyword
|
||||||
|
const res: any = await prescriptionApi.getPersonList(params)
|
||||||
|
employeeOptions.value = (res && res.data) ? res.data : []
|
||||||
|
} catch (err) {
|
||||||
|
console.error('获取员工列表失败', err)
|
||||||
|
employeeOptions.value = []
|
||||||
|
} finally {
|
||||||
|
employeeLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const loadRelatives = async (employeeId: number | string) => {
|
||||||
|
try {
|
||||||
|
relativeLoading.value = true
|
||||||
|
if (typeof employeeId === 'string' && employeeId.startsWith('tmp_')) {
|
||||||
|
relativeOptions.value = []
|
||||||
|
showRelativeSelect.value = false
|
||||||
|
ElMessage.info('该员工为本地新增,暂无家属数据,请手动输入家属姓名')
|
||||||
|
} else {
|
||||||
|
const res: any = await prescriptionApi.getPersonList({ type: 2, employeeId })
|
||||||
|
relativeOptions.value = (res && res.data) ? res.data : []
|
||||||
|
showRelativeSelect.value = relativeOptions.value.length > 0
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error('加载家属失败', err)
|
||||||
|
relativeOptions.value = []
|
||||||
|
showRelativeSelect.value = false
|
||||||
|
} finally {
|
||||||
|
relativeLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const fetchRelationTypes = async () => {
|
||||||
|
try {
|
||||||
|
const res: any = await prescriptionApi.getRelationTypes()
|
||||||
|
relationTypes.value = (res && res.data) ? res.data : []
|
||||||
|
} catch (err) {
|
||||||
|
relationTypes.value = [
|
||||||
|
{ id: 1, name: '配偶' },
|
||||||
|
{ id: 2, name: '子女' },
|
||||||
|
{ id: 3, name: '父母' },
|
||||||
|
{ id: 4, name: '兄弟姐妹' },
|
||||||
|
{ id: 5, name: '其他' }
|
||||||
|
]
|
||||||
|
console.error('获取关系类型失败', err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const loadAllMedicinals = async () => {
|
||||||
|
try {
|
||||||
|
medicinalLoading.value = true
|
||||||
|
const res: any = await medicinalApi.getDictList()
|
||||||
|
medicinalOptions.value = (res && res.data) ? res.data : []
|
||||||
|
} catch (err) {
|
||||||
|
console.error('加载药材失败', err)
|
||||||
|
medicinalOptions.value = []
|
||||||
|
} finally {
|
||||||
|
medicinalLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 选择回调
|
||||||
|
const handleEmployeeChange = (selectedId: string | number | undefined) => {
|
||||||
|
if (selectedId && !isViewMode.value) { // 仅在非查看模式执行
|
||||||
|
formData.value.newEmployeeName = ''
|
||||||
|
showEmployeeSelect.value = true
|
||||||
|
const selectedEmployee = employeeOptions.value.find(item => item.id === selectedId)
|
||||||
|
if (selectedEmployee) {
|
||||||
|
formData.value.birthday = selectedEmployee.birthday
|
||||||
|
formData.value.height = selectedEmployee.height
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const handleEmployeeClear = () => {
|
||||||
|
if (!isViewMode.value) { // 仅在非查看模式执行
|
||||||
|
formData.value.newEmployeeName = ''
|
||||||
|
formData.value.birthday = undefined
|
||||||
|
formData.value.height = undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const handleRelatedEmployeeChange = (selectedId: string | number | undefined) => {
|
||||||
|
if (selectedId && !isViewMode.value) { // 仅在非查看模式执行
|
||||||
|
formData.value.newRelatedEmployeeName = ''
|
||||||
|
showRelatedEmployeeSelect.value = true
|
||||||
|
formData.value.relativeId = undefined
|
||||||
|
formData.value.newRelativeName = ''
|
||||||
|
loadRelatives(selectedId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const handleRelatedEmployeeClear = () => {
|
||||||
|
if (!isViewMode.value) { // 仅在非查看模式执行
|
||||||
|
formData.value.newRelatedEmployeeName = ''
|
||||||
|
formData.value.relativeId = undefined
|
||||||
|
formData.value.newRelativeName = ''
|
||||||
|
formData.value.birthday = undefined
|
||||||
|
formData.value.height = undefined
|
||||||
|
formData.value.relationShip = undefined
|
||||||
|
relativeOptions.value = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const handleRelativeChange = (selectedId: string | number | undefined) => {
|
||||||
|
if (selectedId && !isViewMode.value) { // 仅在非查看模式执行
|
||||||
|
formData.value.newRelativeName = ''
|
||||||
|
showRelativeSelect.value = true
|
||||||
|
const selectedRelative = relativeOptions.value.find(item => item.id === selectedId)
|
||||||
|
if (selectedRelative) {
|
||||||
|
formData.value.birthday = selectedRelative.birthday
|
||||||
|
formData.value.height = selectedRelative.height
|
||||||
|
formData.value.relationShip = selectedRelative.relationShip
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const handleRelativeClear = () => {
|
||||||
|
if (!isViewMode.value) { // 仅在非查看模式执行
|
||||||
|
formData.value.newRelativeName = ''
|
||||||
|
formData.value.birthday = undefined
|
||||||
|
formData.value.height = undefined
|
||||||
|
formData.value.relationShip = undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const handleMedicinalChange = (index: number) => {
|
||||||
|
if (!isViewMode.value) { // 仅在非查看模式执行
|
||||||
|
const selectedMedicinalId = formData.value.herbs[index].id;
|
||||||
|
if (selectedMedicinalId) {
|
||||||
|
const sel = medicinalOptions.value.find(m => m.id === selectedMedicinalId);
|
||||||
|
formData.value.herbs[index].medicinalName = sel ? sel.medicinalName : '';
|
||||||
|
} else {
|
||||||
|
formData.value.herbs[index].medicinalName = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const handlePersonTypeChange = () => {
|
||||||
|
if (!isViewMode.value) { // 仅在非查看模式执行
|
||||||
|
formData.value.employeeId = undefined
|
||||||
|
formData.value.newEmployeeName = ''
|
||||||
|
formData.value.relatedEmployeeId = undefined
|
||||||
|
formData.value.newRelatedEmployeeName = ''
|
||||||
|
formData.value.relativeId = undefined
|
||||||
|
formData.value.newRelativeName = ''
|
||||||
|
formData.value.relationShip = undefined
|
||||||
|
formData.value.birthday = undefined
|
||||||
|
formData.value.height = undefined
|
||||||
|
showEmployeeSelect.value = true
|
||||||
|
showRelatedEmployeeSelect.value = true
|
||||||
|
showRelativeSelect.value = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const addHerb = () => {
|
||||||
|
if (!isViewMode.value) { // 仅在非查看模式执行
|
||||||
|
formData.value.herbs.push({ id: undefined, medicinalName: '', amountG: 0, note: '' })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const removeHerb = (index: number) => {
|
||||||
|
if (!isViewMode.value) { // 仅在非查看模式执行
|
||||||
|
formData.value.herbs.splice(index, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增员工相关
|
||||||
|
const handleOpenAddEmployeeDialog = () => {
|
||||||
|
if (!isViewMode.value) {
|
||||||
|
formData.value.employeeId = undefined
|
||||||
|
formData.value.newEmployeeName = ''
|
||||||
|
formData.value.birthday = undefined
|
||||||
|
formData.value.height = undefined
|
||||||
|
newEmployeeForm.value.name = ''
|
||||||
|
showAddEmployeeDialog.value = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const confirmAddEmployee = async () => {
|
||||||
|
if (!newEmployeeFormRef.value || isViewMode.value) return
|
||||||
|
try {
|
||||||
|
await newEmployeeFormRef.value.validate()
|
||||||
|
const name = newEmployeeForm.value.name.trim()
|
||||||
|
if (checkNameDuplicate(name, true)) {
|
||||||
|
ElMessage.warning('该员工姓名已存在,请更换姓名')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const tempId = genTempId('tmp_emp')
|
||||||
|
employeeOptions.value.unshift({ id: tempId, name })
|
||||||
|
localCreatedPersons.value.push({ tempId, name, isEmployee: true })
|
||||||
|
formData.value.employeeId = tempId
|
||||||
|
formData.value.newEmployeeName = ''
|
||||||
|
formData.value.birthday = undefined
|
||||||
|
formData.value.height = undefined
|
||||||
|
showEmployeeSelect.value = true
|
||||||
|
showAddEmployeeDialog.value = false
|
||||||
|
newEmployeeForm.value.name = ''
|
||||||
|
ElMessage.success('员工已添加')
|
||||||
|
} catch (err) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增关联员工相关
|
||||||
|
const handleOpenAddRelatedEmployeeDialog = () => {
|
||||||
|
if (!isViewMode.value) {
|
||||||
|
formData.value.relatedEmployeeId = undefined
|
||||||
|
formData.value.newRelatedEmployeeName = ''
|
||||||
|
formData.value.relativeId = undefined
|
||||||
|
formData.value.newRelativeName = ''
|
||||||
|
formData.value.birthday = undefined
|
||||||
|
formData.value.height = undefined
|
||||||
|
formData.value.relationShip = undefined
|
||||||
|
newRelatedEmployeeForm.value.name = ''
|
||||||
|
showAddRelatedEmployeeDialog.value = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const confirmAddRelatedEmployee = async () => {
|
||||||
|
if (!newRelatedEmployeeFormRef.value || isViewMode.value) return
|
||||||
|
try {
|
||||||
|
await newRelatedEmployeeFormRef.value.validate()
|
||||||
|
const name = newRelatedEmployeeForm.value.name.trim()
|
||||||
|
if (checkNameDuplicate(name, true)) {
|
||||||
|
ElMessage.warning('该员工姓名已存在,请更换姓名')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const tempId = genTempId('tmp_emp')
|
||||||
|
employeeOptions.value.unshift({ id: tempId, name })
|
||||||
|
localCreatedPersons.value.push({ tempId, name, isEmployee: true })
|
||||||
|
formData.value.relatedEmployeeId = tempId
|
||||||
|
formData.value.newRelatedEmployeeName = ''
|
||||||
|
formData.value.relativeId = undefined
|
||||||
|
formData.value.newRelativeName = ''
|
||||||
|
formData.value.birthday = undefined
|
||||||
|
formData.value.height = undefined
|
||||||
|
formData.value.relationShip = undefined
|
||||||
|
showRelatedEmployeeSelect.value = true
|
||||||
|
showAddRelatedEmployeeDialog.value = false
|
||||||
|
newRelatedEmployeeForm.value.name = ''
|
||||||
|
loadRelatives(tempId)
|
||||||
|
ElMessage.success('关联员工已添加')
|
||||||
|
} catch (err) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增家属相关
|
||||||
|
const handleOpenAddRelativeDialog = () => {
|
||||||
|
if (!isViewMode.value) {
|
||||||
|
formData.value.relativeId = undefined
|
||||||
|
formData.value.newRelativeName = ''
|
||||||
|
formData.value.birthday = undefined
|
||||||
|
formData.value.height = undefined
|
||||||
|
formData.value.relationShip = undefined
|
||||||
|
newRelativeForm.value.name = ''
|
||||||
|
showAddRelativeDialog.value = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const confirmAddRelative = async () => {
|
||||||
|
if (!newRelativeFormRef.value || isViewMode.value) return
|
||||||
|
try {
|
||||||
|
await newRelativeFormRef.value.validate()
|
||||||
|
const name = newRelativeForm.value.name.trim()
|
||||||
|
const employeeId = formData.value.relatedEmployeeId
|
||||||
|
if (!employeeId) {
|
||||||
|
ElMessage.warning('请先选择关联员工')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (checkNameDuplicate(name, false)) {
|
||||||
|
ElMessage.warning('该家属姓名已存在,请更换姓名')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const tempId = genTempId('tmp_rel')
|
||||||
|
relativeOptions.value.unshift({ id: tempId, name, employeeId })
|
||||||
|
localCreatedPersons.value.push({
|
||||||
|
tempId,
|
||||||
|
name,
|
||||||
|
isEmployee: false,
|
||||||
|
employeeTempId: typeof employeeId === 'string' && employeeId.startsWith('tmp_') ? employeeId : undefined,
|
||||||
|
employeeId: typeof employeeId === 'number' ? employeeId : undefined,
|
||||||
|
relationShip: formData.value.relationShip
|
||||||
|
})
|
||||||
|
formData.value.relativeId = tempId
|
||||||
|
formData.value.newRelativeName = ''
|
||||||
|
formData.value.birthday = undefined
|
||||||
|
formData.value.height = undefined
|
||||||
|
formData.value.relationShip = undefined
|
||||||
|
showRelativeSelect.value = true
|
||||||
|
showAddRelativeDialog.value = false
|
||||||
|
newRelativeForm.value.name = ''
|
||||||
|
ElMessage.success('家属已添加')
|
||||||
|
} catch (err) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重置/关闭/提交
|
||||||
|
const handleClose = () => {
|
||||||
|
emit('update:visible', false)
|
||||||
|
resetForm()
|
||||||
|
}
|
||||||
|
const handleVisibleChange = (value: boolean) => {
|
||||||
|
emit('update:visible', value)
|
||||||
|
if (!value) resetForm()
|
||||||
|
}
|
||||||
|
const resetForm = () => {
|
||||||
|
formData.value = {
|
||||||
|
personType: 1,
|
||||||
|
employeeId: undefined,
|
||||||
|
newEmployeeName: '',
|
||||||
|
relatedEmployeeId: undefined,
|
||||||
|
newRelatedEmployeeName: '',
|
||||||
|
relativeId: undefined,
|
||||||
|
newRelativeName: '',
|
||||||
|
relationShip: undefined,
|
||||||
|
birthday: undefined,
|
||||||
|
weight: undefined,
|
||||||
|
height: undefined,
|
||||||
|
herbs: [],
|
||||||
|
diagnosisResult: '',
|
||||||
|
userMedicinaAdvice: '',
|
||||||
|
visitDate: ''
|
||||||
|
}
|
||||||
|
localCreatedPersons.value = []
|
||||||
|
showEmployeeSelect.value = true
|
||||||
|
showRelatedEmployeeSelect.value = true
|
||||||
|
showRelativeSelect.value = true
|
||||||
|
newEmployeeForm.value.name = ''
|
||||||
|
newRelatedEmployeeForm.value.name = ''
|
||||||
|
newRelativeForm.value.name = ''
|
||||||
|
showAddEmployeeDialog.value = false
|
||||||
|
showAddRelatedEmployeeDialog.value = false
|
||||||
|
showAddRelativeDialog.value = false
|
||||||
|
}
|
||||||
|
const handleSubmit = async () => {
|
||||||
|
if (!formRef.value || isViewMode.value) return
|
||||||
|
try {
|
||||||
|
await formRef.value.validate()
|
||||||
|
} catch (err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
submitLoading.value = true
|
||||||
|
try {
|
||||||
|
const personObj: any = {}
|
||||||
|
const isPatientEmployee = formData.value.personType === 1
|
||||||
|
personObj.isEmployee = isPatientEmployee
|
||||||
|
|
||||||
|
if (isPatientEmployee) {
|
||||||
|
if (formData.value.employeeId) {
|
||||||
|
if (typeof formData.value.employeeId === 'string' && String(formData.value.employeeId).startsWith('tmp_')) {
|
||||||
|
const tmpEmp = localCreatedPersons.value.find(p => p.tempId === formData.value.employeeId && p.isEmployee)
|
||||||
|
const name = tmpEmp ? tmpEmp.name : undefined
|
||||||
|
if (name) {
|
||||||
|
personObj.name = name
|
||||||
|
personObj.employeeIsTemp = true
|
||||||
|
personObj.employeeName = name
|
||||||
|
} else {
|
||||||
|
personObj.name = employeeOptions.value.find(e => e.id === formData.value.employeeId)?.name
|
||||||
|
personObj.employeeIsTemp = true
|
||||||
|
personObj.employeeName = personObj.name
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
personObj.id = Number(formData.value.employeeId)
|
||||||
|
personObj.name = employeeOptions.value.find(e => e.id === formData.value.employeeId)?.name
|
||||||
|
}
|
||||||
|
} else if (formData.value.newEmployeeName) {
|
||||||
|
personObj.name = formData.value.newEmployeeName.trim()
|
||||||
|
personObj.employeeIsTemp = true
|
||||||
|
personObj.employeeName = personObj.name
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (formData.value.relativeId) {
|
||||||
|
if (typeof formData.value.relativeId === 'string' && String(formData.value.relativeId).startsWith('tmp_')) {
|
||||||
|
const tmpRel = localCreatedPersons.value.find(p => p.tempId === formData.value.relativeId && !p.isEmployee)
|
||||||
|
personObj.name = tmpRel ? tmpRel.name : relativeOptions.value.find(r => r.id === formData.value.relativeId)?.name
|
||||||
|
personObj.tempId = formData.value.relativeId
|
||||||
|
} else {
|
||||||
|
personObj.id = Number(formData.value.relativeId)
|
||||||
|
personObj.name = relativeOptions.value.find(r => r.id === formData.value.relativeId)?.name
|
||||||
|
}
|
||||||
|
} else if (formData.value.newRelativeName) {
|
||||||
|
personObj.name = formData.value.newRelativeName.trim()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (formData.value.relatedEmployeeId) {
|
||||||
|
if (typeof formData.value.relatedEmployeeId === 'string' && String(formData.value.relatedEmployeeId).startsWith('tmp_')) {
|
||||||
|
const tmpEmp = localCreatedPersons.value.find(p => p.tempId === formData.value.relatedEmployeeId && p.isEmployee)
|
||||||
|
const name = tmpEmp ? tmpEmp.name : employeeOptions.value.find(e => e.id === formData.value.relatedEmployeeId)?.name
|
||||||
|
if (name) {
|
||||||
|
personObj.employeeIsTemp = true
|
||||||
|
personObj.employeeName = name
|
||||||
|
} else {
|
||||||
|
personObj.employeeId = formData.value.relatedEmployeeId
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
personObj.employeeId = Number(formData.value.relatedEmployeeId)
|
||||||
|
}
|
||||||
|
} else if (formData.value.newRelatedEmployeeName) {
|
||||||
|
personObj.employeeIsTemp = true
|
||||||
|
personObj.employeeName = formData.value.newRelatedEmployeeName.trim()
|
||||||
|
}
|
||||||
|
|
||||||
|
personObj.relationShip = formData.value.relationShip
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((!personObj.name || personObj.name === undefined) && personObj.id && typeof personObj.id === 'string' && String(personObj.id).startsWith('tmp_')) {
|
||||||
|
const tmp = localCreatedPersons.value.find(p => p.tempId === personObj.id)
|
||||||
|
if (tmp) personObj.name = tmp.name
|
||||||
|
}
|
||||||
|
|
||||||
|
personObj.birthday = formData.value.birthday
|
||||||
|
personObj.weight = formData.value.weight
|
||||||
|
personObj.height = formData.value.height
|
||||||
|
|
||||||
|
const herbsPayload = formData.value.herbs.map(h => ({
|
||||||
|
id: h.id || 0,
|
||||||
|
amountG: h.amountG,
|
||||||
|
note: h.note
|
||||||
|
}))
|
||||||
|
|
||||||
|
const payload: any = {
|
||||||
|
id: props.prescriptionId ?? undefined,
|
||||||
|
person: personObj,
|
||||||
|
diagnosisResult: formData.value.diagnosisResult,
|
||||||
|
userMedicinaAdvice: formData.value.userMedicinaAdvice,
|
||||||
|
visitDate: formData.value.visitDate,
|
||||||
|
herbs: herbsPayload
|
||||||
|
}
|
||||||
|
|
||||||
|
const res: any = await prescriptionApi.save(payload)
|
||||||
|
|
||||||
|
if (res && (res.code === 0 || res.data !== undefined)) {
|
||||||
|
ElMessage.success(props.isEdit ? '处方更新成功' : '处方保存成功')
|
||||||
|
emit('refresh-list')
|
||||||
|
handleClose()
|
||||||
|
} else {
|
||||||
|
ElMessage.success('保存成功')
|
||||||
|
emit('refresh-list')
|
||||||
|
handleClose()
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error('保存处方失败', err)
|
||||||
|
} finally {
|
||||||
|
submitLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 监听弹窗显示
|
||||||
|
watch(() => props.visible, async (newVal) => {
|
||||||
|
if (newVal) {
|
||||||
|
resetForm()
|
||||||
|
await Promise.all([
|
||||||
|
fetchEmployees(),
|
||||||
|
fetchRelationTypes(),
|
||||||
|
loadAllMedicinals()
|
||||||
|
])
|
||||||
|
|
||||||
|
// 编辑/查看模式:加载详情
|
||||||
|
if ((props.isEdit || isViewMode.value) && props.prescriptionId) {
|
||||||
|
try {
|
||||||
|
const res: any = await prescriptionApi.getDetail(props.prescriptionId)
|
||||||
|
const detail = res?.data ?? null
|
||||||
|
|
||||||
|
if (detail) {
|
||||||
|
const person = detail.person || {}
|
||||||
|
formData.value.personType = person.isEmployee ? 1 : 2
|
||||||
|
|
||||||
|
if (formData.value.personType === 1) {
|
||||||
|
formData.value.employeeId = person.id ?? undefined
|
||||||
|
formData.value.birthday = person.birthday ?? undefined
|
||||||
|
formData.value.height = person.height ?? undefined
|
||||||
|
} else {
|
||||||
|
formData.value.relatedEmployeeId = person.employeeId ?? undefined
|
||||||
|
formData.value.relativeId = person.id ?? undefined
|
||||||
|
formData.value.birthday = person.birthday ?? undefined
|
||||||
|
formData.value.height = person.height ?? undefined
|
||||||
|
formData.value.relationShip = person.relationShip ?? undefined
|
||||||
|
if (formData.value.relatedEmployeeId) {
|
||||||
|
loadRelatives(formData.value.relatedEmployeeId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
formData.value.weight = person.weight ?? undefined
|
||||||
|
formData.value.diagnosisResult = detail.diagnosisResult ?? ''
|
||||||
|
formData.value.userMedicinaAdvice = detail.userMedicinaAdvice ?? ''
|
||||||
|
formData.value.visitDate = detail.visitDate ?? ''
|
||||||
|
formData.value.herbs = (detail.herbs || []).map((h: any) => ({
|
||||||
|
id: h.medicinalId,
|
||||||
|
medicinalName: h.medicinalName,
|
||||||
|
amountG: h.amountG,
|
||||||
|
note: h.note || ''
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.modal-class {
|
||||||
|
max-height: 60vh !important;
|
||||||
|
overflow-y: auto !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.prescription-form {
|
||||||
|
.form-section {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #303133;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-footer {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.items-center {
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-2 {
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-1 {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ml-4 {
|
||||||
|
margin-left: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.w-full {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mt-2 {
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,375 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog v-model="visibleRef" title="处方报告" width="1500px" :body-class="'report-modal-body'" :show-close="false"
|
||||||
|
:top="'0'" append-to-body>
|
||||||
|
<!-- 报告核心内容 -->
|
||||||
|
<div class="report-content">
|
||||||
|
<!-- 3.1 就诊人基本信息 -->
|
||||||
|
<div class="report-section">
|
||||||
|
<h3 class="section-heading">一、就诊人基本信息</h3>
|
||||||
|
<div class="info-grid">
|
||||||
|
<div class="info-item">
|
||||||
|
<span class="info-label">就诊人姓名:</span>
|
||||||
|
<span class="info-value">{{ reportData.patientName || "暂无数据" }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="info-item">
|
||||||
|
<span class="info-label">出生日期:</span>
|
||||||
|
<span class="info-value">{{ reportData.birthday || "暂无数据" }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="info-item">
|
||||||
|
<span class="info-label">身高:</span>
|
||||||
|
<span class="info-value">{{ reportData.height ? `${reportData.height} cm` : "暂无数据" }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="info-item">
|
||||||
|
<span class="info-label">体重:</span>
|
||||||
|
<span class="info-value">{{ reportData.weight ? `${reportData.weight} kg` : "暂无数据" }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="info-item">
|
||||||
|
<span class="info-label">就诊时间:</span>
|
||||||
|
<span class="info-value">{{ reportData.visitDate || "暂无数据" }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 3.2 药材消耗明细(超紧凑卡片布局) -->
|
||||||
|
<div class="report-section mt-16">
|
||||||
|
<h3 class="section-heading">二、药材消耗明细</h3>
|
||||||
|
<div class="herbs-grid-container">
|
||||||
|
<!-- 单个药材卡片(更小尺寸) -->
|
||||||
|
<div class="herb-card" v-for="(herb, index) in reportData.herbs" :key="index">
|
||||||
|
<div class="herb-name">
|
||||||
|
<span class="herb-label">名称:</span>
|
||||||
|
{{ herb.medicinalName || "未命名药材" }}
|
||||||
|
</div>
|
||||||
|
<div class="herb-amount">
|
||||||
|
<span class="herb-label">用量:</span>
|
||||||
|
{{ herb.amountG !== undefined ? `${herb.amountG} g` : "0 g" }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 无药材空状态 -->
|
||||||
|
<div v-if="reportData.herbs.length === 0" class="empty-herbs">
|
||||||
|
<el-icon size="24" color="#9ca3af" class="empty-icon">
|
||||||
|
<DocumentEmpty />
|
||||||
|
</el-icon>
|
||||||
|
<p class="empty-text">当前处方暂无药材消耗记录</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 3.3 诊断与用药建议 -->
|
||||||
|
<div class="report-section mt-16">
|
||||||
|
<h3 class="section-heading">三、诊断与用药建议</h3>
|
||||||
|
<div class="advice-container">
|
||||||
|
<div class="advice-item">
|
||||||
|
<span class="advice-label">诊断结果:</span>
|
||||||
|
<div class="advice-content">
|
||||||
|
{{ reportData.diagnosisResult || "暂无诊断结果描述" }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="advice-item mt-8">
|
||||||
|
<span class="advice-label">用药建议:</span>
|
||||||
|
<div class="advice-content">
|
||||||
|
{{ reportData.userMedicinaAdvice || "暂无用药建议描述" }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="handleClose">关闭报告</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, watch } from "vue";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
import { prescriptionApi } from "@/api";
|
||||||
|
|
||||||
|
// Props定义
|
||||||
|
interface Props {
|
||||||
|
modelValue: boolean;
|
||||||
|
prescriptionId?: number;
|
||||||
|
}
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
modelValue: false,
|
||||||
|
prescriptionId: undefined,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 弹窗显隐控制
|
||||||
|
const visibleRef = ref(props.modelValue);
|
||||||
|
const emit = defineEmits<{
|
||||||
|
"update:modelValue": [value: boolean];
|
||||||
|
}>();
|
||||||
|
|
||||||
|
// 监听父组件传值,同步弹窗状态
|
||||||
|
watch(
|
||||||
|
() => props.modelValue,
|
||||||
|
(newVal) => {
|
||||||
|
visibleRef.value = newVal;
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
// 数据状态
|
||||||
|
const loading = ref(false);
|
||||||
|
const error = ref(false);
|
||||||
|
const errorMsg = ref("");
|
||||||
|
const reportData = ref({
|
||||||
|
patientName: "",
|
||||||
|
birthday: "",
|
||||||
|
height: undefined,
|
||||||
|
weight: undefined,
|
||||||
|
visitDate: "",
|
||||||
|
herbs: [] as Array<{ medicinalName: string; amountG: number; note: string }>,
|
||||||
|
diagnosisResult: "",
|
||||||
|
userMedicinaAdvice: "",
|
||||||
|
});
|
||||||
|
|
||||||
|
// 加载报告数据
|
||||||
|
const fetchReportData = async () => {
|
||||||
|
if (!props.prescriptionId) return;
|
||||||
|
try {
|
||||||
|
loading.value = true;
|
||||||
|
error.value = false;
|
||||||
|
const res: any = await prescriptionApi.getDetail(props.prescriptionId);
|
||||||
|
const detail = res?.data || {};
|
||||||
|
const person = detail.person || {};
|
||||||
|
reportData.value = {
|
||||||
|
patientName: person.name || "",
|
||||||
|
birthday: person.birthday || "",
|
||||||
|
height: person.height,
|
||||||
|
weight: person.weight,
|
||||||
|
visitDate: detail.visitDate || "",
|
||||||
|
herbs: (detail.herbs || []).map((h: any) => ({
|
||||||
|
medicinalName: h.medicinalName || "未命名药材",
|
||||||
|
amountG: h.amountG || 0,
|
||||||
|
note: h.note || "",
|
||||||
|
})),
|
||||||
|
diagnosisResult: detail.diagnosisResult || "",
|
||||||
|
userMedicinaAdvice: detail.userMedicinaAdvice || "",
|
||||||
|
};
|
||||||
|
} catch (err: any) {
|
||||||
|
error.value = true;
|
||||||
|
errorMsg.value = err.message || "加载报告失败,请检查网络";
|
||||||
|
ElMessage.error(errorMsg.value);
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 关闭弹窗
|
||||||
|
const handleClose = () => {
|
||||||
|
emit("update:modelValue", false);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 弹窗关闭前重置数据
|
||||||
|
const handleBeforeClose = () => {
|
||||||
|
reportData.value = {
|
||||||
|
patientName: "",
|
||||||
|
birthday: "",
|
||||||
|
height: undefined,
|
||||||
|
weight: undefined,
|
||||||
|
visitDate: "",
|
||||||
|
herbs: [],
|
||||||
|
diagnosisResult: "",
|
||||||
|
userMedicinaAdvice: "",
|
||||||
|
};
|
||||||
|
error.value = false;
|
||||||
|
errorMsg.value = "";
|
||||||
|
};
|
||||||
|
|
||||||
|
// 监听处方ID变化,重新加载数据
|
||||||
|
watch(
|
||||||
|
() => props.prescriptionId,
|
||||||
|
(newId) => {
|
||||||
|
if (props.modelValue && newId) {
|
||||||
|
fetchReportData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.report-modal-body {
|
||||||
|
// padding: 20px !important;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #303133;
|
||||||
|
background: #fff;
|
||||||
|
overflow-y: auto !important;
|
||||||
|
max-height: 100vh !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
/* 报告通用样式 */
|
||||||
|
.report-content {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.report-section {
|
||||||
|
padding: 15px;
|
||||||
|
border: 1px solid #e6e6e6;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-heading {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #1f2937;
|
||||||
|
margin: 0 0 12px 0;
|
||||||
|
padding-bottom: 8px;
|
||||||
|
border-bottom: 2px solid #409eff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 就诊人基本信息样式 */
|
||||||
|
.info-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
line-height: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-label {
|
||||||
|
font-weight: 600;
|
||||||
|
color: #4b5563;
|
||||||
|
min-width: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-value {
|
||||||
|
flex: 1;
|
||||||
|
word-break: break-all;
|
||||||
|
color: #303133;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 药材消耗明细样式(超紧凑设计) */
|
||||||
|
.herbs-grid-container {
|
||||||
|
// display: grid;
|
||||||
|
// /* 核心:每列最小宽度缩小到150px,可根据需要进一步减小到120px */
|
||||||
|
// grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
|
||||||
|
// gap: 8px;
|
||||||
|
/* 卡片间距缩小 */
|
||||||
|
padding: 8px 0;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 15px;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 单个药材卡片(更小尺寸) */
|
||||||
|
.herb-card {
|
||||||
|
padding: 8px;
|
||||||
|
/* 内边距大幅缩小 */
|
||||||
|
border: 1px solid #e6e6e6;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: #f9fafb;
|
||||||
|
line-height: 1.3;
|
||||||
|
/* 行高压缩 */
|
||||||
|
font-size: 12px;
|
||||||
|
/* 字体缩小 */
|
||||||
|
min-width: 70px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 卡片内标签样式 */
|
||||||
|
.herb-label {
|
||||||
|
font-weight: 600;
|
||||||
|
color: #4b5563;
|
||||||
|
font-size: 13px;
|
||||||
|
/* 标签字体更小 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 药材空状态样式 */
|
||||||
|
.empty-herbs {
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
text-align: center;
|
||||||
|
padding: 30px 0;
|
||||||
|
color: #9ca3af;
|
||||||
|
background: #f9fafb;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-icon {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 诊断与用药建议样式 */
|
||||||
|
.advice-container {
|
||||||
|
padding: 8px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.advice-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.advice-label {
|
||||||
|
font-weight: 600;
|
||||||
|
color: #4b5563;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.advice-content {
|
||||||
|
padding: 8px 12px;
|
||||||
|
border: 1px solid #e6e6e6;
|
||||||
|
border-radius: 4px;
|
||||||
|
min-height: 60px;
|
||||||
|
line-height: 1.5;
|
||||||
|
background: #f9fafb;
|
||||||
|
word-break: break-all;
|
||||||
|
color: #303133;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 间距工具类 */
|
||||||
|
.mt-8 {
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mt-16 {
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 加载/错误样式 */
|
||||||
|
.loading-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-text {
|
||||||
|
margin-top: 16px;
|
||||||
|
color: #606266;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 300px;
|
||||||
|
color: #f56c6c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-icon {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-text {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.retry-btn {
|
||||||
|
min-width: 100px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
<template>
|
||||||
|
<div class="table-box">
|
||||||
|
<!-- 原有:处方列表(仅操作列新增“查看报告”按钮) -->
|
||||||
|
<ProTable ref="proTable" title="处方列表" :columns="columns" :request-api="getPrescriptionListApi" :row-key="rowKey">
|
||||||
|
<!-- 原有:表格头部按钮(不变) -->
|
||||||
|
<template #tableHeader>
|
||||||
|
<s-button suffix="处方" type="success" @click="handleAddPrescription" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 原有:就诊人类型自定义插槽(不变) -->
|
||||||
|
<template #personType="scope">
|
||||||
|
<el-space>
|
||||||
|
<span v-if="scope.row.personType === 1">公司员工</span>
|
||||||
|
<span v-else-if="scope.row.personType === 2">
|
||||||
|
员工家属,所属员工:{{ scope.row.employeeName || "未知" }}
|
||||||
|
</span>
|
||||||
|
<span v-else>未知类型</span>
|
||||||
|
</el-space>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 关键改动:操作列新增“查看报告”按钮 -->
|
||||||
|
<template #operation="{ row }">
|
||||||
|
<s-button link :opt="FormOptEnum.VIEW" size="small" @click="handleViewDetail(row.id)">
|
||||||
|
查看详情
|
||||||
|
</s-button>
|
||||||
|
<s-button v-if="row.canEdit" link :opt="FormOptEnum.EDIT" size="small" class="ml-2" @click="handleEdit(row.id)">
|
||||||
|
编辑
|
||||||
|
</s-button>
|
||||||
|
<!-- 新增:触发报告弹窗 -->
|
||||||
|
<s-button link :opt="FormOptEnum.VIEW" size="small" class="ml-2" @click="handleOpenReport(row.id)">
|
||||||
|
查看报告
|
||||||
|
</s-button>
|
||||||
|
</template>
|
||||||
|
</ProTable>
|
||||||
|
|
||||||
|
<!-- 原有:处方详情/编辑弹窗(不变) -->
|
||||||
|
<PrescriptionDetailDialog v-model:visible="showDetailDialog" :prescription-id="currentPrescriptionId"
|
||||||
|
:is-edit="isEdit" @refresh-list="handleRefresh" />
|
||||||
|
|
||||||
|
<!-- 关键改动:引入独立的报告弹窗组件 -->
|
||||||
|
<PrescriptionReportDialog v-model="showReportDialog" :prescription-id="currentReportId" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts" name="PrescriptionModule">
|
||||||
|
import { ref } from "vue";
|
||||||
|
import ProTable from "@/components/ProTable/index.vue";
|
||||||
|
import type { ProTableInstance, ColumnProps } from "@/components/ProTable/interface";
|
||||||
|
import { prescriptionApi } from "@/api";
|
||||||
|
// 原有:引入详情弹窗组件(不变)
|
||||||
|
import PrescriptionDetailDialog from "./components/PrescriptionDetailDialog.vue";
|
||||||
|
// 关键改动:引入独立的报告弹窗组件
|
||||||
|
import PrescriptionReportDialog from "./components/PrescriptionReportDialog.vue";
|
||||||
|
import { FormOptEnum } from "@/enums";
|
||||||
|
|
||||||
|
// 原有:表格ref、详情弹窗状态(不变)
|
||||||
|
const proTable = ref<ProTableInstance | null>(null);
|
||||||
|
const showDetailDialog = ref(false);
|
||||||
|
const currentPrescriptionId = ref<number | undefined>(undefined);
|
||||||
|
const isEdit = ref(false);
|
||||||
|
|
||||||
|
// 关键改动:新增报告弹窗相关状态
|
||||||
|
const showReportDialog = ref(false); // 报告弹窗显隐
|
||||||
|
const currentReportId = ref<number | undefined>(undefined); // 当前报告对应的处方ID
|
||||||
|
|
||||||
|
// 原有:就诊人类型选项、表格列配置(不变)
|
||||||
|
const personTypeOptions = [
|
||||||
|
{ label: "公司员工", value: 1 },
|
||||||
|
{ label: "员工家属", value: 2 }
|
||||||
|
];
|
||||||
|
const columns: ColumnProps<any>[] = [
|
||||||
|
{ type: "selection", fixed: "left", width: 80 },
|
||||||
|
{ prop: "personName", label: "就诊人", search: { el: "input" } },
|
||||||
|
{
|
||||||
|
prop: "personType",
|
||||||
|
label: "就诊人类型",
|
||||||
|
sortable: false,
|
||||||
|
enum: personTypeOptions,
|
||||||
|
search: { el: "select" }
|
||||||
|
},
|
||||||
|
{ prop: "visitDate", label: "就诊时间" },
|
||||||
|
{ prop: "totalMedicineCost", label: "预估处方药材成本(元)" },
|
||||||
|
{ prop: "operation", label: "操作", width: 280, fixed: "right" }
|
||||||
|
];
|
||||||
|
const rowKey = "id";
|
||||||
|
const getPrescriptionListApi = (params: any) => {
|
||||||
|
return prescriptionApi.getList(params);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 原有:新增、查看详情、编辑、刷新逻辑(不变)
|
||||||
|
const handleAddPrescription = () => {
|
||||||
|
currentPrescriptionId.value = undefined;
|
||||||
|
isEdit.value = false;
|
||||||
|
showDetailDialog.value = true;
|
||||||
|
};
|
||||||
|
const handleViewDetail = (id: number) => {
|
||||||
|
currentPrescriptionId.value = id;
|
||||||
|
isEdit.value = false;
|
||||||
|
showDetailDialog.value = true;
|
||||||
|
};
|
||||||
|
const handleEdit = (id: number) => {
|
||||||
|
currentPrescriptionId.value = id;
|
||||||
|
isEdit.value = true;
|
||||||
|
showDetailDialog.value = true;
|
||||||
|
};
|
||||||
|
const handleRefresh = () => {
|
||||||
|
proTable.value?.refresh?.();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 关键改动:新增“打开报告弹窗”方法
|
||||||
|
const handleOpenReport = (id: number) => {
|
||||||
|
currentReportId.value = id; // 传递当前处方ID给报告组件
|
||||||
|
showReportDialog.value = true; // 显示报告弹窗
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
/* 原有样式(不变):确保操作列按钮不换行 */
|
||||||
|
.table-box {
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -19,17 +19,17 @@
|
|||||||
<el-tab-pane label="账号登录" name="pwd">
|
<el-tab-pane label="账号登录" name="pwd">
|
||||||
<LoginForm :tenant-option="props.sysTenantOption" :tenant-options="props.tenantOptions" />
|
<LoginForm :tenant-option="props.sysTenantOption" :tenant-options="props.tenantOptions" />
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane label="手机号登录" name="phone">
|
<!-- <el-tab-pane label="手机号登录" name="phone">
|
||||||
<LoginPhoneForm :tenant-option="props.sysTenantOption" :tenant-options="props.tenantOptions" />
|
<LoginPhoneForm :tenant-option="props.sysTenantOption" :tenant-options="props.tenantOptions" />
|
||||||
</el-tab-pane>
|
</el-tab-pane> -->
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
<div class="fixed-corner">
|
<div class="fixed-corner">
|
||||||
<span>{{ props.sysVersion }}</span>
|
<!-- <span>{{ props.sysVersion }}</span> -->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Footer />
|
<!-- <Footer /> -->
|
||||||
<choose-module v-if="auth.showChooseModule" :show-modal="true" />
|
<choose-module v-if="auth.showChooseModule" :show-modal="true" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -62,7 +62,7 @@ interface LoginProps {
|
|||||||
|
|
||||||
//默认值
|
//默认值
|
||||||
const props = reactive<LoginProps>({
|
const props = reactive<LoginProps>({
|
||||||
sysName: "SimpleAdmin",
|
sysName: "未病局管理系统",
|
||||||
sysVersion: "",
|
sysVersion: "",
|
||||||
sysLogo: "",
|
sysLogo: "",
|
||||||
sysTenantOption: TenantEnum.CLOSE,
|
sysTenantOption: TenantEnum.CLOSE,
|
||||||
@@ -107,6 +107,7 @@ function updateSysConfig(props: LoginProps, config: ReturnType<typeof useConfigS
|
|||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@use "./index";
|
@use "./index";
|
||||||
|
|
||||||
.demo-tabs>.el-tabs__content {
|
.demo-tabs>.el-tabs__content {
|
||||||
padding: 32px;
|
padding: 32px;
|
||||||
font-size: 32px;
|
font-size: 32px;
|
||||||
|
|||||||
@@ -1,85 +0,0 @@
|
|||||||
<template>
|
|
||||||
<!-- 关键修改:v-model → :visible + @update:visible -->
|
|
||||||
<el-dialog :visible="visible" @update:visible="handleUpdateVisible" :title="`${medicinalName} - 消耗记录`" width="800px">
|
|
||||||
<el-table v-loading="loading" :data="consumptionRecords" border style="width: 100%" empty-text="暂无消耗记录">
|
|
||||||
<el-table-column prop="amountG" label="使用量(g)" width="120"></el-table-column>
|
|
||||||
<el-table-column label="使用人员" width="200">
|
|
||||||
<template #default="scope">
|
|
||||||
<span>{{ scope.row.personName }}</span>
|
|
||||||
<el-tag size="small" type="info" v-if="scope.row.isRelative" style="margin-left: 8px">
|
|
||||||
家属({{ scope.row.employeeName || "未知员工" }})
|
|
||||||
</el-tag>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column prop="useTime" label="使用时间" width="200">
|
|
||||||
<template #default="scope">
|
|
||||||
{{ scope.row.useTime ? new Date(scope.row.useTime).toLocaleString() : "-" }}
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
</el-table>
|
|
||||||
</el-dialog>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { defineProps, defineEmits, ref, watch } from "vue";
|
|
||||||
import { getConsumptionRecords, Medicinal } from "@/api/modules/biz/WeiBingJu/medicinal";
|
|
||||||
import { ElMessage } from "element-plus";
|
|
||||||
|
|
||||||
// 1. 接收父组件prop
|
|
||||||
const props = defineProps({
|
|
||||||
visible: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
medicinalId: {
|
|
||||||
type: Number,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
medicinalName: {
|
|
||||||
type: String,
|
|
||||||
default: "药材"
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 2. 定义发射事件:update:visible + 关闭通知
|
|
||||||
const emit = defineEmits(["update:visible", "close"]);
|
|
||||||
|
|
||||||
// 状态数据
|
|
||||||
const loading = ref(false);
|
|
||||||
const consumptionRecords = ref<Medicinal.ConsumptionRecord[]>([]);
|
|
||||||
|
|
||||||
// 3. 监听弹窗状态变化
|
|
||||||
const handleUpdateVisible = (newVisible: boolean) => {
|
|
||||||
emit("update:visible", newVisible);
|
|
||||||
// 弹窗关闭时清空数据
|
|
||||||
if (!newVisible) {
|
|
||||||
consumptionRecords.value = [];
|
|
||||||
emit("close");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 监听visible变化:弹窗显示时加载消耗记录
|
|
||||||
watch(
|
|
||||||
() => props.visible,
|
|
||||||
async newVal => {
|
|
||||||
if (newVal && props.medicinalId) {
|
|
||||||
await fetchConsumptionRecords();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ immediate: true }
|
|
||||||
);
|
|
||||||
|
|
||||||
// 加载消耗记录
|
|
||||||
const fetchConsumptionRecords = async () => {
|
|
||||||
loading.value = true;
|
|
||||||
try {
|
|
||||||
const res = await getConsumptionRecords({ medicinalId: props.medicinalId });
|
|
||||||
consumptionRecords.value = res;
|
|
||||||
} catch (err: any) {
|
|
||||||
ElMessage.error(err.message || "加载消耗记录失败");
|
|
||||||
consumptionRecords.value = [];
|
|
||||||
} finally {
|
|
||||||
loading.value = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
@@ -1,714 +0,0 @@
|
|||||||
<template>
|
|
||||||
<el-dialog :model-value="visible" @update:model-value="handleUpdateVisible" :title="dialogTitle" width="900px" destroy-on-close>
|
|
||||||
<!-- 人员信息 -->
|
|
||||||
<el-card shadow="hover" class="mb-4">
|
|
||||||
<template #header><span>人员信息</span></template>
|
|
||||||
<el-form :model="personForm" label-width="120px" :disabled="!isEdit" ref="personFormRef" :rules="personFormRules">
|
|
||||||
<!-- 1. 人员类型 -->
|
|
||||||
<el-form-item label="人员类型" required prop="isEmployee">
|
|
||||||
<el-radio-group v-model="personForm.isEmployee" @change="handlePersonTypeChange">
|
|
||||||
<el-radio :label="true">公司员工</el-radio>
|
|
||||||
<el-radio :label="false">员工家属</el-radio>
|
|
||||||
</el-radio-group>
|
|
||||||
</el-form-item>
|
|
||||||
|
|
||||||
<!-- 2. 员工场景:员工选择/新增 -->
|
|
||||||
<template v-if="personForm.isEmployee">
|
|
||||||
<!-- 员工下拉选择(默认显示) -->
|
|
||||||
<el-form-item v-if="showEmployeeSelect" label="员工姓名" required prop="employeeId">
|
|
||||||
<el-select
|
|
||||||
v-model="personForm.employeeId"
|
|
||||||
placeholder="搜索或选择员工"
|
|
||||||
filterable
|
|
||||||
remote
|
|
||||||
:remote-method="handleEmployeeSearch"
|
|
||||||
@change="handleEmployeeChange"
|
|
||||||
clearable
|
|
||||||
>
|
|
||||||
<!-- 正常员工选项 -->
|
|
||||||
<el-option v-for="emp in employeeOptions" :key="emp.id" :label="emp.name" :value="emp.id" />
|
|
||||||
<!-- 未找到选项(仅搜索后无结果时显示) -->
|
|
||||||
<el-option v-if="employeeOptions.length === 0 && employeeKeyword" :key="0" :label="`未找到,新增员工:${employeeKeyword}`" :value="0" />
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
|
|
||||||
<!-- 员工新增文本框(点击"未找到"后显示) -->
|
|
||||||
<el-form-item v-if="!showEmployeeSelect" label="员工姓名" required prop="newEmployeeName">
|
|
||||||
<el-input
|
|
||||||
v-model="personForm.newEmployeeName"
|
|
||||||
placeholder="输入新员工姓名"
|
|
||||||
@blur="() => (personForm.name = personForm.newEmployeeName)"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<!-- 3. 家属场景:关联员工选择 + 家属选择/新增 -->
|
|
||||||
<template v-else>
|
|
||||||
<!-- 3.1 关联员工选择(第一步) -->
|
|
||||||
<el-form-item v-if="showRelatedEmployeeSelect" label="关联员工" required prop="relatedEmployeeId">
|
|
||||||
<el-select
|
|
||||||
v-model="personForm.relatedEmployeeId"
|
|
||||||
placeholder="搜索或选择关联员工"
|
|
||||||
filterable
|
|
||||||
remote
|
|
||||||
:remote-method="handleRelatedEmployeeSearch"
|
|
||||||
@change="handleRelatedEmployeeChange"
|
|
||||||
clearable
|
|
||||||
>
|
|
||||||
<!-- 正常关联员工选项 -->
|
|
||||||
<el-option v-for="emp in relatedEmployeeOptions" :key="emp.id" :label="emp.name" :value="emp.id" />
|
|
||||||
<!-- 未找到选项 -->
|
|
||||||
<el-option
|
|
||||||
v-if="relatedEmployeeOptions.length === 0 && relatedEmployeeKeyword"
|
|
||||||
:key="0"
|
|
||||||
:label="`未找到,新增关联员工:${relatedEmployeeKeyword}`"
|
|
||||||
:value="0"
|
|
||||||
/>
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
|
|
||||||
<!-- 3.2 关联员工新增(点击"未找到"后显示) -->
|
|
||||||
<el-form-item v-if="!showRelatedEmployeeSelect" label="关联员工姓名" required prop="newRelatedEmployeeName">
|
|
||||||
<el-input v-model="personForm.newRelatedEmployeeName" placeholder="输入新关联员工姓名" />
|
|
||||||
</el-form-item>
|
|
||||||
|
|
||||||
<!-- 3.3 家属选择(选择关联员工后显示) -->
|
|
||||||
<el-form-item v-if="showRelativeSelect && personForm.relatedEmployeeId" label="家属姓名" required prop="relativeId">
|
|
||||||
<el-select
|
|
||||||
v-model="personForm.relativeId"
|
|
||||||
placeholder="搜索或选择家属"
|
|
||||||
filterable
|
|
||||||
remote
|
|
||||||
:remote-method="handleRelativeSearch"
|
|
||||||
@change="handleRelativeChange"
|
|
||||||
clearable
|
|
||||||
>
|
|
||||||
<!-- 正常家属选项 -->
|
|
||||||
<el-option v-for="rel in relativeOptions" :key="rel.id" :label="rel.name" :value="rel.id" />
|
|
||||||
<!-- 未找到选项 -->
|
|
||||||
<el-option v-if="relativeOptions.length === 0 && relativeKeyword" :key="0" :label="`未找到,新增家属:${relativeKeyword}`" :value="0" />
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
|
|
||||||
<!-- 3.4 家属新增(点击"未找到"后显示 / 关联员工新增时同步显示) -->
|
|
||||||
<el-form-item v-if="!showRelativeSelect || !showRelatedEmployeeSelect" label="家属姓名" required prop="newRelativeName">
|
|
||||||
<el-input
|
|
||||||
v-model="personForm.newRelativeName"
|
|
||||||
placeholder="输入新家属姓名"
|
|
||||||
@blur="() => (personForm.name = personForm.newRelativeName)"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
|
||||||
|
|
||||||
<!-- 3.5 亲属关系(家属场景必选) -->
|
|
||||||
<el-form-item label="亲属关系" required prop="relationShip" v-if="personForm.relatedEmployeeId || !showRelatedEmployeeSelect">
|
|
||||||
<el-select v-model="personForm.relationShip" clearable>
|
|
||||||
<el-option v-for="item in relationTypes" :key="item.id" :label="item.name" :value="item.id" />
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<!-- 4. 公共信息:年龄/体重/身高(复用原有逻辑) -->
|
|
||||||
<el-form-item label="年龄" prop="age">
|
|
||||||
<el-input v-model.number="personForm.age" placeholder="输入年龄" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="体重(kg)" prop="weight">
|
|
||||||
<el-input v-model.number="personForm.weight" placeholder="输入体重" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="身高(cm)" prop="height">
|
|
||||||
<el-input v-model.number="personForm.height" placeholder="输入身高" />
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
|
||||||
</el-card>
|
|
||||||
|
|
||||||
<!-- 药材消耗、诊断建议等原有模块(保持不变) -->
|
|
||||||
<el-card shadow="hover" class="mb-4">
|
|
||||||
<template #header>
|
|
||||||
<div class="flex justify-between items-center">
|
|
||||||
<span>药材消耗</span>
|
|
||||||
<el-button v-if="isEdit" type="primary" size="small" @click="handleAddHerb"> 添加药材 </el-button>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<el-table :data="herbList" border :disabled="!isEdit" empty-text="暂无药材消耗记录">
|
|
||||||
<el-table-column label="药材名称" required>
|
|
||||||
<template #default="scope">
|
|
||||||
<el-select
|
|
||||||
v-model="scope.row.medicinalId"
|
|
||||||
placeholder="搜索或选择药材"
|
|
||||||
filterable
|
|
||||||
remote
|
|
||||||
:remote-method="kw => handleHerbSearch(kw, scope.$index)"
|
|
||||||
@change="val => handleHerbChange(val, scope.$index)"
|
|
||||||
:disabled="!isEdit"
|
|
||||||
clearable
|
|
||||||
>
|
|
||||||
<el-option v-for="item in scope.row.medicinalOptions" :key="item.id" :label="item.name" :value="item.id" />
|
|
||||||
<el-option
|
|
||||||
v-if="scope.row.medicinalOptions.length === 0 && scope.row.keyword"
|
|
||||||
:key="0"
|
|
||||||
:label="`新增药材:${scope.row.keyword}`"
|
|
||||||
:value="0"
|
|
||||||
/>
|
|
||||||
</el-select>
|
|
||||||
<el-input v-if="scope.row.showNewInput" v-model="scope.row.newName" placeholder="输入新药材名称" class="mt-2" :disabled="!isEdit" />
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column label="消耗(g)" required>
|
|
||||||
<template #default="scope">
|
|
||||||
<el-input v-model.number="scope.row.amountG" type="number" min="0.1" placeholder="输入消耗克数" :disabled="!isEdit" />
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column label="备注">
|
|
||||||
<template #default="scope">
|
|
||||||
<el-input v-model="scope.row.note" placeholder="输入备注" :disabled="!isEdit" />
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column label="操作" v-if="isEdit">
|
|
||||||
<template #default="scope">
|
|
||||||
<el-button type="text" text-color="#ff4d4f" @click="handleDeleteHerb(scope.$index)"> 删除 </el-button>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
</el-table>
|
|
||||||
</el-card>
|
|
||||||
|
|
||||||
<div class="flex gap-4 mb-4">
|
|
||||||
<el-card shadow="hover" class="flex-1">
|
|
||||||
<template #header><span>诊断结果</span></template>
|
|
||||||
<el-input v-model="prescriptionForm.diagnosisResult" type="textarea" rows="5" placeholder="输入诊断结果" :disabled="!isEdit" />
|
|
||||||
</el-card>
|
|
||||||
<el-card shadow="hover" class="flex-1">
|
|
||||||
<template #header><span>用药建议</span></template>
|
|
||||||
<el-input v-model="prescriptionForm.userMedicinaAdvice" type="textarea" rows="5" placeholder="输入用药建议" :disabled="!isEdit" />
|
|
||||||
</el-card>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<el-card shadow="hover" class="mb-4">
|
|
||||||
<el-form-item label="就诊时间" required>
|
|
||||||
<el-date-picker
|
|
||||||
v-model="prescriptionForm.visitDate"
|
|
||||||
type="datetime"
|
|
||||||
placeholder="选择就诊时间"
|
|
||||||
value-format="YYYY-MM-DD HH:mm:ss"
|
|
||||||
:disabled="!isEdit"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
|
||||||
</el-card>
|
|
||||||
|
|
||||||
<template #footer>
|
|
||||||
<el-button @click="handleCancel">取消</el-button>
|
|
||||||
<el-button type="primary" @click="handleSave" v-if="isEdit">
|
|
||||||
{{ prescriptionId ? "保存修改" : "新增处方" }}
|
|
||||||
</el-button>
|
|
||||||
</template>
|
|
||||||
</el-dialog>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { ref, reactive, watch, computed, nextTick } from "vue";
|
|
||||||
import { ElMessage, ElMessageBox, ElForm, FormItemRule } from "element-plus";
|
|
||||||
import { prescriptionApi } from "@/api/modules/biz/WeiBingJu/prescription";
|
|
||||||
|
|
||||||
// 1. props/emit定义
|
|
||||||
const props = defineProps({
|
|
||||||
visible: { type: Boolean, default: false },
|
|
||||||
prescriptionId: { type: Number, default: 0 },
|
|
||||||
isEdit: { type: Boolean, default: false }
|
|
||||||
});
|
|
||||||
const emit = defineEmits(["update:visible", "close", "refreshList"]);
|
|
||||||
|
|
||||||
// 2. 基础变量
|
|
||||||
const dialogTitle = computed(() => {
|
|
||||||
if (props.prescriptionId === 0) return "新增就诊处方";
|
|
||||||
return props.isEdit ? "编辑处方" : "处方详情";
|
|
||||||
});
|
|
||||||
const loading = ref(false);
|
|
||||||
const personFormRef = ref<InstanceType<typeof ElForm>>();
|
|
||||||
const relationTypes = ref<any[]>([]); // 亲属关系列表
|
|
||||||
const herbList = ref<any[]>([]); // 药材列表(原有逻辑)
|
|
||||||
|
|
||||||
// 3. 处方表单(原有逻辑)
|
|
||||||
const prescriptionForm = reactive({
|
|
||||||
diagnosisResult: "",
|
|
||||||
userMedicinaAdvice: "",
|
|
||||||
visitDate: new Date().toISOString().slice(0, 16) // 默认当前时间
|
|
||||||
});
|
|
||||||
|
|
||||||
// 4. 人员表单(核心重构:区分员工/家属场景)
|
|
||||||
const personForm = reactive({
|
|
||||||
// 基础字段
|
|
||||||
id: undefined, // 人员ID(编辑时用)
|
|
||||||
name: "", // 人员姓名(最终提交用)
|
|
||||||
isEmployee: true, // 是否员工(true=员工,false=家属)
|
|
||||||
|
|
||||||
// 员工场景字段
|
|
||||||
employeeId: undefined, // 已选员工ID
|
|
||||||
newEmployeeName: "", // 新增员工姓名
|
|
||||||
|
|
||||||
// 家属场景字段
|
|
||||||
relatedEmployeeId: undefined, // 关联员工ID
|
|
||||||
newRelatedEmployeeName: "", // 新增关联员工姓名
|
|
||||||
relativeId: undefined, // 已选家属ID
|
|
||||||
newRelativeName: "", // 新增家属姓名
|
|
||||||
relationShip: undefined, // 亲属关系ID
|
|
||||||
|
|
||||||
// 公共字段
|
|
||||||
age: undefined,
|
|
||||||
weight: undefined,
|
|
||||||
height: undefined
|
|
||||||
});
|
|
||||||
|
|
||||||
// 5. 下拉/新增状态控制(核心:控制显示隐藏)
|
|
||||||
const state = reactive({
|
|
||||||
// 员工场景
|
|
||||||
showEmployeeSelect: true, // 是否显示员工下拉(默认显示)
|
|
||||||
employeeOptions: [] as any[], // 员工下拉选项
|
|
||||||
employeeKeyword: "", // 员工搜索关键词
|
|
||||||
|
|
||||||
// 家属场景
|
|
||||||
showRelatedEmployeeSelect: true, // 是否显示关联员工下拉(默认显示)
|
|
||||||
relatedEmployeeOptions: [] as any[], // 关联员工下拉选项
|
|
||||||
relatedEmployeeKeyword: "", // 关联员工搜索关键词
|
|
||||||
|
|
||||||
showRelativeSelect: true, // 是否显示家属下拉(默认显示)
|
|
||||||
relativeOptions: [] as any[], // 家属下拉选项
|
|
||||||
relativeKeyword: "" // 家属搜索关键词
|
|
||||||
});
|
|
||||||
|
|
||||||
// 6. 表单验证规则
|
|
||||||
const personFormRules = reactive<Record<string, FormItemRule[]>>({
|
|
||||||
isEmployee: [{ required: true, message: "请选择人员类型", trigger: "change" }],
|
|
||||||
employeeId: [{ required: true, message: "请选择员工", trigger: "change" }],
|
|
||||||
newEmployeeName: [{ required: true, message: "请输入员工姓名", trigger: "blur" }],
|
|
||||||
relatedEmployeeId: [{ required: true, message: "请选择关联员工", trigger: "change" }],
|
|
||||||
newRelatedEmployeeName: [{ required: true, message: "请输入关联员工姓名", trigger: "blur" }],
|
|
||||||
relativeId: [{ required: true, message: "请选择家属", trigger: "change" }],
|
|
||||||
newRelativeName: [{ required: true, message: "请输入家属姓名", trigger: "blur" }],
|
|
||||||
relationShip: [{ required: true, message: "请选择亲属关系", trigger: "change" }],
|
|
||||||
age: [{ type: "number", message: "请输入合法年龄", trigger: "blur" }],
|
|
||||||
weight: [{ type: "number", message: "请输入合法体重", trigger: "blur" }],
|
|
||||||
height: [{ type: "number", message: "请输入合法身高", trigger: "blur" }]
|
|
||||||
});
|
|
||||||
|
|
||||||
// 7. 初始化逻辑(监听弹窗显示/隐藏)
|
|
||||||
watch(
|
|
||||||
() => props.visible,
|
|
||||||
async val => {
|
|
||||||
if (val) {
|
|
||||||
await fetchRelationTypes(); // 加载亲属关系
|
|
||||||
if (props.prescriptionId) {
|
|
||||||
await fetchPrescriptionDetail(); // 编辑/详情:加载已有数据
|
|
||||||
} else {
|
|
||||||
resetForm(); // 新增:重置表单
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
resetForm(); // 弹窗关闭:重置表单
|
|
||||||
emit("close");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ immediate: true }
|
|
||||||
);
|
|
||||||
|
|
||||||
// 8. 基础接口请求(原有逻辑优化)
|
|
||||||
// 加载亲属关系
|
|
||||||
const fetchRelationTypes = async () => {
|
|
||||||
try {
|
|
||||||
const res = await prescriptionApi.getRelationTypes();
|
|
||||||
relationTypes.value = res || [];
|
|
||||||
} catch (err) {
|
|
||||||
relationTypes.value = [];
|
|
||||||
ElMessage.error("加载亲属关系失败");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 加载处方详情(编辑/详情场景)
|
|
||||||
const fetchPrescriptionDetail = async () => {
|
|
||||||
loading.value = true;
|
|
||||||
try {
|
|
||||||
const res = await prescriptionApi.getDetail({ id: props.prescriptionId });
|
|
||||||
if (!res) return;
|
|
||||||
|
|
||||||
// 填充处方信息
|
|
||||||
prescriptionForm.diagnosisResult = res.diagnosisResult || "";
|
|
||||||
prescriptionForm.userMedicinaAdvice = res.userMedicinaAdvice || "";
|
|
||||||
prescriptionForm.visitDate = res.visitDate || new Date().toISOString().slice(0, 16);
|
|
||||||
|
|
||||||
// 填充人员信息
|
|
||||||
const { person } = res;
|
|
||||||
if (person) {
|
|
||||||
personForm.id = person.id;
|
|
||||||
personForm.name = person.name;
|
|
||||||
personForm.isEmployee = person.EmployeeId === undefined; // 员工:EmployeeId为空
|
|
||||||
personForm.age = person.age;
|
|
||||||
personForm.weight = person.weight;
|
|
||||||
personForm.height = person.height;
|
|
||||||
personForm.relationShip = person.RelationShip;
|
|
||||||
|
|
||||||
// 员工场景:赋值员工ID
|
|
||||||
if (personForm.isEmployee) {
|
|
||||||
personForm.employeeId = person.id;
|
|
||||||
state.employeeOptions = [{ id: person.id, name: person.name }];
|
|
||||||
}
|
|
||||||
// 家属场景:赋值关联员工ID和家属ID
|
|
||||||
else {
|
|
||||||
personForm.relatedEmployeeId = person.EmployeeId;
|
|
||||||
personForm.relativeId = person.id;
|
|
||||||
// 加载关联员工选项
|
|
||||||
state.relatedEmployeeOptions = [{ id: person.EmployeeId, name: res.employeeName || "" }];
|
|
||||||
// 加载家属选项
|
|
||||||
state.relativeOptions = [{ id: person.id, name: person.name }];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 填充药材信息(原有逻辑)
|
|
||||||
herbList.value = (res.herbs || []).map((h: any) => ({
|
|
||||||
medicinalId: h.medicinalId,
|
|
||||||
medicinalOptions: [{ id: h.medicinalId, name: h.medicinalName }],
|
|
||||||
keyword: h.medicinalName,
|
|
||||||
showNewInput: false,
|
|
||||||
newName: "",
|
|
||||||
amountG: h.amountG,
|
|
||||||
note: h.note || ""
|
|
||||||
}));
|
|
||||||
} catch (err) {
|
|
||||||
ElMessage.error("加载处方详情失败");
|
|
||||||
} finally {
|
|
||||||
loading.value = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 9. 员工场景交互逻辑
|
|
||||||
// 员工下拉搜索
|
|
||||||
const handleEmployeeSearch = async (keyword: string) => {
|
|
||||||
state.employeeKeyword = keyword.trim();
|
|
||||||
if (!keyword) {
|
|
||||||
state.employeeOptions = [];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 调用接口查询员工(personType=1表示员工)
|
|
||||||
const res = await prescriptionApi.getPersonList({ personType: 1, keyword });
|
|
||||||
state.employeeOptions = res || [];
|
|
||||||
};
|
|
||||||
|
|
||||||
// 员工下拉选择(含"未找到"逻辑)
|
|
||||||
const handleEmployeeChange = async (val: number) => {
|
|
||||||
if (val === 0) {
|
|
||||||
// 点击"未找到":隐藏下拉,显示新增文本框
|
|
||||||
state.showEmployeeSelect = false;
|
|
||||||
personForm.employeeId = undefined; // 清空下拉值
|
|
||||||
personForm.newEmployeeName = state.employeeKeyword; // 预填搜索关键词
|
|
||||||
} else {
|
|
||||||
// 选择已有员工:显示下拉,清空新增文本框
|
|
||||||
state.showEmployeeSelect = true;
|
|
||||||
personForm.newEmployeeName = "";
|
|
||||||
// 赋值人员姓名
|
|
||||||
const selectedEmp = state.employeeOptions.find(emp => emp.id === val);
|
|
||||||
if (selectedEmp) personForm.name = selectedEmp.name;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 10. 家属场景交互逻辑
|
|
||||||
// 关联员工下拉搜索
|
|
||||||
const handleRelatedEmployeeSearch = async (keyword: string) => {
|
|
||||||
state.relatedEmployeeKeyword = keyword.trim();
|
|
||||||
if (!keyword) {
|
|
||||||
state.relatedEmployeeOptions = [];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 调用接口查询员工(personType=1表示员工)
|
|
||||||
const res = await prescriptionApi.getPersonList({ personType: 1, keyword });
|
|
||||||
state.relatedEmployeeOptions = res || [];
|
|
||||||
};
|
|
||||||
|
|
||||||
// 关联员工下拉选择(含"未找到"逻辑)
|
|
||||||
const handleRelatedEmployeeChange = async (val: number) => {
|
|
||||||
if (val === 0) {
|
|
||||||
// 点击"未找到":隐藏关联员工下拉,显示新增文本框+家属新增文本框
|
|
||||||
state.showRelatedEmployeeSelect = false;
|
|
||||||
state.showRelativeSelect = false; // 隐藏家属下拉
|
|
||||||
personForm.relatedEmployeeId = undefined;
|
|
||||||
personForm.newRelatedEmployeeName = state.relatedEmployeeKeyword;
|
|
||||||
personForm.relativeId = undefined;
|
|
||||||
} else {
|
|
||||||
// 选择已有关联员工:显示关联员工下拉,加载家属列表
|
|
||||||
state.showRelatedEmployeeSelect = true;
|
|
||||||
state.showRelativeSelect = true; // 显示家属下拉
|
|
||||||
personForm.newRelatedEmployeeName = "";
|
|
||||||
personForm.newRelativeName = "";
|
|
||||||
// 加载该员工的家属(personType=2表示家属,传employeeId)
|
|
||||||
await handleLoadRelatives(val);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 加载关联员工的家属列表
|
|
||||||
const handleLoadRelatives = async (employeeId: number) => {
|
|
||||||
try {
|
|
||||||
const res = await prescriptionApi.getPersonList({
|
|
||||||
personType: 2, // 假设personType=2表示家属
|
|
||||||
employeeId
|
|
||||||
});
|
|
||||||
state.relativeOptions = res || [];
|
|
||||||
} catch (err) {
|
|
||||||
state.relativeOptions = [];
|
|
||||||
ElMessage.error("加载家属列表失败");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 家属下拉搜索
|
|
||||||
const handleRelativeSearch = async (keyword: string) => {
|
|
||||||
state.relativeKeyword = keyword.trim();
|
|
||||||
if (!keyword || !personForm.relatedEmployeeId) {
|
|
||||||
state.relativeOptions = [];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 调用接口查询家属(传关联员工ID)
|
|
||||||
const res = await prescriptionApi.getPersonList({
|
|
||||||
personType: 2,
|
|
||||||
employeeId: personForm.relatedEmployeeId,
|
|
||||||
keyword
|
|
||||||
});
|
|
||||||
state.relativeOptions = res || [];
|
|
||||||
};
|
|
||||||
|
|
||||||
// 家属下拉选择(含"未找到"逻辑)
|
|
||||||
const handleRelativeChange = async (val: number) => {
|
|
||||||
if (val === 0) {
|
|
||||||
// 点击"未找到":隐藏家属下拉,显示家属新增文本框
|
|
||||||
state.showRelativeSelect = false;
|
|
||||||
personForm.relativeId = undefined;
|
|
||||||
personForm.newRelativeName = state.relativeKeyword;
|
|
||||||
} else {
|
|
||||||
// 选择已有家属:显示家属下拉,清空新增文本框
|
|
||||||
state.showRelativeSelect = true;
|
|
||||||
personForm.newRelativeName = "";
|
|
||||||
// 赋值家属姓名
|
|
||||||
const selectedRel = state.relativeOptions.find(rel => rel.id === val);
|
|
||||||
if (selectedRel) personForm.name = selectedRel.name;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 11. 人员类型切换逻辑(重置状态)
|
|
||||||
const handlePersonTypeChange = () => {
|
|
||||||
// 重置所有状态
|
|
||||||
state.showEmployeeSelect = true;
|
|
||||||
state.showRelatedEmployeeSelect = true;
|
|
||||||
state.showRelativeSelect = true;
|
|
||||||
state.employeeOptions = [];
|
|
||||||
state.relatedEmployeeOptions = [];
|
|
||||||
state.relativeOptions = [];
|
|
||||||
state.employeeKeyword = "";
|
|
||||||
state.relatedEmployeeKeyword = "";
|
|
||||||
state.relativeKeyword = "";
|
|
||||||
|
|
||||||
// 重置表单字段
|
|
||||||
personForm.employeeId = undefined;
|
|
||||||
personForm.newEmployeeName = "";
|
|
||||||
personForm.relatedEmployeeId = undefined;
|
|
||||||
personForm.newRelatedEmployeeName = "";
|
|
||||||
personForm.relativeId = undefined;
|
|
||||||
personForm.newRelativeName = "";
|
|
||||||
personForm.relationShip = undefined;
|
|
||||||
personForm.name = "";
|
|
||||||
|
|
||||||
// 重置表单验证
|
|
||||||
nextTick(() => {
|
|
||||||
personFormRef.value?.clearValidate();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// 12. 药材相关逻辑(保持原有)
|
|
||||||
const handleAddHerb = () => {
|
|
||||||
herbList.value.push({
|
|
||||||
medicinalId: undefined,
|
|
||||||
medicinalOptions: [],
|
|
||||||
keyword: "",
|
|
||||||
showNewInput: false,
|
|
||||||
newName: "",
|
|
||||||
amountG: undefined,
|
|
||||||
note: ""
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleDeleteHerb = (index: number) => {
|
|
||||||
herbList.value.splice(index, 1);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleHerbSearch = async (keyword: string, index: number) => {
|
|
||||||
const res = await prescriptionApi.searchMedicinals({ keyword });
|
|
||||||
herbList.value[index].keyword = keyword;
|
|
||||||
herbList.value[index].medicinalOptions = res || [];
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleHerbChange = (val: number | 0, index: number) => {
|
|
||||||
if (val === 0) {
|
|
||||||
herbList.value[index].showNewInput = true;
|
|
||||||
herbList.value[index].newName = herbList.value[index].keyword;
|
|
||||||
} else {
|
|
||||||
herbList.value[index].showNewInput = false;
|
|
||||||
herbList.value[index].newName = "";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 13. 表单提交/取消逻辑(优化参数组装)
|
|
||||||
const handleSave = async () => {
|
|
||||||
// 表单验证
|
|
||||||
if (!personFormRef.value?.validate()) return;
|
|
||||||
// 药材验证
|
|
||||||
if (herbList.value.length === 0) {
|
|
||||||
return ElMessage.warning("请至少添加一条药材消耗记录");
|
|
||||||
}
|
|
||||||
// 诊断结果验证
|
|
||||||
if (!prescriptionForm.diagnosisResult.trim()) {
|
|
||||||
return ElMessage.warning("请输入诊断结果");
|
|
||||||
}
|
|
||||||
|
|
||||||
loading.value = true;
|
|
||||||
try {
|
|
||||||
// 处理新增员工/家属的情况
|
|
||||||
let newPersonId: number | undefined = personForm.id;
|
|
||||||
if (!newPersonId) {
|
|
||||||
if (personForm.isEmployee) {
|
|
||||||
// 新增员工
|
|
||||||
if (state.showEmployeeSelect) {
|
|
||||||
newPersonId = personForm.employeeId; // 选择已有员工
|
|
||||||
} else {
|
|
||||||
// 新增员工:调用addPerson接口
|
|
||||||
newPersonId = await prescriptionApi.addPerson({
|
|
||||||
name: personForm.newEmployeeName.trim(),
|
|
||||||
isEmployee: true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 新增家属:先处理关联员工(如有新增)
|
|
||||||
let relatedEmpId = personForm.relatedEmployeeId;
|
|
||||||
if (!state.showRelatedEmployeeSelect) {
|
|
||||||
// 新增关联员工
|
|
||||||
relatedEmpId = await prescriptionApi.addPerson({
|
|
||||||
name: personForm.newRelatedEmployeeName.trim(),
|
|
||||||
isEmployee: true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 新增家属
|
|
||||||
if (state.showRelativeSelect) {
|
|
||||||
newPersonId = personForm.relativeId; // 选择已有家属
|
|
||||||
} else {
|
|
||||||
// 新增家属:调用addPerson接口
|
|
||||||
newPersonId = await prescriptionApi.addPerson({
|
|
||||||
name: personForm.newRelativeName.trim(),
|
|
||||||
isEmployee: false,
|
|
||||||
EmployeeId: relatedEmpId,
|
|
||||||
RelationShip: personForm.relationShip
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 组装药材参数
|
|
||||||
const herbParams = herbList.value.map(h => ({
|
|
||||||
medicinalId: h.medicinalId,
|
|
||||||
amountG: h.amountG,
|
|
||||||
note: h.note?.trim()
|
|
||||||
}));
|
|
||||||
|
|
||||||
// 最终提交参数
|
|
||||||
const submitParams = {
|
|
||||||
id: props.prescriptionId || undefined,
|
|
||||||
PersonId: newPersonId, // 人员ID(新增/编辑后的值)
|
|
||||||
diagnosisResult: prescriptionForm.diagnosisResult.trim(),
|
|
||||||
userMedicinaAdvice: prescriptionForm.userMedicinaAdvice.trim(),
|
|
||||||
visitDate: prescriptionForm.visitDate,
|
|
||||||
herbs: herbParams
|
|
||||||
};
|
|
||||||
|
|
||||||
// 提交保存
|
|
||||||
await prescriptionApi.save(submitParams);
|
|
||||||
ElMessage.success(props.prescriptionId ? "修改成功" : "新增成功");
|
|
||||||
emit("update:visible", false);
|
|
||||||
emit("refreshList");
|
|
||||||
} catch (err: any) {
|
|
||||||
ElMessage.error(err.message || "保存失败");
|
|
||||||
} finally {
|
|
||||||
loading.value = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleCancel = () => {
|
|
||||||
if (props.isEdit) {
|
|
||||||
ElMessageBox.confirm("是否放弃未保存的修改?", "确认取消", { type: "warning" })
|
|
||||||
.then(() => emit("update:visible", false))
|
|
||||||
.catch(); // 无逻辑时可省略函数体
|
|
||||||
} else {
|
|
||||||
emit("update:visible", false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleUpdateVisible = (newVisible: boolean) => {
|
|
||||||
emit("update:visible", newVisible);
|
|
||||||
};
|
|
||||||
|
|
||||||
// 重置表单
|
|
||||||
const resetForm = () => {
|
|
||||||
// 重置处方表单
|
|
||||||
prescriptionForm.diagnosisResult = "";
|
|
||||||
prescriptionForm.userMedicinaAdvice = "";
|
|
||||||
prescriptionForm.visitDate = new Date().toISOString().slice(0, 16);
|
|
||||||
|
|
||||||
// 重置人员表单
|
|
||||||
Object.assign(personForm, {
|
|
||||||
id: undefined,
|
|
||||||
name: "",
|
|
||||||
isEmployee: true,
|
|
||||||
employeeId: undefined,
|
|
||||||
newEmployeeName: "",
|
|
||||||
relatedEmployeeId: undefined,
|
|
||||||
newRelatedEmployeeName: "",
|
|
||||||
relativeId: undefined,
|
|
||||||
newRelativeName: "",
|
|
||||||
relationShip: undefined,
|
|
||||||
age: undefined,
|
|
||||||
weight: undefined,
|
|
||||||
height: undefined
|
|
||||||
});
|
|
||||||
|
|
||||||
// 重置状态
|
|
||||||
Object.assign(state, {
|
|
||||||
showEmployeeSelect: true,
|
|
||||||
employeeOptions: [],
|
|
||||||
employeeKeyword: "",
|
|
||||||
showRelatedEmployeeSelect: true,
|
|
||||||
relatedEmployeeOptions: [],
|
|
||||||
relatedEmployeeKeyword: "",
|
|
||||||
showRelativeSelect: true,
|
|
||||||
relativeOptions: [],
|
|
||||||
relativeKeyword: ""
|
|
||||||
});
|
|
||||||
|
|
||||||
// 重置药材列表
|
|
||||||
herbList.value = [];
|
|
||||||
|
|
||||||
// 重置表单验证
|
|
||||||
nextTick(() => {
|
|
||||||
personFormRef.value?.clearValidate();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.flex {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
.justify-between {
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
.items-center {
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
.gap-4 {
|
|
||||||
gap: 16px;
|
|
||||||
}
|
|
||||||
.flex-1 {
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
.el-form-item {
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,103 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="table-box">
|
|
||||||
<el-card class="mt-4">
|
|
||||||
<ProTable ref="proTable" title="处方列表" :columns="columns" :request-api="getPrescriptionListApi" :row-key="rowKey">
|
|
||||||
<template #tableHeader>
|
|
||||||
<s-button suffix="处方" type="success" @click="handleAddPrescription" />
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #operation="scope">
|
|
||||||
<s-button link :opt="FormOptEnum.VIEW" size="small" @click="handleViewDetail(scope.row.id)"> 查看详情 </s-button>
|
|
||||||
<s-button link :opt="FormOptEnum.EDIT" size="small" class="ml-2" @click="handleEdit(scope.row.id)" v-if="scope.row.canEdit">
|
|
||||||
编辑
|
|
||||||
</s-button>
|
|
||||||
</template>
|
|
||||||
</ProTable>
|
|
||||||
</el-card>
|
|
||||||
|
|
||||||
<!-- 弹窗:查看/编辑处方 -->
|
|
||||||
<prescription-detail-dialog
|
|
||||||
:visible="showDetailDialog"
|
|
||||||
:prescription-id="currentPrescriptionId"
|
|
||||||
:is-edit="isEdit"
|
|
||||||
@update:visible="val => (showDetailDialog = val)"
|
|
||||||
@refresh-list="handleRefresh"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts" name="prescriptionModule">
|
|
||||||
import { ref } from "vue";
|
|
||||||
import ProTable from "@/components/ProTable/index.vue";
|
|
||||||
import type { ProTableInstance, ColumnProps } from "@/components/ProTable/interface";
|
|
||||||
import { prescriptionApi } from "@/api";
|
|
||||||
import PrescriptionDetailDialog from "./components/PrescriptionDetailDialog.vue";
|
|
||||||
import { FormOptEnum } from "@/enums";
|
|
||||||
|
|
||||||
// ProTable ref
|
|
||||||
const proTable = ref<ProTableInstance | null>(null);
|
|
||||||
|
|
||||||
// 弹窗状态
|
|
||||||
const showDetailDialog = ref(false);
|
|
||||||
const currentPrescriptionId = ref<number | null>(null);
|
|
||||||
const isEdit = ref(false);
|
|
||||||
|
|
||||||
// 表格列配置
|
|
||||||
const columns: ColumnProps<any>[] = [
|
|
||||||
{ type: "selection", fixed: "left", width: 80 },
|
|
||||||
{ prop: "personName", label: "就诊人", search: { el: "input" } },
|
|
||||||
{
|
|
||||||
prop: "personType",
|
|
||||||
label: "就诊人类型",
|
|
||||||
formatter: (row: any) => (row.personType === 1 ? "公司员工" : `员工家属(${row.employeeName || "未知"})`)
|
|
||||||
},
|
|
||||||
{ prop: "visitDate", label: "就诊时间" },
|
|
||||||
{ prop: "operation", label: "操作", width: 180, fixed: "right" }
|
|
||||||
];
|
|
||||||
|
|
||||||
// rowKey定义
|
|
||||||
const rowKey = (row: any) => row.id;
|
|
||||||
|
|
||||||
// 请求接口
|
|
||||||
const getPrescriptionListApi = (params: any) => {
|
|
||||||
return prescriptionApi.getList(params);
|
|
||||||
};
|
|
||||||
|
|
||||||
// 新增处方
|
|
||||||
const handleAddPrescription = () => {
|
|
||||||
currentPrescriptionId.value = null;
|
|
||||||
isEdit.value = true;
|
|
||||||
showDetailDialog.value = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
// 查看详情
|
|
||||||
const handleViewDetail = (id: number) => {
|
|
||||||
currentPrescriptionId.value = id;
|
|
||||||
isEdit.value = false;
|
|
||||||
showDetailDialog.value = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
// 编辑
|
|
||||||
const handleEdit = (id: number) => {
|
|
||||||
currentPrescriptionId.value = id;
|
|
||||||
isEdit.value = true;
|
|
||||||
showDetailDialog.value = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
// 刷新表格
|
|
||||||
const handleRefresh = () => {
|
|
||||||
proTable.value?.refresh?.();
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped lang="scss">
|
|
||||||
.table-box {
|
|
||||||
padding-bottom: 24px;
|
|
||||||
}
|
|
||||||
.mt-4 {
|
|
||||||
margin-top: 16px;
|
|
||||||
}
|
|
||||||
.ml-2 {
|
|
||||||
margin-left: 8px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -5,34 +5,23 @@
|
|||||||
!-->
|
!-->
|
||||||
<template>
|
<template>
|
||||||
<div class="main-box">
|
<div class="main-box">
|
||||||
<TreeFilter
|
<TreeFilter ref="treeFilter" label="name" title="组织列表" :request-api="sysOrgApi.tree"
|
||||||
ref="treeFilter"
|
:default-value="initParam.orgId" @change="changeTreeFilter" />
|
||||||
label="name"
|
|
||||||
title="组织列表"
|
|
||||||
:request-api="sysOrgApi.tree"
|
|
||||||
:default-value="initParam.orgId"
|
|
||||||
@change="changeTreeFilter"
|
|
||||||
/>
|
|
||||||
<div class="table-box">
|
<div class="table-box">
|
||||||
<ProTable ref="proTable" :columns="columns" :request-api="sysRoleApi.page" :init-param="initParam">
|
<ProTable ref="proTable" :columns="columns" :request-api="sysRoleApi.page" :init-param="initParam">
|
||||||
<!-- 表格 header 按钮 -->
|
<!-- 表格 header 按钮 -->
|
||||||
<template #tableHeader="scope">
|
<template #tableHeader="scope">
|
||||||
<s-button suffix="角色" @click="onOpen(FormOptEnum.ADD)" />
|
<s-button suffix="角色" @click="onOpen(FormOptEnum.ADD)" />
|
||||||
<s-button
|
<s-button type="danger" plain suffix="角色" :opt="FormOptEnum.DELETE" :disabled="!scope.isSelected"
|
||||||
type="danger"
|
@click="onDelete(scope.selectedListIds, '删除所选角色')" />
|
||||||
plain
|
|
||||||
suffix="角色"
|
|
||||||
:opt="FormOptEnum.DELETE"
|
|
||||||
:disabled="!scope.isSelected"
|
|
||||||
@click="onDelete(scope.selectedListIds, '删除所选角色')"
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
<!-- 状态 -->
|
<!-- 状态 -->
|
||||||
<template #status="scope">
|
<template #status="scope">
|
||||||
<el-tag v-if="scope.row.status === CommonStatusEnum.ENABLE" type="success">{{
|
<el-tag v-if="scope.row.status === CommonStatusEnum.ENABLE" type="success">{{
|
||||||
dictStore.dictTranslation(SysDictEnum.COMMON_STATUS, scope.row.status)
|
dictStore.dictTranslation(SysDictEnum.COMMON_STATUS, scope.row.status)
|
||||||
}}</el-tag>
|
}}</el-tag>
|
||||||
<el-tag v-else type="danger">{{ dictStore.dictTranslation(SysDictEnum.COMMON_STATUS, scope.row.status) }}</el-tag>
|
<el-tag v-else type="danger">{{ dictStore.dictTranslation(SysDictEnum.COMMON_STATUS, scope.row.status)
|
||||||
|
}}</el-tag>
|
||||||
</template>
|
</template>
|
||||||
<!-- 操作 -->
|
<!-- 操作 -->
|
||||||
<template #operation="scope">
|
<template #operation="scope">
|
||||||
@@ -43,7 +32,8 @@
|
|||||||
<el-link type="primary" :underline="false" :icon="ArrowDown"> 授权 </el-link>
|
<el-link type="primary" :underline="false" :icon="ArrowDown"> 授权 </el-link>
|
||||||
<template #dropdown>
|
<template #dropdown>
|
||||||
<el-dropdown-menu>
|
<el-dropdown-menu>
|
||||||
<el-dropdown-item v-for="(item, index) in cmdEnum" :key="index" :command="command(scope.row, item)">{{ item }}</el-dropdown-item>
|
<el-dropdown-item v-for="(item, index) in cmdEnum" :key="index" :command="command(scope.row, item)">{{
|
||||||
|
item }}</el-dropdown-item>
|
||||||
</el-dropdown-menu>
|
</el-dropdown-menu>
|
||||||
</template>
|
</template>
|
||||||
</el-dropdown>
|
</el-dropdown>
|
||||||
@@ -59,15 +49,9 @@
|
|||||||
<!-- 授权权限组件 -->
|
<!-- 授权权限组件 -->
|
||||||
<GrantPermission ref="grantPermissionRef" />
|
<GrantPermission ref="grantPermissionRef" />
|
||||||
<!-- 用户选择器 -->
|
<!-- 用户选择器 -->
|
||||||
<user-selector
|
<user-selector ref="userSelectorRef" :org-tree-api="sysOrgApi.tree" :position-tree-api="sysPositionApi.tree"
|
||||||
ref="userSelectorRef"
|
:role-tree-api="sysRoleApi.tree" :user-selector-api="sysUserApi.selector" multiple
|
||||||
:org-tree-api="sysOrgApi.tree"
|
@successful="handleChooseUser" />
|
||||||
:position-tree-api="sysPositionApi.tree"
|
|
||||||
:role-tree-api="sysRoleApi.tree"
|
|
||||||
:user-selector-api="sysUserApi.selector"
|
|
||||||
multiple
|
|
||||||
@successful="handleChooseUser"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -209,14 +193,14 @@ function handleCommand(command: Command) {
|
|||||||
successful: RefreshTable
|
successful: RefreshTable
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case cmdEnum.GrantMobileResource:
|
// case cmdEnum.GrantMobileResource:
|
||||||
// 打开授权移动端资源组件
|
// // 打开授权移动端资源组件
|
||||||
grantMobileResourceRef.value?.onOpen({
|
// grantMobileResourceRef.value?.onOpen({
|
||||||
opt: FormOptEnum.EDIT,
|
// opt: FormOptEnum.EDIT,
|
||||||
record: command.row,
|
// record: command.row,
|
||||||
successful: RefreshTable
|
// successful: RefreshTable
|
||||||
});
|
// });
|
||||||
break;
|
// break;
|
||||||
case cmdEnum.GrantPermission:
|
case cmdEnum.GrantPermission:
|
||||||
// 打开授权权限组件
|
// 打开授权权限组件
|
||||||
grantPermissionRef.value?.onOpen({
|
grantPermissionRef.value?.onOpen({
|
||||||
|
|||||||
@@ -6,11 +6,17 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<el-tabs v-model="activeName" class="-mt-4">
|
<el-tabs v-model="activeName" class="-mt-4">
|
||||||
<el-tab-pane label="系统配置" name="sysConfig"><SysBaseConfig :sys-configs="sysBase" /></el-tab-pane>
|
<el-tab-pane label="系统配置" name="sysConfig">
|
||||||
<el-tab-pane label="安全配置" name="safety"><SafetyConfig :sys-configs="safetyConfig" /></el-tab-pane>
|
<SysBaseConfig :sys-configs="sysBase" />
|
||||||
<el-tab-pane label="MQTT配置" name="mqtt"><MqttConfig :sys-configs="mqttConfig" /></el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane label="文件配置" name="file">开发中......</el-tab-pane>
|
<el-tab-pane label="安全配置" name="safety">
|
||||||
<el-tab-pane label="其他配置" name="other"><OtherConfig v-if="activeName === 'other'" /></el-tab-pane>
|
<SafetyConfig :sys-configs="safetyConfig" />
|
||||||
|
</el-tab-pane>
|
||||||
|
<!-- <el-tab-pane label="MQTT配置" name="mqtt"><MqttConfig :sys-configs="mqttConfig" /></el-tab-pane>
|
||||||
|
<el-tab-pane label="文件配置" name="file">开发中......</el-tab-pane> -->
|
||||||
|
<el-tab-pane label="其他配置" name="other">
|
||||||
|
<OtherConfig v-if="activeName === 'other'" />
|
||||||
|
</el-tab-pane>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -19,7 +25,7 @@
|
|||||||
import SysBaseConfig from "./components/sysBaseConfig.vue";
|
import SysBaseConfig from "./components/sysBaseConfig.vue";
|
||||||
import SafetyConfig from "./components/safetyConfig/index.vue";
|
import SafetyConfig from "./components/safetyConfig/index.vue";
|
||||||
import OtherConfig from "./components/otherConfig/index.vue";
|
import OtherConfig from "./components/otherConfig/index.vue";
|
||||||
import MqttConfig from "./components/mqttConfig/index.vue";
|
// import MqttConfig from "./components/mqttConfig/index.vue";
|
||||||
import { SysConfig, sysConfigApi } from "@/api";
|
import { SysConfig, sysConfigApi } from "@/api";
|
||||||
import { SysConfigTypeEnum } from "@/enums";
|
import { SysConfigTypeEnum } from "@/enums";
|
||||||
|
|
||||||
|
|||||||
@@ -60,26 +60,26 @@ const data: BindData[] = [
|
|||||||
/*{ title: '密保手机', description: '已绑定手机', value: '138****8293', type: 'phone', bindStatus: 1 },
|
/*{ title: '密保手机', description: '已绑定手机', value: '138****8293', type: 'phone', bindStatus: 1 },
|
||||||
{ title: '密保邮箱', description: '未绑定邮箱', value: '', type: 'email', bindStatus: 0 },
|
{ title: '密保邮箱', description: '未绑定邮箱', value: '', type: 'email', bindStatus: 0 },
|
||||||
{ title: '实名状态', description: '未实名', value: '', type: 'userReal', bindStatus: 0 },*/
|
{ title: '实名状态', description: '未实名', value: '', type: 'userReal', bindStatus: 0 },*/
|
||||||
{ avatar: "ant-design:qq-outlined", title: "绑定QQ", description: "未绑定", value: "", bindType: BindType.QQ, bindStatus: 0, color: "1890FF" },
|
// { avatar: "ant-design:qq-outlined", title: "绑定QQ", description: "未绑定", value: "", bindType: BindType.QQ, bindStatus: 0, color: "1890FF" },
|
||||||
{
|
// {
|
||||||
avatar: "ant-design:wechat-outlined",
|
// avatar: "ant-design:wechat-outlined",
|
||||||
title: "绑定微信",
|
// title: "绑定微信",
|
||||||
description: "未绑定",
|
// description: "未绑定",
|
||||||
value: "",
|
// value: "",
|
||||||
bindType: BindType.WeChat,
|
// bindType: BindType.WeChat,
|
||||||
bindStatus: 0,
|
// bindStatus: 0,
|
||||||
color: "1AAD19"
|
// color: "1AAD19"
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
avatar: "ant-design:alipay-circle-outlined",
|
// avatar: "ant-design:alipay-circle-outlined",
|
||||||
title: "绑定支付宝",
|
// title: "绑定支付宝",
|
||||||
description: "未绑定",
|
// description: "未绑定",
|
||||||
value: "",
|
// value: "",
|
||||||
bindType: BindType.AliPay,
|
// bindType: BindType.AliPay,
|
||||||
bindStatus: 0,
|
// bindStatus: 0,
|
||||||
color: "178bf5"
|
// color: "178bf5"
|
||||||
},
|
// },
|
||||||
{ avatar: "simple-icons:gitee", title: "绑定Gitee", description: "未绑定", value: "", bindType: BindType.Gitee, bindStatus: 0, color: "d84040" }
|
// { avatar: "simple-icons:gitee", title: "绑定Gitee", description: "未绑定", value: "", bindType: BindType.Gitee, bindStatus: 0, color: "d84040" }
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -102,34 +102,55 @@ function bindAction(bindType: BindType) {
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.list-item {
|
.list-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
border-bottom: 1px solid #f0f0f0;
|
border-bottom: 1px solid #f0f0f0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-content {
|
.item-content {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
color: #585252; /* 调整字体颜色为深灰色 */
|
color: #585252;
|
||||||
|
|
||||||
|
/* 调整字体颜色为深灰色 */
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-content h3 {
|
.item-content h3 {
|
||||||
margin: 0 0 10px; /* 添加一些间距 */
|
margin: 0 0 10px;
|
||||||
|
|
||||||
|
/* 添加一些间距 */
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-weight: normal; /* 调整标题字体为正常粗细 */
|
font-weight: normal;
|
||||||
color: #242425; /* 标题字体颜色稍深一点 */
|
|
||||||
|
/* 调整标题字体为正常粗细 */
|
||||||
|
color: #242425;
|
||||||
|
|
||||||
|
/* 标题字体颜色稍深一点 */
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-content p {
|
.item-content p {
|
||||||
margin: 0; /* 移除段落默认的上下外边距 */
|
margin: 0;
|
||||||
|
|
||||||
|
/* 移除段落默认的上下外边距 */
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: #8f8f94; /* 标题字体颜色稍深一点 */
|
color: #8f8f94;
|
||||||
|
|
||||||
|
/* 标题字体颜色稍深一点 */
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-action {
|
.item-action {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-action .el-button {
|
.item-action .el-button {
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
color: #409eff; /* 为按钮文字设置主题颜色 */
|
color: #409eff;
|
||||||
|
|
||||||
|
/* 为按钮文字设置主题颜色 */
|
||||||
}
|
}
|
||||||
|
|
||||||
.bind-icon {
|
.bind-icon {
|
||||||
padding-right: 10px;
|
padding-right: 10px;
|
||||||
padding-left: 10px;
|
padding-left: 10px;
|
||||||
|
|||||||
@@ -13,7 +13,9 @@
|
|||||||
<img :src="userInfo?.avatar" />
|
<img :src="userInfo?.avatar" />
|
||||||
<a style="cursor: pointer" @click="uploadAvatar">
|
<a style="cursor: pointer" @click="uploadAvatar">
|
||||||
<div :class="userInfo?.avatar ? 'mask' : 'mask-notImg'">
|
<div :class="userInfo?.avatar ? 'mask' : 'mask-notImg'">
|
||||||
<el-icon><Upload /></el-icon>
|
<el-icon>
|
||||||
|
<Upload />
|
||||||
|
</el-icon>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
@@ -31,7 +33,8 @@
|
|||||||
<el-divider />
|
<el-divider />
|
||||||
<div class="account-center-team">
|
<div class="account-center-team">
|
||||||
<div v-if="userInfo?.signature" class="mb-2" style="width: 100%">
|
<div v-if="userInfo?.signature" class="mb-2" style="width: 100%">
|
||||||
<el-image :src="userInfo?.signature" style="height: 120px; border: 1px solid rgb(236 236 236)" width="100%" />
|
<el-image :src="userInfo?.signature" style="height: 120px; border: 1px solid rgb(236 236 236)"
|
||||||
|
width="100%" />
|
||||||
</div>
|
</div>
|
||||||
<el-button @click="openSignName">打开签名板</el-button>
|
<el-button @click="openSignName">打开签名板</el-button>
|
||||||
</div>
|
</div>
|
||||||
@@ -41,10 +44,18 @@
|
|||||||
<el-col :lg="17" :md="24">
|
<el-col :lg="17" :md="24">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<el-tabs v-model="activeName" class="-mt-4" @tab-click="tabClick">
|
<el-tabs v-model="activeName" class="-mt-4" @tab-click="tabClick">
|
||||||
<el-tab-pane label="基本信息" :name="centerStore.getAccountBasic"><AccountBasic /></el-tab-pane>
|
<el-tab-pane label="基本信息" :name="centerStore.getAccountBasic">
|
||||||
<el-tab-pane label="账号相关" :name="centerStore.getFile"><AccountBind /></el-tab-pane>
|
<AccountBasic />
|
||||||
<el-tab-pane label="快捷方式" :name="centerStore.getShort"><ShortcutSetting /></el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane label="我的消息" :name="centerStore.getMessage"><MyMessage /></el-tab-pane>
|
<el-tab-pane label="账号相关" :name="centerStore.getFile">
|
||||||
|
<AccountBind />
|
||||||
|
</el-tab-pane>
|
||||||
|
<!-- <el-tab-pane label="快捷方式" :name="centerStore.getShort">
|
||||||
|
<ShortcutSetting />
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane label="我的消息" :name="centerStore.getMessage">
|
||||||
|
<MyMessage />
|
||||||
|
</el-tab-pane> -->
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
</div>
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
@@ -135,6 +146,7 @@ centerStore.$subscribe((mutations, state) => {
|
|||||||
.account-center-avatarHolder {
|
.account-center-avatarHolder {
|
||||||
margin-bottom: 24px;
|
margin-bottom: 24px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
&>.avatar {
|
&>.avatar {
|
||||||
width: 104px;
|
width: 104px;
|
||||||
height: 104px;
|
height: 104px;
|
||||||
@@ -142,11 +154,13 @@ centerStore.$subscribe((mutations, state) => {
|
|||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
|
|
||||||
img {
|
img {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.mask {
|
.mask {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -161,6 +175,7 @@ centerStore.$subscribe((mutations, state) => {
|
|||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mask-notImg {
|
.mask-notImg {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -175,12 +190,15 @@ centerStore.$subscribe((mutations, state) => {
|
|||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.avatar a:hover .mask {
|
.avatar a:hover .mask {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.avatar a:hover .mask-notImg {
|
.avatar a:hover .mask-notImg {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.username {
|
.username {
|
||||||
margin-bottom: 4px;
|
margin-bottom: 4px;
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
@@ -188,12 +206,14 @@ centerStore.$subscribe((mutations, state) => {
|
|||||||
line-height: 28px;
|
line-height: 28px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.account-center-detail {
|
.account-center-detail {
|
||||||
p {
|
p {
|
||||||
position: relative;
|
position: relative;
|
||||||
padding-left: 26px;
|
padding-left: 26px;
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
i {
|
i {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 4px;
|
top: 4px;
|
||||||
@@ -202,16 +222,20 @@ centerStore.$subscribe((mutations, state) => {
|
|||||||
height: 14px;
|
height: 14px;
|
||||||
background: url("/src/assets/icons/userDetail.svg");
|
background: url("/src/assets/icons/userDetail.svg");
|
||||||
}
|
}
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
background-position: 0 0;
|
background-position: 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.group {
|
.group {
|
||||||
background-position: 0 -22px;
|
background-position: 0 -22px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.address {
|
.address {
|
||||||
background-position: 0 -44px;
|
background-position: 0 -44px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.account-center-team {
|
.account-center-team {
|
||||||
.members {
|
.members {
|
||||||
a {
|
a {
|
||||||
@@ -219,6 +243,7 @@ centerStore.$subscribe((mutations, state) => {
|
|||||||
height: 24px;
|
height: 24px;
|
||||||
margin: 12px 0;
|
margin: 12px 0;
|
||||||
line-height: 24px;
|
line-height: 24px;
|
||||||
|
|
||||||
.member {
|
.member {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
max-width: 100px;
|
max-width: 100px;
|
||||||
@@ -231,6 +256,7 @@ centerStore.$subscribe((mutations, state) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.el-tabs__item) {
|
:deep(.el-tabs__item) {
|
||||||
font-size: large;
|
font-size: large;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user