dev
|
|
@ -0,0 +1,30 @@
|
|||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
.DS_Store
|
||||
dist
|
||||
dist-ssr
|
||||
coverage
|
||||
*.local
|
||||
|
||||
/cypress/videos/
|
||||
/cypress/screenshots/
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
*.tsbuildinfo
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
# web
|
||||
|
||||
This template should help get you started developing with Vue 3 in Vite.
|
||||
|
||||
## Recommended IDE Setup
|
||||
|
||||
[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur).
|
||||
|
||||
## Type Support for `.vue` Imports in TS
|
||||
|
||||
TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the TypeScript language service aware of `.vue` types.
|
||||
|
||||
## Customize configuration
|
||||
|
||||
See [Vite Configuration Reference](https://vite.dev/config/).
|
||||
|
||||
## Project Setup
|
||||
|
||||
```sh
|
||||
npm install
|
||||
```
|
||||
|
||||
### Compile and Hot-Reload for Development
|
||||
|
||||
```sh
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### Type-Check, Compile and Minify for Production
|
||||
|
||||
```sh
|
||||
npm run build
|
||||
```
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<link rel="icon" href="/favicon.ico">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Vite App</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"name": "web",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "run-p type-check \"build-only {@}\" --",
|
||||
"preview": "vite preview",
|
||||
"build-only": "vite build",
|
||||
"type-check": "vue-tsc --build"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^1.8.4",
|
||||
"echarts": "^5.6.0",
|
||||
"element-plus": "^2.9.7",
|
||||
"pinia": "^3.0.1",
|
||||
"vue": "^3.5.13",
|
||||
"vue-router": "^4.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tsconfig/node22": "^22.0.1",
|
||||
"@types/node": "^22.14.0",
|
||||
"@vitejs/plugin-vue": "^5.2.3",
|
||||
"@vue/tsconfig": "^0.7.0",
|
||||
"npm-run-all2": "^7.0.2",
|
||||
"sass": "^1.86.3",
|
||||
"typescript": "~5.8.0",
|
||||
"vite": "^6.2.4",
|
||||
"vite-plugin-vue-devtools": "^7.7.2",
|
||||
"vue-tsc": "^2.2.8"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
config.json
|
||||
|
After Width: | Height: | Size: 126 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 4.4 KiB |
|
After Width: | Height: | Size: 3.6 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 834 B |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 987 B |
|
After Width: | Height: | Size: 675 B |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1015 B |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 941 B |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 5.2 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 6.5 KiB |
|
After Width: | Height: | Size: 5.4 KiB |
|
After Width: | Height: | Size: 6.1 KiB |
|
After Width: | Height: | Size: 44 KiB |
|
|
@ -0,0 +1,10 @@
|
|||
<template>
|
||||
<RouterView />
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
</style>
|
||||
|
||||
<script setup lang="ts">
|
||||
</script>
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
{
|
||||
"01": "汉族",
|
||||
"02": "蒙古族",
|
||||
"03": "回族",
|
||||
"04": "藏族",
|
||||
"05": "维吾尔族",
|
||||
"06": "苗族",
|
||||
"07": "彝族",
|
||||
"08": "壮族",
|
||||
"09": "布依族",
|
||||
"10": "朝鲜族",
|
||||
"11": "满族",
|
||||
"12": "侗族",
|
||||
"13": "瑶族",
|
||||
"14": "白族",
|
||||
"15": "土家族",
|
||||
"16": "哈尼族",
|
||||
"17": "哈萨克族",
|
||||
"18": "傣族",
|
||||
"19": "黎族",
|
||||
"20": "傈僳族",
|
||||
"21": "佤族",
|
||||
"22": "畲族",
|
||||
"23": "高山族",
|
||||
"24": "拉祜族",
|
||||
"25": "水族",
|
||||
"26": "东乡族",
|
||||
"27": "纳西族",
|
||||
"28": "景颇族",
|
||||
"29": "柯尔克孜族",
|
||||
"30": "土族",
|
||||
"31": "达斡尔族",
|
||||
"32": "仫佬族",
|
||||
"33": "羌族",
|
||||
"34": "布朗族",
|
||||
"35": "撒拉族",
|
||||
"36": "毛南族",
|
||||
"37": "仡佬族",
|
||||
"38": "锡伯族",
|
||||
"39": "阿昌族",
|
||||
"40": "普米族",
|
||||
"41": "塔吉克族",
|
||||
"42": "怒族",
|
||||
"43": "乌孜别克族",
|
||||
"44": "俄罗斯族",
|
||||
"45": "鄂温克族",
|
||||
"46": "德昂族",
|
||||
"47": "保安族",
|
||||
"48": "裕固族",
|
||||
"49": "京族",
|
||||
"50": "塔塔尔族",
|
||||
"51": "独龙族",
|
||||
"52": "鄂伦春族",
|
||||
"53": "赫哲族",
|
||||
"54": "门巴族",
|
||||
"55": "珞巴族",
|
||||
"56": "基诺族"
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
export const priceBtnList = [
|
||||
{name: '医保', type: 1, img: '/src/assets/images/price/yiBaoKa.png', color: '#39b035'},
|
||||
{name: '微信', type: 2, img: '/src/assets/images/price/weiXin.png', color: '#39b035'},
|
||||
{name: '支付宝', type: 3, img: '/src/assets/images/price/zhiFuBao.png', color: '#409eff'},
|
||||
{name: '现金', type: 4, img: '/src/assets/images/price/xianJin.png', color: '#faf205'},
|
||||
{name: '其他', type: 5, img: '/src/assets/images/price/qiTa.png', color: '#05c5ff'},
|
||||
]
|
||||
export const priceBtnListNoSocial = [
|
||||
{name: '微信', type: 2, img: '/src/assets/images/price/weiXin.png', color: '#39b035'},
|
||||
{name: '支付宝', type: 3, img: '/src/assets/images/price/zhiFuBao.png', color: '#409eff'},
|
||||
{name: '现金', type: 4, img: '/src/assets/images/price/xianJin.png', color: '#faf205'},
|
||||
{name: '其他', type: 5, img: '/src/assets/images/price/qiTa.png', color: '#05c5ff'},
|
||||
]
|
||||
|
||||
export const reconciliationResult =
|
||||
{
|
||||
"0": "平",
|
||||
"1": "不平",
|
||||
"101": "中心多",
|
||||
"102": "医药机构多",
|
||||
"103": "数据不一致"
|
||||
}
|
||||
export const medTypeJson ={
|
||||
"41": "定点药店购药",
|
||||
"11": "普通门诊",
|
||||
"140201": "门诊特病",
|
||||
"140104": "门诊慢病",
|
||||
"1301": "急诊抢救",
|
||||
"9107": "体检",
|
||||
"110104": "门诊统筹",
|
||||
"21": "普通住院",
|
||||
"990301": "统筹区内转院",
|
||||
"990901": "特殊病住院",
|
||||
"71": "家庭病床",
|
||||
"210303": "精神病住院",
|
||||
"28": "日间手术",
|
||||
"15": "门诊特药",
|
||||
"51": "生育门诊",
|
||||
"52": "生育住院",
|
||||
"530102": "计划生育门诊",
|
||||
"530202": "计划生育住院",
|
||||
"990503": "日间病床(日间治疗)",
|
||||
"990101": "门诊单病种(门诊治疗病种)",
|
||||
"12": "门诊挂号",
|
||||
"1102": "新冠门诊",
|
||||
"2110": "新冠住院",
|
||||
"23": "转外诊治住院",
|
||||
"990502": "特殊情况门诊(用于家庭医生签约)",
|
||||
"110105": "门诊统筹手术病种",
|
||||
"990504": "特殊日间病床",
|
||||
"14": "门诊慢特病",
|
||||
"1404": "城乡两病门诊",
|
||||
"510102": "产前检查",
|
||||
"108": "辅助生殖门诊"
|
||||
}
|
||||
export const tempList = [
|
||||
["咳嗽", "干咳", "咳痰", "夜咳", "晨咳", "咽干", "咽痒", "咽痛", "痰中带血", "声音嘶哑", "咽部异物感", "反复感冒", "发热", "喷嚏", "流涕", "鼻塞", "头痛", "头晕", "耳鸣", "汗多", "盗汗", "自汗", "出汗", "易汗出"],
|
||||
["胃胀", "胃痛", "胃不适", "腹胀", "腹痛", "腹泻", "恶心", "呕吐", "反酸", "嗳气", "烧心", "纳差", "便秘", "便溏", "便血", "黑便", "大便干", "大便黏", "五更泻", "腹痛欲便", "里急后重", "排便不爽", "溏结不调"],
|
||||
["胸闷", "胸痛", "心悸", "气短", "气喘", "气促", "眠差", "眠浅", "多梦", "易醒", "早醒", "入睡困难", "嗜睡", "尿频", "尿急", "尿痛", "尿不尽", "尿灼热", "尿分叉", "夜尿多", "尿浊", "尿血", "水肿", "阳痿", "早泄"],
|
||||
["胁痛", "颈椎痛", "关节痛", "关节僵硬", "四肢麻木", "半身麻木", "四肢无力", "偏瘫", "拘挛", "肩痛", "背痛", "腰痛", "眼干", "0千", "口苦", "牙痛", "齿衄", "口疮", "皮疹", "斑疹", "丘疹", "风团", "皮肤红斑", "皮肤瘙痒"],
|
||||
["闭经", "崩漏", "月经量多", "月经量少", "经期错乱", "带下量多", "带下量少", "带下异味", "黄带", "痛经", "月经提前", "月经延后"],
|
||||
["偶尔1天", "2天", "3天", "4天", "5天", "1个月", "2个月", "3个月", "半年", "1年", "1周", "2周", "3周"]
|
||||
]
|
||||
|
||||
|
|
@ -0,0 +1,292 @@
|
|||
{
|
||||
"A01": "预防保健科",
|
||||
"A02": "全科医疗科",
|
||||
"A03": {
|
||||
"name": "内科",
|
||||
"children": {
|
||||
"A03.01": "呼吸内科专业",
|
||||
"A03.02": "消化内科专业",
|
||||
"A03.03": "神经内科专业",
|
||||
"A03.04": "心血管内科专业",
|
||||
"A03.05": "血液内科专业",
|
||||
"A03.06": "肾病学专业",
|
||||
"A03.07": "内分泌专业",
|
||||
"A03.08": "免疫学专业",
|
||||
"A03.09": "变态反应专业",
|
||||
"A03.10": "老年病专业",
|
||||
"A03.11": "其他"
|
||||
}
|
||||
},
|
||||
"A04": {
|
||||
"name": "外科",
|
||||
"children": {
|
||||
"A04.01": "普通外科专业",
|
||||
"A04.01.01": "肝脏移植项目",
|
||||
"A04.01.02": "胰腺移植项目",
|
||||
"A04.01.03": "小肠移植项目",
|
||||
"A04.02": "神经外科专业",
|
||||
"A04.03": "骨科专业",
|
||||
"A04.04": "泌尿外科专业",
|
||||
"A04.04.01": "肾脏移植项目",
|
||||
"A04.05": "胸外科专业",
|
||||
"A04.05.01": "肺脏移植项目",
|
||||
"A04.06": "心脏大血管外科专业",
|
||||
"A04.06.01": "心脏移植项目",
|
||||
"A04.07": "烧伤科专业",
|
||||
"A04.08": "整形外科专业",
|
||||
"A04.09": "其他"
|
||||
}
|
||||
},
|
||||
"A05": {
|
||||
"name": "妇产科",
|
||||
"children": {
|
||||
"A05.01": "妇科专业",
|
||||
"A05.02": "产科专业",
|
||||
"A05.03": "计划生育专业",
|
||||
"A05.04": "优生学专业",
|
||||
"A05.05": "生殖健康与不孕症专业",
|
||||
"A05.06": "其他"
|
||||
}
|
||||
},
|
||||
"A06": {
|
||||
"name": "妇女保健科",
|
||||
"children": {
|
||||
"A06.01": "青春期保健专业",
|
||||
"A06.02": "围产期保健专业",
|
||||
"A06.03": "更年期保健专业",
|
||||
"A06.04": "妇女心理卫生专业",
|
||||
"A06.05": "妇女营养专业",
|
||||
"A06.06": "其他"
|
||||
}
|
||||
},
|
||||
"A07": {
|
||||
"name": "儿科",
|
||||
"children": {
|
||||
"A07.01": "新生儿专业",
|
||||
"A07.02": "小儿传染病专业",
|
||||
"A07.03": "小儿消化专业",
|
||||
"A07.04": "小儿呼吸专业",
|
||||
"A07.05": "小儿心脏病专业",
|
||||
"A07.06": "小儿肾病专业",
|
||||
"A07.07": "小儿血液病专业",
|
||||
"A07.08": "小儿神经病学专业",
|
||||
"A07.09": "小儿内分泌专业",
|
||||
"A07.10": "小儿遗传病专业",
|
||||
"A07.11": "小儿免疫专业",
|
||||
"A07.12": "其他"
|
||||
}
|
||||
},
|
||||
"A08": {
|
||||
"name": "小儿外科",
|
||||
"children": {
|
||||
"A08.01": "小儿普通外科专业",
|
||||
"A08.02": "小儿骨科专业",
|
||||
"A08.03": "小儿泌尿外科专业",
|
||||
"A08.04": "小儿胸心外科专业",
|
||||
"A08.05": "小儿神经外科专业",
|
||||
"A08.06": "其他"
|
||||
}
|
||||
},
|
||||
"A09": {
|
||||
"name": "儿童保健科",
|
||||
"children": {
|
||||
"A09.01": "儿童生长发育专业",
|
||||
"A09.02": "儿童营养专业",
|
||||
"A09.03": "儿童心理卫生专业",
|
||||
"A09.04": "儿童五官保健专业",
|
||||
"A09.05": "儿童康复专业",
|
||||
"A09.06": "其他"
|
||||
}
|
||||
},
|
||||
"A10": "眼科",
|
||||
"A11": {
|
||||
"name": "耳鼻咽喉科",
|
||||
"children": {
|
||||
"A11.01": "耳科专业",
|
||||
"A11.02": "鼻科专业",
|
||||
"A11.03": "咽喉科专业",
|
||||
"A11.04": "其他"
|
||||
}
|
||||
},
|
||||
"A12": {
|
||||
"name": "口腔科",
|
||||
"children": {
|
||||
"A12.01": "牙体牙髓病专业",
|
||||
"A12.02": "牙周病专业",
|
||||
"A12.03": "口腔黏膜病专业",
|
||||
"A12.04": "儿童口腔专业",
|
||||
"A12.05": "口腔颌骨外科专业",
|
||||
"A12.06": "口腔修复专业",
|
||||
"A12.07": "口腔正畸专业",
|
||||
"A12.08": "口腔种植专业",
|
||||
"A12.09": "口腔麻醉专业",
|
||||
"A12.10": "口腔颌面医学影像专业"
|
||||
}
|
||||
},
|
||||
"A13": {
|
||||
"name": "皮肤科",
|
||||
"children": {
|
||||
"A13.01": "皮肤病专业",
|
||||
"A13.02": "性传播疾病专业",
|
||||
"A13.03": "其他"
|
||||
}
|
||||
},
|
||||
"A14": "医疗美容科",
|
||||
"A15": {
|
||||
"name": "精神科",
|
||||
"children": {
|
||||
"A15.01": "精神病专业",
|
||||
"A15.02": "精神卫生专业",
|
||||
"A15.03": "药物依赖专业",
|
||||
"A15.04": "精神康复专业",
|
||||
"A15.05": "社区防治专业",
|
||||
"A15.06": "临床心理专业",
|
||||
"A15.07": "司法精神专业",
|
||||
"A15.08": "其他"
|
||||
}
|
||||
},
|
||||
"A16": {
|
||||
"name": "传染科",
|
||||
"children": {
|
||||
"A16.01": "肠道传染病专业",
|
||||
"A16.02": "呼吸道传染病专业",
|
||||
"A16.03": "肝炎专业",
|
||||
"A16.04": "虫媒传染病专业",
|
||||
"A16.05": "动物源性传染病专业",
|
||||
"A16.06": "蠕虫病专业",
|
||||
"A16.07": "其它"
|
||||
}
|
||||
},
|
||||
"A17": "结核病科",
|
||||
"A18": "地方病科",
|
||||
"A19": "肿瘤科",
|
||||
"A20": "急诊医学科",
|
||||
"A21": "康复医学科",
|
||||
"A22": "运动医学科",
|
||||
"A23": {
|
||||
"name": "职业病科",
|
||||
"children": {
|
||||
"A23.01": "职业中毒专业",
|
||||
"A23.02": "尘肺专业",
|
||||
"A23.03": "放射病专业",
|
||||
"A23.04": "物理因素损伤专业",
|
||||
"A23.05": "职业健康监护专业",
|
||||
"A23.06": "其他"
|
||||
}
|
||||
},
|
||||
"A24": "临终关怀科",
|
||||
"A25": "特种医学与军事医学科",
|
||||
"A26": "麻醉科",
|
||||
"A27": "疼痛科",
|
||||
"A28": "重症医学科",
|
||||
"A30": {
|
||||
"name": "医学检验科",
|
||||
"children": {
|
||||
"A30.01": "临床体液、血液专业",
|
||||
"A30.02": "临床微生物学专业",
|
||||
"A30.03": "临床生化检验专业",
|
||||
"A30.04": "临床免疫、血清学专业",
|
||||
"A30.05": "临床细胞分子遗传学专业",
|
||||
"A30.06": "其他"
|
||||
}
|
||||
},
|
||||
"A31": "病理科",
|
||||
"A32": {
|
||||
"name": "医学影像科",
|
||||
"children": {
|
||||
"A32.01": "X线诊断专业",
|
||||
"A32.02": "CT诊断专业",
|
||||
"A32.03": "磁共振成像诊断专业",
|
||||
"A32.04": "核医学专业",
|
||||
"A32.05": "超声诊断专业",
|
||||
"A32.06": "心电诊断专业",
|
||||
"A32.07": "脑电及脑血流图诊断专业",
|
||||
"A32.08": "神经肌肉电图专业",
|
||||
"A32.09": "介入放射学专业",
|
||||
"A32.10": "放射治疗专业",
|
||||
"A32.11": "其他"
|
||||
}
|
||||
},
|
||||
"A50": {
|
||||
"name": "中医科",
|
||||
"children": {
|
||||
"A50.01": "内科专业",
|
||||
"A50.02": "外科专业",
|
||||
"A50.03": "妇产科专业",
|
||||
"A50.04": "儿科专业",
|
||||
"A50.05": "皮肤科专业",
|
||||
"A50.06": "眼科专业",
|
||||
"A50.07": "耳鼻咽喉科专业",
|
||||
"A50.08": "口腔科专业",
|
||||
"A50.09": "肿瘤科专业",
|
||||
"A50.10": "骨伤科专业",
|
||||
"A50.11": "肛肠科专业",
|
||||
"A50.12": "老年病科专业",
|
||||
"A50.13": "针灸科专业",
|
||||
"A50.14": "推拿科专业",
|
||||
"A50.15": "康复医学专业",
|
||||
"A50.16": "急诊科专业",
|
||||
"A50.17": "预防保健科专业",
|
||||
"A50.18": "其他"
|
||||
}
|
||||
},
|
||||
"A51": {
|
||||
"name": "民族医学科",
|
||||
"children": {
|
||||
"A51.01": "维吾尔医学",
|
||||
"A51.02": "藏医学",
|
||||
"A51.03": "蒙医学",
|
||||
"A51.04": "彝医学",
|
||||
"A51.05": "傣医学",
|
||||
"A51.06": "其他"
|
||||
}
|
||||
},
|
||||
"A52": "中西医结合科",
|
||||
"A69": "其他业务科室",
|
||||
"B01": "传染病预防控制科(中心)",
|
||||
"B02": "性病艾滋病预防控制科(中心)",
|
||||
"B03": "结核病预防控制科(中心)",
|
||||
"B04": "血吸虫预防控制科(中心)",
|
||||
"B05": "慢性非传染性疾病预防控制科(中心)",
|
||||
"B06": "寄生虫病预防控制科(中心)",
|
||||
"B07": "地方病控制科(中心)",
|
||||
"B08": "精神卫生科(中心)",
|
||||
"B09": "妇幼保健科",
|
||||
"B10": "免疫规划科(中心)",
|
||||
"B11": "农村改水技术指导科(中心)",
|
||||
"B12": "疾病控制与应急处理办公室",
|
||||
"B13": "食品卫生科",
|
||||
"B14": "环境卫生所",
|
||||
"B15": "职业卫生科",
|
||||
"B16": "放射卫生科",
|
||||
"B17": "学校卫生科",
|
||||
"B18": "健康教育科(中心)",
|
||||
"B19": "预防医学门诊",
|
||||
"B69": "其他业务科室",
|
||||
"C01": "综合卫生监督科",
|
||||
"C02": "产品卫生监督科",
|
||||
"C03": "职业卫生监督科",
|
||||
"C04": "环境卫生监督科",
|
||||
"C05": "传染病执法监督科",
|
||||
"C06": "医疗服务监督科",
|
||||
"C07": "稽查科(大队)",
|
||||
"C08": "许可受理科",
|
||||
"C09": "放射卫生监督科",
|
||||
"C10": "学校卫生监督科",
|
||||
"C11": "食品安全监督科",
|
||||
"C69": "其他",
|
||||
"D71": "护理部",
|
||||
"D72": "药剂科(药房)",
|
||||
"D73": "感染科",
|
||||
"D74": "输血科(血库)",
|
||||
"D81": "办公室",
|
||||
"D82": "人事科",
|
||||
"D83": "财务科",
|
||||
"D84": "设备科",
|
||||
"D85": "信息科(中心)",
|
||||
"D86": "医政科",
|
||||
"D87": "教育培训科",
|
||||
"D88": "总务科",
|
||||
"D89": "新农合管理办公室",
|
||||
"D99": "其他科室"
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"0": "未知",
|
||||
"1": "男",
|
||||
"2": "女",
|
||||
"9": "未说明"
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"310": "职工基本医疗保险",
|
||||
"31003": "医疗保险个人账户(用人单位)",
|
||||
"312": "农民工住院医疗",
|
||||
"320": "公务员医疗补助",
|
||||
"321": "公务员医疗补助(市直统发)",
|
||||
"323": "公务员医疗补助(市直非统发)",
|
||||
"330": "大额医疗费用补助",
|
||||
"331": "二次补助",
|
||||
"340": "离休人员医疗保障",
|
||||
"350": "一至六级残废军人医疗补助",
|
||||
"360": "老红军医疗保障",
|
||||
"370": "企业补充医疗保险",
|
||||
"380": "新型农村合作医疗",
|
||||
"390": "城乡居民基本医疗保险",
|
||||
"391": "城镇居民基本医疗保险",
|
||||
"392": "城乡居民大病医疗保险",
|
||||
"399": "其他特殊人员医疗保障",
|
||||
"39901": "劳模医疗保障",
|
||||
"39902": "补充百分之10医疗",
|
||||
"39903": "城乡居民补充医疗保险",
|
||||
"39904": "建国前老工人医疗保险",
|
||||
"39905": "二乙医疗保险",
|
||||
"39906": "意外伤害医疗保险",
|
||||
"410": "长期照护保险",
|
||||
"510": "生育保险",
|
||||
"520": "公务员生育"
|
||||
}
|
||||
|
|
@ -0,0 +1,143 @@
|
|||
[
|
||||
{
|
||||
"name": "首页",
|
||||
"icon": "icon-shouye",
|
||||
"path": "/home/index",
|
||||
"children": [
|
||||
{
|
||||
"name": "首页",
|
||||
"path": "/home/index"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "零售",
|
||||
"icon": "icon-renminbi1688",
|
||||
"path": "/retail/retail",
|
||||
"children": [
|
||||
{
|
||||
"name": "零售",
|
||||
"path": "/retail/retail"
|
||||
},
|
||||
{
|
||||
"name": "零售单",
|
||||
"path": "/retail/sales"
|
||||
},
|
||||
{
|
||||
"name": "对账",
|
||||
"path": "/retail/flows"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "库存",
|
||||
"icon": "icon-cangku",
|
||||
"path": "/inventory/goods",
|
||||
"children": [
|
||||
{
|
||||
"name": "商品",
|
||||
"path": "/inventory/goods"
|
||||
},
|
||||
{
|
||||
"name": "采购",
|
||||
"path": "/inventory/purchase"
|
||||
},
|
||||
{
|
||||
"name": "领用",
|
||||
"path": "/inventory/use"
|
||||
},
|
||||
{
|
||||
"name": "供应商",
|
||||
"path": "/inventory/supplier"
|
||||
},
|
||||
{
|
||||
"name": "盘点",
|
||||
"path": "/inventory/check"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "会员",
|
||||
"icon": "icon-huiyuan",
|
||||
"path": "/member/index",
|
||||
"children": [
|
||||
{
|
||||
"name": "首页",
|
||||
"path": "/member/index"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "医保",
|
||||
"icon": "icon-yibao",
|
||||
"path": "/social/directory",
|
||||
"children": [
|
||||
{
|
||||
"name": "医保目录",
|
||||
"path": "/social/directory"
|
||||
},
|
||||
{
|
||||
"name": "数据更新",
|
||||
"path": "/social/update"
|
||||
},
|
||||
{
|
||||
"name": "进销存上报",
|
||||
"path": "/social/inventoryUp"
|
||||
},
|
||||
{
|
||||
"name": "结算",
|
||||
"path": "/social/costRecord"
|
||||
},
|
||||
{
|
||||
"name": "对账",
|
||||
"path": "/social/accountRecords"
|
||||
},
|
||||
{
|
||||
"name": "自费病人",
|
||||
"path": "/social/selfPerson"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "统计",
|
||||
"icon": "icon-tongjifenxi-xiangmubiaogetongji",
|
||||
"path": "/statistics/overview",
|
||||
"children": [
|
||||
{
|
||||
"name": "营收统计",
|
||||
"path": "/statistics/overView"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "设置",
|
||||
"icon": "icon-shezhi",
|
||||
"path": "/settings/baseinfo",
|
||||
"children": [
|
||||
{
|
||||
"name": "基本设置",
|
||||
"path": "/settings/baseinfo"
|
||||
},
|
||||
{
|
||||
"name": "授权设置",
|
||||
"path": "/settings/auth"
|
||||
},
|
||||
{
|
||||
"name": "用户管理",
|
||||
"path": "/settings/userManage"
|
||||
},
|
||||
{
|
||||
"name": "打印管理",
|
||||
"path": "/settings/print"
|
||||
},
|
||||
{
|
||||
"name": "模版管理",
|
||||
"path": "/settings/template"
|
||||
},
|
||||
{
|
||||
"name": "操作日志",
|
||||
"path": "/settings/operationLog"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
{
|
||||
"01": "汉族",
|
||||
"02": "蒙古族",
|
||||
"03": "回族",
|
||||
"04": "藏族",
|
||||
"05": "维吾尔族",
|
||||
"06": "苗族",
|
||||
"07": "彝族",
|
||||
"08": "壮族",
|
||||
"09": "布依族",
|
||||
"10": "朝鲜族",
|
||||
"11": "满族",
|
||||
"12": "侗族",
|
||||
"13": "瑶族",
|
||||
"14": "白族",
|
||||
"15": "土家族",
|
||||
"16": "哈尼族",
|
||||
"17": "哈萨克族",
|
||||
"18": "傣族",
|
||||
"19": "黎族",
|
||||
"20": "傈僳族",
|
||||
"21": "佤族",
|
||||
"22": "畲族",
|
||||
"23": "高山族",
|
||||
"24": "拉祜族",
|
||||
"25": "水族",
|
||||
"26": "东乡族",
|
||||
"27": "纳西族",
|
||||
"28": "景颇族",
|
||||
"29": "柯尔克孜族",
|
||||
"30": "土族",
|
||||
"31": "达斡尔族",
|
||||
"32": "仫佬族",
|
||||
"33": "羌族",
|
||||
"34": "布朗族",
|
||||
"35": "撒拉族",
|
||||
"36": "毛南族",
|
||||
"37": "仡佬族",
|
||||
"38": "锡伯族",
|
||||
"39": "阿昌族",
|
||||
"40": "普米族",
|
||||
"41": "塔吉克族",
|
||||
"42": "怒族",
|
||||
"43": "乌孜别克族",
|
||||
"44": "俄罗斯族",
|
||||
"45": "鄂温克族",
|
||||
"46": "德昂族",
|
||||
"47": "保安族",
|
||||
"48": "裕固族",
|
||||
"49": "京族",
|
||||
"50": "塔塔尔族",
|
||||
"51": "独龙族",
|
||||
"52": "鄂伦春族",
|
||||
"53": "赫哲族",
|
||||
"54": "门巴族",
|
||||
"55": "珞巴族",
|
||||
"56": "基诺族"
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"01": "居民身份证(户口簿)",
|
||||
"02": "中国人民解放军军官证",
|
||||
"03": "中国人民武装警察警官证",
|
||||
"04": "香港特区护照/港澳居民来往内地通行证",
|
||||
"05": "澳门特区护照/港澳居民来往内地通行证",
|
||||
"06": "台湾居民来往大陆通行证",
|
||||
"07": "外国人永久居留证",
|
||||
"08": "外国人护照",
|
||||
"09": "残疾人证",
|
||||
"10": "军烈属证明",
|
||||
"11": "外国人就业证",
|
||||
"12": "外国专家证",
|
||||
"13": "外国人常驻记者证",
|
||||
"14": "台港澳人员就业证",
|
||||
"15": "回国(来华)定居专家证",
|
||||
"16": "中国护照",
|
||||
"17": "港澳台居民居住证",
|
||||
"90": "社会保障卡",
|
||||
"99": "其他身份证件",
|
||||
"990102": "扶贫人口编码",
|
||||
"990201": "医学出生证明"
|
||||
}
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
{
|
||||
"11": "在职",
|
||||
"1101": "职工在职",
|
||||
"1102": "公务员在职",
|
||||
"11021": "转制并轨在职",
|
||||
"1103": "灵活就业人员在职",
|
||||
"11031": "保健对象在职",
|
||||
"1104": "减员职工",
|
||||
"1105": "农民工",
|
||||
"1111": "伤残军人在职",
|
||||
"1112": "伤残军人退休",
|
||||
"1113": "职工在职(农垦)",
|
||||
"1114": "公务员退休(特)",
|
||||
"116003": "失业人员",
|
||||
"116004": "子女",
|
||||
"116006": "企业高管(在职)",
|
||||
"116011": "非财政划拨在职保健对象",
|
||||
"116012": "国务院特殊津贴在职人员",
|
||||
"116013": "在职副厅以上干部",
|
||||
"116014": "在职残疾军人",
|
||||
"116015": "二等乙级在职职工",
|
||||
"116016": "下岗职工",
|
||||
"116017": "在职二级保健对象",
|
||||
"12": "退休人员",
|
||||
"1201": "职工退休",
|
||||
"1202": "公务员退休",
|
||||
"1203": "灵活就业人员退休",
|
||||
"12031": "保健对象退休",
|
||||
"1204": "退职职工",
|
||||
"1205": "转制并轨退休",
|
||||
"126000": "老工人",
|
||||
"126001": "退休新人",
|
||||
"126002": "退休非新人",
|
||||
"126003": "提前退休",
|
||||
"126004": "退休二级保健对象",
|
||||
"126009": "非财政划拨退休保健对象",
|
||||
"126010": "国务院特殊津贴退休人员",
|
||||
"126013": "退休副厅以上干部",
|
||||
"126014": "省直代管512退休干部",
|
||||
"126015": "退休残疾军人",
|
||||
"126016": "二等乙级退休职工",
|
||||
"126017": "退休(满足年限)",
|
||||
"126018": "退休保健对象",
|
||||
"126019": "退休(不满足年限)",
|
||||
"126022": "企业高管(退休)",
|
||||
"13": "离休",
|
||||
"1300": "离休人员",
|
||||
"136001": "行政离休",
|
||||
"136002": "财政供养离休人员",
|
||||
"136003": "缴专项基金的建国前工人",
|
||||
"136004": "地震截瘫(市属离休)",
|
||||
"136005": "离休省属有级别",
|
||||
"136006": "离休省属无级别",
|
||||
"136007": "离休市属有级别",
|
||||
"136008": "离休市属无级别",
|
||||
"136009": "市直离休",
|
||||
"136010": "建国前老工人(市属离休)",
|
||||
"136011": "二等乙(市属离休)",
|
||||
"136012": "企业离休",
|
||||
"136013": "已剥离专项基金的建国前工人",
|
||||
"136014": "普通离休(非地市)",
|
||||
"136015": "省属离休人员",
|
||||
"136016": "市直机关事业单位离休",
|
||||
"136017": "企业自筹离休人员",
|
||||
"136018": "普通离休(地市级)",
|
||||
"136019": "市属离休人员",
|
||||
"136020": "市直企业离休",
|
||||
"136021": "特殊离休",
|
||||
"136022": "垦区离休人员",
|
||||
"136023": "省直代管离休",
|
||||
"136024": "享受副省部级待遇离休",
|
||||
"14": "居民(未成年)",
|
||||
"1401": "新生儿",
|
||||
"1402": "学龄前儿童",
|
||||
"1403": "中小学生",
|
||||
"1404": "大学生",
|
||||
"1405": "未成年(未入学)",
|
||||
"1406": "低保学生儿童",
|
||||
"146001": "市直财政供养人员",
|
||||
"146002": "残疾人员",
|
||||
"146004": "低保人员",
|
||||
"146005": "重度残疾学生",
|
||||
"1461": "积分入学(百佳学子)",
|
||||
"149901": "学生儿童",
|
||||
"15": "居民(成年)",
|
||||
"1501": "普通居民(成年)",
|
||||
"151": "居民",
|
||||
"156001": "普通居民",
|
||||
"16": "居民(老年)",
|
||||
"17": "农牧民少",
|
||||
"18": "农牧民中",
|
||||
"20": "农牧民老",
|
||||
"33": "一至六级残疾军人",
|
||||
"34": "建国前老工人 ",
|
||||
"99": "其他"
|
||||
}
|
||||
|
|
@ -0,0 +1,123 @@
|
|||
// 主题色
|
||||
$primary-color: #409EFF;
|
||||
$success-color: #67C23A;
|
||||
$warning-color: #E6A23C;
|
||||
$danger-color: #F56C6C;
|
||||
$info-color: #909399;
|
||||
|
||||
// 文字颜色
|
||||
$text-primary: #303133;
|
||||
// 次级文字颜色
|
||||
$text-color-secondary: #909399;
|
||||
|
||||
// 边框颜色
|
||||
$border-color-base: #DCDFE6;
|
||||
$border-color-light: #E4E7ED;
|
||||
$border-color-lighter: #EBEEF5;
|
||||
$border-color-extra-light: #F2F6FC;
|
||||
|
||||
// 背景颜色
|
||||
$background-color-base: #eee;
|
||||
$background-color-main: #5078c8;
|
||||
$background-color-panel: #FFFFFF;
|
||||
$background-color-b1:#E2E2E2;
|
||||
|
||||
// 字体大小
|
||||
$font-size-extra-large: 20px;
|
||||
$font-size-large: 18px;
|
||||
$font-size-medium: 16px;
|
||||
$font-size-base: 14px;
|
||||
$font-size-small: 13px;
|
||||
$font-size-extra-small: 12px;
|
||||
|
||||
// 边框圆角
|
||||
$border-radius-base: 4px;
|
||||
$border-radius-small: 2px;
|
||||
$border-radius-large: 8px;
|
||||
$border-radius-circle: 50%;
|
||||
|
||||
// 间距
|
||||
$spacing-base: 8px;
|
||||
$spacing-small: 4px;
|
||||
$spacing-large: 16px;
|
||||
$spacing-extra-large: 24px;
|
||||
|
||||
// 尺寸
|
||||
$padding-base: 18px;
|
||||
$margin-base: 8px;
|
||||
|
||||
// 阴影
|
||||
$box-shadow-base: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04);
|
||||
$box-shadow-light: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
||||
|
||||
// 过渡
|
||||
$transition-duration: 0.3s;
|
||||
$transition-timing-function: ease-in-out;
|
||||
|
||||
// 布局
|
||||
$header-height: 60px;
|
||||
$sidebar-width: 200px;
|
||||
$sidebar-collapse-width: 64px;
|
||||
|
||||
@mixin space{
|
||||
margin: $spacing-base;
|
||||
}
|
||||
// 圆角混合器
|
||||
@mixin border-radius {
|
||||
border-radius: $border-radius-base;
|
||||
}
|
||||
@mixin center-wrapper{
|
||||
max-width: 1920px;
|
||||
min-width: 1280px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
// 内间距混合器
|
||||
@mixin padding {
|
||||
padding: $padding-base;
|
||||
}
|
||||
|
||||
// 外边距混合器
|
||||
@mixin margin{
|
||||
margin: $margin-base;
|
||||
}
|
||||
|
||||
|
||||
// 阴影混合器
|
||||
@mixin box-shadow {
|
||||
box-shadow: $box-shadow-base;
|
||||
}
|
||||
|
||||
// 背景颜色混合器
|
||||
@mixin background-color {
|
||||
background-color: $background-color-base;
|
||||
}
|
||||
@mixin background-color-panel {
|
||||
background-color: $background-color-panel;
|
||||
}
|
||||
|
||||
// 文字颜色混合器
|
||||
@mixin text-color {
|
||||
color: $text-primary;
|
||||
}
|
||||
|
||||
// 边框颜色混合器
|
||||
@mixin border{
|
||||
border:1px solid $border-color-base;
|
||||
}
|
||||
|
||||
// 字体大小混合器
|
||||
@mixin font-size {
|
||||
font-size: $font-size-base;
|
||||
}
|
||||
|
||||
// 间距混合器
|
||||
@mixin spacing{
|
||||
margin: $spacing-base;
|
||||
padding: $spacing-base;
|
||||
}
|
||||
@mixin main-background {
|
||||
background-color: $background-color-main;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
.layout-container{
|
||||
.header{
|
||||
height: 80px;
|
||||
}
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
.layout-main{
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
}
|
||||
.footer{
|
||||
height: 50px;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
@use "base";
|
||||
|
||||
ul, li {
|
||||
list-style: none; /* 移除项目符号(如圆点、数字等) */
|
||||
margin: 0; /* 清除默认外边距 */
|
||||
padding: 0; /* 清除默认内边距 */
|
||||
}
|
||||
|
||||
// 重置样式
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html, body {
|
||||
height: 100%;
|
||||
font-family: PingFangSC, PingFang SC, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||
font-size: base.$font-size-base;
|
||||
color: base.$text-primary;
|
||||
background-color: base.$background-color-base;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
#app {
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
html {
|
||||
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: base.$background-color-base;
|
||||
//font-family: Helvetica Neue, Helvetica, Arial, PingFang SC, MyHeiTi, Hiragino Sans GB, Heiti SC, WenQuanYi Micro Hei, sans-serif !important;
|
||||
font-family: Source Han Sans, serif;
|
||||
}
|
||||
|
||||
.center-wrapper {
|
||||
@include base.center-wrapper;
|
||||
}
|
||||
|
||||
.container-wrapper {
|
||||
height: 100%;
|
||||
//background-color: base.$background-color-panel;
|
||||
@include base.center-wrapper;
|
||||
//@include base.padding;
|
||||
@include base.border-radius;
|
||||
@include base.box-shadow;
|
||||
}
|
||||
|
||||
.space {
|
||||
@include base.space;
|
||||
}
|
||||
|
||||
.container-wrapper_flex {
|
||||
@include base.center-wrapper;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.content-wrapper {
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
width: 100%;
|
||||
@include base.padding;
|
||||
@include base.border-radius;
|
||||
@include base.box-shadow;
|
||||
@include base.background-color-panel;
|
||||
margin-top: 10px;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
// 清除圆角
|
||||
.clear-border-radius {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
// 清除背景色
|
||||
.clear-background-color {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
// 清除内边距
|
||||
.clear-padding {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
// 清除外边距
|
||||
.clear-margin {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
<script setup lang="ts">
|
||||
import {CloseBold} from "@element-plus/icons-vue";
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="close"><el-icon><CloseBold /></el-icon></div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.close{
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 10px;
|
||||
color: #6e6e6e;
|
||||
font-size: 24px;
|
||||
&:hover{
|
||||
color: #409eff;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<script setup lang="ts">
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="divider"></div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.divider{
|
||||
display: block;
|
||||
height: 0;
|
||||
width: 100%;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
<script setup lang="ts">
|
||||
import { ref, watch } from "vue";
|
||||
|
||||
let _width = ref(0);
|
||||
let _height = ref(0);
|
||||
let _isShow = ref(false);
|
||||
const { width, height, isShow } = defineProps(['width', 'height', 'isShow']);
|
||||
|
||||
_isShow.value = isShow == null ? false : isShow;
|
||||
_width.value = width == null ? 1200 : width;
|
||||
_height.value = height == null ? 800 : height;
|
||||
|
||||
watch(() => isShow, (newVal) => {
|
||||
_isShow.value = newVal == null ? false : newVal;
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<transition name="el-fade-in">
|
||||
<div class="mask" v-if="_isShow">
|
||||
<div class="content-wrapper" :style="{ width: _width + 'px', height: _height + 'px' }" v-if="_isShow">
|
||||
<el-scrollbar height="100%">
|
||||
<slot></slot>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.mask {
|
||||
position: fixed;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 20px;
|
||||
z-index: 999;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
.content-wrapper {
|
||||
position: relative;
|
||||
background-color: #FFF;
|
||||
border-radius: 6px;
|
||||
padding: 20px;
|
||||
overflow: hidden;
|
||||
max-height: 90vh;
|
||||
z-index: 1999;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
<script setup lang="ts">
|
||||
import {ref, watchEffect} from 'vue';
|
||||
|
||||
const value1 = ref<any>('');
|
||||
|
||||
watchEffect(() => {
|
||||
value1.value = new Date()
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="my-picker">
|
||||
<el-date-picker :teleported="false" v-model="value1" type="date" placeholder="Pick a day"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
|
||||
.my-picker .el-input {
|
||||
width: 0;
|
||||
height: 0;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.my-picker .el-popper {
|
||||
|
||||
display: block !important;
|
||||
transition: none !important;
|
||||
position: initial !important;
|
||||
}
|
||||
|
||||
.el-picker__popper.el-popper .el-popper__arrow:before {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
|
||||
|
||||
<template>
|
||||
<el-popover placement="bottom-start" trigger="click" :width="props.width" >
|
||||
<template #reference>
|
||||
<el-input v-model="input" :style="{'width': props.width+'px'}" clearable></el-input>
|
||||
</template>
|
||||
<div class="code-popo" v-if="props.list.length > 0">
|
||||
<div class="code-item" v-for="item in props.list" >
|
||||
<div class="code-item-name" v-for="subItem in item" @click="inputStr(subItem)">
|
||||
{{subItem}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-popover>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import {ref} from "vue";
|
||||
const input = defineModel<string | null>();
|
||||
const props = defineProps({
|
||||
list: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
width: {
|
||||
type: Number,
|
||||
default: 1000
|
||||
}
|
||||
})
|
||||
|
||||
const inputStr = (str: string) => {
|
||||
let strList = input.value?input.value.split(","):[];
|
||||
strList.push(str);
|
||||
input.value = strList.join(",");
|
||||
}
|
||||
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
@use "@/assets/scss/base.scss";
|
||||
.code-popo{
|
||||
width: 100%;
|
||||
.code-item{
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
padding: 5px 0;
|
||||
border-bottom: 1px solid base.$border-color-base;
|
||||
.code-item-name{
|
||||
flex: 0 0 calc(100% / 12);
|
||||
font-size: base.$font-size-small;
|
||||
box-sizing: border-box;
|
||||
padding: 5px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
&:hover{
|
||||
color: base.$background-color-main;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
|
||||
<template>
|
||||
<el-popover placement="bottom-start" trigger="click" :width="props.width" ref="popoverRef">
|
||||
<template #reference>
|
||||
<el-input style="width: 100%;"
|
||||
v-model="keyword"
|
||||
:prefix-icon="Plus"
|
||||
:placeholder="props.placeholder"
|
||||
:style="{'width': props.width+'px'}"
|
||||
clearable
|
||||
@input="changeInput"
|
||||
class="no-border-input"
|
||||
>
|
||||
</el-input>
|
||||
</template>
|
||||
<div class="container">
|
||||
<el-table
|
||||
:data="searchList" style="width: 100%"
|
||||
@row-click="clickRow"
|
||||
:show-header="props.showHeader"
|
||||
max-height="200px"
|
||||
>
|
||||
<el-table-column
|
||||
v-for="item in showConfig"
|
||||
:prop="item.prop"
|
||||
:label="item.label"
|
||||
show-overflow-tooltip
|
||||
></el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</el-popover>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">import { ref } from "vue";
|
||||
import { post } from "@/utils/request.ts";
|
||||
import { Plus } from "@element-plus/icons-vue";
|
||||
|
||||
const keyword = ref("");
|
||||
const popoverRef = ref();
|
||||
|
||||
interface showConfig {
|
||||
prop: string;
|
||||
label: string;
|
||||
}
|
||||
|
||||
const props = defineProps({
|
||||
requestApi: {
|
||||
type: String,
|
||||
default: ""
|
||||
},
|
||||
width: {
|
||||
type: Number,
|
||||
default: 1000
|
||||
},
|
||||
showConfig: {
|
||||
type: Array as () => showConfig[],
|
||||
default: () => []
|
||||
},
|
||||
showHeader: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: ""
|
||||
}
|
||||
});
|
||||
|
||||
const searchList = ref([]);
|
||||
|
||||
const changeInput = (inputStr: string) => {
|
||||
if (!props.requestApi || props.requestApi === "") {
|
||||
return;
|
||||
}
|
||||
post(props.requestApi, { keyword: keyword.value }).then((res: any) => {
|
||||
searchList.value = res;
|
||||
});
|
||||
};
|
||||
|
||||
const emit = defineEmits(['selectedCallBack']);
|
||||
|
||||
const clickRow = (row: any) => {
|
||||
emit('selectedCallBack', row);
|
||||
popoverRef.value.hide();
|
||||
};
|
||||
|
||||
const beforeShow = () => {
|
||||
if (searchList.value.length === 0) {
|
||||
popoverRef.value.hide();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.no-border-input {
|
||||
:deep(.el-input__wrapper) {
|
||||
border: none !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
:deep(.el-input__inner) {
|
||||
border: none !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
<template>
|
||||
<el-cascader
|
||||
v-model="selectedArea"
|
||||
:options="areaOptions"
|
||||
:props="cascaderProps"
|
||||
placeholder="请选择省市区"
|
||||
clearable
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {ref} from 'vue'
|
||||
import areaData from '@/assets/config/area.json'
|
||||
|
||||
interface Area {
|
||||
name: string
|
||||
code: string
|
||||
city?: Area[] // 省级包含city字段
|
||||
area?: Area[] // 市级包含area字段
|
||||
}
|
||||
|
||||
// 递归处理多级区域数据
|
||||
const formatAreas = (areas: Area[]):any[] => {
|
||||
return areas.map(area => ({
|
||||
value: area.code,
|
||||
label: area.name,
|
||||
children: getChildren(area) // 动态获取子级字段
|
||||
}))
|
||||
}
|
||||
// 获取子级数据(优先取city字段,其次area字段)
|
||||
const getChildren = (area: Area) => {
|
||||
if (area.city && area.city.length > 0) {
|
||||
return formatAreas(area.city)
|
||||
}
|
||||
if (area.area && area.area.length > 0) {
|
||||
return formatAreas(area.area)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
const areaOptions = formatAreas(areaData)
|
||||
|
||||
const selectedArea = ref<string[]>([])
|
||||
|
||||
const cascaderProps = {
|
||||
value: 'value',
|
||||
label: 'label',
|
||||
children: 'children',
|
||||
checkStrictly: true,
|
||||
emitPath: true // 确保返回完整路径
|
||||
}
|
||||
|
||||
interface CascaderOption {
|
||||
value: string
|
||||
label: string
|
||||
children?: CascaderOption[]
|
||||
}
|
||||
|
||||
</script>
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
<template>
|
||||
<el-upload
|
||||
class="avatar-uploader"
|
||||
:action="url"
|
||||
:show-file-list="false"
|
||||
:on-success="handleSuccess"
|
||||
:before-upload="beforeUpload"
|
||||
:on-error="handleError"
|
||||
>
|
||||
<img v-if="imageUrl" :src="imageUrl" class="avatar" alt=""/>
|
||||
<el-icon v-else><Plus /></el-icon>
|
||||
</el-upload>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {ElMessage} from 'element-plus'
|
||||
import {Plus} from '@element-plus/icons-vue'
|
||||
import {defineModel,ref} from 'vue'
|
||||
import {loadConfig} from "@/utils/config.ts";
|
||||
const url = defineModel()
|
||||
const imageUrl = ref<any>()
|
||||
const getImageUrl = (url: any) => {
|
||||
loadConfig().then(res=>{
|
||||
imageUrl.value = res.base_url +'file/getImage/'+ url
|
||||
})
|
||||
}
|
||||
const emit = defineEmits(['uploadSuccess'])
|
||||
const handleSuccess = (response:any) => {
|
||||
ElMessage.success('文件上传成功!'); // 添加成功提示
|
||||
getImageUrl(response.data)
|
||||
emit('uploadSuccess',response.data)
|
||||
}
|
||||
const handleError = () => {
|
||||
ElMessage.error('文件上传失败');
|
||||
}
|
||||
|
||||
const beforeUpload = (file:any) => {
|
||||
const isLt2M = file.size / 1024 / 1024 < 2;
|
||||
if (!isLt2M) {
|
||||
ElMessage.error('上传文件大小不能超过 2MB!');
|
||||
}
|
||||
return isLt2M;
|
||||
}
|
||||
defineExpose({getImageUrl})
|
||||
</script>
|
||||
<style scoped>
|
||||
.avatar-uploader .el-upload {
|
||||
border: 1px dashed #d9d9d9;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.avatar-uploader .el-upload:hover {
|
||||
border-color: #409EFF;
|
||||
}
|
||||
.avatar-uploader-icon {
|
||||
font-size: 28px;
|
||||
color: #8c939d;
|
||||
width: 178px;
|
||||
}
|
||||
.avatar {
|
||||
width: 178px;
|
||||
height: 178px;
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,197 @@
|
|||
<script setup lang="ts">
|
||||
|
||||
import {getKey} from "@/utils/discrotyUtil.ts";
|
||||
import insutypes from "@/assets/config/insutypes.json";
|
||||
import {onMounted, onUnmounted, ref} from "vue";
|
||||
import {ElMessage} from "element-plus";
|
||||
import {post} from "@/utils/request.ts";
|
||||
import type {Request, Response} from "@/utils/ws.ts";
|
||||
import {useWsStore} from "@/stores/wsStore.ts";
|
||||
|
||||
const wsStore = useWsStore();
|
||||
const isReading = ref(false)
|
||||
const socialCard:any = defineModel();
|
||||
const ReadSocialCard = async (readType: string) => {
|
||||
socialCard.value.lastUse="cardPay"
|
||||
isReading.value = true;
|
||||
let config_db: any = await post('common/config/getall');
|
||||
let config: any = {}
|
||||
config.ACCESS_KEY = config_db.social_ACCESS_KEY;
|
||||
config.SECRETKEY = config_db.social_SECRETKEY;
|
||||
config.IP = config_db.social_IP;
|
||||
config.PORT = config_db.social_PORT;
|
||||
config.ORGID = config_db.social_fixmedinsCode;
|
||||
config.EC_URL = config_db.social_EC_URL;
|
||||
let data: any = {}
|
||||
data.officeId = "1"
|
||||
data.officeName = "内科";
|
||||
data.operatorId = "1";
|
||||
data.operatorName = "陈庭荣";
|
||||
data.readType = readType;
|
||||
let request: Request = {
|
||||
type: "ReadCard",
|
||||
config: config,
|
||||
data: data
|
||||
}
|
||||
wsStore.sendMessage(request);
|
||||
};
|
||||
const reciceMessage = (response: Response) => {
|
||||
if(socialCard.value.lastUse!="cardPay"){
|
||||
return;
|
||||
}
|
||||
if (response.Code == 301) {
|
||||
let msg = response.Message;
|
||||
ElMessage({
|
||||
message: msg,
|
||||
type: 'warning',
|
||||
});
|
||||
isReading.value = false;
|
||||
return;
|
||||
}
|
||||
let readType = response.Data.readType;
|
||||
if (!readType) {
|
||||
return
|
||||
}
|
||||
|
||||
const params = {
|
||||
mdtrtCertType: readType,
|
||||
mdtrtCertNo: response.Data.mdtrt_cert_no,
|
||||
certno: response.Data.certno,
|
||||
psnName: response.Data.psn_name,
|
||||
psnCertType: "01",
|
||||
cardSn: response.Data.card_sn ? response.Data.card_sn : "",
|
||||
}
|
||||
getInfoFor1101(params)
|
||||
}
|
||||
const getInfoFor1101 = (params: any) => {
|
||||
post("social/person/getCustomSocialInfo", {data: params}).then((res: any) => {
|
||||
socialCard.value.data = res;
|
||||
socialCard.value.mdtrtCertType = params.mdtrtCertType;
|
||||
socialCard.value.mdtrtCertNo = params.mdtrtCertNo;
|
||||
socialCard.value.payInfo.selfpay_prop_type = res.insuinfo[0].insutype;
|
||||
}).finally(() => {
|
||||
isReading.value = false;
|
||||
})
|
||||
}
|
||||
onMounted(async () => {
|
||||
wsStore.setMessageCallback(reciceMessage)
|
||||
});
|
||||
onUnmounted(()=>{
|
||||
wsStore.removeAllMessageCallback()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="card-pay">
|
||||
<div class="left">医保<br/>信息</div>
|
||||
<div class="right">
|
||||
<div class="insuinfo" v-if="socialCard.data">
|
||||
<div class="line">
|
||||
<div class="label">姓名</div>
|
||||
<div class="info">{{ socialCard.data.baseinfo.psn_name }}</div>
|
||||
<div class="btn" @click="socialCard.data=null">退出</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="label">险种</div>
|
||||
<div class="info">
|
||||
<el-select v-model="socialCard.payInfo.selfpay_prop_type" placeholder="请选择" style="width: 100%">
|
||||
<el-option
|
||||
v-for="(item,index) in socialCard.data.insuinfo"
|
||||
:key="item.insutype"
|
||||
:label="'账户余额'+getKey(insutypes, item.insutype)+'('+item.balc.toFixed(2)+')'"
|
||||
:value="item.insutype"
|
||||
>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="card-empty" v-else>
|
||||
<div class="tip" v-loading="isReading">暂无医保信息</div>
|
||||
<div class="btn-wrapper"> <div class="btn" @click="ReadSocialCard('03')" tabindex="-1">医保卡</div>
|
||||
<div class="btn" @click="ReadSocialCard('01')" tabindex="-1">电子码</div>
|
||||
<div class="btn" @click="ReadSocialCard('02')" tabindex="-1">身份证</div>
|
||||
<div class="btn" @click="ReadSocialCard('04')" tabindex="-1">人脸识别</div></div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.card-pay {
|
||||
position: relative;
|
||||
display: flex;
|
||||
|
||||
.left {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background: #DDD;
|
||||
text-align: center;
|
||||
line-height: 30px;
|
||||
font-size: 24px;
|
||||
color: #666;
|
||||
padding: 20px;
|
||||
box-sizing: border-box;
|
||||
border-radius: 10px 0 0 10px;
|
||||
}
|
||||
|
||||
.right {
|
||||
position: relative;
|
||||
flex: 1;
|
||||
background: #EEE;
|
||||
box-sizing: border-box;
|
||||
padding: 10px;
|
||||
border-radius: 0 10px 10px 0;
|
||||
.line{
|
||||
position: relative;
|
||||
display: flex;
|
||||
height: 40px;
|
||||
box-sizing: border-box;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
line-height: 40px;
|
||||
.label{
|
||||
position: relative;
|
||||
width: 40px;
|
||||
}
|
||||
.info{
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
.card-empty{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
.tip{
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
text-align: center;
|
||||
line-height: 40px;
|
||||
}
|
||||
.btn-wrapper{
|
||||
position: relative;
|
||||
height: 30px;
|
||||
display: flex;
|
||||
.btn{
|
||||
flex: 1;
|
||||
margin-left: 5px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.btn{
|
||||
text-align: center;
|
||||
line-height: 30px;
|
||||
outline: none;
|
||||
color: #409EFF;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,185 @@
|
|||
<template>
|
||||
<div class="container">
|
||||
<div class="search">
|
||||
<el-input v-model="query.keyword" placeholder="根据姓名搜索"/>
|
||||
<el-button type="success" @click="addChargeOrder" size="small">+收费</el-button>
|
||||
</div>
|
||||
<div class="list">
|
||||
<el-scrollbar>
|
||||
<ul>
|
||||
<li class="list-item" :class="curItem.id == item.id ? 'active' : ''" v-for="(item, index) in orderList"
|
||||
:key="index" @click="clickItem(item)">
|
||||
<span>
|
||||
<img v-if="item.patinetGender=='男'" class="avatar" src="/static/images/outpatient/man.png"
|
||||
alt="头像"/>
|
||||
<img v-if="item.patinetGender=='女'" class="avatar" src="/static/images/outpatient/women.png"
|
||||
alt="头像"/>
|
||||
</span>
|
||||
<span class="item_name">{{ item.patientName }}</span>
|
||||
<el-tooltip
|
||||
class="box-item"
|
||||
effect="dark"
|
||||
:content="formatTime(item.createDatetime)||'-'"
|
||||
placement="bottom-start"
|
||||
>
|
||||
<span class="item_time">
|
||||
{{ formatTime(item.createDatetime) || '-' }}
|
||||
</span>
|
||||
</el-tooltip>
|
||||
<span>01-01</span>
|
||||
</li>
|
||||
</ul>
|
||||
</el-scrollbar>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import {onMounted, ref} from "vue";
|
||||
import {post} from "@/utils/request.ts";
|
||||
import Panel from "@/components/common/Panel.vue";
|
||||
import {formatTime} from "@/utils/dateUtils.ts";
|
||||
const curItem = ref<any>({});
|
||||
const emit = defineEmits(['clickItem'])
|
||||
const clickItem = (item: any) => {
|
||||
curItem.value = item
|
||||
emit('clickItem', item);
|
||||
}
|
||||
|
||||
const orderList = ref<any>([]);
|
||||
const query = ref({
|
||||
pageSize: 20,
|
||||
pageNum: 1,
|
||||
keyword: ""
|
||||
})
|
||||
const addChargeOrder = () => {
|
||||
const newOrder = {
|
||||
id:-1,
|
||||
patientName :"匿名患者",
|
||||
payType : -1,
|
||||
}
|
||||
if (orderList.value[0]?.id == -1){
|
||||
return
|
||||
}
|
||||
orderList.value.unshift(newOrder)
|
||||
clickFirst()
|
||||
}
|
||||
const clickFirst = () => {
|
||||
clickItem(orderList.value[0])
|
||||
}
|
||||
const getOrderList = () => {
|
||||
post("charge/list", {query: query.value}).then(
|
||||
(res: any) => {
|
||||
orderList.value = res.list
|
||||
clickFirst()
|
||||
}
|
||||
)
|
||||
}
|
||||
const delDraft = () =>{
|
||||
orderList.value.shift();
|
||||
clickFirst()
|
||||
}
|
||||
defineExpose({delDraft})
|
||||
onMounted(()=>{
|
||||
getOrderList()
|
||||
})
|
||||
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.container{
|
||||
display: flex;
|
||||
flex-direction: column; // 确保子元素垂直排列
|
||||
width: 100%;
|
||||
.search{
|
||||
height: 25px;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.list {
|
||||
display: flex;
|
||||
min-height: 0;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
|
||||
.list-title {
|
||||
height: 48px;
|
||||
background: #F5FAFF;
|
||||
padding: 0 27px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
color: rgba(34, 42, 57, 0.8);
|
||||
font-style: normal;
|
||||
|
||||
span {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
ul {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
|
||||
.list-item {
|
||||
height: 48px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 18px;
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
color: rgba(34, 42, 57, 0.7);
|
||||
font-style: normal;
|
||||
cursor: pointer;
|
||||
|
||||
span {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.avatar {
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: rgba(#4D6DE4, 0.1);
|
||||
}
|
||||
|
||||
.item_name {
|
||||
flex: 1.5;
|
||||
white-space: nowrap; // 防止文本换行
|
||||
overflow: hidden; // 隐藏溢出的文本
|
||||
text-overflow: ellipsis; // 显示省略号
|
||||
}
|
||||
|
||||
.item_time {
|
||||
flex: 2;
|
||||
white-space: nowrap; // 防止文本换行
|
||||
overflow: hidden; // 隐藏溢出的文本
|
||||
text-overflow: ellipsis; // 显示省略号
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.active {
|
||||
color: #fff;
|
||||
background: #4D6DE4;
|
||||
|
||||
&:hover {
|
||||
background: #4D6DE4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
<template>
|
||||
<el-table :data="list" max-height="150">
|
||||
<el-table-column prop="name" label="名称"></el-table-column>
|
||||
<el-table-column prop="selectedPrice" label="单价"></el-table-column>
|
||||
<el-table-column prop="number" label="数量">
|
||||
<template #default="scope">
|
||||
<el-input-number v-model="scope.row.selectedNum" min="0" @change="handleNumChange"></el-input-number>
|
||||
<el-dropdown>
|
||||
<span style="line-height: 30px;margin-left: 10px">{{ scope.row.selectedUnit }}</span>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu v-if="scope.row.trdnFlag == 1">
|
||||
<el-dropdown-item @click="selectUnit(scope.row,scope.row.packagingUnit)">{{ scope.row.packagingUnit }}
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item @click="selectUnit(scope.row,scope.row.minPackagingUnit)">{{ scope.row.minPackagingUnit }}
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作">
|
||||
<template #default="scope">
|
||||
<el-button type="danger" link @click="delGoods(scope.row)">X</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<SearchInput :request-api="goodsSearchApi" :show-config="goodsShowConfig" @selectedCallBack="goodsSelect"></SearchInput>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import SearchInput from "@/components/SearchInput.vue";
|
||||
|
||||
const list = defineModel<any>();
|
||||
const delGoods = (item: any) => {
|
||||
list.value = list.value.filter((i: any) => i.id != item.id)
|
||||
}
|
||||
|
||||
const goodsSearchApi = "goods/goods/search";
|
||||
const goodsShowConfig = [
|
||||
{
|
||||
label: "项目名称",
|
||||
prop: "name",
|
||||
},
|
||||
{
|
||||
label: "项目类型",
|
||||
prop: "type",
|
||||
},
|
||||
{
|
||||
label: "售价",
|
||||
prop: "unitPrice",
|
||||
},
|
||||
]
|
||||
const goodsSelect = (row: any) => {
|
||||
|
||||
row.selectedNum = 1
|
||||
row.selectedUnit = row.packagingUnit
|
||||
row.selectedPrice = row.unitPrice
|
||||
list.value.push(row)
|
||||
emit('totalPriceChange')
|
||||
}
|
||||
const selectUnit = (item: any, unit: any) => {
|
||||
item.selectedUnit = unit;
|
||||
if (unit == item.packagingUnit) {
|
||||
item.selectedPrice = item.unitPrice
|
||||
}else if (unit == item.minPackagingUnit) {
|
||||
item.selectedPrice = item.disassemblyPrice
|
||||
}
|
||||
emit('totalPriceChange')
|
||||
|
||||
}
|
||||
const emit = defineEmits(["totalPriceChange"])
|
||||
const handleNumChange = ()=>{
|
||||
emit('totalPriceChange')
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
|
||||
</style>
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
<template>
|
||||
<el-table :data="list" max-height="150">
|
||||
<el-table-column prop="name" label="名称"></el-table-column>
|
||||
<el-table-column prop="unit" label="单位"></el-table-column>
|
||||
<el-table-column prop="unitPrice" label="单价"></el-table-column>
|
||||
<el-table-column prop="number" label="数量"></el-table-column>
|
||||
<el-table-column label="操作">
|
||||
<template #default="scope">
|
||||
<el-button type="danger" link @click="delService(scope.row)">X</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<SearchInput :request-api="serviceSearchApi" :show-config="serviceShowConfig" @selectedCallBack="serviceSelect"></SearchInput>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import SearchInput from "@/components/SearchInput.vue";
|
||||
|
||||
const list =defineModel<any>();
|
||||
const delService = (item: any) => {
|
||||
list.value = list.value.filter((i: any) => i.id != item.id)
|
||||
}
|
||||
|
||||
const serviceSearchApi = "item/search";
|
||||
const serviceShowConfig = [
|
||||
{
|
||||
label: "服务名称",
|
||||
prop: "itemName",
|
||||
},
|
||||
{
|
||||
label: "服务医保码",
|
||||
prop: "itemSocialCode",
|
||||
},
|
||||
{
|
||||
label: "售价",
|
||||
prop: "unitPrice",
|
||||
},
|
||||
]
|
||||
const emit = defineEmits(['selectedCallBack'])
|
||||
const serviceSelect = (row: any) => {
|
||||
row.name = row.itemName
|
||||
row.number = 1
|
||||
list.value.push(row)
|
||||
emit('selectedCallBack',row)
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
|
||||
</style>
|
||||
|
|
@ -0,0 +1,195 @@
|
|||
<template>
|
||||
<Mask :width="300" :height="438" :is-show="show">
|
||||
<el-card>
|
||||
<template #header>
|
||||
<div class="header">
|
||||
<span>收费</span>
|
||||
<CloseBtn @click="show = false" style="margin-top: 12px"></CloseBtn>
|
||||
</div>
|
||||
</template>
|
||||
<div class="panel">
|
||||
<div class="price">¥{{ prop.money }}</div>
|
||||
<div class="social" >
|
||||
<CardPay v-model="socialCard"/>
|
||||
</div>
|
||||
<div class="price-type">
|
||||
<div
|
||||
class="price-type-item"
|
||||
:class="['btn',payType==item.type?'active':'']"
|
||||
v-for="(item,index) in priceBtnList"
|
||||
@click="changePriceType(item.type)"
|
||||
>
|
||||
<div class="image" :style="{'background-color':item.color}">
|
||||
<img style="width: 16px;height: 16px;" :src="item.img" alt=""/>
|
||||
</div>
|
||||
<span>{{item.name}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="footer">
|
||||
<el-checkbox v-model="printReceipt">同时打印凭证</el-checkbox>
|
||||
<el-button @click="completeSettlement()" type="primary">完成收费</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-card>
|
||||
</Mask>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
||||
import {nextTick, onMounted, onUnmounted, ref} from "vue";
|
||||
import CloseBtn from "@/components/CloseBtn.vue";
|
||||
import {post} from "@/utils/request.ts";
|
||||
import Mask from "@/components/Mask.vue";
|
||||
import CardPay from "@/components/charge/CardPay.vue";
|
||||
import {medTypeJson, priceBtnList} from "@/assets/config/constants.ts"
|
||||
import {useWsStore} from "@/stores/wsStore.ts";
|
||||
const wsStore = useWsStore();
|
||||
const socialCard =defineModel<any>();
|
||||
const prop=defineProps({
|
||||
money: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
})
|
||||
|
||||
const show = ref(false)
|
||||
const printReceipt = ref(false);
|
||||
const payType = ref(null);
|
||||
const retailOrder = ref<any>(null);
|
||||
const init = (order: any) => {
|
||||
retailOrder.value = order;
|
||||
console.log(order)
|
||||
show.value = true;
|
||||
}
|
||||
defineExpose({init})
|
||||
const changePriceType = (type: any) => {
|
||||
payType.value = type;
|
||||
}
|
||||
const emit = defineEmits(['orderComplete','orderCanceled'])
|
||||
const completeSettlement = ()=>{
|
||||
if (!retailOrder.value){
|
||||
return;
|
||||
}
|
||||
if (payType.value == null){
|
||||
return
|
||||
}
|
||||
if(payType.value == 1){
|
||||
//医保结算
|
||||
console.log('医保结算',socialCard.value)
|
||||
socialSettlement();
|
||||
}else {
|
||||
debugger
|
||||
//其他结算
|
||||
post('charge/completeOrder',{id:retailOrder.value.id,payType:payType.value}).then((res:any)=>{
|
||||
orderCompleted()
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
const orderCompleted = ()=>{
|
||||
show.value = false;
|
||||
emit('orderComplete',printReceipt.value)
|
||||
}
|
||||
const orderCanceled = ()=>{
|
||||
show.value = false;
|
||||
emit('orderCanceled')
|
||||
}
|
||||
|
||||
const getBalcByInsutype = (type:any) =>{
|
||||
let balc =0;
|
||||
for (const item of socialCard.value.data.insuinfo) {
|
||||
if (item.insutype == type) {
|
||||
balc = item.balc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return balc
|
||||
}
|
||||
|
||||
const socialSettlement = ()=>{
|
||||
const params = {
|
||||
mdtrtCertType: socialCard.value.mdtrtCertType,
|
||||
mdtrtCertNo: socialCard.value.mdtrtCertNo,
|
||||
psnNo: socialCard.value.data.baseinfo.psn_no,
|
||||
orderId:retailOrder.value.id,
|
||||
insutype: socialCard.value.payInfo.selfpay_prop_type,
|
||||
payType: payType.value,
|
||||
curBalc:getBalcByInsutype(socialCard.value.payInfo.selfpay_prop_type)
|
||||
}
|
||||
//预结算
|
||||
post("retail/socialPrePay",{orderInfo:params}).then((res:any)=>{
|
||||
openPsnPayment(res,params)
|
||||
})
|
||||
|
||||
}
|
||||
const psnPaymentRef = ref();
|
||||
const openPsnPayment = (payInfo:any,orderInfo:any)=>{
|
||||
nextTick(()=>{
|
||||
psnPaymentRef.value.open(payInfo,orderInfo);
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
<style scoped lang="scss">
|
||||
.panel {
|
||||
.price{
|
||||
height: 50px;
|
||||
text-align: center;
|
||||
font-size: 25px;
|
||||
font-weight: 600;
|
||||
color: rgba(237, 120, 23, 0.8);
|
||||
}
|
||||
.price-type {
|
||||
display: flex;
|
||||
margin-top: 20px;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
.btn {
|
||||
height: 45px;
|
||||
width: 95px;
|
||||
font-size: 14px;
|
||||
border-radius: 10px;
|
||||
display: flex;
|
||||
background: #efecec;
|
||||
margin-bottom: 10px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 10px;
|
||||
cursor: pointer;
|
||||
.image{
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-right: 3px;
|
||||
border-radius: 23px;
|
||||
background-color: #ffffff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
//color: #fff;
|
||||
//background-color: #409EFF;
|
||||
border: 1px solid #409EFF;
|
||||
}
|
||||
}
|
||||
|
||||
.active {
|
||||
color: #fff;
|
||||
background-color: #409EFF;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
.footer{
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
<template>
|
||||
<footer>
|
||||
@版权所有:沈阳嘉尔网络科技有限公司
|
||||
</footer>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@use "@/assets/scss/base";
|
||||
footer{
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
background-color: base.$background-color-main;
|
||||
line-height: 40px;
|
||||
color: #FFF;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
<script setup lang="ts">
|
||||
|
||||
</script>
|
||||
|
|
@ -0,0 +1,145 @@
|
|||
<template>
|
||||
<header>
|
||||
<div class="center-wrapper">
|
||||
<div class="menu">
|
||||
<router-link to="/home" class="menu-item" active-class="active active1">首页</router-link>
|
||||
<router-link to="/registration" class="menu-item" active-class="active active2">挂号</router-link>
|
||||
<router-link to="/outpatient" class="menu-item" active-class="active active3">接诊</router-link>
|
||||
<router-link to="/charge" class="menu-item" active-class="active active4">收费</router-link>
|
||||
<router-link to="/inventory" class="menu-item" active-class="active active5">库存</router-link>
|
||||
<router-link to="/member" class="menu-item" active-class="active active6">会员</router-link>
|
||||
<router-link to="/social" class="menu-item" active-class="active active7">医保</router-link>
|
||||
<router-link to="/statistics" class="menu-item" active-class="active active8">统计</router-link>
|
||||
<router-link to="/settings" class="menu-item" active-class="active active9">设置</router-link>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@use "@/assets/scss/base";
|
||||
|
||||
.menu {
|
||||
position: relative;
|
||||
text-align: center;
|
||||
line-height: 50px;
|
||||
|
||||
.menu-item {
|
||||
display: inline-block;
|
||||
color: #FFF;
|
||||
outline: none;
|
||||
text-decoration: none;
|
||||
font-size: 18px;
|
||||
width: 140px;
|
||||
height: 50px;
|
||||
position: relative;
|
||||
|
||||
span {
|
||||
display: inline-block;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
display: inline-block;
|
||||
width: 26px;
|
||||
height: 50px;
|
||||
vertical-align: middle;
|
||||
border-radius: 12px;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 100%;
|
||||
background-position:0 10px;
|
||||
}
|
||||
|
||||
&:nth-child(1)::before {
|
||||
background-image: url('/static/images/menu_icon/1.png'); // 替换为实际的图片路径
|
||||
}
|
||||
|
||||
&:nth-child(2)::before {
|
||||
background-image: url('/static/images/menu_icon/2.png'); // 替换为实际的图片路径
|
||||
}
|
||||
|
||||
&:nth-child(3)::before {
|
||||
background-image: url('/static/images/menu_icon/3.png'); // 替换为实际的图片路径
|
||||
}
|
||||
|
||||
&:nth-child(4)::before {
|
||||
background-image: url('/static/images/menu_icon/4.png'); // 替换为实际的图片路径
|
||||
}
|
||||
|
||||
&:nth-child(5)::before {
|
||||
background-image: url('/static/images/menu_icon/5.png'); // 替换为实际的图片路径
|
||||
}
|
||||
|
||||
&:nth-child(6)::before {
|
||||
background-image: url('/static/images/menu_icon/6.png'); // 替换为实际的图片路径
|
||||
}
|
||||
|
||||
&:nth-child(7)::before {
|
||||
background-image: url('/static/images/menu_icon/7.png'); // 替换为实际的图片路径
|
||||
}
|
||||
|
||||
&:nth-child(8)::before {
|
||||
background-image: url('/static/images/menu_icon/8.png'); // 替换为实际的图片路径
|
||||
}
|
||||
|
||||
&:nth-child(9)::before {
|
||||
background-image: url('/static/images/menu_icon/9.png'); // 替换为实际的图片路径
|
||||
}
|
||||
}
|
||||
|
||||
.active {
|
||||
background: #fff;
|
||||
color: base.$background-color-main;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.active1:before {
|
||||
background-image: url('/static/images/menu_icon/1-active.png') !important;
|
||||
}
|
||||
|
||||
.active2:before {
|
||||
background-image: url('/static/images/menu_icon/2-active.png') !important;
|
||||
}
|
||||
|
||||
.active3:before {
|
||||
background-image: url('/static/images/menu_icon/3-active.png') !important;
|
||||
}
|
||||
|
||||
.active4:before {
|
||||
background-image: url('/static/images/menu_icon/4-active.png') !important;
|
||||
}
|
||||
|
||||
.active5:before {
|
||||
background-image: url('/static/images/menu_icon/5-active.png') !important;
|
||||
}
|
||||
|
||||
.active6:before {
|
||||
background-image: url('/static/images/menu_icon/6-actvie.png') !important;
|
||||
}
|
||||
|
||||
.active7:before {
|
||||
background-image: url('/static/images/menu_icon/7-active.png') !important;
|
||||
}
|
||||
|
||||
.active8:before {
|
||||
background-image: url('/static/images/menu_icon/8-active.png') !important;
|
||||
}
|
||||
|
||||
.active9:before {
|
||||
background-image: url('/static/images/menu_icon/9-active.png') !important;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
header {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 80px;
|
||||
|
||||
background-color: base.$background-color-main;
|
||||
padding: 15px 0;
|
||||
}
|
||||
</style>
|
||||
<script setup lang="ts">
|
||||
</script>
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
<script setup lang="ts">
|
||||
import { ref, watch,defineEmits } from "vue";
|
||||
import { CloseBold } from '@element-plus/icons-vue'
|
||||
|
||||
let _width = ref(0);
|
||||
let _height = ref(0);
|
||||
let _isShow = ref(false);
|
||||
const { width, height, isShow,title } = defineProps(['width', 'height', 'isShow','title']);
|
||||
|
||||
_isShow.value = isShow == null ? false : isShow;
|
||||
_width.value = width == null ? 1200 : width;
|
||||
_height.value = height == null ? 800 : height;
|
||||
console.log(_width, _height, _isShow);
|
||||
|
||||
watch(() => isShow, (newVal) => {
|
||||
_isShow.value = newVal == null ? false : newVal;
|
||||
});
|
||||
const emit=defineEmits(['close']);
|
||||
const close = () => {
|
||||
emit('close',false);
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<teleport to="body">
|
||||
<transition name="el-fade-in">
|
||||
<div class="mask" v-if="_isShow">
|
||||
<div class="mask-wrapper" :style="{ width: _width + 'px', height: _height + 'px' }" v-if="_isShow">
|
||||
<div class="header">
|
||||
<div class="title">{{title}}</div>
|
||||
<div class="close" @click="close"><el-icon><CloseBold/></el-icon></div>
|
||||
</div>
|
||||
<el-scrollbar height="100%">
|
||||
<slot></slot>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</teleport>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.mask {
|
||||
position: fixed;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 20px;
|
||||
z-index: 999;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
.mask-wrapper {
|
||||
position: relative;
|
||||
background-color: #FFF;
|
||||
border-radius: 6px;
|
||||
padding:0 20px 20px 20px;
|
||||
overflow: hidden;
|
||||
max-height: 90vh;
|
||||
z-index: 1999;
|
||||
.header{
|
||||
position: relative;
|
||||
height: 72px;
|
||||
padding: 0 4px;
|
||||
.title{
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left:0;
|
||||
font-weight: 800;
|
||||
font-size: 20px;
|
||||
color: #333333;
|
||||
font-style: normal;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
.close{
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 0;
|
||||
color: #6e6e6e;
|
||||
font-size: 32px;
|
||||
transform: translateY(-50%);
|
||||
&:hover{
|
||||
color: #409eff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
<template>
|
||||
<div class="panel" :class="props.isFullHeight ? 'panel--flex' : ''">
|
||||
<div class="panel-header" v-if="props.showHeader">
|
||||
<div class="panel-header-title">{{props.title}}</div>
|
||||
<div class="panel-header-tools" v-if="props.showTools">
|
||||
<slot name="tools"></slot>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-content" :style="!props.showHeader ? 'padding-top: 0' : ''">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.panel {
|
||||
background: #fff;
|
||||
border-radius: 6px;
|
||||
&-header {
|
||||
position: relative;
|
||||
height: 58px;
|
||||
padding-right: 18px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
&:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 17px;
|
||||
width: 7px;
|
||||
height: 24px;
|
||||
background: #4D6DE4;
|
||||
border-radius: 3px;
|
||||
}
|
||||
&-title {
|
||||
width: 150px;
|
||||
font-weight: 800;
|
||||
font-size: 20px;
|
||||
color: #333333;
|
||||
font-style: normal;
|
||||
text-indent: 17px;
|
||||
line-height: 48px;
|
||||
}
|
||||
|
||||
&-tools {
|
||||
}
|
||||
}
|
||||
&-content {
|
||||
|
||||
}
|
||||
}
|
||||
.panel--flex{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
height: 100%;
|
||||
.panel-content{
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
|
||||
<script setup lang="ts">
|
||||
|
||||
const props = defineProps({
|
||||
title: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
isFullHeight: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
showTools: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
showHeader: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
})
|
||||
|
||||
</script>
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
<template xmlns="http://www.w3.org/1999/html">
|
||||
<Mask :width="1100" :height="600" :is-show="show" :top="100" title="过期商品详情" @close="show=false">
|
||||
<el-table :data="tableData" style="width: 100%" class="table" max-height="1000px">
|
||||
<el-table-column label="名称" prop="name"></el-table-column>
|
||||
<el-table-column label="剩余天数">
|
||||
<template #default="scope">
|
||||
<span class="remaining-date">
|
||||
{{scope.row.remaining_days <0?'已过期':scope.row.remaining_days+"天后到期"}}
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="商品数量" prop="">
|
||||
<template #default="scope">
|
||||
{{
|
||||
scope.row.whole_number
|
||||
}}{{ scope.row.packaging_unit }}
|
||||
<span v-if="scope.row.fragment_number>0">
|
||||
{{ scope.row.fragment_number }}{{ scope.row.min_packaging_unit }}
|
||||
</span>
|
||||
</template>
|
||||
|
||||
</el-table-column>
|
||||
<el-table-column label="过期时间" prop="expiry_date"></el-table-column>
|
||||
<el-table-column label="采购单号" prop="inventory_purchase_code"></el-table-column>
|
||||
<el-table-column label="批次号" prop="production_batch_code"></el-table-column>
|
||||
<el-table-column label="生产日期" prop="production_date"></el-table-column>
|
||||
|
||||
</el-table>
|
||||
</Mask>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import Mask from "@/components/common/Mask.vue";
|
||||
import {ref} from "vue";
|
||||
import CloseBtn from "@/components/CloseBtn.vue";
|
||||
const tableData = ref<any>([]);
|
||||
const show = ref(false);
|
||||
const init = (list:any) => {
|
||||
tableData.value = list;
|
||||
show.value = true;
|
||||
};
|
||||
defineExpose({init})
|
||||
const close = () => {
|
||||
show.value = false;
|
||||
};
|
||||
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.table{
|
||||
margin-top: 30px;
|
||||
.remaining-date{
|
||||
color: red;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
<template>
|
||||
<Mask :width="1100" :height="600" :is-show="show" :top="100" title="库存预警详情" @close="close">
|
||||
<el-table :data="tableData" style="width: 100%" class="table" max-height="1000px">
|
||||
<el-table-column label="名称" prop="name"></el-table-column>
|
||||
<el-table-column label="剩余库存">
|
||||
<template #default="scope">
|
||||
{{
|
||||
scope.row.inventoryWholeNumber
|
||||
}}{{ scope.row.packagingUnit }}
|
||||
<span v-if="scope.row.inventoryFragmentNumber>0">
|
||||
{{ scope.row.inventoryFragmentNumber }}{{ scope.row.minPackagingUnit }}
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="库存预警线">
|
||||
<template #default="scope">
|
||||
小于等于{{scope.row.inventoryWarnNumber}}{{scope.row.packagingUnit}}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="医保码" prop="hilistCode" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="生产企业" prop="producer" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="商品备注" prop="remark" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="是否允许拆零">
|
||||
<template #default="scope">
|
||||
{{scope.row.trdnFlag?"允许":"不允许"}}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
</el-table>
|
||||
</Mask>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import Mask from "@/components/common/Mask.vue";
|
||||
import {ref} from "vue";
|
||||
import CloseBtn from "@/components/CloseBtn.vue";
|
||||
const tableData = ref<any>([]);
|
||||
const show = ref(false);
|
||||
const init = (list:any) => {
|
||||
|
||||
tableData.value = list;
|
||||
show.value = true;
|
||||
};
|
||||
defineExpose({init})
|
||||
const close = () => {
|
||||
show.value = false;
|
||||
};
|
||||
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.table{
|
||||
margin-top: 30px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
<script setup lang="ts">
|
||||
import {ref} from "vue";
|
||||
import {post} from "@/utils/request.ts";
|
||||
|
||||
const state = ref([])
|
||||
const options = ref([])
|
||||
const selectRef = ref();
|
||||
const querySearchAsync = (queryString: string, cb: (arg: any) => void) => {
|
||||
post("goods/goods/search", {keyword: queryString}).then((res: any) => {
|
||||
options.value = res;
|
||||
let list = res;
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
list[i].value = list[i].name;
|
||||
}
|
||||
// cb(res)
|
||||
})
|
||||
}
|
||||
const emit = defineEmits(['selectCallBack'])
|
||||
const handleSelect = (item: any) => {
|
||||
console.log(item,'item')
|
||||
let goods = JSON.parse(JSON.stringify(item));
|
||||
console.log("goods",goods)
|
||||
let inventory = {
|
||||
hilistCode: goods.hilistCode,
|
||||
unitPrice: goods.unitPrice,
|
||||
packagingUnit: goods.packagingUnit,
|
||||
minPackagingUnit: goods.minPackagingUnit,
|
||||
|
||||
goodId: goods.id,
|
||||
name: goods.name,
|
||||
wholeNumber: 0,
|
||||
purchaseUnitPrice: goods.purchaseUnitPrice,
|
||||
disassemblyPrice : goods.disassemblyPrice
|
||||
}
|
||||
if (selectRef.value) {
|
||||
(selectRef.value as HTMLElement).blur();
|
||||
}
|
||||
emit('selectCallBack', inventory);
|
||||
state.value = []
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="search_box">
|
||||
<el-select-v2
|
||||
v-model="state"
|
||||
style="width: 100%"
|
||||
filterable
|
||||
remote
|
||||
ref="selectRef"
|
||||
:remote-method="querySearchAsync"
|
||||
:options="options"
|
||||
placeholder="输入关键字搜索药品"
|
||||
:fit-input-width="800"
|
||||
>
|
||||
<template #header>
|
||||
<div class="header">
|
||||
<div class="text">药品</div>
|
||||
<div class="text">规格</div>
|
||||
<div class="text">库存</div>
|
||||
<div class="text">厂家</div>
|
||||
<div class="text">最近供应商</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="{ item }">
|
||||
<div class="row" @click="handleSelect(item)">
|
||||
<div class="text" style="margin-left: 0px">{{ item.name }}</div>
|
||||
<div class="text">{{item.minPackagingNumber}}*{{item.minPackagingUnit}}/{{ item.packagingUnit }}</div>
|
||||
<div class="text">
|
||||
{{ item.inventoryWholeNumber }}{{ item.packagingUnit }}
|
||||
<template v-if="item.inventoryFragmentNumber > 0">
|
||||
{{ item.inventoryFragmentNumber }}{{ item.minPackagingUnit }}
|
||||
</template>
|
||||
</div>
|
||||
<div class="text">{{ item.producer }}</div>
|
||||
<div class="text" style="margin-left: 15px">无</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #footer>
|
||||
</template>
|
||||
</el-select-v2>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.search_box {
|
||||
//background-color: rgb(148.6, 212.3, 117.1);
|
||||
background-color: #fff;
|
||||
padding: 10px;
|
||||
border-radius: 10px;
|
||||
box-sizing: border-box;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
|
||||
|
||||
}
|
||||
.header {
|
||||
display: flex;
|
||||
|
||||
.text {
|
||||
font-size: 16px;
|
||||
width: 200px;
|
||||
color: #6a6a6a;
|
||||
}
|
||||
}
|
||||
.row {
|
||||
display: flex;
|
||||
max-height: 500px;
|
||||
|
||||
.text {
|
||||
font-size: 12px;
|
||||
width: 150px;
|
||||
margin-left: 10px;
|
||||
overflow: hidden; /* 隐藏超出部分 */
|
||||
text-overflow: ellipsis; /* 显示省略号 */
|
||||
white-space: nowrap; /* 防止换行 */
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
|
||||
|
||||
<template>
|
||||
<div class="box">
|
||||
<ul class="item-list">
|
||||
<div v-for="(item, index) in units" :class="['item',(index+1)%4 == 0 ? 'last-item' : '',item==curItem?'active':'']" @click="selectItem(item)">{{item}}</div>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
const curItem = defineModel();
|
||||
const emit = defineEmits(['selected'])
|
||||
const props = defineProps({
|
||||
units: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
})
|
||||
const selectItem = (item:any) => {
|
||||
|
||||
if(curItem.value == item){
|
||||
curItem.value = null;
|
||||
return
|
||||
}
|
||||
curItem.value = item
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.box{
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
position:absolute;
|
||||
background: #fff;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 322px;
|
||||
height: auto;
|
||||
border: 1px solid #ddd;
|
||||
z-index: 999;
|
||||
}
|
||||
.item-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.item{
|
||||
display: flex;
|
||||
width: 80px;
|
||||
height: 36px;
|
||||
background: #fff;
|
||||
color: #000;
|
||||
border: 1px solid #ededed;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
&:hover{
|
||||
color: #000;
|
||||
background: #eff3f6;
|
||||
}
|
||||
&.last-item {
|
||||
margin-right: 0; /* 最后一个元素不加右边距 */
|
||||
}
|
||||
|
||||
}
|
||||
.active{
|
||||
background: #00ace9 !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
@ -0,0 +1,285 @@
|
|||
<template>
|
||||
<CloseBtn @click="exit"></CloseBtn>
|
||||
<el-descriptions title="新增领用" border label-width="100">
|
||||
<el-descriptions-item label="领用人" width="200">
|
||||
<el-input v-model="formData.name" disabled></el-input>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="备注">
|
||||
<el-input v-model="formData.remark"></el-input>
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<GoodsSearch @selectCallBack="goodsSelectCallBack"></GoodsSearch>
|
||||
<table class="simple-table" style="margin-top: 15px;">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>名称</th>
|
||||
<th>批次</th>
|
||||
<th>生产批号</th>
|
||||
<th>有效期</th>
|
||||
<th>当前库存</th>
|
||||
<th>出库数量</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<template v-for="(item,index) in tableList">
|
||||
<tr>
|
||||
<td>{{ item.name }}</td>
|
||||
<td>
|
||||
<el-select
|
||||
v-model="item.selectList"
|
||||
multiple
|
||||
@change="addLine(item)"
|
||||
:teleported="false"
|
||||
style="width: 100px;"
|
||||
collapse-tags
|
||||
popper-class="table-select">
|
||||
<div class="select-header">
|
||||
<span>批次ID</span>
|
||||
<span>生产批号</span>
|
||||
<span>入库数据</span>
|
||||
<span>有效期</span>
|
||||
<span>进价</span>
|
||||
</div>
|
||||
<el-option
|
||||
v-for="(subItem,subIndex) in item.batchList"
|
||||
:key="subItem.id"
|
||||
:label="subItem.id"
|
||||
:value="subItem.id">
|
||||
<div class="option-row">
|
||||
<span>{{ subItem.id }}</span>
|
||||
<span>{{ subItem.productionBatchCode }}</span>
|
||||
<span>{{ subItem.productionDate }}</span>
|
||||
<span>{{ subItem.expiryDate }}</span>
|
||||
<span>{{ subItem.purchaseUnitPrice }}</span>
|
||||
</div>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</td>
|
||||
<td></td>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
{{ item.wholeNumber }}{{ item.packagingUnit }}
|
||||
<template v-if="item.trdnFlag == 1">
|
||||
{{ item.fragmentNumber }}{{ item.minPackagingUnit }}
|
||||
</template>
|
||||
</td>
|
||||
<td>
|
||||
{{ item.totalOutWholeNumber }}{{ item.packagingUnit }}
|
||||
<template v-if="item.trdnFlag == 1">
|
||||
{{ item.totalFragmentNumber }}{{ item.minPackagingUnit }}
|
||||
</template>
|
||||
</td>
|
||||
</tr>
|
||||
<template v-for="subItem in item.children">
|
||||
<tr>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
<td>{{ subItem.productionBatchCode }}</td>
|
||||
<td>{{ subItem.expiryDate }}</td>
|
||||
<td>
|
||||
{{ subItem.wholeNumber }}{{ subItem.packagingUnit }}
|
||||
<template v-if="item.trdnFlag == 1">
|
||||
{{ subItem.fragmentNumber }}{{ subItem.minPackagingUnit }}
|
||||
</template>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<el-input v-model.number="subItem.outWholeNumber" size="small" style="width: 50px" @change="changeOutNumber(item)">
|
||||
<template #suffix>
|
||||
{{ item.packagingUnit }}
|
||||
</template>
|
||||
</el-input>
|
||||
<el-input v-model.number="subItem.outFragmentNumber" size="small" style="width: 50px"
|
||||
@change="changeOutNumber(item)" v-if="item.trdnFlag == 1">
|
||||
<template #suffix>
|
||||
{{ item.minPackagingUnit }}
|
||||
</template>
|
||||
</el-input>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
</template>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="bottom">
|
||||
<el-button type="primary" @click="save">保存</el-button>
|
||||
<el-button type="primary" @click="exit">关闭</el-button>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import {onMounted, ref, unref} from "vue";
|
||||
import GoodsSearch from "@/components/inventory/GoodsSearch.vue";
|
||||
import {post} from "@/utils/request.ts";
|
||||
import CloseBtn from "@/components/CloseBtn.vue";
|
||||
|
||||
const emit = defineEmits(['close'])
|
||||
const exit = () => {
|
||||
emit('close')
|
||||
|
||||
}
|
||||
|
||||
const formData = ref({
|
||||
useUserId: null,
|
||||
name: '',
|
||||
username: "",
|
||||
remark: ''
|
||||
})
|
||||
|
||||
interface Inventory {
|
||||
goodId: string | number;
|
||||
batchList?: any[];// 添加 batchList 属性
|
||||
children: childCheck[];
|
||||
packagingUnit?: string;
|
||||
minPackagingUnit?: string;
|
||||
totalOutWholeNumber: number;
|
||||
totalFragmentNumber: number;
|
||||
wholeNumber?: number;
|
||||
fragmentNumber?: number;
|
||||
selectList?: number[]; // 添加 selectList 属性并指定类型
|
||||
name?: string;
|
||||
trdnFlag?: number;
|
||||
|
||||
|
||||
}
|
||||
|
||||
const tableList = ref<Inventory[]>([]);
|
||||
const findIndexForTableList = (goodId: any) => {
|
||||
return tableList.value.findIndex((item: any) => item.goodId === goodId);
|
||||
}
|
||||
const goodsSelectCallBack = (inventory: any) => {
|
||||
if (findIndexForTableList(inventory.goodId) != -1) {
|
||||
return
|
||||
}
|
||||
post("inventory/goods/getByGoodsId", {goodsId: inventory.goodId}).then((res: any) => {
|
||||
inventory.batchList = res.inventoryGoodsList
|
||||
inventory.minPackagingUnit = res.minPackagingUnit
|
||||
inventory.trdnFlag = res.trdnFlag
|
||||
inventory.totalOutWholeNumber = 0;
|
||||
inventory.totalFragmentNumber = 0;
|
||||
inventory.wholeNumber = res.inventoryWholeNumber;
|
||||
inventory.fragmentNumber = res.inventoryFragmentNumber;
|
||||
inventory.packagingUnit = res.packagingUnit
|
||||
tableList.value.push(inventory)
|
||||
})
|
||||
console.log(inventory)
|
||||
}
|
||||
|
||||
interface childCheck {
|
||||
id?: number,
|
||||
goodsId: number,
|
||||
name: string,
|
||||
productionBatchCode: string,
|
||||
minPackagingNumber: number,
|
||||
productionDate: string
|
||||
expiryDate: string,
|
||||
purchaseUnitPrice: number,
|
||||
wholeNumber: number,
|
||||
packagingUnit: string,
|
||||
fragmentNumber: number,
|
||||
fragmentPrice: string,
|
||||
minPackagingUnit: string;
|
||||
outFragmentNumber: number;
|
||||
outWholeNumber: number;
|
||||
|
||||
|
||||
}
|
||||
|
||||
const addLine = (row: any) => {
|
||||
post('inventory/goods/getListByIds', {idList: row.selectList}).then((list: any) => {
|
||||
let children = [];
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
let inventoryGoods = list[i];
|
||||
let index = row.children ? row.children.findIndex((item: any) => item.id === inventoryGoods.id) : -1;
|
||||
if (index > -1) {
|
||||
children.push(row.children[index]);
|
||||
} else {
|
||||
let childCheck: childCheck = {
|
||||
name: inventoryGoods.name,
|
||||
id: inventoryGoods.id,
|
||||
goodsId: inventoryGoods.goodId,
|
||||
minPackagingNumber: row.minPackagingNumber,
|
||||
productionBatchCode: inventoryGoods.productionBatchCode,
|
||||
productionDate: inventoryGoods.productionDate,
|
||||
expiryDate: inventoryGoods.expiryDate,
|
||||
purchaseUnitPrice: inventoryGoods.purchaseUnitPrice,
|
||||
wholeNumber: inventoryGoods.wholeNumber,
|
||||
packagingUnit: inventoryGoods.packagingUnit,
|
||||
fragmentNumber: inventoryGoods.fragmentNumber,
|
||||
fragmentPrice: inventoryGoods.fragmentPrice,
|
||||
minPackagingUnit: row.minPackagingUnit,
|
||||
outFragmentNumber: inventoryGoods.outFragmentNumber,
|
||||
outWholeNumber: inventoryGoods.outWholeNumber,
|
||||
|
||||
}
|
||||
children.push(childCheck);
|
||||
}
|
||||
}
|
||||
|
||||
row.children = children;
|
||||
console.log("row", row)
|
||||
})
|
||||
}
|
||||
const changeOutNumber = (row: any) => {
|
||||
let totalOutWholeNumber = 0;
|
||||
let totalOutFragmentNumber = 0;
|
||||
for (let i = 0; i < row.children.length; i++) {
|
||||
let child = row.children[i];
|
||||
totalOutWholeNumber += child.outWholeNumber ? child.outWholeNumber : 0;
|
||||
totalOutFragmentNumber += child.outFragmentNumber ? child.outFragmentNumber : 0;
|
||||
}
|
||||
row.totalOutWholeNumber = totalOutWholeNumber;
|
||||
row.totalFragmentNumber = totalOutFragmentNumber;
|
||||
console.log(row)
|
||||
}
|
||||
const save = () => {
|
||||
let children = [];
|
||||
console.log(tableList.value)
|
||||
// for (let i = 0; i < tableList.value.length; i++) {
|
||||
// let item = tableList.value[i];
|
||||
// for (let j = 0; j < item.children.length; j++) {
|
||||
// let child = item.children[j];
|
||||
// if (child && (child.outWholeNumber > 0 || child.outFragmentNumber > 0)) {
|
||||
// let childrenItem = {
|
||||
// id: child.id,
|
||||
// outWholeNumber: child.outWholeNumber,
|
||||
// outFragmentNumber: child.outFragmentNumber,
|
||||
// }
|
||||
// children.push(childrenItem);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
// }
|
||||
// let dataJson = JSON.stringify(tableList.value);
|
||||
post("inventory/apply/create", {useInfo: formData.value, data: tableList.value}).then((res: any) => {
|
||||
exit()
|
||||
})
|
||||
|
||||
|
||||
}
|
||||
const getUserInfo = () => {
|
||||
post("manager/user/verify", null).then((res: any) => {
|
||||
formData.value.useUserId = res.id;
|
||||
formData.value.name = res.name;
|
||||
formData.value.username = res.username;
|
||||
})
|
||||
}
|
||||
onMounted(() => {
|
||||
getUserInfo()
|
||||
})
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.btn {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
|
||||
.bottom {
|
||||
margin-top: 10px;
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
bottom: 10px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,224 @@
|
|||
<template>
|
||||
<CloseBtn @click="exit"></CloseBtn>
|
||||
<el-descriptions title="详情领用" border label-width="100">
|
||||
<el-descriptions-item label="领用人" width="200">
|
||||
<el-input v-model="formData.name" disabled></el-input>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="备注">
|
||||
<el-input v-model="formData.remark" disabled></el-input>
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<table class="simple-table" style="margin-top: 15px;">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>名称</th>
|
||||
<th>批次</th>
|
||||
<th>生产批号</th>
|
||||
<th>有效期</th>
|
||||
<th>当前库存</th>
|
||||
<th>出库数量</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<template v-for="(item,index) in tableList" :key="index">
|
||||
<tr>
|
||||
<td>{{ item.name }}</td>
|
||||
<td>
|
||||
<el-select
|
||||
v-model="item.selectList"
|
||||
multiple
|
||||
@change="addLine(item)"
|
||||
:teleported="false"
|
||||
style="width: 100px;"
|
||||
collapse-tags
|
||||
popper-class="table-select">
|
||||
<div class="select-header">
|
||||
<span>批次ID</span>
|
||||
<span>生产批号</span>
|
||||
<span>入库数据</span>
|
||||
<span>有效期</span>
|
||||
<span>进价</span>
|
||||
</div>
|
||||
<el-option
|
||||
v-for="(subItem) in item.batchList"
|
||||
:key="subItem.id"
|
||||
:label="subItem.id"
|
||||
:value="subItem.id"
|
||||
:disabled="true"
|
||||
>
|
||||
<div class="option-row">
|
||||
<span>{{ subItem.id }}</span>
|
||||
<span>{{ subItem.productionBatchCode }}</span>
|
||||
<span>{{ subItem.productionDate }}</span>
|
||||
<span>{{ subItem.expiryDate }}</span>
|
||||
<span>{{ subItem.purchaseUnitPrice }}</span>
|
||||
</div>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</td>
|
||||
<td></td>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
{{ item.wholeNumber }}{{ item.packagingUnit }}
|
||||
<template v-if="item.trdnFlag == 1">
|
||||
{{ item.fragmentNumber }}{{ item.minPackagingUnit }}
|
||||
</template>
|
||||
</td>
|
||||
<td>
|
||||
{{ item.totalOutWholeNumber }}{{ item.packagingUnit }}
|
||||
<template v-if="item.trdnFlag == 1">
|
||||
{{ item.totalFragmentNumber }}{{ item.minPackagingUnit }}
|
||||
</template>
|
||||
</td>
|
||||
</tr>
|
||||
<template v-for="subItem in item.children">
|
||||
<tr>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
<td>{{ subItem.productionBatchCode }}</td>
|
||||
<td>{{ subItem.expiryDate }}</td>
|
||||
<td>
|
||||
{{ subItem.wholeNumber }}{{ subItem.packagingUnit }}
|
||||
<template v-if="item.trdnFlag == 1">
|
||||
{{ subItem.fragmentNumber }}{{ subItem.minPackagingUnit }}
|
||||
</template>
|
||||
</td>
|
||||
<td>
|
||||
{{ subItem.outWholeNumber }}{{ subItem.packagingUnit }}
|
||||
<template v-if="item.trdnFlag == 1">
|
||||
{{ subItem.outFragmentNumber }}{{ subItem.minPackagingUnit }}
|
||||
</template>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
</template>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="bottom">
|
||||
<el-button type="primary" @click="exit">关闭</el-button>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import {onMounted, ref, defineProps} from "vue";
|
||||
import {post} from "@/utils/request.ts";
|
||||
import CloseBtn from "@/components/CloseBtn.vue";
|
||||
|
||||
const props = defineProps({
|
||||
id: {
|
||||
type: String,
|
||||
default: null
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['close'])
|
||||
const exit = () => {
|
||||
emit('close')
|
||||
|
||||
}
|
||||
|
||||
const formData = ref({
|
||||
useUserId: null,
|
||||
name: '',
|
||||
username: "",
|
||||
remark: ''
|
||||
})
|
||||
|
||||
interface Inventory {
|
||||
goodId: string | number;
|
||||
batchList?: any[];// 添加 batchList 属性
|
||||
children: childCheck[];
|
||||
packagingUnit?: string;
|
||||
minPackagingUnit?: string;
|
||||
totalOutWholeNumber: number;
|
||||
totalFragmentNumber: number;
|
||||
wholeNumber?: number;
|
||||
fragmentNumber?: number;
|
||||
selectList?: number[]; // 添加 selectList 属性并指定类型
|
||||
name?: string;
|
||||
trdnFlag?: number;
|
||||
}
|
||||
const tableList = ref<Inventory[]>([]);
|
||||
interface childCheck {
|
||||
id?: number,
|
||||
goodsId: number,
|
||||
name: string,
|
||||
productionBatchCode: string,
|
||||
minPackagingNumber: number,
|
||||
productionDate: string
|
||||
expiryDate: string,
|
||||
purchaseUnitPrice: number,
|
||||
wholeNumber: number,
|
||||
packagingUnit: string,
|
||||
fragmentNumber: number,
|
||||
fragmentPrice: string,
|
||||
minPackagingUnit: string;
|
||||
outFragmentNumber: number;
|
||||
outWholeNumber: number;
|
||||
|
||||
|
||||
}
|
||||
const addLine = (row: any) => {
|
||||
post('inventory/goods/getListByIds', {idList: row.selectList}).then((list: any) => {
|
||||
let children = [];
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
let inventoryGoods = list[i];
|
||||
let index = row.children ? row.children.findIndex((item: any) => item.id === inventoryGoods.id) : -1;
|
||||
if (index > -1) {
|
||||
children.push(row.children[index]);
|
||||
} else {
|
||||
let childCheck: childCheck = {
|
||||
name: inventoryGoods.name,
|
||||
id: inventoryGoods.id,
|
||||
goodsId: inventoryGoods.goodId,
|
||||
minPackagingNumber: row.minPackagingNumber,
|
||||
productionBatchCode: inventoryGoods.productionBatchCode,
|
||||
productionDate: inventoryGoods.productionDate,
|
||||
expiryDate: inventoryGoods.expiryDate,
|
||||
purchaseUnitPrice: inventoryGoods.purchaseUnitPrice,
|
||||
wholeNumber: inventoryGoods.wholeNumber,
|
||||
packagingUnit: inventoryGoods.packagingUnit,
|
||||
fragmentNumber: inventoryGoods.fragmentNumber,
|
||||
fragmentPrice: inventoryGoods.fragmentPrice,
|
||||
minPackagingUnit: row.minPackagingUnit,
|
||||
outFragmentNumber: inventoryGoods.outFragmentNumber,
|
||||
outWholeNumber: inventoryGoods.outWholeNumber,
|
||||
|
||||
}
|
||||
children.push(childCheck);
|
||||
}
|
||||
}
|
||||
row.children = children;
|
||||
})
|
||||
}
|
||||
const getUserInfo = () => {
|
||||
post("manager/user/verify", null).then((res: any) => {
|
||||
formData.value.useUserId = res.id;
|
||||
formData.value.name = res.name;
|
||||
formData.value.username = res.username;
|
||||
})
|
||||
}
|
||||
const detail = () => {
|
||||
post("inventory/apply/getApplyDetail", {id: props.id}).then((res: any) => {
|
||||
formData.value = res.useInfo;
|
||||
tableList.value = JSON.parse(res);
|
||||
})
|
||||
}
|
||||
onMounted(() => {
|
||||
getUserInfo()
|
||||
detail()
|
||||
})
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.btn {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
|
||||
.bottom {
|
||||
margin-top: 10px;
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
bottom: 10px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,457 @@
|
|||
<template>
|
||||
<div class="body_wrapper">
|
||||
<div class="top">
|
||||
<el-descriptions
|
||||
title="盘点单"
|
||||
direction="vertical"
|
||||
:column="1"
|
||||
/>
|
||||
<el-input class="remark" v-model="remark">
|
||||
<template #prepend>备注</template>
|
||||
</el-input>
|
||||
</div>
|
||||
<div class="content">
|
||||
<GoodsSearch @selectCallBack="goodsSelectCallBack"></GoodsSearch>
|
||||
<table class="simple-table" style="margin-top: 15px;">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>名称</th>
|
||||
<th>批次</th>
|
||||
<th>最小包装数量</th>
|
||||
<th>库存</th>
|
||||
<th>改后库存</th>
|
||||
<th>变化量</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<template v-for="(item,index) in list">
|
||||
<tr>
|
||||
<td>{{ item.name }}</td>
|
||||
<td>
|
||||
<!--<el-checkbox-group v-model="item.childIdList" @change="addLine(item)">
|
||||
<el-checkbox v-for="(subItem,subIndex) in item.selectList" :label="subItem.id" :value="subItem.id" />
|
||||
</el-checkbox-group>-->
|
||||
<el-select
|
||||
v-model="item.childIdList"
|
||||
@change="addLine(item)"
|
||||
multiple
|
||||
:teleported="false"
|
||||
style="width: 150px;"
|
||||
collapse-tags
|
||||
popper-class="table-select">
|
||||
<div class="select-header">
|
||||
<span>批次ID</span>
|
||||
<span>生产批号</span>
|
||||
<span>入库时间</span>
|
||||
<span>有效期</span>
|
||||
<span>进价</span>
|
||||
</div>
|
||||
<el-option
|
||||
v-for="(subItem,subIndex) in item.selectList"
|
||||
:key="subItem.id"
|
||||
:label="subItem.id"
|
||||
:value="subItem.id">
|
||||
<div class="option-row">
|
||||
<span>{{ subItem.id }}</span>
|
||||
<span>{{ subItem.productionBatchCode }}</span>
|
||||
<span>{{ subItem.productionDate }}</span>
|
||||
<span>{{ subItem.expiryDate }}</span>
|
||||
<span>{{ subItem.purchaseUnitPrice }}</span>
|
||||
</div>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</td>
|
||||
<td>{{ item.minPackagingNumber }}</td>
|
||||
<td>
|
||||
{{ item.before.wholeNumber }}{{ item.packagingUnit }}
|
||||
<template v-if="item.trdnFlag ==1">
|
||||
{{ item.before.fragmentNumber }}{{ item.minPackagingUnit }}
|
||||
</template>
|
||||
|
||||
</td>
|
||||
<td>
|
||||
<el-form v-show="item.childIdList.length===0">
|
||||
<el-input v-model.number="item.after.wholeNumber" style="width: 60px" @change="setChange(item)">
|
||||
<template #suffix>{{ item.packagingUnit }}</template>
|
||||
</el-input>
|
||||
<el-input v-model.number="item.after.fragmentNumber" style="width: 60px;margin-left: 5px"
|
||||
@change="setChange(item)" v-if="item.trdnFlag ==1">
|
||||
<template #suffix>{{ item.minPackagingUnit }}</template>
|
||||
</el-input>
|
||||
</el-form>
|
||||
</td>
|
||||
<td>
|
||||
{{ item.change.wholeNumber }}{{ item.packagingUnit }}
|
||||
<template v-if="item.trdnFlag ==1">
|
||||
{{ item.change.fragmentNumber }}{{ item.minPackagingUnit }}
|
||||
</template>
|
||||
</td>
|
||||
</tr>
|
||||
<template v-for="(subItem,subIndex) in item.children">
|
||||
<tr>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
<td> {{ subItem.before.wholeNumber }}{{ item.packagingUnit }}
|
||||
<template v-if="item.trdnFlag ==1">
|
||||
{{ subItem.before.fragmentNumber }}{{ item.minPackagingUnit }}
|
||||
</template>
|
||||
</td>
|
||||
<td>
|
||||
<el-input v-model.number="subItem.after.wholeNumber" style="width: 60px" @change="setChange(subItem)">
|
||||
<template #suffix>{{ item.packagingUnit }}</template>
|
||||
</el-input>
|
||||
<el-input v-model.number="subItem.after.fragmentNumber" style="width: 60px;margin-left: 5px"
|
||||
@change="setChange(subItem)" v-if="item.trdnFlag ==1">
|
||||
<template #suffix>{{ item.minPackagingUnit }}</template>
|
||||
</el-input>
|
||||
</td>
|
||||
<td>
|
||||
{{ subItem.change.wholeNumber }}{{ item.packagingUnit }}
|
||||
<template v-if="item.trdnFlag ==1">
|
||||
{{ item.change.fragmentNumber }}{{ item.minPackagingUnit }}
|
||||
</template>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
</template>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bottom">
|
||||
<el-button @click="save" type="primary">保存</el-button>
|
||||
<el-button @click="exit" type="primary">关闭</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.body_wrapper {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
min-height: 0;
|
||||
flex-direction: column;
|
||||
|
||||
.top {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 60px;
|
||||
}
|
||||
|
||||
.content {
|
||||
display: block;
|
||||
width: 100%;
|
||||
flex: 1;
|
||||
//min-height: 0;
|
||||
|
||||
table {
|
||||
//border-collapse: collapse;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
th,
|
||||
td {
|
||||
//border: 1px solid #ccc;
|
||||
padding: 8px;
|
||||
text-align: left;
|
||||
|
||||
}
|
||||
|
||||
th {
|
||||
//background-color: #F9F9F9;
|
||||
}
|
||||
|
||||
/* 可选:为可点击的行添加鼠标悬停效果 */
|
||||
tr:hover {
|
||||
//background-color: #f5f5f5;
|
||||
}
|
||||
}
|
||||
|
||||
.bottom {
|
||||
height: 60px;
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
bottom: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
|
||||
.text {
|
||||
font-size: 16px;
|
||||
width: 200px;
|
||||
color: #6a6a6a;
|
||||
}
|
||||
}
|
||||
|
||||
/* 表格容器 */
|
||||
.simple-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-size: 14px;
|
||||
border: none;
|
||||
color: #606266;
|
||||
|
||||
thead {
|
||||
background-color: #f5f7fa;
|
||||
|
||||
th {
|
||||
padding: 12px 0;
|
||||
text-align: left;
|
||||
font-weight: bold; /* 表头加粗 */
|
||||
font-size: 14px; /* 表头字号 */
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
}
|
||||
}
|
||||
|
||||
tbody {
|
||||
tr:hover {
|
||||
background-color: #f5f7fa; /* 悬停效果 */
|
||||
}
|
||||
|
||||
td {
|
||||
padding: 12px 0;
|
||||
text-align: left;
|
||||
font-size: 14px; /* 单元格字号 */
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.table-select {
|
||||
.el-select-dropdown__item {
|
||||
padding: 0 !important;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
// 表头样式
|
||||
.select-header {
|
||||
display: flex;
|
||||
padding: 8px 16px;
|
||||
background: #f5f7fa;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
|
||||
span {
|
||||
flex: 1;
|
||||
min-width: 110px;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
// 选项行样式
|
||||
.option-row {
|
||||
display: flex;
|
||||
padding: 8px 16px;
|
||||
|
||||
span {
|
||||
flex: 1;
|
||||
min-width: 110px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.remark {
|
||||
// 前置标签背景色
|
||||
:deep(.el-input-group__prepend) {
|
||||
background-color: #fffdec;
|
||||
}
|
||||
|
||||
// 输入框主体背景色
|
||||
:deep(.el-input__wrapper) {
|
||||
background-color: #fffdec;
|
||||
}
|
||||
}
|
||||
|
||||
.bottom {
|
||||
margin-top: 10px;
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
bottom: 10px;
|
||||
}
|
||||
</style>
|
||||
<script setup lang="ts">
|
||||
import {onMounted} from "vue";
|
||||
import {post} from "@/utils/request.ts";
|
||||
import {ref} from "vue";
|
||||
import GoodsSearch from "@/components/inventory/GoodsSearch.vue";
|
||||
|
||||
const remark = ref("");
|
||||
const state = ref([])
|
||||
const options = ref([])
|
||||
|
||||
|
||||
const goodsSelectCallBack = (item: any) => {
|
||||
|
||||
if (findIndexForTableList(item.goodId) != -1) {
|
||||
return
|
||||
}
|
||||
addRow(item.goodId);
|
||||
state.value = []
|
||||
}
|
||||
const findIndexForTableList = (goodId: any) => {
|
||||
return list.value.findIndex((item: any) => item.goodsId === goodId);
|
||||
}
|
||||
|
||||
|
||||
interface Check {
|
||||
id?: number,
|
||||
goodsId: number,
|
||||
name: string,
|
||||
minPackagingUnit: string,
|
||||
packagingUnit: string,
|
||||
minPackagingNumber: number,
|
||||
listSize: number,
|
||||
trdnFlag: number,
|
||||
childIdList: number[],
|
||||
before: {
|
||||
wholeNumber: number,
|
||||
fragmentNumber: number,
|
||||
},
|
||||
after: {
|
||||
wholeNumber: number,
|
||||
fragmentNumber: number,
|
||||
},
|
||||
change: {
|
||||
wholeNumber: number,
|
||||
fragmentNumber: number,
|
||||
}
|
||||
children: childCheck[],
|
||||
selectList: seletcType[],
|
||||
}
|
||||
|
||||
interface seletcType {
|
||||
id: number,
|
||||
wholeNumber: number,
|
||||
fragmentNumber: number,
|
||||
productionBatchCode: string,
|
||||
productionDate: string,
|
||||
expiryDate: string,
|
||||
purchaseUnitPrice: string
|
||||
}
|
||||
|
||||
interface childCheck {
|
||||
id?: number,
|
||||
goodsId: number,
|
||||
name: string,
|
||||
minPackagingNumber: number,
|
||||
before: {
|
||||
wholeNumber: number,
|
||||
fragmentNumber: number,
|
||||
},
|
||||
after: {
|
||||
wholeNumber: number,
|
||||
fragmentNumber: number,
|
||||
},
|
||||
change: {
|
||||
wholeNumber: number,
|
||||
fragmentNumber: number,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const list = ref<Check[]>([])
|
||||
const emit = defineEmits(['close'])
|
||||
onMounted(() => {
|
||||
//addRow(1);
|
||||
})
|
||||
let setChange = function (row: any) {
|
||||
let totalBefore = row.before.wholeNumber * row.minPackagingNumber + row.before.fragmentNumber; // 使用原始数据
|
||||
let totalAfter = row.after.wholeNumber * row.minPackagingNumber + row.after.fragmentNumber; // 使用原始数据
|
||||
console.log(totalBefore, totalAfter)
|
||||
let diff = totalAfter - totalBefore;
|
||||
|
||||
row.change.wholeNumber = Math.trunc(diff / row.minPackagingNumber);
|
||||
row.change.fragmentNumber = diff % row.minPackagingNumber
|
||||
}
|
||||
let addLine = (row: any) => {
|
||||
post("inventory/goods/getListByIds", {idList: row.childIdList}).then((list: any) => {
|
||||
let children = [];
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
let inventoryGoods = list[i];
|
||||
let index = row.children.findIndex((item: any) => item.id === inventoryGoods.id);
|
||||
if (index > -1) {
|
||||
children.push(row.children[index]);
|
||||
} else {
|
||||
let childCheck: childCheck = {
|
||||
name: inventoryGoods.name,
|
||||
id: inventoryGoods.id,
|
||||
goodsId: inventoryGoods.goodId,
|
||||
minPackagingNumber: row.minPackagingNumber,
|
||||
before: {
|
||||
wholeNumber: inventoryGoods.wholeNumber,
|
||||
fragmentNumber: inventoryGoods.fragmentNumber,
|
||||
},
|
||||
after: {
|
||||
wholeNumber: inventoryGoods.wholeNumber,
|
||||
fragmentNumber: inventoryGoods.fragmentNumber,
|
||||
},
|
||||
change: {
|
||||
wholeNumber: 0,
|
||||
fragmentNumber: 0,
|
||||
}
|
||||
}
|
||||
children.push(childCheck);
|
||||
}
|
||||
}
|
||||
|
||||
row.children = children;
|
||||
})
|
||||
}
|
||||
let addRow = (goodsId: number) => {
|
||||
post("inventory/goods/getByGoodsId", {goodsId}).then((res: any) => {
|
||||
let check: Check = {
|
||||
goodsId: res.id,
|
||||
name: res.name,
|
||||
listSize: res.listSize,
|
||||
childIdList: [],
|
||||
minPackagingNumber: res.minPackagingNumber,
|
||||
packagingUnit: res.packagingUnit,
|
||||
minPackagingUnit: res.minPackagingUnit,
|
||||
trdnFlag: res.trdnFlag,
|
||||
before: {
|
||||
wholeNumber: res.wholeNumber,
|
||||
fragmentNumber: res.fragmentNumber,
|
||||
},
|
||||
after: {
|
||||
wholeNumber: res.wholeNumber,
|
||||
fragmentNumber: res.fragmentNumber,
|
||||
},
|
||||
change: {
|
||||
wholeNumber: 0,
|
||||
fragmentNumber: 0,
|
||||
},
|
||||
children: [],
|
||||
selectList: [],
|
||||
}
|
||||
let inventoryGoodsList = res.inventoryGoodsList
|
||||
|
||||
for (let i = 0; i < inventoryGoodsList.length; i++) {
|
||||
let inventoryGoods = inventoryGoodsList[i];
|
||||
let childCheck: seletcType = {
|
||||
id: inventoryGoods.id,
|
||||
wholeNumber: inventoryGoods.wholeNumber,
|
||||
fragmentNumber: inventoryGoods.fragmentNumber,
|
||||
productionBatchCode: inventoryGoods.productionBatchCode,
|
||||
productionDate: inventoryGoods.productionDate,
|
||||
expiryDate: inventoryGoods.expiryDate,
|
||||
purchaseUnitPrice: inventoryGoods.purchaseUnitPrice,
|
||||
}
|
||||
check.selectList.push(childCheck)
|
||||
}
|
||||
list.value.push(check)
|
||||
})
|
||||
}
|
||||
let save = () => {
|
||||
post("inventory/check/save", {list: list.value, remark: remark.value}).then((res: any) => {
|
||||
emit('close');
|
||||
})
|
||||
// emit('close');
|
||||
}
|
||||
let exit = () => {
|
||||
emit('close');
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,350 @@
|
|||
<template>
|
||||
<div class="body_wrapper">
|
||||
<div class="top">
|
||||
<el-descriptions
|
||||
title="盘点详情"
|
||||
direction="vertical"
|
||||
:column="1"
|
||||
/>
|
||||
<el-input class="remark" v-model="remark">
|
||||
<template #prepend>备注</template>
|
||||
</el-input>
|
||||
</div>
|
||||
<div class="content">
|
||||
<table class="simple-table" style="margin-top: 15px;">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>名称</th>
|
||||
<th>批次</th>
|
||||
<th>最小包装数量</th>
|
||||
<th>库存</th>
|
||||
<th>改后库存</th>
|
||||
<th>变化量</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<template v-for="(item,index) in list">
|
||||
<tr>
|
||||
<td>{{ item.name }}</td>
|
||||
<td v-if="item.childIdList.length=0">无</td>
|
||||
<td v-else>
|
||||
<el-select
|
||||
v-model="item.childIdList"
|
||||
multiple
|
||||
:teleported="false"
|
||||
style="width: 150px;"
|
||||
collapse-tags
|
||||
popper-class="table-select"
|
||||
:collapse-tags-tooltip="true"
|
||||
>
|
||||
<div class="select-header">
|
||||
<span>批次ID</span>
|
||||
<span>生产批号</span>
|
||||
<span>入库时间</span>
|
||||
<span>有效期</span>
|
||||
<span>进价</span>
|
||||
</div>
|
||||
<el-option
|
||||
v-for="(subItem,subIndex) in item.selectList"
|
||||
:key="subItem.id"
|
||||
:label="subItem.id"
|
||||
:value="subItem.id"
|
||||
disabled
|
||||
>
|
||||
<div class="option-row">
|
||||
<span>{{ subItem.id }}</span>
|
||||
<span>{{ subItem.productionBatchCode }}</span>
|
||||
<span>{{ subItem.productionDate }}</span>
|
||||
<span>{{ subItem.expiryDate }}</span>
|
||||
<span>{{ subItem.purchaseUnitPrice }}</span>
|
||||
</div>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</td>
|
||||
<td>{{ item.minPackagingNumber }}</td>
|
||||
<td>
|
||||
{{ item.before.wholeNumber }}{{ item.packagingUnit }}
|
||||
<template v-if="item.trdnFlag ==1">
|
||||
{{ item.before.fragmentNumber }}{{ item.minPackagingUnit }}
|
||||
</template>
|
||||
</td>
|
||||
<td>
|
||||
{{ item.after.wholeNumber }}{{ item.packagingUnit }}
|
||||
<template v-if="item.trdnFlag ==1">
|
||||
{{ item.after.fragmentNumber }}{{ item.minPackagingUnit }}
|
||||
</template>
|
||||
</td>
|
||||
<td>
|
||||
{{ item.change.wholeNumber }}{{ item.packagingUnit }}
|
||||
<template v-if="item.trdnFlag ==1">
|
||||
{{ item.change.fragmentNumber }}{{ item.minPackagingUnit }}
|
||||
</template>
|
||||
</td>
|
||||
</tr>
|
||||
<template v-for="(subItem,subIndex) in item.children">
|
||||
<tr>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
<td>
|
||||
{{ subItem.before.wholeNumber }}{{ item.packagingUnit }}
|
||||
<template v-if="item.trdnFlag ==1">
|
||||
{{ subItem.before.fragmentNumber }}{{ item.minPackagingUnit }}
|
||||
</template>
|
||||
</td>
|
||||
<td>
|
||||
{{ subItem.after.wholeNumber }}{{ item.packagingUnit }}
|
||||
<template v-if="item.trdnFlag ==1">
|
||||
{{ subItem.after.fragmentNumber }}{{ item.minPackagingUnit }}
|
||||
</template>
|
||||
</td>
|
||||
<td>
|
||||
{{ subItem.change.wholeNumber }}{{ item.packagingUnit }}
|
||||
<template v-if="item.trdnFlag ==1">
|
||||
{{ item.change.fragmentNumber }}{{ item.minPackagingUnit }}
|
||||
</template>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
</template>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bottom">
|
||||
<el-button @click="exit" type="primary">关闭</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.body_wrapper {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
min-height: 0;
|
||||
flex-direction: column;
|
||||
|
||||
.top {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 60px;
|
||||
}
|
||||
|
||||
.content {
|
||||
display: block;
|
||||
width: 100%;
|
||||
flex: 1;
|
||||
//min-height: 0;
|
||||
|
||||
table {
|
||||
//border-collapse: collapse;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
th,
|
||||
td {
|
||||
//border: 1px solid #ccc;
|
||||
padding: 8px;
|
||||
text-align: left;
|
||||
|
||||
}
|
||||
|
||||
th {
|
||||
//background-color: #F9F9F9;
|
||||
}
|
||||
|
||||
/* 可选:为可点击的行添加鼠标悬停效果 */
|
||||
tr:hover {
|
||||
//background-color: #f5f5f5;
|
||||
}
|
||||
}
|
||||
|
||||
.bottom {
|
||||
height: 60px;
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
bottom: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
|
||||
.text {
|
||||
font-size: 16px;
|
||||
width: 200px;
|
||||
color: #6a6a6a;
|
||||
}
|
||||
}
|
||||
|
||||
/* 表格容器 */
|
||||
.simple-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-size: 14px;
|
||||
border: none;
|
||||
color: #606266;
|
||||
|
||||
thead {
|
||||
background-color: #f5f7fa;
|
||||
|
||||
th {
|
||||
padding: 12px 0;
|
||||
text-align: left;
|
||||
font-weight: bold; /* 表头加粗 */
|
||||
font-size: 14px; /* 表头字号 */
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
}
|
||||
}
|
||||
|
||||
tbody {
|
||||
tr:hover {
|
||||
background-color: #f5f7fa; /* 悬停效果 */
|
||||
}
|
||||
|
||||
td {
|
||||
padding: 12px 0;
|
||||
text-align: left;
|
||||
font-size: 14px; /* 单元格字号 */
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.table-select {
|
||||
.el-select-dropdown__item {
|
||||
padding: 0 !important;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
// 表头样式
|
||||
.select-header {
|
||||
display: flex;
|
||||
padding: 8px 16px;
|
||||
background: #f5f7fa;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
|
||||
span {
|
||||
flex: 1;
|
||||
min-width: 110px;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
// 选项行样式
|
||||
.option-row {
|
||||
display: flex;
|
||||
padding: 8px 16px;
|
||||
|
||||
span {
|
||||
flex: 1;
|
||||
min-width: 110px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.remark {
|
||||
// 前置标签背景色
|
||||
:deep(.el-input-group__prepend) {
|
||||
background-color: #fffdec;
|
||||
}
|
||||
|
||||
// 输入框主体背景色
|
||||
:deep(.el-input__wrapper) {
|
||||
background-color: #fffdec;
|
||||
}
|
||||
}
|
||||
|
||||
.bottom {
|
||||
margin-top: 10px;
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
bottom: 10px;
|
||||
}
|
||||
</style>
|
||||
<script setup lang="ts">
|
||||
import {onMounted,defineProps} from "vue";
|
||||
import {post} from "@/utils/request.ts";
|
||||
import {ref} from "vue";
|
||||
const props = defineProps({
|
||||
id: {
|
||||
type: String,
|
||||
default: null
|
||||
}
|
||||
})
|
||||
|
||||
const remark = ref("");
|
||||
interface Check {
|
||||
id?: number,
|
||||
goodsId: number,
|
||||
name: string,
|
||||
minPackagingUnit: string,
|
||||
packagingUnit: string,
|
||||
minPackagingNumber: number,
|
||||
listSize: number,
|
||||
trdnFlag: number,
|
||||
childIdList: number[],
|
||||
before: {
|
||||
wholeNumber: number,
|
||||
fragmentNumber: number,
|
||||
},
|
||||
after: {
|
||||
wholeNumber: number,
|
||||
fragmentNumber: number,
|
||||
},
|
||||
change: {
|
||||
wholeNumber: number,
|
||||
fragmentNumber: number,
|
||||
}
|
||||
children: childCheck[],
|
||||
selectList: seletcType[],
|
||||
}
|
||||
|
||||
interface seletcType {
|
||||
id: number,
|
||||
wholeNumber: number,
|
||||
fragmentNumber: number,
|
||||
productionBatchCode: string,
|
||||
productionDate: string,
|
||||
expiryDate: string,
|
||||
purchaseUnitPrice: string
|
||||
}
|
||||
|
||||
interface childCheck {
|
||||
id?: number,
|
||||
goodsId: number,
|
||||
name: string,
|
||||
minPackagingNumber: number,
|
||||
before: {
|
||||
wholeNumber: number,
|
||||
fragmentNumber: number,
|
||||
},
|
||||
after: {
|
||||
wholeNumber: number,
|
||||
fragmentNumber: number,
|
||||
},
|
||||
change: {
|
||||
wholeNumber: number,
|
||||
fragmentNumber: number,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const list = ref<Check[]>([])
|
||||
const emit = defineEmits(['close'])
|
||||
onMounted(() => {
|
||||
detail()
|
||||
})
|
||||
let exit = () => {
|
||||
emit('close');
|
||||
}
|
||||
const detail = () => {
|
||||
post("inventory/check/getCheckDetail",{id: props.id}).then((res: any) => {
|
||||
list.value = JSON.parse(res);
|
||||
})
|
||||
}
|
||||
|
||||
defineExpose({detail})
|
||||
</script>
|
||||
|
|
@ -0,0 +1,172 @@
|
|||
|
||||
|
||||
<template>
|
||||
<CloseBtn @click="close"></CloseBtn>
|
||||
<!-- <div class="close" @click="close"><el-icon><Close /></el-icon></div>-->
|
||||
<el-table
|
||||
:data="cateList"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-table-column
|
||||
width="200">
|
||||
<template #default="scope">
|
||||
<el-input v-model="scope.row.name" v-if="scope.row.isEdit"></el-input>
|
||||
<span v-else>{{ scope.row.name }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
width="120">
|
||||
<template #default="scope">
|
||||
<div >
|
||||
<div v-if="scope.row.isAdd" style="display: flex;">
|
||||
<el-button type="primary" size="small" @click="saveDo" class="btn">确定</el-button>
|
||||
<el-button size="small" @click="cancelAdd" class="btn">取消</el-button>
|
||||
</div>
|
||||
<div v-else>
|
||||
<span @click="move(-1,scope.row)" class="btn" ><el-icon><ArrowUpBold /></el-icon></span>
|
||||
<span @click="move(1,scope.row)" class="btn"><el-icon><ArrowDownBold /></el-icon></span>
|
||||
<span @click="scope.row.isEdit=true" class="btn" id="edit"><el-icon><Edit /></el-icon></span>
|
||||
<span @click="getCountByCateId(scope.row.id)" class="btn"> <el-icon><Delete /></el-icon></span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-divider/>
|
||||
<el-button type="primary" @click="add" id="add">添加</el-button>
|
||||
<el-button type="primary" @click="save">保存</el-button>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import {onMounted, onUnmounted, ref} from "vue";
|
||||
import {post} from "@/utils/request.ts";
|
||||
import {ElMessageBox} from "element-plus";
|
||||
import CloseBtn from "@/components/CloseBtn.vue";
|
||||
const props = defineProps({
|
||||
type: {
|
||||
type: Number,
|
||||
},
|
||||
})
|
||||
interface CateItem {
|
||||
id?: number;
|
||||
name: string;
|
||||
type: number|undefined;
|
||||
isEdit: boolean;
|
||||
isAdd: boolean;
|
||||
sort: number;
|
||||
}
|
||||
const cateList = ref<CateItem[]>([]);
|
||||
const getCateList = () => {
|
||||
post("goods/cate/list",{type:props.type}).then((res:any)=>{
|
||||
cateList.value=res
|
||||
})
|
||||
}
|
||||
onMounted(()=>{
|
||||
getCateList()
|
||||
document.addEventListener("click", handleClickOutside);
|
||||
})
|
||||
onUnmounted(()=>{
|
||||
document.removeEventListener("click", handleClickOutside);
|
||||
})
|
||||
const handleClickOutside = (event: MouseEvent) => {
|
||||
const target = event.target as HTMLElement;
|
||||
if (!target.closest('.el-input')&&!target.closest('#edit')&&!target.closest('#add')) {
|
||||
cateList.value.forEach(item => {
|
||||
item.isEdit = false;
|
||||
});
|
||||
}
|
||||
};
|
||||
const emit = defineEmits(['close'])
|
||||
const close = () => {
|
||||
emit('close')
|
||||
}
|
||||
const getCountByCateId = (cateId:any)=>{
|
||||
let count =0;
|
||||
post("goods/goods/getByCateId",{cateId:cateId}).
|
||||
then((res:any)=>{
|
||||
count=res
|
||||
ElMessageBox.confirm(
|
||||
`有${count}个西药属于该二级分类,删除后将一同清空西药的分类。是否确定删除?`,
|
||||
'Warning',
|
||||
{
|
||||
confirmButtonText: '确认删除',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
}
|
||||
).then(() => {
|
||||
del(cateId)
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
|
||||
}
|
||||
const del = async (id:any) => {
|
||||
await post("goods/cate/del",{id})
|
||||
getCateList()
|
||||
}
|
||||
const saveDo = async ()=>{
|
||||
cateList.value.forEach((item,index)=>{
|
||||
item.sort=index+1
|
||||
if(item.name === ''){
|
||||
removeItemByIndex(index)
|
||||
}
|
||||
|
||||
})
|
||||
await post("goods/cate/save",{cateList:cateList.value})
|
||||
getCateList()
|
||||
|
||||
|
||||
}
|
||||
const save = ()=>{
|
||||
saveDo()
|
||||
close()
|
||||
}
|
||||
const removeItemByIndex = (index: number) => {
|
||||
if (index >= 0 && index < cateList.value.length) {
|
||||
cateList.value.splice(index, 1);
|
||||
}
|
||||
}
|
||||
// const save = async ()=>{
|
||||
// await post("goods/cate/save",cateList.value)
|
||||
// getCateList()
|
||||
// }
|
||||
|
||||
const add = () => {
|
||||
const newCate: CateItem = {
|
||||
name: '',
|
||||
type: props.type,
|
||||
isEdit: true,
|
||||
isAdd: true,
|
||||
sort: cateList.value.length+1
|
||||
}
|
||||
cateList.value.push(newCate)
|
||||
}
|
||||
//移动 -1上移 1下移
|
||||
const move = (direction:number,row :any)=>{
|
||||
const index = cateList.value.findIndex(item => item.id === row.id);
|
||||
if(index === -1)return;
|
||||
const targetIndex = index + direction;
|
||||
if(targetIndex<0||targetIndex>=cateList.value.length)return;
|
||||
// 交换元素位置
|
||||
[cateList.value[index], cateList.value[targetIndex]] = [cateList.value[targetIndex], cateList.value[index]];
|
||||
console.log(cateList)
|
||||
|
||||
}
|
||||
const cancelAdd = ()=>{
|
||||
cateList.value.pop()
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.close{
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
font-size: 24px;
|
||||
z-index: 1999;
|
||||
}
|
||||
.btn {
|
||||
margin-left: 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||