初始版本,目前线上可用
1
frontEnd/.env.development
Normal file
@@ -0,0 +1 @@
|
||||
VITE_API_BASE_URL = "http://localhost:8101"
|
||||
1
frontEnd/.env.production
Normal file
@@ -0,0 +1 @@
|
||||
VITE_API_BASE_URL = "http://106.52.204.157/api"
|
||||
25
frontEnd/.gitignore
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
.vscode
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
16
frontEnd/README.md
Normal file
@@ -0,0 +1,16 @@
|
||||
# Vue 3 + TypeScript + Vite
|
||||
|
||||
This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
|
||||
|
||||
## Recommended IDE Setup
|
||||
|
||||
- [VS Code](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar)
|
||||
|
||||
## Type Support For `.vue` Imports in TS
|
||||
|
||||
Since TypeScript cannot handle type information for `.vue` imports, they are shimmed to be a generic Vue component type by default. In most cases this is fine if you don't really care about component prop types outside of templates. However, if you wish to get actual prop types in `.vue` imports (for example to get props validation when using manual `h(...)` calls), you can enable Volar's Take Over mode by following these steps:
|
||||
|
||||
1. Run `Extensions: Show Built-in Extensions` from VS Code's command palette, look for `TypeScript and JavaScript Language Features`, then right click and select `Disable (Workspace)`. By default, Take Over mode will enable itself if the default TypeScript extension is disabled.
|
||||
2. Reload the VS Code window by running `Developer: Reload Window` from the command palette.
|
||||
|
||||
You can learn more about Take Over mode [here](https://github.com/johnsoncodehk/volar/discussions/471).
|
||||
17
frontEnd/index.html
Normal file
@@ -0,0 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="./index.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>德孝善延伸服务系统</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<!-- <script src="https://lf1-cdn-tos.bytegoofy.com/obj/iconpark/icons_29405_22.fc87eeefd2303d03e310328c39223ebb.js"></script> -->
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
4232
frontEnd/package-lock.json
generated
Normal file
39
frontEnd/package.json
Normal file
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"name": "basesystemforvue3",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@element-plus/icons-vue": "^2.0.10",
|
||||
"axios": "^1.6.0",
|
||||
"dayjs": "^1.11.5",
|
||||
"echarts": "^5.4.3",
|
||||
"element-china-area-data": "^6.1.0",
|
||||
"element-plus": "^2.8.7",
|
||||
"exceljs": "^4.4.0",
|
||||
"file-saver": "^2.0.5",
|
||||
"html2canvas": "^1.4.1",
|
||||
"js-md5": "^0.8.3",
|
||||
"pinia": "^2.0.22",
|
||||
"print-js": "^1.6.0",
|
||||
"vue": "^3.2.37",
|
||||
"vue-json-excel3": "^1.0.29",
|
||||
"vue-router": "^4.1.5",
|
||||
"vue3-print-nb": "^0.1.4",
|
||||
"xlsx": "^0.20.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/file-saver": "^2.0.7",
|
||||
"@types/node": "^18.8.0",
|
||||
"@vitejs/plugin-vue": "^3.1.0",
|
||||
"sass": "^1.79.3",
|
||||
"typescript": "^4.6.4",
|
||||
"vite": "^3.2.11",
|
||||
"vue-tsc": "^0.40.4"
|
||||
}
|
||||
}
|
||||
1
frontEnd/public/assets/icon/作废.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1747273996941" class="icon" viewBox="0 0 1092 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="20912" xmlns:xlink="http://www.w3.org/1999/xlink" width="213.28125" height="200"><path d="M443.733333 955.733333H136.533333c-40.96 0-68.266667-27.306667-68.266666-68.266666V136.533333c0-40.96 27.306667-68.266667 68.266666-68.266666h614.4c40.96 0 68.266667 27.306667 68.266667 68.266666v170.666667c0 20.48 13.653333 34.133333 34.133333 34.133333s34.133333-13.653333 34.133334-34.133333V136.533333c0-75.093333-61.44-136.533333-136.533334-136.533333H136.533333C61.44 0 0 61.44 0 136.533333v750.933334c0 75.093333 61.44 136.533333 136.533333 136.533333h307.2c20.48 0 34.133333-13.653333 34.133334-34.133333s-13.653333-34.133333-34.133334-34.133334z" fill="#777777" p-id="20913"></path><path d="M682.666667 307.2c0-20.48-13.653333-34.133333-34.133334-34.133333h-409.6c-20.48 0-34.133333 13.653333-34.133333 34.133333s13.653333 34.133333 34.133333 34.133333h409.6c20.48 0 34.133333-13.653333 34.133334-34.133333zM238.933333 477.866667c-20.48 0-34.133333 13.653333-34.133333 34.133333s13.653333 34.133333 34.133333 34.133333h204.8c20.48 0 34.133333-13.653333 34.133334-34.133333S464.213333 477.866667 443.733333 477.866667h-204.8zM785.066667 409.6C614.4 409.6 477.866667 546.133333 477.866667 716.8S614.4 1024 785.066667 1024s307.2-136.533333 307.2-307.2S955.733333 409.6 785.066667 409.6z m0 546.133333C655.36 955.733333 546.133333 846.506667 546.133333 716.8S655.36 477.866667 785.066667 477.866667 1024 587.093333 1024 716.8 914.773333 955.733333 785.066667 955.733333z" fill="#777777" p-id="20914"></path><path d="M907.946667 600.746667c-13.653333-13.653333-34.133333-13.653333-47.786667 0l-75.093333 75.093333-75.093334-75.093333c-13.653333-13.653333-34.133333-13.653333-47.786666 0s-13.653333 34.133333 0 47.786666l75.093333 75.093334-75.093333 75.093333c-13.653333 13.653333-13.653333 34.133333 0 47.786667 13.653333 13.653333 34.133333 13.653333 47.786666 0l75.093334-75.093334 75.093333 75.093334c13.653333 13.653333 34.133333 13.653333 47.786667 0 13.653333-13.653333 13.653333-34.133333 0-47.786667l-75.093334-75.093333 75.093334-75.093334c13.653333-13.653333 13.653333-34.133333 0-47.786666z" fill="#777777" p-id="20915"></path></svg>
|
||||
|
After Width: | Height: | Size: 2.3 KiB |
1
frontEnd/public/assets/icon/打印机.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1747273678337" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="12063" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M810.6496 341.3504H213.3504a128 128 0 0 0-128 128v256a85.3504 85.3504 0 0 0 85.2992 85.2992h21.3504V768a128 128 0 0 1 128-128h384a128 128 0 0 1 128 128v42.6496h21.3504a85.3504 85.3504 0 0 0 85.2992-85.2992v-256a128 128 0 0 0-128-128zM768 554.6496a64 64 0 1 1 0-128 64 64 0 0 1 0 128z" fill="#A1A5B3" p-id="12064"></path><path d="M704 746.6496c11.776 0 21.3504 9.5744 21.3504 21.3504v106.6496c0 11.776-9.5744 21.3504-21.3504 21.3504h-384a21.3504 21.3504 0 0 1-21.3504-21.3504V768c0-11.776 9.5744-21.3504 21.3504-21.3504h384m0-64h-384c-47.104 0-85.3504 38.2464-85.3504 85.3504v106.6496c0 47.104 38.2464 85.3504 85.3504 85.3504h384c47.104 0 85.3504-38.1952 85.3504-85.3504V768c0-47.104-38.2464-85.3504-85.3504-85.3504z m85.3504-384H234.6496V192a128 128 0 0 1 128-128h298.7008a128 128 0 0 1 128 128v106.6496z" fill="#C2C4CC" p-id="12065"></path><path d="M650.6496 853.3504H373.3504a32 32 0 0 1 0-64h277.2992a32 32 0 1 1 0 64z" fill="#C2C4CC" p-id="12066"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
1
frontEnd/public/assets/icon/日收入.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1747275888152" class="icon" viewBox="0 0 1025 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="37586" xmlns:xlink="http://www.w3.org/1999/xlink" width="200.1953125" height="200"><path d="M658.285714 475.428571c10.971429 0 18.285714-7.314286 18.285715-18.285714s-7.314286-18.285714-18.285715-18.285714h-65.828571l58.514286-58.514286c7.314286-7.314286 7.314286-18.285714 0-25.6-7.314286-7.314286-18.285714-7.314286-25.6 0L541.257143 438.857143h-21.942857l-84.114286-84.114286c-7.314286-7.314286-18.285714-7.314286-25.6 0-7.314286 7.314286-7.314286 18.285714 0 25.6l58.514286 58.514286H402.285714c-10.971429 0-18.285714 7.314286-18.285714 18.285714s7.314286 18.285714 18.285714 18.285714h109.714286v73.142858h-109.714286c-10.971429 0-18.285714 7.314286-18.285714 18.285714s7.314286 18.285714 18.285714 18.285714h109.714286v91.428572c0 10.971429 7.314286 18.285714 18.285714 18.285714s18.285714-7.314286 18.285715-18.285714V585.142857h109.714285c10.971429 0 18.285714-7.314286 18.285715-18.285714s-7.314286-18.285714-18.285715-18.285714h-109.714285v-73.142858h109.714285z" p-id="37587"></path><path d="M983.771429 548.571429h-73.142858V219.428571c0-40.228571-32.914286-73.142857-73.142857-73.142857H223.085714c-40.228571 0-73.142857 32.914286-73.142857 73.142857v329.142858h-73.142857c-40.228571 0-51.2 25.6-21.942857 54.857142l435.2 398.628572c14.628571 14.628571 32.914286 21.942857 51.2 21.942857s36.571429-7.314286 51.2-21.942857l424.228571-398.628572c18.285714-29.257143 7.314286-54.857143-32.914285-54.857142zM559.542857 976.457143c-7.314286 7.314286-14.628571 10.971429-21.942857 10.971428s-18.285714-3.657143-21.942857-10.971428L87.771429 585.142857h98.742857V219.428571c0-21.942857 14.628571-36.571429 36.571428-36.571428H841.142857c21.942857 0 36.571429 14.628571 36.571429 36.571428v365.714286h98.742857L559.542857 976.457143z" p-id="37588"></path></svg>
|
||||
|
After Width: | Height: | Size: 2.0 KiB |
1
frontEnd/public/assets/icon/服务.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1747273925868" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="19834" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M899.584 254.976h-1.024c-3.072-0.512-5.632-0.512-8.704-0.512-27.64288 0-50.68288 16.384-60.416 43.008l-50.176 155.648c-8.19712-3.072-16.896-4.608-26.11712-4.608-14.336 0-28.672 3.584-43.00288 11.264l-163.328 87.04c-13.824 7.168-25.6 17.92-35.328 31.23712-9.728-13.31712-22.016-24.064-35.328-31.23712L312.32 459.264c-14.336-7.68-28.672-11.264-43.008-11.264-9.216 0-17.92 1.536-26.112 4.608L193.024 296.96c-9.216-26.624-32.256-43.008-60.416-43.008-3.072 0-5.632 0-8.704 0.512H122.88c-26.624 4.608-55.296 29.696-55.808 74.24v0.512l7.168 193.536c0 29.70112 9.728 60.928 28.672 91.648 10.24 16.384 23.04 30.208 35.328 43.52l0.512 0.512 99.328 95.744c18.432 17.92 36.352 34.304 48.128 53.76l79.36 129.19296c5.632 9.216 15.36 14.84288 25.6 14.84288 5.632 0 11.264-1.536 16.384-4.60288 14.848-9.22112 18.944-27.14112 9.728-41.984L336.384 773.12c-15.36-25.088-35.84-45.056-56.832-65.536l-98.304-95.232c-29.184-29.17888-46.08-64-47.104-94.72l-7.168-193.536c0-3.584 0.512-9.728 5.632-10.752h0.512c0 0.512 0.512 0.512 0.512 1.024l56.32 176.128 3.072 13.824c3.072 20.48 8.192 43.008 37.888 70.656 4.096 5.63712 9.728 9.728 12.8 11.776l57.344 45.568c7.168 6.144 14.336 7.168 19.456 7.168 8.704 0 16.896-4.10112 22.528-11.264 11.264-13.31712 9.728-31.23712-3.584-41.984l-58.88-46.592c-18.432-14.34112-21.504-25.6-20.992-28.67712 1.536-1.536 4.608-2.56 7.68-2.56 4.096 0 9.728 1.536 14.336 4.096l163.328 87.04c20.48 12.288 32.256 45.06112 31.744 70.144l2.048 96.256v0.51712c0.512 6.144 3.072 11.776 7.168 16.384 4.608 5.632 11.264 9.72288 18.432 11.25888l4.608 1.024h1.024l4.608-1.024c7.168-1.536 13.824-5.632 18.432-11.25888 4.10112-4.608 6.66112-10.75712 7.168-16.384v-0.512l2.048-96.256c0-25.08288 11.776-57.856 31.73888-70.144l162.82112-87.04c5.632-2.56 10.752-4.096 14.84288-4.096 3.07712 0 6.144 1.024 7.68 2.56 0 3.072-2.56 13.824-20.992 28.67712l-58.88 46.592c-13.31712 11.264-14.848 28.672-3.584 41.984 6.144 7.16288 14.336 11.264 22.528 11.264 4.60288 0 11.776-1.024 19.456-7.168l57.344-45.568c3.072-2.04288 8.69888-6.13888 12.8-11.776 29.17888-27.64288 34.816-50.176 37.88288-70.656l3.07712-13.824 56.32-175.616c0.512-1.024 0.512-1.536 1.01888-1.536h1.024c4.608 0.512 5.12 6.656 5.12 10.752l-7.16288 193.536c-1.024 30.72-17.92 65.024-46.59712 94.208l-98.304 95.232C718.848 727.04 698.88 747.52 683.008 772.608l-77.99296 132.77184c-9.216 14.848-4.608 32.768 10.24 41.984 5.12 3.07712 10.752 4.608 16.384 4.608 10.24 0 19.96288-5.63712 25.6-14.848L733.696 807.424c11.776-19.456 29.696-35.84 48.128-53.76l98.816-95.232 1.024-1.01888c12.28288-13.31712 25.08288-27.14112 35.32288-43.52C935.424 583.68 945.664 551.936 945.664 522.24l7.16288-193.536V327.68c2.05312-42.496-26.61888-68.096-53.24288-72.704z" p-id="19835"></path><path d="M512.24064 518.656c-5.31968 0-10.22976-1.4592-15.45216-4.58752-9.45152-5.7344-232.07424-142.30528-233.53856-288.99328 0-85.68832 56.13056-155.4432 144.01024-155.4432 29.07648 0 72.43264 38.2976 96.32256 52.62848l7.79264 4.67456 7.84384-4.57728c25.0368-14.60224 67.69664-52.72576 96.49664-52.72576 87.87456 0 144.00512 69.80096 144.00512 155.5968 0 146.42176-222.62272 283.13088-232.09984 288.87552a27.52 27.52 0 0 1-15.38048 4.55168zM408.0128 129.28512c-54.56384 0-83.59936 43.03872-83.59936 95.94368 0 73.06752 96.49664 165.2736 179.12832 222.03392l8.69888 5.97504 8.69888-5.97504c82.6368-56.7552 179.12832-148.96128 179.12832-222.03392 0-52.90496-29.36832-95.94368-84.352-95.94368-25.10848 0-64.72704 40.15616-83.6608 57.28256-5.44768 5.1968-12.29824 7.89504-19.9168 7.89504a30.16704 30.16704 0 0 1-20.42368-7.84896c-18.9696-17.16224-58.5984-57.32864-83.70176-57.32864z" p-id="19836"></path></svg>
|
||||
|
After Width: | Height: | Size: 3.9 KiB |
1
frontEnd/public/assets/icon/登记.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1747275042139" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="25426" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M944.014 711.668L798.505 857.177 696.633 959.053h-96.869a30.514 30.514 0 0 1-30.293-30.3v-97.1l101.757-101.755 145.51-145.51a50 50 0 0 1 70.711 0l56.565 56.565a50 50 0 0 1 0 70.715z m-63.639-49.5l-14.142-14.142a20 20 0 0 0-28.285 0l-208.477 208.48v42.547h42.309l208.6-208.6a20 20 0 0 0-0.005-28.283z m-35.047-150.215a30 30 0 0 1-30-30v-337a20 20 0 0 0-20-20h-650a20 20 0 0 0-20 20v734a20 20 0 0 0 20 20h306a30 30 0 0 1 0 60h-336a50 50 0 0 1-50-50v-794a50 50 0 0 1 50-50h710a50 50 0 0 1 50 50v367a30 30 0 0 1-30 30z m-629-145.021a29.979 29.979 0 0 1 29.979-29.979h448.042a29.979 29.979 0 1 1 0 59.957H246.307a29.979 29.979 0 0 1-29.979-29.978z m365.021 175.021H246.307a29.979 29.979 0 0 1-29.979-29.979v-0.042a29.979 29.979 0 0 1 29.979-29.979h335.042a29.979 29.979 0 0 1 29.979 29.979v0.042a29.979 29.979 0 0 1-29.979 29.979z m-335.042 145a29.979 29.979 0 1 1 0-59.957h221.226a29.979 29.979 0 1 1 0 59.957H246.307z" fill="#333333" p-id="25427"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
1
frontEnd/public/assets/icon/结算.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1747275059293" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="26485" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M260.125 588.88l546.277 0 0 50.089-546.277 0 0-50.089zM258.793 781.037l546.272 0 1.266 53.712-546.206 0-1.331-53.712zM553.801 392.334l252.6 0 0 50.914-252.6 0 0-50.914zM608.075 195.662l198.326 0 0 51.863-198.326 0 0-51.863zM851.983 992l-662.768 0c-43.677 0-79.163-37.266-79.163-82.977l0-794.046c0-45.712 35.486-82.977 79.163-82.977l662.768 0c43.677 0 79.162 37.266 79.162 82.977l0 793.985c0 45.773-35.55 83.038-79.162 83.038l0 0 0 0 0 0zM178.994 82.215c-8.952 0-16.444 9.398-16.444 20.444l0 818.68c0 11.113 7.555 20.444 16.444 20.444l683.271 0c8.952 0 16.442-9.398 16.442-20.444l0-818.68c0-11.11-7.555-20.444-16.442-20.444l-683.271 0zM473.112 340.084c7.173 12.253 10.857 26.603 10.857 43.044 0 25.141-7.492 46.149-22.474 62.915-15.047 16.758-36.63 26.722-65.007 29.706l0 43.107-36.058 0 0-42.915c-47.169-4.888-76.434-32.314-87.67-82.271l55.8-14.604c5.143 31.426 22.221 47.169 51.298 47.169 13.582 0 23.615-3.366 30.026-10.096 6.412-6.788 9.651-14.853 9.651-24.377 0-9.904-3.239-17.33-9.651-22.347-6.348-5.08-20.632-11.487-42.66-19.297-19.808-6.918-35.362-13.714-46.534-20.505-11.11-6.667-20.188-16.062-27.17-28.184-6.983-12.127-10.412-26.284-10.412-42.282 0-21.074 6.282-40.122 18.666-56.943 12.504-16.887 31.99-27.235 58.719-30.981l0-33.265 36.058 0 0 33.265c40.313 4.827 66.47 27.615 78.405 68.434l-49.837 20.441c-9.712-27.992-24.63-42.024-45.01-42.024-10.157 0-18.347 3.113-24.44 9.397-6.219 6.282-9.332 13.84-9.332 22.727 0 9.076 2.981 15.998 8.952 20.885 5.966 4.824 18.661 10.857 38.214 17.967 21.396 7.81 38.283 15.3 50.407 22.155 12.19 6.982 21.839 16.63 29.202 28.882l0 0 0 0 0 0z" fill="#272636" p-id="26486"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.9 KiB |
1
frontEnd/public/assets/icon/结账.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1747273710053" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="13144" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M221.3 954.9c-24.7 0-47.6-10.3-64.6-29.1C139.5 906.9 130 881 130 853V655.3H71.4c-2.7 0-4.8-2.5-4.8-5.6v-46.5c0-3.1 2.2-5.6 4.8-5.6H130V429.1H71.4c-2.7 0-4.8-2.5-4.8-5.6V377c0-3.1 2.2-5.6 4.8-5.6H130v-194c0-58.9 40.9-106.7 91.2-106.7h639.3c50.3 0 91.2 47.9 91.2 106.7l-1 624V853c0 28.1-9.4 53.9-26.6 72.8-17 18.7-40 29.1-64.6 29.1H221.3zM758.8 873c0 4.7-0.2 9.4-0.6 14l-0.8 9.7h102.2c23.8 0 42.5-19.2 42.5-43.7v-14.9l-1-660.8c0-26.1-18.1-47.3-40.4-47.3H758.8v743z m-578-20c0 25.3 17 43.7 40.4 43.7H711l-0.8-9.7c-0.4-4.7-0.6-9.3-0.6-14V130H221.3c-22.3 0-40.4 21.2-40.4 47.3v194h57.6c2.7 0 4.8 2.5 4.8 5.6v46.5c0 3.1-2.2 5.6-4.8 5.6h-57.6v168.5h57.6c2.7 0 4.8 2.5 4.8 5.6v46.5c0 3.1-2.2 5.6-4.8 5.6h-57.6V853z m0 0" fill="" p-id="13145"></path><path d="M580.9 505c8.2 0 14.8-11.7 14.8-20.4 0-8.6-6.6-20.4-14.8-20.4h-61.2l44.7-84.8c1.1-3.9-3.4-17.1-10.6-21.3-7.1-4.2-18.6-1.5-22.6 6.1l-52.7 100.1H475l-52.7-100.1c-6.6-11.5-16.2-10.3-23.4-6.1-7.1 4.2-11.6 15.4-10.6 21.3l44.6 84.8h-64.7c-8.2 0-14.8 11.7-14.8 20.4 0 8.6 6.6 20.4 14.8 20.4H458v52.1h-89.8c-8.2 0-14.8 11.7-14.8 20.4 0 8.6 6.6 20.4 14.8 20.4H458v63.3c0 8.6 9.9 15.7 18 15.7 8.2 0 18-7 18-15.7v-63.3h86.6c8.2 0 14.8-11.7 14.8-20.4 0-8.6-6.6-20.4-14.8-20.4H494V505h86.9z m0 0" fill="" p-id="13146"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
1
frontEnd/public/assets/icon/统计.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1747275431177" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="30181" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M856.71 784.19H167.86v-640a8 8 0 0 0-8-8h-40a8 8 0 0 0-8 8v688c0 4.42 3.2 8 7.14 8h737.71c3.94 0 7.14-3.58 7.14-8v-40c0.01-4.42-3.19-8-7.14-8z" p-id="30182"></path><path d="M280.73 625.25L247 591.12a8 8 0 0 1 0.06-11.31l256.62-253.75a8 8 0 0 1 11.28 0L658.7 469.79a8 8 0 0 0 11.21 0.1l190-183.19a8 8 0 0 1 11.31 0.21l33.32 34.55a8 8 0 0 1-0.21 11.31l-235.2 226.8a8 8 0 0 1-11.21-0.1L514.71 416.34a8 8 0 0 0-11.28 0L292 625.32a8 8 0 0 1-11.27-0.07z" p-id="30183"></path></svg>
|
||||
|
After Width: | Height: | Size: 809 B |
1
frontEnd/public/assets/icon/销售明细.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1747275809833" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="34834" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M721.175273 116.503273a186.181818 186.181818 0 0 1 186.181818 186.181818v418.909091a186.181818 186.181818 0 0 1-186.181818 186.181818h-418.909091a186.181818 186.181818 0 0 1-186.181818-186.181818v-418.909091a186.181818 186.181818 0 0 1 186.181818-186.181818h418.909091z m0 69.818182h-418.909091a116.363636 116.363636 0 0 0-116.130909 108.730181l-0.232728 7.633455v418.909091a116.363636 116.363636 0 0 0 108.683637 116.130909l7.68 0.232727h418.909091a116.363636 116.363636 0 0 0 116.084363-108.730182l0.279273-7.633454v-418.909091a116.363636 116.363636 0 0 0-108.730182-116.130909l-7.633454-0.232727z m-11.357091 430.405818a34.909091 34.909091 0 0 1 0 69.818182h-279.272727a34.909091 34.909091 0 1 1 0-69.818182h279.272727z m-395.636364 0a34.909091 34.909091 0 1 1 0 69.818182 34.909091 34.909091 0 0 1 0-69.818182z m395.636364-139.636364a34.909091 34.909091 0 0 1 0 69.818182h-279.272727a34.909091 34.909091 0 1 1 0-69.818182h279.272727z m-395.636364 0a34.909091 34.909091 0 1 1 0 69.818182 34.909091 34.909091 0 0 1 0-69.818182z m395.636364-139.636364a34.909091 34.909091 0 0 1 0 69.818182h-279.272727a34.909091 34.909091 0 1 1 0-69.818182h279.272727z m-395.636364 0a34.909091 34.909091 0 1 1 0 69.818182 34.909091 34.909091 0 0 1 0-69.818182z" fill="#353B5E" p-id="34835"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
1
frontEnd/public/assets/icon/销售统计.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1747275770123" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="32916" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M259.584 656.896v58.368c0 29.184 17.408 53.248 38.912 53.248 21.504 0 38.912-24.064 38.912-53.248v-57.856c0-29.184-17.408-53.248-38.912-53.248-21.504-0.512-38.912 23.552-38.912 52.736zM482.816 768c22.016 0 39.424-19.456 39.424-43.008v-207.36c0-23.552-17.92-43.008-39.424-43.008-22.016 0-39.424 19.456-39.424 43.008v207.36c-0.512 23.552 17.408 43.008 39.424 43.008z" p-id="32917"></path><path d="M820.736 81.408h-294.4c-17.92 0-33.28 15.872-33.28 34.304s15.36 34.304 33.28 34.304h294.4c31.232 0 55.296 25.088 55.296 57.344v617.472c0 32.256-24.064 57.344-55.296 57.344H193.536c-31.232 0-55.296-25.088-55.296-57.344v-305.152c0-18.432-15.36-34.304-33.28-34.304s-33.28 15.872-33.28 34.304v305.152c0 69.12 55.296 126.464 121.856 126.464h627.2c66.56 0 121.856-57.344 121.856-126.464V208.384c0-69.12-55.296-126.976-121.856-126.976z" p-id="32918"></path><path d="M719.872 714.752V343.04c0-29.184-17.408-53.248-39.424-53.248-21.504 0-39.424 24.064-39.424 53.248v371.712c0 29.184 17.408 53.248 39.424 53.248 21.504 0 39.424-24.064 39.424-53.248zM136.192 201.728H112.64c-8.704 0-16.384 3.072-23.04 9.216-6.656 6.144-9.728 14.336-9.728 23.04 0 9.216 3.584 17.408 9.728 23.552 6.656 6.144 14.336 9.216 23.04 9.216h43.52v89.088c0 8.704 3.072 16.384 9.216 23.04 6.144 6.656 14.336 9.728 23.04 9.728 8.704 0 16.896-3.584 23.04-9.728 6.144-6.144 9.728-14.336 9.728-23.04V266.752h43.52c8.704 0 16.384-3.072 22.528-9.216 6.144-6.144 9.216-14.336 9.216-23.552 0-8.704-3.072-16.384-9.216-22.528-6.144-6.144-13.824-9.216-22.528-9.216h-23.04l51.2-61.44c6.144-6.656 8.704-14.848 7.68-23.552-1.024-8.704-4.608-15.872-11.264-22.016-6.144-5.12-12.8-7.68-20.48-7.68h-3.584c-8.704 1.024-16.384 5.12-21.504 11.776L188.416 163.84 134.144 98.816c-5.632-6.656-13.312-10.752-22.016-11.776h-3.584c-7.68 0-14.848 2.56-20.48 8.192-6.144 5.632-10.24 13.312-10.752 22.016-1.024 8.704 1.536 16.896 6.656 23.552l52.224 60.928z" p-id="32919"></path></svg>
|
||||
|
After Width: | Height: | Size: 2.2 KiB |
1
frontEnd/public/assets/icon/零售.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1747273771618" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="16143" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M706.56 343.04v81.92h-76.8V343.04H399.36v81.92H317.44V343.04H194.56v537.6h640V343.04h-128zM317.44 266.24v-15.36c0-102.4 87.04-189.44 194.56-189.44s194.56 87.04 194.56 189.44v15.36H870.4c20.48 0 40.96 15.36 40.96 40.96v614.4c0 20.48-15.36 40.96-40.96 40.96H153.6c-20.48 0-40.96-15.36-40.96-40.96V307.2c0-20.48 15.36-40.96 40.96-40.96h163.84z m81.92 0h230.4v-15.36c0-61.44-51.2-112.64-112.64-112.64s-112.64 51.2-112.64 112.64v15.36h-5.12z" p-id="16144"></path></svg>
|
||||
|
After Width: | Height: | Size: 798 B |
1
frontEnd/public/assets/icon/零售管理.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1747275013441" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="23438" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M585.64608 594.3296h-188.416c-16.384 0-28.672 12.288-28.672 28.672v258.048h245.76v-258.048c0-16.384-12.288-28.672-28.672-28.672z m-12.288 40.96v204.8h-163.84v-204.8h163.84z" p-id="23439"></path><path d="M163.75808 573.8496v245.76c0 8.192 8.192 16.384 16.384 20.48h618.496c8.192 0 16.384-8.192 20.48-16.384v-249.856h40.96v245.76c0 32.768-24.576 57.344-57.344 61.44h-618.496c-32.768 0-57.344-24.576-61.44-57.344v-249.856h40.96zM782.25408 123.2896c16.384 0 28.672 8.192 36.864 20.48l4.096 4.096 73.728 167.936-36.864 16.384-73.728-167.936-4.096-4.096h-581.632-4.096l-73.728 176.128-40.96-16.384 73.728-167.936c8.192-16.384 24.576-24.576 40.96-28.672H782.25408z" p-id="23440"></path><path d="M876.46208 270.7456c20.48 40.96 32.768 69.632 36.864 94.208 4.096 32.768-8.192 69.632-40.96 90.112-61.44 36.864-114.688 28.672-155.648-20.48l-4.096-4.096c-20.48 32.768-49.152 49.152-86.016 53.248h-8.192c-36.864 0-69.632-20.48-98.304-57.344l-4.096-8.192-4.096 4.096c-24.576 36.864-53.248 53.248-86.016 57.344h-8.192c-36.864 0-73.728-20.48-114.688-65.536l-8.192-8.192v4.096c-28.672 36.864-61.44 57.344-94.208 61.44h-8.192c-65.536 12.288-126.976-36.864-126.976-86.016 0-16.384 8.192-40.96 20.48-73.728l8.192-20.48c0-4.096 4.096-8.192 4.096-12.288l8.192-8.192 36.864 16.384-12.288 20.48-4.096 16.384-8.192 16.384c-8.192 20.48-12.288 36.864-12.288 45.056 0 20.48 40.96 53.248 77.824 49.152 32.768-4.096 61.44-24.576 86.016-61.44l4.096-8.192 16.384-24.576 20.48 20.48c40.96 53.248 77.824 77.824 106.496 77.824 24.576 0 49.152-20.48 73.728-61.44l4.096-8.192 20.48-36.864 16.384 36.864c28.672 49.152 53.248 73.728 86.016 73.728 28.672 0 53.248-16.384 69.632-57.344l4.096-8.192 16.384-36.864 20.48 36.864c32.768 61.44 69.632 73.728 118.784 40.96 16.384-12.288 24.576-28.672 24.576-49.152 0-12.288-8.192-28.672-20.48-53.248l-8.192-20.48-4.096-8.192 36.864-16.384z" p-id="23441"></path><path d="M143.36 593.18272c12.288 0 20.48-8.192 20.48-20.48s-8.192-20.48-20.48-20.48-20.48 8.192-20.48 20.48 8.192 20.48 20.48 20.48zM839.68 593.18272c12.288 0 20.48-8.192 20.48-20.48s-8.192-20.48-20.48-20.48-20.48 8.192-20.48 20.48 8.192 20.48 20.48 20.48z" p-id="23442"></path></svg>
|
||||
|
After Width: | Height: | Size: 2.4 KiB |
1
frontEnd/public/assets/images/Excel.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1746776612034" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3346" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M0 0m184.32 0l655.36 0q184.32 0 184.32 184.32l0 655.36q0 184.32-184.32 184.32l-655.36 0q-184.32 0-184.32-184.32l0-655.36q0-184.32 184.32-184.32Z" fill="#FFFFFF" p-id="3347"></path><path d="M266.24 512h276.48v163.84h-276.48z" fill="#2D5B3A" p-id="3348"></path><path d="M542.72 512h276.48v163.84h-276.48zM266.24 348.16h276.48v163.84h-276.48z" fill="#387A47" p-id="3349"></path><path d="M542.72 348.16h276.48v163.84h-276.48z" fill="#4FA16B" p-id="3350"></path><path d="M266.24 675.84h552.96v122.88a40.96 40.96 0 0 1-40.96 40.96h-471.04a40.96 40.96 0 0 1-40.96-40.96v-122.88z" fill="#2D5B3A" p-id="3351"></path><path d="M307.2 184.32h235.52v163.84h-276.48v-122.88a40.96 40.96 0 0 1 40.96-40.96z" fill="#4FA16B" p-id="3352"></path><path d="M81.92 327.68m40.96 0l286.72 0q40.96 0 40.96 40.96l0 286.72q0 40.96-40.96 40.96l-286.72 0q-40.96 0-40.96-40.96l0-286.72q0-40.96 40.96-40.96Z" fill="#357541" p-id="3353"></path><path d="M542.72 184.32h235.52a40.96 40.96 0 0 1 40.96 40.96v122.88h-276.48v-163.84z" fill="#63C187" p-id="3354"></path><path d="M174.17216 410.89024l63.93856 100.05504-64.29696 102.16448h45.7728l44.032-70.77888h1.44384l44.36992 70.77888h48.128l-65.44384-102.16448 66.56-100.05504h-47.43168l-42.60864 72.76544h-1.82272l-42.82368-72.76544z" fill="#FFFFFF" p-id="3355"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
BIN
frontEnd/public/assets/images/defaultImg.png
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
frontEnd/public/assets/images/qinWei.jpg
Normal file
|
After Width: | Height: | Size: 1.3 MiB |
BIN
frontEnd/public/excelTemple/日收入统计.xlsx
Normal file
BIN
frontEnd/public/excelTemple/销售明细.xlsx
Normal file
BIN
frontEnd/public/index.ico
Normal file
|
After Width: | Height: | Size: 91 KiB |
14
frontEnd/src/App.vue
Normal file
@@ -0,0 +1,14 @@
|
||||
<template>
|
||||
<div class="view-content">
|
||||
<router-view></router-view>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
</script>
|
||||
<style scoped>
|
||||
.view-content {
|
||||
min-height: 100vh;
|
||||
min-width: 100vw;
|
||||
}
|
||||
|
||||
</style>
|
||||
540
frontEnd/src/assets/css/aliIcon/demo.css
Normal file
@@ -0,0 +1,540 @@
|
||||
/* Logo 字体 */
|
||||
@font-face {
|
||||
font-family: "iconfont logo";
|
||||
src: url("https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834");
|
||||
src: url("https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix")
|
||||
format("embedded-opentype"),
|
||||
url("https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834")
|
||||
format("woff"),
|
||||
url("https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834")
|
||||
format("truetype"),
|
||||
url("https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont")
|
||||
format("svg");
|
||||
}
|
||||
|
||||
.logo {
|
||||
font-family: "iconfont logo";
|
||||
font-size: 160px;
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
/* tabs */
|
||||
.nav-tabs {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.nav-tabs .nav-more {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
height: 42px;
|
||||
line-height: 42px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
#tabs {
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
#tabs li {
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
border-bottom: 2px solid transparent;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
margin-bottom: -1px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
#tabs .active {
|
||||
border-bottom-color: #f00;
|
||||
color: #222;
|
||||
}
|
||||
|
||||
.tab-container .content {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* 页面布局 */
|
||||
.main {
|
||||
padding: 30px 100px;
|
||||
width: 960px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.main .logo {
|
||||
color: #333;
|
||||
text-align: left;
|
||||
margin-bottom: 30px;
|
||||
line-height: 1;
|
||||
height: 110px;
|
||||
margin-top: -50px;
|
||||
overflow: hidden;
|
||||
*zoom: 1;
|
||||
}
|
||||
|
||||
.main .logo a {
|
||||
font-size: 160px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.helps {
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.helps pre {
|
||||
padding: 20px;
|
||||
margin: 10px 0;
|
||||
border: solid 1px #e7e1cd;
|
||||
background-color: #fffdef;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.icon_lists {
|
||||
width: 100% !important;
|
||||
overflow: hidden;
|
||||
*zoom: 1;
|
||||
}
|
||||
|
||||
.icon_lists li {
|
||||
width: 100px;
|
||||
margin-bottom: 10px;
|
||||
margin-right: 20px;
|
||||
text-align: center;
|
||||
list-style: none !important;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.icon_lists li .code-name {
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.icon_lists .icon {
|
||||
display: block;
|
||||
height: 100px;
|
||||
line-height: 100px;
|
||||
font-size: 42px;
|
||||
margin: 10px auto;
|
||||
color: #333;
|
||||
-webkit-transition: font-size 0.25s linear, width 0.25s linear;
|
||||
-moz-transition: font-size 0.25s linear, width 0.25s linear;
|
||||
transition: font-size 0.25s linear, width 0.25s linear;
|
||||
}
|
||||
|
||||
.icon_lists .icon:hover {
|
||||
font-size: 100px;
|
||||
}
|
||||
|
||||
.icon_lists .svg-icon {
|
||||
/* 通过设置 font-size 来改变图标大小 */
|
||||
width: 1em;
|
||||
/* 图标和文字相邻时,垂直对齐 */
|
||||
vertical-align: -0.15em;
|
||||
/* 通过设置 color 来改变 SVG 的颜色/fill */
|
||||
fill: currentColor;
|
||||
/* path 和 stroke 溢出 viewBox 部分在 IE 下会显示
|
||||
normalize.css 中也包含这行 */
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.icon_lists li .name,
|
||||
.icon_lists li .code-name {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
/* markdown 样式 */
|
||||
.markdown {
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
.highlight {
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.markdown img {
|
||||
vertical-align: middle;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.markdown h1 {
|
||||
color: #404040;
|
||||
font-weight: 500;
|
||||
line-height: 40px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.markdown h2,
|
||||
.markdown h3,
|
||||
.markdown h4,
|
||||
.markdown h5,
|
||||
.markdown h6 {
|
||||
color: #404040;
|
||||
margin: 1.6em 0 0.6em 0;
|
||||
font-weight: 500;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.markdown h1 {
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
.markdown h2 {
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
.markdown h3 {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.markdown h4 {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.markdown h5 {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.markdown h6 {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.markdown hr {
|
||||
height: 1px;
|
||||
border: 0;
|
||||
background: #e9e9e9;
|
||||
margin: 16px 0;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.markdown p {
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
.markdown > p,
|
||||
.markdown > blockquote,
|
||||
.markdown > .highlight,
|
||||
.markdown > ol,
|
||||
.markdown > ul {
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
.markdown ul > li {
|
||||
list-style: circle;
|
||||
}
|
||||
|
||||
.markdown > ul li,
|
||||
.markdown blockquote ul > li {
|
||||
margin-left: 20px;
|
||||
padding-left: 4px;
|
||||
}
|
||||
|
||||
.markdown > ul li p,
|
||||
.markdown > ol li p {
|
||||
margin: 0.6em 0;
|
||||
}
|
||||
|
||||
.markdown ol > li {
|
||||
list-style: decimal;
|
||||
}
|
||||
|
||||
.markdown > ol li,
|
||||
.markdown blockquote ol > li {
|
||||
margin-left: 20px;
|
||||
padding-left: 4px;
|
||||
}
|
||||
|
||||
.markdown code {
|
||||
margin: 0 3px;
|
||||
padding: 0 5px;
|
||||
background: #eee;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.markdown strong,
|
||||
.markdown b {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.markdown > table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0px;
|
||||
empty-cells: show;
|
||||
border: 1px solid #e9e9e9;
|
||||
width: 95%;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.markdown > table th {
|
||||
white-space: nowrap;
|
||||
color: #333;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.markdown > table th,
|
||||
.markdown > table td {
|
||||
border: 1px solid #e9e9e9;
|
||||
padding: 8px 16px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.markdown > table th {
|
||||
background: #f7f7f7;
|
||||
}
|
||||
|
||||
.markdown blockquote {
|
||||
font-size: 90%;
|
||||
color: #999;
|
||||
border-left: 4px solid #e9e9e9;
|
||||
padding-left: 0.8em;
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
.markdown blockquote p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.markdown .anchor {
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.markdown .waiting {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.markdown h1:hover .anchor,
|
||||
.markdown h2:hover .anchor,
|
||||
.markdown h3:hover .anchor,
|
||||
.markdown h4:hover .anchor,
|
||||
.markdown h5:hover .anchor,
|
||||
.markdown h6:hover .anchor {
|
||||
opacity: 1;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.markdown > br,
|
||||
.markdown > p > br {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.hljs {
|
||||
display: block;
|
||||
background: white;
|
||||
padding: 0.5em;
|
||||
color: #333333;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.hljs-comment,
|
||||
.hljs-meta {
|
||||
color: #969896;
|
||||
}
|
||||
|
||||
.hljs-string,
|
||||
.hljs-variable,
|
||||
.hljs-template-variable,
|
||||
.hljs-strong,
|
||||
.hljs-emphasis,
|
||||
.hljs-quote {
|
||||
color: #df5000;
|
||||
}
|
||||
|
||||
.hljs-keyword,
|
||||
.hljs-selector-tag,
|
||||
.hljs-type {
|
||||
color: #a71d5d;
|
||||
}
|
||||
|
||||
.hljs-literal,
|
||||
.hljs-symbol,
|
||||
.hljs-bullet,
|
||||
.hljs-attribute {
|
||||
color: #0086b3;
|
||||
}
|
||||
|
||||
.hljs-section,
|
||||
.hljs-name {
|
||||
color: #63a35c;
|
||||
}
|
||||
|
||||
.hljs-tag {
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.hljs-title,
|
||||
.hljs-attr,
|
||||
.hljs-selector-id,
|
||||
.hljs-selector-class,
|
||||
.hljs-selector-attr,
|
||||
.hljs-selector-pseudo {
|
||||
color: #795da3;
|
||||
}
|
||||
|
||||
.hljs-addition {
|
||||
color: #55a532;
|
||||
background-color: #eaffea;
|
||||
}
|
||||
|
||||
.hljs-deletion {
|
||||
color: #bd2c00;
|
||||
background-color: #ffecec;
|
||||
}
|
||||
|
||||
.hljs-link {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* 代码高亮 */
|
||||
/* PrismJS 1.15.0
|
||||
https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */
|
||||
/**
|
||||
* prism.js default theme for JavaScript, CSS and HTML
|
||||
* Based on dabblet (http://dabblet.com)
|
||||
* @author Lea Verou
|
||||
*/
|
||||
code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
color: black;
|
||||
background: none;
|
||||
text-shadow: 0 1px white;
|
||||
font-family: Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace;
|
||||
text-align: left;
|
||||
white-space: pre;
|
||||
word-spacing: normal;
|
||||
word-break: normal;
|
||||
word-wrap: normal;
|
||||
line-height: 1.5;
|
||||
|
||||
-moz-tab-size: 4;
|
||||
-o-tab-size: 4;
|
||||
tab-size: 4;
|
||||
|
||||
-webkit-hyphens: none;
|
||||
-moz-hyphens: none;
|
||||
-ms-hyphens: none;
|
||||
hyphens: none;
|
||||
}
|
||||
|
||||
pre[class*="language-"]::-moz-selection,
|
||||
pre[class*="language-"] ::-moz-selection,
|
||||
code[class*="language-"]::-moz-selection,
|
||||
code[class*="language-"] ::-moz-selection {
|
||||
text-shadow: none;
|
||||
background: #b3d4fc;
|
||||
}
|
||||
|
||||
pre[class*="language-"]::selection,
|
||||
pre[class*="language-"] ::selection,
|
||||
code[class*="language-"]::selection,
|
||||
code[class*="language-"] ::selection {
|
||||
text-shadow: none;
|
||||
background: #b3d4fc;
|
||||
}
|
||||
|
||||
@media print {
|
||||
code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
text-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Code blocks */
|
||||
pre[class*="language-"] {
|
||||
padding: 1em;
|
||||
margin: 0.5em 0;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
:not(pre) > code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
background: #f5f2f0;
|
||||
}
|
||||
|
||||
/* Inline code */
|
||||
:not(pre) > code[class*="language-"] {
|
||||
padding: 0.1em;
|
||||
border-radius: 0.3em;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.token.comment,
|
||||
.token.prolog,
|
||||
.token.doctype,
|
||||
.token.cdata {
|
||||
color: slategray;
|
||||
}
|
||||
|
||||
.token.punctuation {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.namespace {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.token.property,
|
||||
.token.tag,
|
||||
.token.boolean,
|
||||
.token.number,
|
||||
.token.constant,
|
||||
.token.symbol,
|
||||
.token.deleted {
|
||||
color: #905;
|
||||
}
|
||||
|
||||
.token.selector,
|
||||
.token.attr-name,
|
||||
.token.string,
|
||||
.token.char,
|
||||
.token.builtin,
|
||||
.token.inserted {
|
||||
color: #690;
|
||||
}
|
||||
|
||||
.token.handler,
|
||||
.token.entity,
|
||||
.token.url,
|
||||
.language-css .token.string,
|
||||
.style .token.string {
|
||||
color: #9a6e3a;
|
||||
background: hsla(0, 0%, 100%, 0.5);
|
||||
}
|
||||
|
||||
.token.atrule,
|
||||
.token.attr-value,
|
||||
.token.keyword {
|
||||
color: #07a;
|
||||
}
|
||||
|
||||
.token.function,
|
||||
.token.class-name {
|
||||
color: #dd4a68;
|
||||
}
|
||||
|
||||
.token.regex,
|
||||
.token.important,
|
||||
.token.variable {
|
||||
color: #e90;
|
||||
}
|
||||
|
||||
.token.important,
|
||||
.token.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.token.italic {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.token.entity {
|
||||
cursor: help;
|
||||
}
|
||||
832
frontEnd/src/assets/css/aliIcon/demo_index.html
Normal file
@@ -0,0 +1,832 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>iconfont Demo</title>
|
||||
<link rel="shortcut icon" href="//img.alicdn.com/imgextra/i4/O1CN01Z5paLz1O0zuCC7osS_!!6000000001644-55-tps-83-82.svg" type="image/x-icon"/>
|
||||
<link rel="icon" type="image/svg+xml" href="//img.alicdn.com/imgextra/i4/O1CN01Z5paLz1O0zuCC7osS_!!6000000001644-55-tps-83-82.svg"/>
|
||||
<link rel="stylesheet" href="https://g.alicdn.com/thx/cube/1.3.2/cube.min.css">
|
||||
<link rel="stylesheet" href="demo.css">
|
||||
<link rel="stylesheet" href="iconfont.css">
|
||||
<script src="iconfont.js"></script>
|
||||
<!-- jQuery -->
|
||||
<script src="https://a1.alicdn.com/oss/uploads/2018/12/26/7bfddb60-08e8-11e9-9b04-53e73bb6408b.js"></script>
|
||||
<!-- 代码高亮 -->
|
||||
<script src="https://a1.alicdn.com/oss/uploads/2018/12/26/a3f714d0-08e6-11e9-8a15-ebf944d7534c.js"></script>
|
||||
<style>
|
||||
.main .logo {
|
||||
margin-top: 0;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.main .logo a {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.main .logo .sub-title {
|
||||
margin-left: 0.5em;
|
||||
font-size: 22px;
|
||||
color: #fff;
|
||||
background: linear-gradient(-45deg, #3967FF, #B500FE);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="main">
|
||||
<h1 class="logo"><a href="https://www.iconfont.cn/" title="iconfont 首页" target="_blank">
|
||||
<img width="200" src="https://img.alicdn.com/imgextra/i3/O1CN01Mn65HV1FfSEzR6DKv_!!6000000000514-55-tps-228-59.svg">
|
||||
|
||||
</a></h1>
|
||||
<div class="nav-tabs">
|
||||
<ul id="tabs" class="dib-box">
|
||||
<li class="dib active"><span>Unicode</span></li>
|
||||
<li class="dib"><span>Font class</span></li>
|
||||
<li class="dib"><span>Symbol</span></li>
|
||||
</ul>
|
||||
|
||||
<a href="https://www.iconfont.cn/manage/index?manage_type=myprojects&projectId=2881943" target="_blank" class="nav-more">查看项目</a>
|
||||
|
||||
</div>
|
||||
<div class="tab-container">
|
||||
<div class="content unicode" style="display: block;">
|
||||
<ul class="icon_lists dib-box">
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system"></span>
|
||||
<div class="name">日志下载-下载所有</div>
|
||||
<div class="code-name">&#xe757;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system"></span>
|
||||
<div class="name">导航</div>
|
||||
<div class="code-name">&#xe611;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system"></span>
|
||||
<div class="name">qq</div>
|
||||
<div class="code-name">&#xe601;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system"></span>
|
||||
<div class="name">微信</div>
|
||||
<div class="code-name">&#xe602;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system"></span>
|
||||
<div class="name">电话</div>
|
||||
<div class="code-name">&#xe61b;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system"></span>
|
||||
<div class="name">地址</div>
|
||||
<div class="code-name">&#xe652;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system"></span>
|
||||
<div class="name">姓名</div>
|
||||
<div class="code-name">&#xe635;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system"></span>
|
||||
<div class="name">top_联系方式</div>
|
||||
<div class="code-name">&#xe612;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system"></span>
|
||||
<div class="name">童装性别</div>
|
||||
<div class="code-name">&#xe614;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system"></span>
|
||||
<div class="name">首页</div>
|
||||
<div class="code-name">&#xe68a;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system"></span>
|
||||
<div class="name">设置</div>
|
||||
<div class="code-name">&#xe62a;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system"></span>
|
||||
<div class="name">账号管理</div>
|
||||
<div class="code-name">&#xe639;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system"></span>
|
||||
<div class="name">角色管理</div>
|
||||
<div class="code-name">&#xe640;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system"></span>
|
||||
<div class="name">菜单</div>
|
||||
<div class="code-name">&#xe65d;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system"></span>
|
||||
<div class="name">菜单</div>
|
||||
<div class="code-name">&#xe609;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system"></span>
|
||||
<div class="name">部门</div>
|
||||
<div class="code-name">&#xe686;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system"></span>
|
||||
<div class="name">版权</div>
|
||||
<div class="code-name">&#xe66d;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system"></span>
|
||||
<div class="name">登陆-box-线</div>
|
||||
<div class="code-name">&#xe89f;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system"></span>
|
||||
<div class="name">3.1电话</div>
|
||||
<div class="code-name">&#xe600;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system"></span>
|
||||
<div class="name">个人信息</div>
|
||||
<div class="code-name">&#xe641;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system"></span>
|
||||
<div class="name">全屏</div>
|
||||
<div class="code-name">&#xe632;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system"></span>
|
||||
<div class="name">个人信息</div>
|
||||
<div class="code-name">&#xe603;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system"></span>
|
||||
<div class="name">关机</div>
|
||||
<div class="code-name">&#xe689;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system"></span>
|
||||
<div class="name">email</div>
|
||||
<div class="code-name">&#xe6b0;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system"></span>
|
||||
<div class="name">密码</div>
|
||||
<div class="code-name">&#xe60f;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system"></span>
|
||||
<div class="name">验证码</div>
|
||||
<div class="code-name">&#xe619;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system"></span>
|
||||
<div class="name">用户名</div>
|
||||
<div class="code-name">&#xe78f;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system"></span>
|
||||
<div class="name">用户登陆统计</div>
|
||||
<div class="code-name">&#xe6ae;</div>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
<div class="article markdown">
|
||||
<h2 id="unicode-">Unicode 引用</h2>
|
||||
<hr>
|
||||
|
||||
<p>Unicode 是字体在网页端最原始的应用方式,特点是:</p>
|
||||
<ul>
|
||||
<li>支持按字体的方式去动态调整图标大小,颜色等等。</li>
|
||||
<li>默认情况下不支持多色,直接添加多色图标会自动去色。</li>
|
||||
</ul>
|
||||
<blockquote>
|
||||
<p>注意:新版 iconfont 支持两种方式引用多色图标:SVG symbol 引用方式和彩色字体图标模式。(使用彩色字体图标需要在「编辑项目」中开启「彩色」选项后并重新生成。)</p>
|
||||
</blockquote>
|
||||
<p>Unicode 使用步骤如下:</p>
|
||||
<h3 id="-font-face">第一步:拷贝项目下面生成的 <code>@font-face</code></h3>
|
||||
<pre><code class="language-css"
|
||||
>@font-face {
|
||||
font-family: 'base-system';
|
||||
src: url('iconfont.woff2?t=1713884780448') format('woff2'),
|
||||
url('iconfont.woff?t=1713884780448') format('woff'),
|
||||
url('iconfont.ttf?t=1713884780448') format('truetype');
|
||||
}
|
||||
</code></pre>
|
||||
<h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
|
||||
<pre><code class="language-css"
|
||||
>.base-system {
|
||||
font-family: "base-system" !important;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
</code></pre>
|
||||
<h3 id="-">第三步:挑选相应图标并获取字体编码,应用于页面</h3>
|
||||
<pre>
|
||||
<code class="language-html"
|
||||
><span class="base-system">&#x33;</span>
|
||||
</code></pre>
|
||||
<blockquote>
|
||||
<p>"base-system" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。</p>
|
||||
</blockquote>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content font-class">
|
||||
<ul class="icon_lists dib-box">
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system base-system-rizhixiazai-xiazaisuoyou"></span>
|
||||
<div class="name">
|
||||
日志下载-下载所有
|
||||
</div>
|
||||
<div class="code-name">.base-system-rizhixiazai-xiazaisuoyou
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system base-system-daohang"></span>
|
||||
<div class="name">
|
||||
导航
|
||||
</div>
|
||||
<div class="code-name">.base-system-daohang
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system base-system-qq"></span>
|
||||
<div class="name">
|
||||
qq
|
||||
</div>
|
||||
<div class="code-name">.base-system-qq
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system base-system-weixin"></span>
|
||||
<div class="name">
|
||||
微信
|
||||
</div>
|
||||
<div class="code-name">.base-system-weixin
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system base-system-dianhua"></span>
|
||||
<div class="name">
|
||||
电话
|
||||
</div>
|
||||
<div class="code-name">.base-system-dianhua
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system base-system-dizhi"></span>
|
||||
<div class="name">
|
||||
地址
|
||||
</div>
|
||||
<div class="code-name">.base-system-dizhi
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system base-system-xingming"></span>
|
||||
<div class="name">
|
||||
姓名
|
||||
</div>
|
||||
<div class="code-name">.base-system-xingming
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system base-system-top_lianxifangshi"></span>
|
||||
<div class="name">
|
||||
top_联系方式
|
||||
</div>
|
||||
<div class="code-name">.base-system-top_lianxifangshi
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system base-system-tongzhuangxingbie"></span>
|
||||
<div class="name">
|
||||
童装性别
|
||||
</div>
|
||||
<div class="code-name">.base-system-tongzhuangxingbie
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system base-system-home"></span>
|
||||
<div class="name">
|
||||
首页
|
||||
</div>
|
||||
<div class="code-name">.base-system-home
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system base-system-shezhi"></span>
|
||||
<div class="name">
|
||||
设置
|
||||
</div>
|
||||
<div class="code-name">.base-system-shezhi
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system base-system-zhanghaoguanli"></span>
|
||||
<div class="name">
|
||||
账号管理
|
||||
</div>
|
||||
<div class="code-name">.base-system-zhanghaoguanli
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system base-system-navicon-jsgl"></span>
|
||||
<div class="name">
|
||||
角色管理
|
||||
</div>
|
||||
<div class="code-name">.base-system-navicon-jsgl
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system base-system-caidan"></span>
|
||||
<div class="name">
|
||||
菜单
|
||||
</div>
|
||||
<div class="code-name">.base-system-caidan
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system base-system-caidan1"></span>
|
||||
<div class="name">
|
||||
菜单
|
||||
</div>
|
||||
<div class="code-name">.base-system-caidan1
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system base-system-bumen"></span>
|
||||
<div class="name">
|
||||
部门
|
||||
</div>
|
||||
<div class="code-name">.base-system-bumen
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system base-system-banquan"></span>
|
||||
<div class="name">
|
||||
版权
|
||||
</div>
|
||||
<div class="code-name">.base-system-banquan
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system base-system-denglu-box-xian"></span>
|
||||
<div class="name">
|
||||
登陆-box-线
|
||||
</div>
|
||||
<div class="code-name">.base-system-denglu-box-xian
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system base-system-31dianhua"></span>
|
||||
<div class="name">
|
||||
3.1电话
|
||||
</div>
|
||||
<div class="code-name">.base-system-31dianhua
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system base-system-gerenxinxi"></span>
|
||||
<div class="name">
|
||||
个人信息
|
||||
</div>
|
||||
<div class="code-name">.base-system-gerenxinxi
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system base-system-quanping"></span>
|
||||
<div class="name">
|
||||
全屏
|
||||
</div>
|
||||
<div class="code-name">.base-system-quanping
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system base-system-gerenxinxi1"></span>
|
||||
<div class="name">
|
||||
个人信息
|
||||
</div>
|
||||
<div class="code-name">.base-system-gerenxinxi1
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system base-system-guanji"></span>
|
||||
<div class="name">
|
||||
关机
|
||||
</div>
|
||||
<div class="code-name">.base-system-guanji
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system base-system-youxiang"></span>
|
||||
<div class="name">
|
||||
email
|
||||
</div>
|
||||
<div class="code-name">.base-system-youxiang
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system base-system-mima"></span>
|
||||
<div class="name">
|
||||
密码
|
||||
</div>
|
||||
<div class="code-name">.base-system-mima
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system base-system-yanzhengma"></span>
|
||||
<div class="name">
|
||||
验证码
|
||||
</div>
|
||||
<div class="code-name">.base-system-yanzhengma
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system base-system-yonghuming"></span>
|
||||
<div class="name">
|
||||
用户名
|
||||
</div>
|
||||
<div class="code-name">.base-system-yonghuming
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon base-system base-system-yonghudenglutongjigongju"></span>
|
||||
<div class="name">
|
||||
用户登陆统计
|
||||
</div>
|
||||
<div class="code-name">.base-system-yonghudenglutongjigongju
|
||||
</div>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
<div class="article markdown">
|
||||
<h2 id="font-class-">font-class 引用</h2>
|
||||
<hr>
|
||||
|
||||
<p>font-class 是 Unicode 使用方式的一种变种,主要是解决 Unicode 书写不直观,语意不明确的问题。</p>
|
||||
<p>与 Unicode 使用方式相比,具有如下特点:</p>
|
||||
<ul>
|
||||
<li>相比于 Unicode 语意明确,书写更直观。可以很容易分辨这个 icon 是什么。</li>
|
||||
<li>因为使用 class 来定义图标,所以当要替换图标时,只需要修改 class 里面的 Unicode 引用。</li>
|
||||
</ul>
|
||||
<p>使用步骤如下:</p>
|
||||
<h3 id="-fontclass-">第一步:引入项目下面生成的 fontclass 代码:</h3>
|
||||
<pre><code class="language-html"><link rel="stylesheet" href="./iconfont.css">
|
||||
</code></pre>
|
||||
<h3 id="-">第二步:挑选相应图标并获取类名,应用于页面:</h3>
|
||||
<pre><code class="language-html"><span class="base-system base-system-xxx"></span>
|
||||
</code></pre>
|
||||
<blockquote>
|
||||
<p>"
|
||||
base-system" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。</p>
|
||||
</blockquote>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content symbol">
|
||||
<ul class="icon_lists dib-box">
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#base-system-rizhixiazai-xiazaisuoyou"></use>
|
||||
</svg>
|
||||
<div class="name">日志下载-下载所有</div>
|
||||
<div class="code-name">#base-system-rizhixiazai-xiazaisuoyou</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#base-system-daohang"></use>
|
||||
</svg>
|
||||
<div class="name">导航</div>
|
||||
<div class="code-name">#base-system-daohang</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#base-system-qq"></use>
|
||||
</svg>
|
||||
<div class="name">qq</div>
|
||||
<div class="code-name">#base-system-qq</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#base-system-weixin"></use>
|
||||
</svg>
|
||||
<div class="name">微信</div>
|
||||
<div class="code-name">#base-system-weixin</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#base-system-dianhua"></use>
|
||||
</svg>
|
||||
<div class="name">电话</div>
|
||||
<div class="code-name">#base-system-dianhua</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#base-system-dizhi"></use>
|
||||
</svg>
|
||||
<div class="name">地址</div>
|
||||
<div class="code-name">#base-system-dizhi</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#base-system-xingming"></use>
|
||||
</svg>
|
||||
<div class="name">姓名</div>
|
||||
<div class="code-name">#base-system-xingming</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#base-system-top_lianxifangshi"></use>
|
||||
</svg>
|
||||
<div class="name">top_联系方式</div>
|
||||
<div class="code-name">#base-system-top_lianxifangshi</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#base-system-tongzhuangxingbie"></use>
|
||||
</svg>
|
||||
<div class="name">童装性别</div>
|
||||
<div class="code-name">#base-system-tongzhuangxingbie</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#base-system-home"></use>
|
||||
</svg>
|
||||
<div class="name">首页</div>
|
||||
<div class="code-name">#base-system-home</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#base-system-shezhi"></use>
|
||||
</svg>
|
||||
<div class="name">设置</div>
|
||||
<div class="code-name">#base-system-shezhi</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#base-system-zhanghaoguanli"></use>
|
||||
</svg>
|
||||
<div class="name">账号管理</div>
|
||||
<div class="code-name">#base-system-zhanghaoguanli</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#base-system-navicon-jsgl"></use>
|
||||
</svg>
|
||||
<div class="name">角色管理</div>
|
||||
<div class="code-name">#base-system-navicon-jsgl</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#base-system-caidan"></use>
|
||||
</svg>
|
||||
<div class="name">菜单</div>
|
||||
<div class="code-name">#base-system-caidan</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#base-system-caidan1"></use>
|
||||
</svg>
|
||||
<div class="name">菜单</div>
|
||||
<div class="code-name">#base-system-caidan1</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#base-system-bumen"></use>
|
||||
</svg>
|
||||
<div class="name">部门</div>
|
||||
<div class="code-name">#base-system-bumen</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#base-system-banquan"></use>
|
||||
</svg>
|
||||
<div class="name">版权</div>
|
||||
<div class="code-name">#base-system-banquan</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#base-system-denglu-box-xian"></use>
|
||||
</svg>
|
||||
<div class="name">登陆-box-线</div>
|
||||
<div class="code-name">#base-system-denglu-box-xian</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#base-system-31dianhua"></use>
|
||||
</svg>
|
||||
<div class="name">3.1电话</div>
|
||||
<div class="code-name">#base-system-31dianhua</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#base-system-gerenxinxi"></use>
|
||||
</svg>
|
||||
<div class="name">个人信息</div>
|
||||
<div class="code-name">#base-system-gerenxinxi</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#base-system-quanping"></use>
|
||||
</svg>
|
||||
<div class="name">全屏</div>
|
||||
<div class="code-name">#base-system-quanping</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#base-system-gerenxinxi1"></use>
|
||||
</svg>
|
||||
<div class="name">个人信息</div>
|
||||
<div class="code-name">#base-system-gerenxinxi1</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#base-system-guanji"></use>
|
||||
</svg>
|
||||
<div class="name">关机</div>
|
||||
<div class="code-name">#base-system-guanji</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#base-system-youxiang"></use>
|
||||
</svg>
|
||||
<div class="name">email</div>
|
||||
<div class="code-name">#base-system-youxiang</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#base-system-mima"></use>
|
||||
</svg>
|
||||
<div class="name">密码</div>
|
||||
<div class="code-name">#base-system-mima</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#base-system-yanzhengma"></use>
|
||||
</svg>
|
||||
<div class="name">验证码</div>
|
||||
<div class="code-name">#base-system-yanzhengma</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#base-system-yonghuming"></use>
|
||||
</svg>
|
||||
<div class="name">用户名</div>
|
||||
<div class="code-name">#base-system-yonghuming</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#base-system-yonghudenglutongjigongju"></use>
|
||||
</svg>
|
||||
<div class="name">用户登陆统计</div>
|
||||
<div class="code-name">#base-system-yonghudenglutongjigongju</div>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
<div class="article markdown">
|
||||
<h2 id="symbol-">Symbol 引用</h2>
|
||||
<hr>
|
||||
|
||||
<p>这是一种全新的使用方式,应该说这才是未来的主流,也是平台目前推荐的用法。相关介绍可以参考这篇<a href="">文章</a>
|
||||
这种用法其实是做了一个 SVG 的集合,与另外两种相比具有如下特点:</p>
|
||||
<ul>
|
||||
<li>支持多色图标了,不再受单色限制。</li>
|
||||
<li>通过一些技巧,支持像字体那样,通过 <code>font-size</code>, <code>color</code> 来调整样式。</li>
|
||||
<li>兼容性较差,支持 IE9+,及现代浏览器。</li>
|
||||
<li>浏览器渲染 SVG 的性能一般,还不如 png。</li>
|
||||
</ul>
|
||||
<p>使用步骤如下:</p>
|
||||
<h3 id="-symbol-">第一步:引入项目下面生成的 symbol 代码:</h3>
|
||||
<pre><code class="language-html"><script src="./iconfont.js"></script>
|
||||
</code></pre>
|
||||
<h3 id="-css-">第二步:加入通用 CSS 代码(引入一次就行):</h3>
|
||||
<pre><code class="language-html"><style>
|
||||
.icon {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
vertical-align: -0.15em;
|
||||
fill: currentColor;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
</code></pre>
|
||||
<h3 id="-">第三步:挑选相应图标并获取类名,应用于页面:</h3>
|
||||
<pre><code class="language-html"><svg class="icon" aria-hidden="true">
|
||||
<use xlink:href="#icon-xxx"></use>
|
||||
</svg>
|
||||
</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
$('.tab-container .content:first').show()
|
||||
|
||||
$('#tabs li').click(function (e) {
|
||||
var tabContent = $('.tab-container .content')
|
||||
var index = $(this).index()
|
||||
|
||||
if ($(this).hasClass('active')) {
|
||||
return
|
||||
} else {
|
||||
$('#tabs li').removeClass('active')
|
||||
$(this).addClass('active')
|
||||
|
||||
tabContent.hide().eq(index).fadeIn()
|
||||
}
|
||||
})
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
127
frontEnd/src/assets/css/aliIcon/iconfont.css
Normal file
@@ -0,0 +1,127 @@
|
||||
@font-face {
|
||||
font-family: "base-system"; /* Project id 2881943 */
|
||||
src: url('iconfont.woff2?t=1713884780448') format('woff2'),
|
||||
url('iconfont.woff?t=1713884780448') format('woff'),
|
||||
url('iconfont.ttf?t=1713884780448') format('truetype');
|
||||
}
|
||||
|
||||
.base-system {
|
||||
font-family: "base-system" !important;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.base-system-rizhixiazai-xiazaisuoyou:before {
|
||||
content: "\e757";
|
||||
}
|
||||
|
||||
.base-system-daohang:before {
|
||||
content: "\e611";
|
||||
}
|
||||
|
||||
.base-system-qq:before {
|
||||
content: "\e601";
|
||||
}
|
||||
|
||||
.base-system-weixin:before {
|
||||
content: "\e602";
|
||||
}
|
||||
|
||||
.base-system-dianhua:before {
|
||||
content: "\e61b";
|
||||
}
|
||||
|
||||
.base-system-dizhi:before {
|
||||
content: "\e652";
|
||||
}
|
||||
|
||||
.base-system-xingming:before {
|
||||
content: "\e635";
|
||||
}
|
||||
|
||||
.base-system-top_lianxifangshi:before {
|
||||
content: "\e612";
|
||||
}
|
||||
|
||||
.base-system-tongzhuangxingbie:before {
|
||||
content: "\e614";
|
||||
}
|
||||
|
||||
.base-system-home:before {
|
||||
content: "\e68a";
|
||||
}
|
||||
|
||||
.base-system-shezhi:before {
|
||||
content: "\e62a";
|
||||
}
|
||||
|
||||
.base-system-zhanghaoguanli:before {
|
||||
content: "\e639";
|
||||
}
|
||||
|
||||
.base-system-navicon-jsgl:before {
|
||||
content: "\e640";
|
||||
}
|
||||
|
||||
.base-system-caidan:before {
|
||||
content: "\e65d";
|
||||
}
|
||||
|
||||
.base-system-caidan1:before {
|
||||
content: "\e609";
|
||||
}
|
||||
|
||||
.base-system-bumen:before {
|
||||
content: "\e686";
|
||||
}
|
||||
|
||||
.base-system-banquan:before {
|
||||
content: "\e66d";
|
||||
}
|
||||
|
||||
.base-system-denglu-box-xian:before {
|
||||
content: "\e89f";
|
||||
}
|
||||
|
||||
.base-system-31dianhua:before {
|
||||
content: "\e600";
|
||||
}
|
||||
|
||||
.base-system-gerenxinxi:before {
|
||||
content: "\e641";
|
||||
}
|
||||
|
||||
.base-system-quanping:before {
|
||||
content: "\e632";
|
||||
}
|
||||
|
||||
.base-system-gerenxinxi1:before {
|
||||
content: "\e603";
|
||||
}
|
||||
|
||||
.base-system-guanji:before {
|
||||
content: "\e689";
|
||||
}
|
||||
|
||||
.base-system-youxiang:before {
|
||||
content: "\e6b0";
|
||||
}
|
||||
|
||||
.base-system-mima:before {
|
||||
content: "\e60f";
|
||||
}
|
||||
|
||||
.base-system-yanzhengma:before {
|
||||
content: "\e619";
|
||||
}
|
||||
|
||||
.base-system-yonghuming:before {
|
||||
content: "\e78f";
|
||||
}
|
||||
|
||||
.base-system-yonghudenglutongjigongju:before {
|
||||
content: "\e6ae";
|
||||
}
|
||||
|
||||
1
frontEnd/src/assets/css/aliIcon/iconfont.js
Normal file
205
frontEnd/src/assets/css/aliIcon/iconfont.json
Normal file
@@ -0,0 +1,205 @@
|
||||
{
|
||||
"id": "2881943",
|
||||
"name": "默认系统",
|
||||
"font_family": "base-system",
|
||||
"css_prefix_text": "base-system-",
|
||||
"description": "通用项目模板图标库",
|
||||
"glyphs": [
|
||||
{
|
||||
"icon_id": "21182922",
|
||||
"name": "日志下载-下载所有",
|
||||
"font_class": "rizhixiazai-xiazaisuoyou",
|
||||
"unicode": "e757",
|
||||
"unicode_decimal": 59223
|
||||
},
|
||||
{
|
||||
"icon_id": "4437590",
|
||||
"name": "导航",
|
||||
"font_class": "daohang",
|
||||
"unicode": "e611",
|
||||
"unicode_decimal": 58897
|
||||
},
|
||||
{
|
||||
"icon_id": "26701",
|
||||
"name": "qq",
|
||||
"font_class": "qq",
|
||||
"unicode": "e601",
|
||||
"unicode_decimal": 58881
|
||||
},
|
||||
{
|
||||
"icon_id": "77156",
|
||||
"name": "微信",
|
||||
"font_class": "weixin",
|
||||
"unicode": "e602",
|
||||
"unicode_decimal": 58882
|
||||
},
|
||||
{
|
||||
"icon_id": "144688",
|
||||
"name": "电话",
|
||||
"font_class": "dianhua",
|
||||
"unicode": "e61b",
|
||||
"unicode_decimal": 58907
|
||||
},
|
||||
{
|
||||
"icon_id": "658000",
|
||||
"name": "地址",
|
||||
"font_class": "dizhi",
|
||||
"unicode": "e652",
|
||||
"unicode_decimal": 58962
|
||||
},
|
||||
{
|
||||
"icon_id": "908052",
|
||||
"name": "姓名",
|
||||
"font_class": "xingming",
|
||||
"unicode": "e635",
|
||||
"unicode_decimal": 58933
|
||||
},
|
||||
{
|
||||
"icon_id": "17805508",
|
||||
"name": "top_联系方式",
|
||||
"font_class": "top_lianxifangshi",
|
||||
"unicode": "e612",
|
||||
"unicode_decimal": 58898
|
||||
},
|
||||
{
|
||||
"icon_id": "18319239",
|
||||
"name": "童装性别",
|
||||
"font_class": "tongzhuangxingbie",
|
||||
"unicode": "e614",
|
||||
"unicode_decimal": 58900
|
||||
},
|
||||
{
|
||||
"icon_id": "765406",
|
||||
"name": "首页",
|
||||
"font_class": "home",
|
||||
"unicode": "e68a",
|
||||
"unicode_decimal": 59018
|
||||
},
|
||||
{
|
||||
"icon_id": "145433",
|
||||
"name": "设置",
|
||||
"font_class": "shezhi",
|
||||
"unicode": "e62a",
|
||||
"unicode_decimal": 58922
|
||||
},
|
||||
{
|
||||
"icon_id": "2959116",
|
||||
"name": "账号管理",
|
||||
"font_class": "zhanghaoguanli",
|
||||
"unicode": "e639",
|
||||
"unicode_decimal": 58937
|
||||
},
|
||||
{
|
||||
"icon_id": "3702619",
|
||||
"name": "角色管理",
|
||||
"font_class": "navicon-jsgl",
|
||||
"unicode": "e640",
|
||||
"unicode_decimal": 58944
|
||||
},
|
||||
{
|
||||
"icon_id": "5283349",
|
||||
"name": "菜单",
|
||||
"font_class": "caidan",
|
||||
"unicode": "e65d",
|
||||
"unicode_decimal": 58973
|
||||
},
|
||||
{
|
||||
"icon_id": "7720058",
|
||||
"name": "菜单",
|
||||
"font_class": "caidan1",
|
||||
"unicode": "e609",
|
||||
"unicode_decimal": 58889
|
||||
},
|
||||
{
|
||||
"icon_id": "12184880",
|
||||
"name": "部门",
|
||||
"font_class": "bumen",
|
||||
"unicode": "e686",
|
||||
"unicode_decimal": 59014
|
||||
},
|
||||
{
|
||||
"icon_id": "6415223",
|
||||
"name": "版权",
|
||||
"font_class": "banquan",
|
||||
"unicode": "e66d",
|
||||
"unicode_decimal": 58989
|
||||
},
|
||||
{
|
||||
"icon_id": "12990693",
|
||||
"name": "登陆-box-线",
|
||||
"font_class": "denglu-box-xian",
|
||||
"unicode": "e89f",
|
||||
"unicode_decimal": 59551
|
||||
},
|
||||
{
|
||||
"icon_id": "201577",
|
||||
"name": "3.1电话",
|
||||
"font_class": "31dianhua",
|
||||
"unicode": "e600",
|
||||
"unicode_decimal": 58880
|
||||
},
|
||||
{
|
||||
"icon_id": "1831590",
|
||||
"name": "个人信息",
|
||||
"font_class": "gerenxinxi",
|
||||
"unicode": "e641",
|
||||
"unicode_decimal": 58945
|
||||
},
|
||||
{
|
||||
"icon_id": "7461023",
|
||||
"name": "全屏",
|
||||
"font_class": "quanping",
|
||||
"unicode": "e632",
|
||||
"unicode_decimal": 58930
|
||||
},
|
||||
{
|
||||
"icon_id": "9656282",
|
||||
"name": "个人信息",
|
||||
"font_class": "gerenxinxi1",
|
||||
"unicode": "e603",
|
||||
"unicode_decimal": 58883
|
||||
},
|
||||
{
|
||||
"icon_id": "14329730",
|
||||
"name": "关机",
|
||||
"font_class": "guanji",
|
||||
"unicode": "e689",
|
||||
"unicode_decimal": 59017
|
||||
},
|
||||
{
|
||||
"icon_id": "19457229",
|
||||
"name": "email",
|
||||
"font_class": "youxiang",
|
||||
"unicode": "e6b0",
|
||||
"unicode_decimal": 59056
|
||||
},
|
||||
{
|
||||
"icon_id": "508253",
|
||||
"name": "密码",
|
||||
"font_class": "mima",
|
||||
"unicode": "e60f",
|
||||
"unicode_decimal": 58895
|
||||
},
|
||||
{
|
||||
"icon_id": "8455373",
|
||||
"name": "验证码",
|
||||
"font_class": "yanzhengma",
|
||||
"unicode": "e619",
|
||||
"unicode_decimal": 58905
|
||||
},
|
||||
{
|
||||
"icon_id": "10232786",
|
||||
"name": "用户名",
|
||||
"font_class": "yonghuming",
|
||||
"unicode": "e78f",
|
||||
"unicode_decimal": 59279
|
||||
},
|
||||
{
|
||||
"icon_id": "21758126",
|
||||
"name": "用户登陆统计",
|
||||
"font_class": "yonghudenglutongjigongju",
|
||||
"unicode": "e6ae",
|
||||
"unicode_decimal": 59054
|
||||
}
|
||||
]
|
||||
}
|
||||
BIN
frontEnd/src/assets/css/aliIcon/iconfont.ttf
Normal file
BIN
frontEnd/src/assets/css/aliIcon/iconfont.woff
Normal file
BIN
frontEnd/src/assets/css/aliIcon/iconfont.woff2
Normal file
73
frontEnd/src/assets/css/default.scss
Normal file
@@ -0,0 +1,73 @@
|
||||
/*图标库*/
|
||||
@import url("./aliIcon/iconfont.css");
|
||||
/*图标库*/
|
||||
/*默认背景颜色*/
|
||||
.default-bckcolor {
|
||||
background-color: #f6f8fa !important;
|
||||
box-sizing: border-box;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
// /* 自定义滚动条轨道 */
|
||||
// *::-webkit-scrollbar {
|
||||
// width: 7px;
|
||||
// }
|
||||
|
||||
// /* 自定义滚动条滑块 */
|
||||
// ::-webkit-scrollbar-thumb {
|
||||
// width: 2px;
|
||||
// background-color: #555;
|
||||
// border: 1px solid #e8e9ea;
|
||||
// }
|
||||
|
||||
.mask {
|
||||
position: fixed;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background-color: rgba(#000, 0.4);
|
||||
}
|
||||
|
||||
/*水平居中*/
|
||||
.inline-center {
|
||||
display: flex !important;
|
||||
align-items: center;
|
||||
}
|
||||
/*垂直居中*/
|
||||
.height-center {
|
||||
display: flex !important;
|
||||
justify-content: center;
|
||||
}
|
||||
.flex-center {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.title {
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.ui-menu {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
align-items: center;
|
||||
.ui-menu-item {
|
||||
padding: 0 15px;
|
||||
cursor: pointer;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
transition: all 0.5s;
|
||||
&:hover {
|
||||
background-color: #e8e9ea;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.width-100 {
|
||||
width: 100%;
|
||||
}
|
||||
.height-100 {
|
||||
height: 100%;
|
||||
}
|
||||
133
frontEnd/src/assets/css/element.scss
Normal file
@@ -0,0 +1,133 @@
|
||||
$base: #306dbb;
|
||||
@forward "element-plus/theme-chalk/src/common/var.scss" with (
|
||||
$colors: (
|
||||
"white": #ffffff,
|
||||
"black": #000000,
|
||||
"primary": (
|
||||
"base": $base,
|
||||
),
|
||||
"success": (
|
||||
"base": #248067,
|
||||
),
|
||||
"warning": (
|
||||
"base": #fb8b05,
|
||||
),
|
||||
"danger": (
|
||||
"base": #f04b22,
|
||||
),
|
||||
"error": (
|
||||
"base": #ec2b24,
|
||||
),
|
||||
"info": (
|
||||
"base": #909399,
|
||||
),
|
||||
),
|
||||
$switch: (
|
||||
"on-color": "#248067",
|
||||
),
|
||||
$dialog: (
|
||||
"border-radius": "8px",
|
||||
)
|
||||
);
|
||||
|
||||
@use "element-plus/theme-chalk/src/index.scss" as *;
|
||||
|
||||
.el-menu {
|
||||
border: none;
|
||||
}
|
||||
// .el-dialog__header{
|
||||
// background-color: $base;
|
||||
// color: #fff;
|
||||
// margin-right: 0;
|
||||
// border-radius: 7px;
|
||||
// border-bottom-left-radius: 0;
|
||||
// border-bottom-right-radius: 0;
|
||||
// .el-dialog__title{
|
||||
// color: #fff;
|
||||
// }
|
||||
// .el-dialog__headerbtn{
|
||||
// .el-dialog__close{
|
||||
// color: #fff;
|
||||
// font-size: 18px;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
.el-dialog__body {
|
||||
padding-bottom: 15px !important;
|
||||
}
|
||||
|
||||
.el-table {
|
||||
th.el-table__cell {
|
||||
background-color: #f1f3f4;
|
||||
&:first-child {
|
||||
border-top-left-radius: 6px;
|
||||
border-bottom-left-radius: 6px;
|
||||
}
|
||||
&:last-child {
|
||||
border-top-right-radius: 6px;
|
||||
border-bottom-right-radius: 6px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.el-table__header-wrapper tr th.el-table-fixed-column--right,
|
||||
.el-table.is-scrolling-none th.el-table-fixed-column--right {
|
||||
background-color: #f1f3f4;
|
||||
}
|
||||
|
||||
.el-descriptions {
|
||||
.el-descriptions__header {
|
||||
position: relative;
|
||||
background-color: #e8eef5;
|
||||
padding: 6px;
|
||||
margin-bottom: 10px;
|
||||
.el-descriptions__title {
|
||||
padding-left: 12px;
|
||||
&::after {
|
||||
content: "";
|
||||
width: 5px;
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
background-color: #15559a;
|
||||
border-radius: 8px;
|
||||
animation: menueLeftLine 0.45s ease;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.base-dialog {
|
||||
.el-dialog__header {
|
||||
padding-top: 10px !important;
|
||||
padding-bottom: 35px !important;
|
||||
}
|
||||
}
|
||||
|
||||
button:focus,
|
||||
button:focus-visible {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.el-message-box__container {
|
||||
flex-direction: column;
|
||||
.el-message-box__status {
|
||||
svg {
|
||||
transform: scale(2.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
.el-message-box__btns {
|
||||
justify-content: center;
|
||||
margin: 8px 0;
|
||||
}
|
||||
|
||||
@keyframes menueLeftLine {
|
||||
0% {
|
||||
height: 0%;
|
||||
}
|
||||
100% {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
8
frontEnd/src/assets/css/reset.scss
Normal file
@@ -0,0 +1,8 @@
|
||||
|
||||
body,html {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
BIN
frontEnd/src/assets/images/index.png
Normal file
|
After Width: | Height: | Size: 91 KiB |
52
frontEnd/src/components/baseEcharts/baseEcharts.vue
Normal file
@@ -0,0 +1,52 @@
|
||||
<template>
|
||||
<div ref="echartDom" style="width: 100%; height: 100%"></div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import * as echarts from "echarts";
|
||||
import { ref, onMounted, onBeforeUnmount, nextTick } from "vue";
|
||||
let echartDom = ref(<HTMLElement | null>null);
|
||||
let emits = defineEmits(["update"]);
|
||||
let props = defineProps({
|
||||
option: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {
|
||||
title: {
|
||||
text: "ECharts 入门示例",
|
||||
},
|
||||
tooltip: {},
|
||||
xAxis: {
|
||||
data: ["衬衫", "羊毛衫", "雪纺衫", "裤子", "高跟鞋", "袜子"],
|
||||
},
|
||||
yAxis: {},
|
||||
series: [
|
||||
{
|
||||
name: "销量",
|
||||
type: "bar",
|
||||
data: [5, 20, 36, 10, 10, 20],
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
function echartResize() {
|
||||
let chartInstance = echarts.getInstanceByDom(echartDom.value as HTMLElement);
|
||||
chartInstance?.resize();
|
||||
}
|
||||
let resizeObserver = new ResizeObserver(() => {
|
||||
echartResize();
|
||||
});
|
||||
onMounted(() => {
|
||||
let chartInstance = echarts.init(echartDom.value);
|
||||
chartInstance.setOption(props.option);
|
||||
|
||||
resizeObserver.observe(echartDom.value as HTMLElement);
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
resizeObserver.disconnect();
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
||||
34
frontEnd/src/components/curdDialog/baseCurdDialog.vue
Normal file
@@ -0,0 +1,34 @@
|
||||
<template>
|
||||
<baseDialog v-bind="$attrs">
|
||||
<slot name="content"> </slot>
|
||||
<slot></slot>
|
||||
<template #footer>
|
||||
<div class="flex-center">
|
||||
<el-button @click="emits('addConfim')" v-if="showPageType.add">{{
|
||||
confirmText || "确定新增"
|
||||
}}</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="emits('editConfim')"
|
||||
v-if="showPageType.edit"
|
||||
>确认修改</el-button
|
||||
>
|
||||
<slot name="footer"></slot>
|
||||
<el-button type="danger" @click="emits('closeConfirm')">关闭</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</baseDialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted } from "vue";
|
||||
const props = defineProps<{
|
||||
/**
|
||||
* 根据增删改查的字段控制按钮的显示和隐藏
|
||||
*/
|
||||
showPageType: { [key: string]: boolean };
|
||||
confirmText?: string;
|
||||
}>();
|
||||
const emits = defineEmits(["addConfim", "editConfim", "closeConfirm"]);
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
||||
76
frontEnd/src/components/curdDialog/pageVisibleState.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
import { ref, reactive, watch } from "vue"
|
||||
interface titleDict {
|
||||
add: string;
|
||||
edit: string;
|
||||
view: string;
|
||||
}
|
||||
|
||||
class pageVisible {
|
||||
/**
|
||||
* 需要操作的页面类型
|
||||
*/
|
||||
executeType = ref('');
|
||||
/**
|
||||
* 实际渲染的二级页面或者dialog的标题
|
||||
*/
|
||||
dialogTitle = ref("");
|
||||
/**
|
||||
* 是否显示二级页面或者dialog
|
||||
*/
|
||||
show2LevelPage = ref(false); // 是否显示二级页面或者dialog
|
||||
/**
|
||||
* 标题的字典,用于在控制页面显示的时候映射对应的标题
|
||||
*/
|
||||
dialogTitleDict = ref<{ [key: string]: any }>({});
|
||||
/**
|
||||
* 显示页面的类型
|
||||
*/
|
||||
showPageType = reactive({
|
||||
add: false,
|
||||
edit: false,
|
||||
view: false,
|
||||
});
|
||||
|
||||
/**
|
||||
* @param dialogTitleDict 传入一个对象,有三个字段,分别是add、edit和view页面的标题<br>
|
||||
* { <br>
|
||||
* add: '添加页面的标题',<br>
|
||||
* view: '查看页面的标题',<br>
|
||||
* edit: '编辑页面的标题'<br>
|
||||
* }
|
||||
*/
|
||||
constructor(dialogTitleDict: titleDict) {
|
||||
this.dialogTitleDict.value = dialogTitleDict;
|
||||
|
||||
// 根据展示的类型更换标题
|
||||
watch(
|
||||
() => this.showPageType,
|
||||
(newVal) => {
|
||||
for (let [key, value] of Object.entries(newVal)) {
|
||||
if (value) {
|
||||
this.show2LevelPage.value = true;
|
||||
this.dialogTitle.value = this.dialogTitleDict.value[key];
|
||||
if(['edit', 'add'].includes(key)) this.executeType.value = key;
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
// 页面关闭,展示的类型全部不显示
|
||||
watch(
|
||||
() => this.show2LevelPage,
|
||||
(newVal) => {
|
||||
if (!newVal.value) {
|
||||
this.showPageType.add = false;
|
||||
this.showPageType.edit = false;
|
||||
this.showPageType.view = false;
|
||||
}
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default pageVisible;
|
||||
17
frontEnd/src/components/dialog/baseDialog.vue
Normal file
@@ -0,0 +1,17 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-bind="$attrs"
|
||||
center
|
||||
class="base-dialog"
|
||||
width="70%"
|
||||
align-center
|
||||
destroy-on-close
|
||||
:close-on-click-modal="false">
|
||||
<slot name="header"></slot>
|
||||
<slot name="default"></slot>
|
||||
<slot name="footer"></slot>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup></script>
|
||||
<style lang="scss" scoped></style>
|
||||
30
frontEnd/src/components/guideList/guideList.vue
Normal file
@@ -0,0 +1,30 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-select
|
||||
v-model="guide"
|
||||
style="width: 150px"
|
||||
filterable
|
||||
placeholder="请选择引导员">
|
||||
<el-option
|
||||
v-for="item in guideOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value" />
|
||||
</el-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import request from "@/lib/request";
|
||||
import { ref } from "vue";
|
||||
|
||||
let guide = defineModel({ default: "" });
|
||||
const guideOptions = ref<guideOption[]>([]);
|
||||
|
||||
request()
|
||||
.get("public/guide")
|
||||
.then((res) => {
|
||||
guideOptions.value = res.data;
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
||||
30
frontEnd/src/components/inforCard/inforCard.vue
Normal file
@@ -0,0 +1,30 @@
|
||||
<template>
|
||||
<div>
|
||||
<base-line-title :title="title"></base-line-title>
|
||||
<div class="infor-card-content">
|
||||
<slot name="content"></slot><slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
const props = defineProps({
|
||||
title: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
});
|
||||
|
||||
const title = props.title;
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.infor-card-content {
|
||||
padding: 15px;
|
||||
}
|
||||
:deep(.base-line-title) {
|
||||
font-size: 1.1rem;
|
||||
font-weight: bold;
|
||||
background-color: #f1f3f4;
|
||||
border-bottom: none;
|
||||
}
|
||||
</style>
|
||||
43
frontEnd/src/components/lineTitle/baseLineTitle.vue
Normal file
@@ -0,0 +1,43 @@
|
||||
<template>
|
||||
<div class="base-line-title">
|
||||
<span class="left-border"></span>
|
||||
{{ props.title }}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, onMounted, ref } from "vue";
|
||||
let props = defineProps({
|
||||
title: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.base-line-title {
|
||||
font-size: 1.5rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 1.8rem;
|
||||
.left-border {
|
||||
background-color: var(--el-color-primary);
|
||||
display: inline-block;
|
||||
height: 100%;
|
||||
width: 4px;
|
||||
margin-right: 10px;
|
||||
border-radius: 12px;
|
||||
animation: leftBorder 0.6s ease-in;
|
||||
animation-fill-mode: forwards;
|
||||
// animation-delay: 1s;
|
||||
}
|
||||
}
|
||||
@keyframes leftBorder{
|
||||
0% {
|
||||
height: 0;
|
||||
}
|
||||
100%{
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
304
frontEnd/src/components/printPage/printRetailPage.vue
Normal file
@@ -0,0 +1,304 @@
|
||||
<!-- PrintTemplate.vue -->
|
||||
<template>
|
||||
<div>
|
||||
<base-dialog v-model="showPrint" title="打印预览" wdith="210mm">
|
||||
<div v-loading="showLoading" element-loading-text="正在准备打印数据...">
|
||||
<div ref="printContainer" class="print-container" id="print-container">
|
||||
<!-- 告知书部分 -->
|
||||
<div class="title">文明节俭治丧告知书</div>
|
||||
<div class="content">尊敬的服务对象:</div>
|
||||
<div class="content" style="text-indent: 7rem">
|
||||
您好!感谢您的信任,选择到我司办理治丧业务。为深化殡葬改革,推进移风易俗,现就推行文明节俭治丧有关事宜向您倡导如下:
|
||||
</div>
|
||||
<div
|
||||
class="content"
|
||||
style="text-indent: 5rem; padding-right: 15px"
|
||||
id="first-content">
|
||||
一、文明治丧,节俭办事,革除陈规陋习,抵制封建迷信,提倡厚养薄葬,弘扬精神美德;
|
||||
</div>
|
||||
<div class="content" style="text-indent: 5rem; padding-right: 15px">
|
||||
二、我司为满足个性化需求,提供优质的非基本服务和丧葬用品,请您在自主选择时杜绝铺张浪费,树立文明新风。
|
||||
</div>
|
||||
|
||||
<!-- 服务清单表格 -->
|
||||
<div class="title">殡仪服务项目清单</div>
|
||||
<table class="service-table service-table-header">
|
||||
<tr>
|
||||
<td style="width: 60pt">逝者姓名</td>
|
||||
<td style="width: 90pt">
|
||||
{{ deceased.name || deceased.deceased?.name }}
|
||||
</td>
|
||||
<td style="width: 60pt">逝者年龄</td>
|
||||
<td style="width: 70pt">
|
||||
{{ deceased.age ?? deceased.deceased?.age }}
|
||||
</td>
|
||||
<td style="width: 50pt">购买人</td>
|
||||
<td style="width: 80pt">
|
||||
{{ deceased.familyName || deceased.deceased?.familyName }}
|
||||
</td>
|
||||
<td style="width: 80pt">购买人电话</td>
|
||||
<td>
|
||||
{{ deceased.familyPhone ?? deceased.deceased?.familyPhone }}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table class="service-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 40pt">序号</th>
|
||||
<th style="width: 80pt">服务项目</th>
|
||||
<th style="width: 35pt">单位</th>
|
||||
<th style="width: 35pt">数量</th>
|
||||
<th style="width: 60pt">收费标准</th>
|
||||
<th style="width: 60pt">小计</th>
|
||||
<th colspan="3">备注</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tr v-for="(item, index) in services" :key="index">
|
||||
<td>{{ index + 1 }}</td>
|
||||
<td>{{ item.name }}</td>
|
||||
<td>{{ item.unit }}</td>
|
||||
<td>{{ item.quantity }}</td>
|
||||
<td>{{ item.price }}元</td>
|
||||
<td>{{ (item.quantity * item.price).toFixed(2) }}</td>
|
||||
<td colspan="3">{{ item.remark }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="5">总计:{{ total }}元</td>
|
||||
<td colspan="2">服务引导员</td>
|
||||
<td style="width: 125pt">
|
||||
{{ deceased.guide || deceased.deceased?.guide }}
|
||||
</td>
|
||||
<td style="width: 125px">家属签字</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table class="service-table service-table-footer">
|
||||
<tr>
|
||||
<td style="width: 60pt">消费确认</td>
|
||||
<td>
|
||||
<div>
|
||||
<span
|
||||
class="confirm-text no-border"
|
||||
v-for="text in confirmText">
|
||||
{{ text }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<span class="confirm-text" v-for="text in confirmText2">
|
||||
{{ text }}
|
||||
</span>
|
||||
<span class="confirm-text">,</span>
|
||||
<span
|
||||
class="confirm-text"
|
||||
style="position: relative; top: 5px"></span>
|
||||
<span
|
||||
class="confirm-text"
|
||||
style="position: relative; top: 5px"></span>
|
||||
<span
|
||||
class="confirm-text"
|
||||
style="position: relative; top: 5px"></span>
|
||||
<span class="confirm-text">。</span>
|
||||
</div>
|
||||
</td>
|
||||
<td style="width: 125px"></td>
|
||||
</tr>
|
||||
</table>
|
||||
<div style="width: 100%; text-align: right">
|
||||
服务时间:{{ deceased.retail.checkoutDate.split(" ")[0] }}
|
||||
</div>
|
||||
<!-- 打印按钮 -->
|
||||
</div>
|
||||
<button class="print-btn" v-print="print">打印单据</button>
|
||||
</div>
|
||||
</base-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { defaultRetail } from "@/defaultForm/defaultRetail";
|
||||
import { computed, nextTick, onMounted, ref, watch } from "vue";
|
||||
import api from "@/lib/request";
|
||||
|
||||
let printContainer = ref();
|
||||
let showLoading = ref(true);
|
||||
const print = {
|
||||
id: "print-container",
|
||||
beforeOpenCallback: () => {
|
||||
showLoading.value = true;
|
||||
},
|
||||
closeCallback() {
|
||||
showLoading.value = false;
|
||||
},
|
||||
};
|
||||
|
||||
let services = ref([]);
|
||||
|
||||
let total = computed(() => {
|
||||
const sum = services.value.reduce((sum, item) => {
|
||||
return sum + parseFloat(parseFloat(item.price).toFixed(2)) * item.quantity;
|
||||
}, 0);
|
||||
return parseFloat(sum.toFixed(2)).toFixed(2); // 最终结果保留两位小数
|
||||
});
|
||||
|
||||
let confirmText = "以上消费项目我已经认真审核,无异议。";
|
||||
let confirmText2 = "以上消费项目我已经认真审核";
|
||||
|
||||
let props = withDefaults(
|
||||
defineProps<{
|
||||
deceased: RegisForm;
|
||||
serviceUrl: string;
|
||||
}>(),
|
||||
{
|
||||
deceased: () => defaultRetail(),
|
||||
serviceUrl: "/deceased-retail/selected-service",
|
||||
}
|
||||
);
|
||||
let showPrint = defineModel();
|
||||
|
||||
watch(
|
||||
() => showPrint.value,
|
||||
() => {
|
||||
showLoading.value = true;
|
||||
api()
|
||||
.get(props.serviceUrl)
|
||||
.then((res) => {
|
||||
if (res.code === 200) {
|
||||
showLoading.value = false;
|
||||
services.value = res.data.list;
|
||||
}
|
||||
});
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
immediate: true,
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.service-table-header {
|
||||
tr td {
|
||||
border-bottom: none !important;
|
||||
page-break-inside: avoid;
|
||||
}
|
||||
margin-bottom: -10pt !important;
|
||||
}
|
||||
.service-table-footer {
|
||||
tr td {
|
||||
border-top: none !important;
|
||||
page-break-inside: avoid;
|
||||
}
|
||||
margin-top: -10pt !important;
|
||||
}
|
||||
/* 基础样式 */
|
||||
.print-container {
|
||||
width: 230mm;
|
||||
margin: 0 auto;
|
||||
font-size: 14pt;
|
||||
color: #000 !important;
|
||||
font-family: Microsoft YaHei, "SimSun", serif !important;
|
||||
padding: 0 5mm;
|
||||
box-sizing: border-box; /* 包含边框计算 */
|
||||
size: auto;
|
||||
|
||||
/* 移除可能引起居中的属性 */
|
||||
display: block !important;
|
||||
align-items: unset !important;
|
||||
justify-content: unset !important;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 20pt;
|
||||
text-align: center;
|
||||
margin-top: 5pt;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.service-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin: 10pt 0;
|
||||
|
||||
td,
|
||||
th {
|
||||
border: 1pt solid #000; // 使用pt单位
|
||||
padding: 0.8mm 1.2mm; // 使用mm单位
|
||||
font-size: 10.5pt;
|
||||
line-height: 1.5;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.total {
|
||||
font-weight: bold;
|
||||
margin: 20px 0;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.print-btn {
|
||||
display: block;
|
||||
width: 120px;
|
||||
margin: 30px auto;
|
||||
padding: 10px;
|
||||
background: #007bff;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* 打印媒体查询 */
|
||||
@media print {
|
||||
/* 重置body和html的布局方式 */
|
||||
body,
|
||||
html {
|
||||
display: block !important;
|
||||
height: auto !important;
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
/* 确保打印容器从顶部开始 */
|
||||
.print-container {
|
||||
min-height: 297mm; /* A4纸高度 */
|
||||
display: block !important;
|
||||
vertical-align: top !important;
|
||||
position: relative;
|
||||
top: 0;
|
||||
transform: none !important;
|
||||
}
|
||||
@page {
|
||||
padding: 0 !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
/* 移除可能存在的flex布局影响 */
|
||||
.el-dialog__wrapper,
|
||||
.el-dialog,
|
||||
.el-dialog__body {
|
||||
display: block !important;
|
||||
height: auto !important;
|
||||
}
|
||||
|
||||
/* 移除对话框的padding */
|
||||
:deep(.el-dialog__body) {
|
||||
padding: 0 !important;
|
||||
}
|
||||
}
|
||||
.confirm-text {
|
||||
border: 1px solid #000;
|
||||
margin: 0 3px;
|
||||
display: inline-block;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
line-height: 18px;
|
||||
}
|
||||
.no-border {
|
||||
border: 1px solid #fff;
|
||||
}
|
||||
:deep(.base-dialog .el-dialog__header) {
|
||||
padding-bottom: none;
|
||||
}
|
||||
</style>
|
||||
272
frontEnd/src/components/printPage/printServicesPage.vue
Normal file
@@ -0,0 +1,272 @@
|
||||
<!-- PrintTemplate.vue -->
|
||||
<template>
|
||||
<div>
|
||||
<base-dialog v-model="showPrint" title="打印预览" wdith="210mm">
|
||||
<div v-loading="showLoading" element-loading-text="正在准备打印数据...">
|
||||
<div ref="printContainer" class="print-container" id="print-container">
|
||||
<!-- 服务清单表格 -->
|
||||
<div class="title">零售清单</div>
|
||||
<table class="service-table service-table-header">
|
||||
<tr>
|
||||
<td style="width: 60pt">逝者姓名</td>
|
||||
<td style="width: 90pt">
|
||||
{{
|
||||
deceased.name ||
|
||||
deceased.deceased?.name ||
|
||||
deceased.deceasedName
|
||||
}}
|
||||
</td>
|
||||
<td style="width: 60pt">逝者年龄</td>
|
||||
<td style="width: 70pt">
|
||||
{{ deceased.age ?? deceased.deceased?.age }}
|
||||
</td>
|
||||
<td style="width: 50pt">购买人</td>
|
||||
<td style="width: 80pt">
|
||||
{{ deceased.familyName ?? deceased.deceased?.familyName }}
|
||||
</td>
|
||||
<td style="width: 80pt">购买人电话</td>
|
||||
<td>
|
||||
{{ deceased.familyPhone ?? deceased.deceased?.familyPhone }}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table class="service-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 40pt">序号</th>
|
||||
<th style="width: 80pt">服务项目</th>
|
||||
<th style="width: 35pt">单位</th>
|
||||
<th style="width: 35pt">数量</th>
|
||||
<th style="width: 60pt">收费标准</th>
|
||||
<th style="width: 60pt">小计</th>
|
||||
<th colspan="3">备注</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tr v-for="(item, index) in services" :key="index">
|
||||
<td>{{ index + 1 }}</td>
|
||||
<td>{{ item.name }}</td>
|
||||
<td>{{ item.unit }}</td>
|
||||
<td>{{ item.quantity }}</td>
|
||||
<td>{{ item.price }}元</td>
|
||||
<td>{{ (item.quantity * item.price).toFixed(2) }}</td>
|
||||
<td colspan="3">{{ item.remark }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="6">总计:{{ total }}元</td>
|
||||
<td colspan="2">服务引导员</td>
|
||||
<td style="width: 125pt">
|
||||
{{ deceased.guide || deceased.deceased?.guide }}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div
|
||||
style="width: 100%; text-align: right"
|
||||
v-if="deceased.checkoutDate || deceased.retail">
|
||||
服务时间:{{
|
||||
deceased.retail
|
||||
? deceased.retail?.checkoutDate.split(" ")[0]
|
||||
: deceased.checkoutDate.split(" ")[0]
|
||||
}}
|
||||
</div>
|
||||
<!-- 打印按钮 -->
|
||||
</div>
|
||||
<button class="print-btn" v-print="print">打印单据</button>
|
||||
</div>
|
||||
</base-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { defaultRetail } from "@/defaultForm/defaultRetail";
|
||||
import { computed, nextTick, onMounted, ref, watch } from "vue";
|
||||
import api from "@/lib/request";
|
||||
|
||||
let printContainer = ref();
|
||||
let showLoading = ref(true);
|
||||
const print = {
|
||||
printStyle: `
|
||||
@page { size: auto; margin: 0;padding: 0;}
|
||||
table { border-collapse: collapse; }
|
||||
td { padding: 3mm; border: 1px solid #666; }
|
||||
.title {
|
||||
margin: 5pt 0;
|
||||
}
|
||||
`,
|
||||
id: "print-container",
|
||||
beforeOpenCallback: () => {
|
||||
showLoading.value = true;
|
||||
},
|
||||
closeCallback() {
|
||||
showLoading.value = false;
|
||||
},
|
||||
};
|
||||
|
||||
let services = ref([]);
|
||||
|
||||
let total = computed(() => {
|
||||
const sum = services.value.reduce((sum, item) => {
|
||||
return sum + parseFloat(parseFloat(item.price).toFixed(2)) * item.quantity;
|
||||
}, 0);
|
||||
return parseFloat(sum.toFixed(2)).toFixed(2); // 最终结果保留两位小数
|
||||
});
|
||||
|
||||
let props = withDefaults(
|
||||
defineProps<{
|
||||
deceased: RegisForm;
|
||||
serviceUrl: string;
|
||||
}>(),
|
||||
{
|
||||
deceased: () => defaultRetail(),
|
||||
serviceUrl: "/deceased-retail/selected-service",
|
||||
}
|
||||
);
|
||||
let showPrint = defineModel();
|
||||
|
||||
watch(
|
||||
() => showPrint.value,
|
||||
() => {
|
||||
showLoading.value = true;
|
||||
api()
|
||||
.get(props.serviceUrl)
|
||||
.then((res) => {
|
||||
if (res.code === 200) {
|
||||
showLoading.value = false;
|
||||
services.value = res.data.list;
|
||||
console.log(props.deceased);
|
||||
}
|
||||
});
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
immediate: true,
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.service-table-header {
|
||||
tr td {
|
||||
border-bottom: none !important;
|
||||
page-break-inside: avoid;
|
||||
}
|
||||
margin-bottom: -10pt !important;
|
||||
}
|
||||
.service-table-footer {
|
||||
tr td {
|
||||
border-top: none !important;
|
||||
page-break-inside: avoid;
|
||||
}
|
||||
margin-top: -10pt !important;
|
||||
}
|
||||
/* 基础样式 */
|
||||
.print-container {
|
||||
width: 230mm;
|
||||
margin: 0 auto;
|
||||
font-size: 14pt;
|
||||
color: #000 !important;
|
||||
font-family: Microsoft YaHei, "SimSun", serif !important;
|
||||
padding: 0 5mm;
|
||||
box-sizing: border-box; /* 包含边框计算 */
|
||||
size: auto;
|
||||
|
||||
/* 移除可能引起居中的属性 */
|
||||
display: block !important;
|
||||
align-items: unset !important;
|
||||
justify-content: unset !important;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 20pt;
|
||||
text-align: center;
|
||||
margin-top: 5pt;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.service-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin: 10pt 0;
|
||||
|
||||
td,
|
||||
th {
|
||||
border: 1pt solid #000; // 使用pt单位
|
||||
padding: 0.8mm 1.2mm; // 使用mm单位
|
||||
font-size: 10.5pt;
|
||||
line-height: 1.5;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.total {
|
||||
font-weight: bold;
|
||||
margin: 20px 0;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.print-btn {
|
||||
display: block;
|
||||
width: 120px;
|
||||
margin: 30px auto;
|
||||
padding: 10px;
|
||||
background: #007bff;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* 打印媒体查询 */
|
||||
@media print {
|
||||
/* 重置body和html的布局方式 */
|
||||
body,
|
||||
html {
|
||||
display: block !important;
|
||||
height: auto !important;
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
/* 确保打印容器从顶部开始 */
|
||||
.print-container {
|
||||
min-height: 297mm; /* A4纸高度 */
|
||||
display: block !important;
|
||||
vertical-align: top !important;
|
||||
position: relative;
|
||||
top: 0;
|
||||
transform: none !important;
|
||||
}
|
||||
|
||||
@page {
|
||||
padding: 0 !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
/* 移除可能存在的flex布局影响 */
|
||||
.el-dialog__wrapper,
|
||||
.el-dialog,
|
||||
.el-dialog__body {
|
||||
display: block !important;
|
||||
height: auto !important;
|
||||
}
|
||||
|
||||
/* 移除对话框的padding */
|
||||
:deep(.el-dialog__body) {
|
||||
padding: 0 !important;
|
||||
}
|
||||
}
|
||||
.confirm-text {
|
||||
border: 1px solid #000;
|
||||
margin: 0 3px;
|
||||
display: inline-block;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
line-height: 18px;
|
||||
}
|
||||
.no-border {
|
||||
border: 1px solid #fff;
|
||||
}
|
||||
:deep(.base-dialog .el-dialog__header) {
|
||||
padding-bottom: none;
|
||||
}
|
||||
</style>
|
||||
69
frontEnd/src/components/retailList/retailList.vue
Normal file
@@ -0,0 +1,69 @@
|
||||
<template>
|
||||
<div>
|
||||
<base-dialog v-model="show" :title="props.title || '零售清单'">
|
||||
<base-table
|
||||
:option="props.option"
|
||||
border
|
||||
:showToolsBar="false"
|
||||
@tableUpdate="tableUpdate">
|
||||
<template #toolsBar>
|
||||
总金额:
|
||||
<span style="font-size: 18px; font-weight: bold"
|
||||
>{{ totalNum }}元</span
|
||||
>
|
||||
</template>
|
||||
<template #colunm>
|
||||
<el-table-column
|
||||
type="index"
|
||||
label="序号"
|
||||
width="80"
|
||||
align="center" />
|
||||
<el-table-column
|
||||
prop="name"
|
||||
label="名称"
|
||||
width="150"
|
||||
align="center" />
|
||||
<el-table-column prop="unit" label="单位" width="60" align="center" />
|
||||
<el-table-column
|
||||
prop="quantity"
|
||||
label="数量"
|
||||
width="80"
|
||||
align="center" />
|
||||
<el-table-column prop="price" label="金额" width="120" align="center">
|
||||
<template #default="{ row }"> {{ row.price }} 元 </template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="remark" label="备注" align="center" />
|
||||
</template>
|
||||
</base-table>
|
||||
</base-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { tableOptionType } from "@/types/table";
|
||||
import { computed, ref } from "vue";
|
||||
|
||||
let show = defineModel({ default: false });
|
||||
|
||||
let props = defineProps<{
|
||||
option: tableOptionType;
|
||||
title?: string;
|
||||
}>();
|
||||
let tableData = ref([]);
|
||||
|
||||
let totalNum = computed(() => {
|
||||
let value = 0.0;
|
||||
if (tableData.value.length) {
|
||||
tableData.value.forEach((item) =>
|
||||
(value = value + Number(item.price).toFixed(2) * item.quantity).toFixed(2)
|
||||
);
|
||||
}
|
||||
|
||||
return value.toFixed(2);
|
||||
});
|
||||
|
||||
function tableUpdate(data) {
|
||||
tableData.value = data;
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
||||
42
frontEnd/src/components/serviceSelect/serviceSelect.vue
Normal file
@@ -0,0 +1,42 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-tree-select
|
||||
check-strictly
|
||||
:check-on-click-node="true"
|
||||
v-model="data"
|
||||
:props="{ label: 'name', value: 'id' }"
|
||||
:data="categoryOptions"
|
||||
:render-after-expand="false"
|
||||
style="width: 240px" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, onMounted } from "vue";
|
||||
import api from "@/lib/request";
|
||||
import { ElMessage } from "element-plus";
|
||||
const data = defineModel({
|
||||
default: 0,
|
||||
});
|
||||
|
||||
const categoryOptions = ref<{ id: number; name: string }[]>([]);
|
||||
|
||||
const loadCategoryTree = async () => {
|
||||
try {
|
||||
const res = await api().get("/service-category/list");
|
||||
if (res.data.list.length) {
|
||||
categoryOptions.value = [{ id: 0, name: "无" }, ...res.data.list];
|
||||
} else {
|
||||
categoryOptions.value = [{ id: 0, name: "无" }];
|
||||
}
|
||||
} catch (err) {
|
||||
ElMessage.error("获取分类树失败");
|
||||
}
|
||||
};
|
||||
|
||||
// 页面加载时获取分类树
|
||||
onMounted(() => {
|
||||
loadCategoryTree();
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
||||
238
frontEnd/src/components/table/baseTable.vue
Normal file
@@ -0,0 +1,238 @@
|
||||
<template>
|
||||
<!-- <el-affix :offset="65" v-if="props.showToolsBar">
|
||||
|
||||
</el-affix> -->
|
||||
<BaseToolBar
|
||||
@refresh="refresh"
|
||||
style="background-color: #fff; padding: 15px 0; margin-top: -15px">
|
||||
<!-- <download-excel :data="tableData.data" :fields="fields">
|
||||
<el-button size="small" style="margin-left: 15px"
|
||||
><template #icon>
|
||||
<el-tooltip placement="top" effect="light">
|
||||
<template #content>导出当前</template>
|
||||
<el-icon>
|
||||
<Download />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</el-button>
|
||||
</download-excel>
|
||||
<download-excel :fetch="requestAllData" :fields="fields">
|
||||
<el-tooltip placement="top" effect="light">
|
||||
<template #content>导出全部</template>
|
||||
<el-button size="small" style="margin-left: 15px"
|
||||
><template #icon
|
||||
><i class="base-system base-system-rizhixiazai-xiazaisuoyou"></i>
|
||||
</template>
|
||||
</el-button> </el-tooltip
|
||||
></download-excel> -->
|
||||
|
||||
<div style="margin-left: 15px"><slot name="toolsBar"></slot></div>
|
||||
|
||||
<template #rightContent>
|
||||
<el-pagination
|
||||
background
|
||||
layout="prev, pager, next, jumper, ->, total"
|
||||
v-if="showPagination"
|
||||
:page-size="tableData.pageSize"
|
||||
:total="tableData.total"
|
||||
:current-page="tableData.pageNumber"
|
||||
size="small"
|
||||
@current-change="currentPageChange" />
|
||||
</template>
|
||||
</BaseToolBar>
|
||||
|
||||
<el-table
|
||||
ref="dataTable"
|
||||
:data="tableData.data"
|
||||
style="
|
||||
width: 100%;
|
||||
min-height: 130px;
|
||||
padding-top: 15px;
|
||||
padding-bottom: 20px;
|
||||
"
|
||||
v-loading="tableLoadingData.show"
|
||||
empty-text="暂无数据"
|
||||
highlight-current-row
|
||||
:element-loading-text="tableLoadingData.text"
|
||||
v-bind="$attrs">
|
||||
<slot></slot>
|
||||
<slot name="colunm"></slot>
|
||||
</el-table>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
reactive,
|
||||
ref,
|
||||
onMounted,
|
||||
watch,
|
||||
nextTick,
|
||||
onBeforeUnmount,
|
||||
} from "vue";
|
||||
import api from "@/lib/request";
|
||||
import { ElMessage } from "element-plus";
|
||||
import BaseToolBar from "./toolBar/baseToolBar.vue";
|
||||
import { tableOptionType, tableDataType } from "@/types/table";
|
||||
let tableLoadingData = reactive({
|
||||
show: false,
|
||||
text: "正在加载数据...",
|
||||
});
|
||||
|
||||
const tableData = ref<tableDataType>({
|
||||
data: [],
|
||||
total: 0,
|
||||
pageNumber: 1,
|
||||
pageSize: 10,
|
||||
});
|
||||
const dataTable = ref<any>(null);
|
||||
const executeType = ref("");
|
||||
|
||||
const methods = {
|
||||
async setDataType(type: "reset" | "list" | "search") {
|
||||
nextTick(async () => {
|
||||
if (executeType.value !== type) {
|
||||
tableData.value.pageNumber = 1;
|
||||
tableData.value.pageSize = 10;
|
||||
}
|
||||
executeType.value = type;
|
||||
|
||||
if (type === "list") await initData();
|
||||
if (type === "search") await queryData();
|
||||
if (type === "reset") {
|
||||
tableData.value.pageNumber = 1;
|
||||
tableData.value.pageSize = 10;
|
||||
await initData();
|
||||
}
|
||||
emits("update");
|
||||
});
|
||||
},
|
||||
};
|
||||
defineExpose({ methods, tableData });
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
option: tableOptionType;
|
||||
showPagination?: boolean;
|
||||
showToolsBar?: boolean;
|
||||
resize?: boolean;
|
||||
fields?: string[];
|
||||
}>(),
|
||||
{
|
||||
option: () => {
|
||||
return {
|
||||
url: "",
|
||||
searchParams: () => {
|
||||
return {};
|
||||
},
|
||||
searchUrl: "",
|
||||
executeType: "list",
|
||||
};
|
||||
},
|
||||
showToolsBar: true,
|
||||
showPagination: true,
|
||||
resize: true,
|
||||
}
|
||||
);
|
||||
|
||||
const emits = defineEmits(["tableUpdate", "searchUpdate", "update"]);
|
||||
|
||||
let tableHeight = ref(300);
|
||||
const updateTableHeight = () => {
|
||||
// 计算高度,减去 header 和分页器的高度
|
||||
const headerHeight = 55; // 你的标题栏高度
|
||||
const toolBarHeight = 147; // 你的分页器高度
|
||||
const padding = 150; // 额外的间距
|
||||
|
||||
tableHeight.value =
|
||||
window.innerHeight - headerHeight - toolBarHeight - padding;
|
||||
};
|
||||
|
||||
// watch(
|
||||
// () => tableData.value.pageNumber,
|
||||
// () => {
|
||||
// nextTick(() => {
|
||||
// methods.setDataType(executeType.value);
|
||||
// });
|
||||
// }
|
||||
// );
|
||||
|
||||
// watch(
|
||||
// () => tableData.value.pageSize,
|
||||
// () => {
|
||||
// nextTick(() => {
|
||||
// methods.setDataType(executeType.value);
|
||||
// });
|
||||
// }
|
||||
// );
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
window.removeEventListener("resize", updateTableHeight);
|
||||
});
|
||||
|
||||
onMounted(async () => {
|
||||
await initData();
|
||||
updateTableHeight();
|
||||
window.addEventListener("resize", updateTableHeight);
|
||||
});
|
||||
|
||||
async function initData() {
|
||||
tableLoadingData.show = true;
|
||||
let dataList = await api().get(props.option.url, {
|
||||
params: {
|
||||
pageSize: tableData.value.pageSize,
|
||||
pageNumber: tableData.value.pageNumber,
|
||||
},
|
||||
});
|
||||
if (dataList.code === 200) {
|
||||
tableData.value.data = dataList.data.list;
|
||||
tableData.value.total = dataList.data.total;
|
||||
emits("tableUpdate", tableData.value.data);
|
||||
}
|
||||
tableLoadingData.show = false;
|
||||
}
|
||||
|
||||
async function queryData() {
|
||||
tableLoadingData.show = true;
|
||||
|
||||
let { pageNumber, pageSize } = tableData.value;
|
||||
let dataList = await api().post(props.option.searchUrl, {
|
||||
...props.option.searchParams,
|
||||
pageSize,
|
||||
pageNumber,
|
||||
});
|
||||
|
||||
if (dataList.code === 200) {
|
||||
tableData.value.data = dataList.data.list;
|
||||
tableData.value.total = dataList.data.total;
|
||||
emits("searchUpdate", tableData.value.data);
|
||||
} else {
|
||||
ElMessage.error("查询出错了,请稍后重试!");
|
||||
}
|
||||
tableLoadingData.show = false;
|
||||
}
|
||||
|
||||
function currentPageChange(newVal: number) {
|
||||
tableData.value.pageNumber = newVal;
|
||||
if (executeType.value === "search") queryData();
|
||||
if (["list", "reset"].includes(executeType.value)) initData();
|
||||
if (!executeType.value) initData();
|
||||
}
|
||||
|
||||
async function requestAllData() {
|
||||
let dataList = await api().get(props.option.url, {
|
||||
params: {
|
||||
pageSize: 999999,
|
||||
pageNumber: 1,
|
||||
...props.option.searchParams,
|
||||
},
|
||||
});
|
||||
return dataList.data.list;
|
||||
}
|
||||
|
||||
function refresh() {
|
||||
if (executeType.value === "search") queryData();
|
||||
if (["list", "reset"].includes(executeType.value)) initData();
|
||||
if (!executeType.value) queryData();
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
||||
@@ -0,0 +1,60 @@
|
||||
<template>
|
||||
<el-row class="table-header">
|
||||
<el-col :span="24">
|
||||
<el-card>
|
||||
<template #header>
|
||||
<base-line-title :title="title"></base-line-title>
|
||||
</template>
|
||||
<slot name="content"></slot>
|
||||
<el-form-item :label-width="labelWidth + 'px'">
|
||||
<el-button
|
||||
@click="emits('search')"
|
||||
size="small"
|
||||
style="margin-left: 15px">
|
||||
<template #icon>
|
||||
<el-icon>
|
||||
<Search />
|
||||
</el-icon> </template
|
||||
>查询</el-button
|
||||
>
|
||||
<el-button type="warning" @click="emits('resetSearch')" size="small">
|
||||
<template #icon>
|
||||
<el-icon>
|
||||
<RefreshRight />
|
||||
</el-icon> </template
|
||||
>重置</el-button
|
||||
>
|
||||
<slot name="operateBtns"></slot>
|
||||
</el-form-item>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, onMounted, ref } from "vue";
|
||||
let props = defineProps<{
|
||||
title: string;
|
||||
labelWidth?: number | string;
|
||||
}>();
|
||||
|
||||
let emits = defineEmits(["resetSearch", "search"]);
|
||||
|
||||
function resetSearch() {
|
||||
emits("resetSearch");
|
||||
}
|
||||
|
||||
function search() {
|
||||
emits("search");
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.table-header {
|
||||
width: 100%;
|
||||
}
|
||||
:deep(.el-card__body) {
|
||||
padding-bottom: 10px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
</style>
|
||||
26
frontEnd/src/components/table/toolBar/baseToolBar.vue
Normal file
@@ -0,0 +1,26 @@
|
||||
<template>
|
||||
<el-row>
|
||||
<el-col :span="24" class="tool-bar">
|
||||
<el-tooltip placement="top" effect="light">
|
||||
<template #content>刷新</template>
|
||||
<el-button size="small" @click="emits('refresh')">
|
||||
<el-icon><Refresh /></el-icon>
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
<slot></slot>
|
||||
<div style="position: absolute; right: 15px">
|
||||
<slot name="rightContent"></slot>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
const emits = defineEmits(["refresh", "downCurrent", "downAll"]);
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.tool-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
14
frontEnd/src/defaultForm/defaultPaymentForm.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import dayjs from "dayjs";
|
||||
|
||||
export function defaultPaymentForm(): PaymentForm {
|
||||
return {
|
||||
checkoutDate: dayjs().format(), // 结账日期
|
||||
handler: "", // 经办人
|
||||
settlementDate: dayjs().format(), // 结算日期
|
||||
cashAmount: 0, // 现金金额
|
||||
unionPayAmount: 0, // 银联支付金额
|
||||
cardAmount: 0, // 刷卡金额
|
||||
publicTransferAmount: 0, // 对公转账金额
|
||||
workshopPayment: 0,
|
||||
};
|
||||
}
|
||||
17
frontEnd/src/defaultForm/defaultRetail.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
export function defaultRetail(): RegisForm {
|
||||
return {
|
||||
name: "", // 逝者姓名
|
||||
idNumber: "", // 证件号码
|
||||
gender: "男", // 性别
|
||||
age: 0, // 年龄
|
||||
buyer: "", // 购买人
|
||||
purchaseDate: "", // 购买日期
|
||||
handler: "", // 经办人
|
||||
salesAmount: 0, // 销售金额
|
||||
guide: "", // 引导员
|
||||
serviceItems: "",
|
||||
familyName: "",
|
||||
familyPhone: "",
|
||||
services: [],
|
||||
};
|
||||
}
|
||||
10
frontEnd/src/defaultForm/defaultSerivceItem.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
export function defaultServiceItem(): ServiceItemType {
|
||||
return {
|
||||
name: "",
|
||||
quantity: 0,
|
||||
category: 0,
|
||||
unit: "",
|
||||
price: 0,
|
||||
remark: "",
|
||||
};
|
||||
}
|
||||
206
frontEnd/src/layout/headMenu.vue
Normal file
@@ -0,0 +1,206 @@
|
||||
<template>
|
||||
<div class="head-content">
|
||||
<div class="nav">
|
||||
<div class="left">
|
||||
<!-- <ul class="ui-menu">
|
||||
<li
|
||||
v-for="item in routerList"
|
||||
class="ui-menu-item"
|
||||
@click="selectTopMenu(item)">
|
||||
{{ item.name }}
|
||||
</li>
|
||||
</ul> -->
|
||||
<el-icon size="45px" class="folder" @click="expandToggle">
|
||||
<Fold v-if="!expand" />
|
||||
<Expand v-else="expand" />
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="right">
|
||||
<div class="right-toolbar">
|
||||
<el-tooltip content="全屏" placement="bottom" effect="light">
|
||||
<el-icon @click="fullScreen"><FullScreen /></el-icon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<div class="options">
|
||||
<el-dropdown :hide-on-click="false">
|
||||
<div class="user-heard" @click="changeInfo">
|
||||
<label style="padding: 0 5px"
|
||||
>你好<strong style="padding: 0 5px">{{
|
||||
replaceUserName(userInforStore.userInfor.name as string)
|
||||
}}</strong></label
|
||||
>
|
||||
<!-- <el-avatar
|
||||
src="https://avatars.githubusercontent.com/u/34113411?v=4">
|
||||
</el-avatar> -->
|
||||
<el-icon>
|
||||
<CaretBottom></CaretBottom>
|
||||
</el-icon>
|
||||
</div>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item @click="personal">个人信息</el-dropdown-item>
|
||||
<el-dropdown-item @click="logout">退出登陆</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<base-dialog v-model="showMyself"> <mySelf /></base-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { nextTick, reactive, ref } from "vue";
|
||||
import { RouteRecordRaw } from "vue-router";
|
||||
import router from "@/routers";
|
||||
import { ElMessageBox } from "element-plus";
|
||||
import { globalState } from "@/store";
|
||||
import { userInfor } from "@/store/user/user";
|
||||
import { Expand } from "@element-plus/icons-vue";
|
||||
import mySelf from "@/pages/system/user/personal.vue";
|
||||
|
||||
const globalStore = globalState();
|
||||
const userInforStore = userInfor();
|
||||
const emits = defineEmits(["change", "expandChange"]);
|
||||
let showUserOption = ref(false);
|
||||
let expand = ref(false);
|
||||
let isFullScene = ref(false);
|
||||
let showMyself = ref(false);
|
||||
|
||||
// 切换类名
|
||||
function changeInfo() {
|
||||
showUserOption.value = !showUserOption.value;
|
||||
}
|
||||
|
||||
// 退出登陆
|
||||
function logout() {
|
||||
ElMessageBox.confirm("确定要退出系统吗?", "提示", {
|
||||
type: "warning",
|
||||
confirmButtonText: "确定退出",
|
||||
cancelButtonText: "取消",
|
||||
}).then(() => {
|
||||
globalStore.setGlobalLoadingShow(true, "正在清空您的数据并退出系统...");
|
||||
|
||||
userInforStore.removeLoginState();
|
||||
userInforStore.removeToken();
|
||||
|
||||
setTimeout(() => {
|
||||
globalStore.setGlobalLoadingShow(false);
|
||||
router.replace({ path: "/login" });
|
||||
}, 2000);
|
||||
});
|
||||
}
|
||||
|
||||
function expandToggle() {
|
||||
expand.value = !expand.value;
|
||||
|
||||
emits("expandChange", expand.value);
|
||||
}
|
||||
|
||||
function personal() {
|
||||
showMyself.value = true;
|
||||
}
|
||||
|
||||
function fullScreen() {
|
||||
if (!isFullScene.value) {
|
||||
document.body.requestFullscreen();
|
||||
} else {
|
||||
document.exitFullscreen();
|
||||
}
|
||||
isFullScene.value = !isFullScene.value;
|
||||
}
|
||||
|
||||
function replaceUserName(name: string) {
|
||||
return name;
|
||||
if (name.length <= 1) return name;
|
||||
|
||||
let nameLen = name.length;
|
||||
|
||||
return name.substring(1, nameLen);
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.head-content {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
margin-left: 200px;
|
||||
width: calc(100% - 200px);
|
||||
height: 50px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: #f1f3f4;
|
||||
|
||||
.nav {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
background-color: #fff;
|
||||
// box-shadow: 20px -5px 28px #c2c2c2;
|
||||
padding: 8px 15px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 55px;
|
||||
align-items: center;
|
||||
z-index: 2;
|
||||
.left {
|
||||
height: 50px;
|
||||
}
|
||||
}
|
||||
|
||||
.route-list {
|
||||
padding: 5px 15px;
|
||||
background-color: #fff;
|
||||
height: 30px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
box-shadow: 0px 1px 0px #c2c2c2;
|
||||
margin-top: 1px;
|
||||
}
|
||||
|
||||
.right,
|
||||
.left {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.right {
|
||||
padding: 0 15px;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
.right-toolbar {
|
||||
height: inherit;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-right: 30px;
|
||||
}
|
||||
.options {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
.user-heard {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.show-user-option {
|
||||
visibility: visible !important;
|
||||
opacity: 1 !important;
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
|
||||
.folder svg {
|
||||
width: 2em;
|
||||
height: 2em;
|
||||
cursor: pointer;
|
||||
}
|
||||
.right-toolbar svg {
|
||||
transform: scale(1.5);
|
||||
}
|
||||
</style>
|
||||
128
frontEnd/src/layout/index.vue
Normal file
@@ -0,0 +1,128 @@
|
||||
<template>
|
||||
<div
|
||||
style="width: 100vw; height: 100vh"
|
||||
v-loading="globalStateStore.globalLodingShow"
|
||||
:element-loading-text="globalStateStore.globalLodingShowText">
|
||||
<headMenuVue
|
||||
@expand-change="expandChange"
|
||||
class="header-menue"
|
||||
:class="{ 'expand-control': expand }"></headMenuVue>
|
||||
<leftMenuVue
|
||||
class="left-menue"
|
||||
:menue-data="realMenue"
|
||||
:class="{ 'expand-close': expand }"></leftMenuVue>
|
||||
<div
|
||||
class="main"
|
||||
:class="{ 'expand-control': expand }"
|
||||
v-loading="globalStateStore.loadingShow"
|
||||
:element-loading-text="globalStateStore.loadingText">
|
||||
<router-view v-slot="{ Component }">
|
||||
<transition name="transition" mode="out-in">
|
||||
<component :is="Component"></component>
|
||||
</transition>
|
||||
</router-view>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import headMenuVue from "./headMenu.vue";
|
||||
import leftMenuVue from "./leftMenu.vue";
|
||||
import router from "@/routers/index";
|
||||
import { globalState } from "@/store";
|
||||
import { RouteRecordRaw } from "vue-router";
|
||||
import { ref, onBeforeMount, onMounted, reactive } from "vue";
|
||||
let filterRoute = ["首页"];
|
||||
let leftMenue: Array<RouteRecordRaw> = router.options.routes.find(
|
||||
(item: RouteRecordRaw) => item?.name === "主页"
|
||||
)?.children as Array<RouteRecordRaw>;
|
||||
let globalStateStore = globalState();
|
||||
let realMenue = leftMenue.filter(
|
||||
(item: RouteRecordRaw) => !filterRoute.includes(item.name as string)
|
||||
);
|
||||
let expand = ref(false);
|
||||
|
||||
onBeforeMount(() => {});
|
||||
onMounted(() => {});
|
||||
|
||||
function expandChange(newVal: boolean) {
|
||||
expand.value = newVal;
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.main {
|
||||
width: calc(100vw - 200px);
|
||||
height: calc(100vh - 50px);
|
||||
position: absolute;
|
||||
top: 50px;
|
||||
margin-left: 200px;
|
||||
overflow-y: auto;
|
||||
background-color: #f1f3f4;
|
||||
padding: 12px;
|
||||
}
|
||||
.left-menue {
|
||||
transition: all 0.3s;
|
||||
color: #fff;
|
||||
user-select: none;
|
||||
background-color: #fff;
|
||||
:deep(.el-menu) {
|
||||
.el-menu-item {
|
||||
&:hover {
|
||||
background-color: #f1f3f4;
|
||||
color: #15559a;
|
||||
}
|
||||
}
|
||||
.is-active {
|
||||
background-color: #f1f3f4;
|
||||
}
|
||||
.el-sub-menu .is-active {
|
||||
::after {
|
||||
content: "";
|
||||
width: 5px;
|
||||
position: absolute;
|
||||
left: -8px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
background-color: #15559a;
|
||||
border-radius: 8px;
|
||||
animation: menueLeftLine 0.45s ease;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.expand {
|
||||
left: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
.main,
|
||||
.header-menue {
|
||||
transition: all 0.3s;
|
||||
}
|
||||
.expand-control {
|
||||
width: 100vw;
|
||||
margin-left: 0;
|
||||
}
|
||||
.expand-close {
|
||||
width: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.transition-enter-to {
|
||||
opacity: 1;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
.transition-enter-from {
|
||||
transform: translateY(5%);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
@keyframes menueLeftLine {
|
||||
0% {
|
||||
height: 0%;
|
||||
}
|
||||
100% {
|
||||
height: 120%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
183
frontEnd/src/layout/leftMenu.vue
Normal file
@@ -0,0 +1,183 @@
|
||||
<template>
|
||||
<div class="menue">
|
||||
<div class="system-title flex-center">
|
||||
<img src="@/assets/images/index.png" alt="" />
|
||||
<span>baseSystem</span>
|
||||
</div>
|
||||
<el-menu
|
||||
router
|
||||
:default-active="router.currentRoute.value.path"
|
||||
:unique-opened="true">
|
||||
<!-- <el-menu-item index="/main"
|
||||
><el-icon> <HomeFilled /> </el-icon>首页</el-menu-item
|
||||
> -->
|
||||
<template v-for="(item, index) in menueData">
|
||||
<template v-if="!item.children">
|
||||
<el-menu-item
|
||||
:index="item.path"
|
||||
v-if="hasParent(item)"
|
||||
:class="{
|
||||
routerActive: router.currentRoute.value.path === item.path,
|
||||
}">
|
||||
<template v-if="item.meta?.icon?.type === 'elem'">
|
||||
<el-icon>
|
||||
<component :is="item.meta!.icon.value"> </component>
|
||||
</el-icon>
|
||||
</template>
|
||||
<template v-if="iconType.includes(item.meta?.icon?.type)">
|
||||
<img
|
||||
:src="'/assets/icon/' + item.meta?.icon?.value"
|
||||
alt=""
|
||||
class="nav-icon" />
|
||||
</template>
|
||||
{{ item.name }}
|
||||
</el-menu-item>
|
||||
</template>
|
||||
<template v-else
|
||||
><el-sub-menu :index="String(index)" v-if="hasParent(item)">
|
||||
<template #title>
|
||||
<template v-if="item.meta?.icon?.type === 'elem'">
|
||||
<el-icon>
|
||||
<component :is="item.meta!.icon.value"> </component>
|
||||
</el-icon>
|
||||
</template>
|
||||
<template v-if="iconType.includes(item.meta?.icon?.type)">
|
||||
<img
|
||||
:src="'/assets/icon/' + item.meta?.icon?.value"
|
||||
alt=""
|
||||
class="nav-icon" /> </template
|
||||
>{{ item.name }}
|
||||
</template>
|
||||
|
||||
<template v-for="(childrenItem, index) in item.children">
|
||||
<el-menu-item
|
||||
:index="childrenItem.path"
|
||||
v-if="hasChild(item, childrenItem)"
|
||||
:class="{
|
||||
routerActive:
|
||||
router.currentRoute.value.path === childrenItem.path,
|
||||
}">
|
||||
<template v-if="childrenItem.meta?.icon?.type === 'elem'">
|
||||
<el-icon>
|
||||
<component :is="childrenItem.meta!.icon.value"> </component>
|
||||
</el-icon>
|
||||
</template>
|
||||
<template
|
||||
v-if="iconType.includes(childrenItem.meta?.icon?.type)">
|
||||
<img
|
||||
:src="'/assets/icon/' + childrenItem.meta?.icon?.value"
|
||||
alt=""
|
||||
class="nav-icon" />
|
||||
</template>
|
||||
{{ childrenItem.name }}
|
||||
</el-menu-item>
|
||||
</template>
|
||||
</el-sub-menu></template
|
||||
>
|
||||
</template>
|
||||
</el-menu>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { RouteRecordRaw } from "vue-router";
|
||||
import { userInfor } from "@/store/user/user";
|
||||
import router from "@/routers/index";
|
||||
import { ref } from "vue";
|
||||
import { systemMenueType } from "@/types/systemMenue";
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
menueData: RouteRecordRaw[];
|
||||
expand?: boolean;
|
||||
}>(),
|
||||
{
|
||||
expand: false,
|
||||
}
|
||||
);
|
||||
|
||||
const iconType = ref(["svg", "png", "jgp"]);
|
||||
const globalUserInfor = userInfor();
|
||||
let userMenue = globalUserInfor.userInfor.routerMenue;
|
||||
|
||||
function hasParent(item: RouteRecordRaw) {
|
||||
let parent = userMenue?.find((routerItem) => routerItem.name === item.name);
|
||||
let childn = item.children?.find((childrenItem) =>
|
||||
userMenue?.find((userItem) => userItem.name === childrenItem.name)
|
||||
);
|
||||
return parent || childn;
|
||||
}
|
||||
function hasChild(parentItem: RouteRecordRaw, item: RouteRecordRaw) {
|
||||
let parent = userMenue?.find(
|
||||
(routerItem) => routerItem.name === parentItem.name
|
||||
);
|
||||
if (parent) {
|
||||
return parent?.children?.find(
|
||||
(userMenueItem) => userMenueItem.name === item.name
|
||||
);
|
||||
} else {
|
||||
return userMenue?.find((userMneueItem) => userMneueItem.name === item.name);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.parent-list {
|
||||
padding: 5px 10px;
|
||||
position: relative;
|
||||
|
||||
.list-border-left {
|
||||
position: absolute;
|
||||
left: 4px;
|
||||
top: 50%;
|
||||
height: 0;
|
||||
border-left: 4px solid #66cccc;
|
||||
border-radius: 15px;
|
||||
transition: all 0.3s;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
&:hover .list-border-left {
|
||||
height: 70%;
|
||||
}
|
||||
}
|
||||
|
||||
.menue {
|
||||
// box-shadow: #000 -25px 0 35px;
|
||||
width: 200px;
|
||||
height: 100vh;
|
||||
overflow-y: auto;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.routerActive {
|
||||
background-color: #f1f3f4;
|
||||
}
|
||||
|
||||
.system-title {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
height: 95px;
|
||||
display: flex;
|
||||
position: relative;
|
||||
flex-direction: column;
|
||||
|
||||
img {
|
||||
width: 60px;
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
bottom: 0;
|
||||
}
|
||||
}
|
||||
.nav-icon {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
font-size: 18px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
</style>
|
||||
91
frontEnd/src/layout/menue.vue
Normal file
@@ -0,0 +1,91 @@
|
||||
<template>
|
||||
<div class="menue">
|
||||
<ul class="menue-list">
|
||||
<li v-for="item in props.menueData">
|
||||
<div
|
||||
class="menue-list-item"
|
||||
:class="{ 'parent-item': item.children?.length }"
|
||||
@click="onRowClick(item)">
|
||||
<span class="list-border-left"></span>
|
||||
<span>{{ item.meta?.describe || item.name }}</span>
|
||||
</div>
|
||||
<menueComponent
|
||||
:menueData="item.children"
|
||||
v-if="item.children?.length"
|
||||
class="children-menue">
|
||||
</menueComponent>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import menueComponent from "./menue.vue";
|
||||
import { RouteRecordRaw } from "vue-router";
|
||||
import { globalState } from "@/store/index";
|
||||
import router from "@/routers/index";
|
||||
const props = defineProps({
|
||||
menueData: Array<RouteRecordRaw>,
|
||||
});
|
||||
const globalStateStore = globalState();
|
||||
|
||||
function onRowClick(row: RouteRecordRaw) {
|
||||
if (!row.children || !row.children.length) {
|
||||
globalStateStore.setSelectMenue(row);
|
||||
globalStateStore.setLoadingShow(true);
|
||||
router.push(row.path);
|
||||
setTimeout(() => {
|
||||
globalStateStore.setLoadingShow(false);
|
||||
}, 1000);
|
||||
} else {
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.parent-list {
|
||||
padding: 5px 10px;
|
||||
position: relative;
|
||||
box-shadow: none;
|
||||
.list-border-left {
|
||||
position: absolute;
|
||||
left: 4px;
|
||||
top: 50%;
|
||||
height: 0;
|
||||
border-left: 4px solid #66cccc;
|
||||
border-radius: 15px;
|
||||
transition: all 0.3s;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
&:hover .list-border-left {
|
||||
height: 70%;
|
||||
}
|
||||
}
|
||||
.menue-list {
|
||||
width: 100%;
|
||||
> li > .menue-list-item {
|
||||
padding: 4px 15px;
|
||||
width: 100%;
|
||||
font-size: 16px;
|
||||
transition: all 0.4s;
|
||||
position: relative;
|
||||
&:hover {
|
||||
background-color: #99cc99;
|
||||
// padding-top: 10px;
|
||||
// padding-bottom: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.children-menue > .menue-list {
|
||||
padding-left: 12px;
|
||||
.menue-list-item {
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
.meunue-active {
|
||||
background-color: #99cc99;
|
||||
}
|
||||
.parent-item:hover {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
</style>
|
||||
17
frontEnd/src/lib/api/publicApiList.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { roleType } from "@/types/role";
|
||||
import { systemMenueType } from "@/types/systemMenue";
|
||||
import api from "@/lib/request";
|
||||
|
||||
export async function roleDataList(): Promise<roleType[]> {
|
||||
let roleList: roleType[] =[];
|
||||
let getData = await api().get('/role/list');
|
||||
roleList = getData.data.list;
|
||||
return roleList
|
||||
}
|
||||
|
||||
export async function menueDataList (): Promise<systemMenueType[]> {
|
||||
let menueList: systemMenueType[] =[];
|
||||
let getData = await api().get('/system-menue/list?all=true');
|
||||
menueList = getData.data.list;
|
||||
return menueList
|
||||
}
|
||||
96
frontEnd/src/lib/request.ts
Normal file
@@ -0,0 +1,96 @@
|
||||
import axios, { AxiosRequestConfig } from "axios";
|
||||
import { userInfor } from "@/store/user/user";
|
||||
import { ElMessage } from "element-plus";
|
||||
import router from "@/routers/index";
|
||||
|
||||
const userInforStore = userInfor();
|
||||
|
||||
interface apiOptions {
|
||||
format: {
|
||||
formData: boolean; // 表单提交
|
||||
multipart: boolean; // 文件上传
|
||||
};
|
||||
}
|
||||
|
||||
interface dataFormat {
|
||||
code: number;
|
||||
msg?: string;
|
||||
data: any;
|
||||
}
|
||||
|
||||
let contentType: { [key: string]: any } = {
|
||||
json: "appliation/json;charset=utf-8;",
|
||||
formData: "application/x-www-form-urlencoded;",
|
||||
multipart: "multipart/form-data;",
|
||||
};
|
||||
let typeKey = "json";
|
||||
class api {
|
||||
format = { formData: false, multipart: false };
|
||||
private instance = axios.create({
|
||||
baseURL: import.meta.env.VITE_API_BASE_URL,
|
||||
});
|
||||
constructor(options?: apiOptions) {
|
||||
if (options) {
|
||||
this.format = { ...this.format, ...options.format };
|
||||
|
||||
if (this.format.formData) typeKey = "formData";
|
||||
if (this.format.multipart) typeKey = "multipart";
|
||||
}
|
||||
|
||||
this.instance.interceptors.request.use(
|
||||
(config) => {
|
||||
this.instance.defaults.headers["Content-Type"] = contentType[typeKey];
|
||||
config.headers["Authorization"] = userInforStore.token;
|
||||
config.headers["refreshToken"] = userInforStore.refreshToken;
|
||||
return config;
|
||||
},
|
||||
(error) => {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
this.instance.interceptors.response.use(
|
||||
(responese) => {
|
||||
if (responese.data.code === 401) {
|
||||
ElMessage.error(responese.data.msg);
|
||||
userInforStore.removeLoginState();
|
||||
userInforStore.removeToken();
|
||||
router.replace("/login");
|
||||
return responese;
|
||||
}
|
||||
if ([501, 501, 503, 500].includes(responese.data.code)) {
|
||||
ElMessage.error(responese.data.msg);
|
||||
return responese;
|
||||
}
|
||||
let newToken = responese.headers["refreshToken"];
|
||||
if (newToken) {
|
||||
userInforStore.setToken(newToken);
|
||||
}
|
||||
return responese;
|
||||
},
|
||||
(error) => {
|
||||
if (error.status === 401) {
|
||||
ElMessage.error(error.response.data.msg);
|
||||
userInforStore.removeLoginState();
|
||||
userInforStore.removeToken();
|
||||
router.replace("/login");
|
||||
}
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
}
|
||||
async get(url: string, config?: AxiosRequestConfig<any> | undefined) {
|
||||
return (await this.instance.get(url, config)).data;
|
||||
}
|
||||
async post(
|
||||
url: string,
|
||||
data?: any,
|
||||
config?: AxiosRequestConfig<any> | undefined
|
||||
) {
|
||||
return (await this.instance.post(url, data, config)).data;
|
||||
}
|
||||
}
|
||||
|
||||
export default function (options?: apiOptions) {
|
||||
return new api(options);
|
||||
}
|
||||
65
frontEnd/src/main.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
import { createApp } from "vue";
|
||||
import "./style.css";
|
||||
import App from "./App.vue";
|
||||
// 引入element-plush
|
||||
import ElementPlus from "element-plus";
|
||||
import "@/assets/css/element.scss";
|
||||
// @ts-ignore
|
||||
import zhCn from "element-plus/dist/locale/zh-cn.mjs";
|
||||
import * as ElementPlusIconsVue from "@element-plus/icons-vue";
|
||||
import "./assets/css/default.scss";
|
||||
import "./assets/css/reset.scss";
|
||||
import { createPinia } from "pinia";
|
||||
import routers from "./routers/index";
|
||||
import { userInfor } from "./store/user/user";
|
||||
import { globalState } from "./store";
|
||||
import globalComponents from "@/util/globalComponents";
|
||||
import JsonExcel from "vue-json-excel3";
|
||||
import print from "vue3-print-nb";
|
||||
|
||||
let app = createApp(App);
|
||||
app.use(print);
|
||||
|
||||
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
|
||||
app.component(key, component);
|
||||
}
|
||||
app.component("downloadExcel", JsonExcel);
|
||||
app
|
||||
.use(createPinia())
|
||||
.use(routers)
|
||||
.use(ElementPlus, { locale: zhCn })
|
||||
.use(globalComponents)
|
||||
.mount("#app");
|
||||
|
||||
// 得挂载后才能使用
|
||||
let userInforState = userInfor();
|
||||
let globalStateState = globalState();
|
||||
let closeLoadingShow = () => globalStateState.setLoadingShow(false);
|
||||
|
||||
routers.afterEach((to) => {
|
||||
globalStateState.setLoadingShow(true, "正在前往");
|
||||
if (!userInforState.token && to.path !== "/login") {
|
||||
let tempUserInfor = JSON.parse(localStorage.getItem("userInfor") as string);
|
||||
let tempToken = localStorage.getItem("token");
|
||||
let temoRefreshToken = localStorage.getItem("refreshToken");
|
||||
let tempHistoryRouter = localStorage.getItem("historyRouterPath");
|
||||
|
||||
if (tempUserInfor && tempToken && temoRefreshToken) {
|
||||
userInforState.setLoginState(tempUserInfor);
|
||||
userInforState.setToken(tempToken);
|
||||
userInforState.setRefToken(temoRefreshToken);
|
||||
|
||||
// 如果有历史路由,保持历史路由路径,无感刷新页面
|
||||
if (tempHistoryRouter) {
|
||||
routers.push({ path: tempHistoryRouter as string });
|
||||
}
|
||||
closeLoadingShow();
|
||||
} else {
|
||||
routers.replace({ path: "/login" });
|
||||
closeLoadingShow();
|
||||
}
|
||||
return;
|
||||
}
|
||||
globalStateState.setHistoryRouterPath(to.path);
|
||||
closeLoadingShow();
|
||||
});
|
||||
10
frontEnd/src/pages/404/404.vue
Normal file
@@ -0,0 +1,10 @@
|
||||
<template>
|
||||
<div>你寻找的页面失踪了</div>
|
||||
</template>
|
||||
|
||||
<script lang='ts' setup>
|
||||
import { reactive,onMounted} from 'vue'
|
||||
const data = reactive({})
|
||||
</script>
|
||||
<style lang='scss' scoped>
|
||||
</style>
|
||||
582
frontEnd/src/pages/checkout/checkout.vue
Normal file
@@ -0,0 +1,582 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-row>
|
||||
<baseTableHeader
|
||||
title="结账登记"
|
||||
@resetSearch="methods.resetSearch"
|
||||
@search="methods.search">
|
||||
<template #content>
|
||||
<el-form :model="searchForm" :inline="true" label-position="right">
|
||||
<el-form-item label="逝者姓名">
|
||||
<el-input
|
||||
v-model="searchForm.name"
|
||||
placeholder="请输入逝者姓名"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="性别">
|
||||
<el-radio-group v-model="searchForm.gender">
|
||||
<el-radio-button value="男" label="男"></el-radio-button>
|
||||
<el-radio-button value="女" label="女"></el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="结账日期">
|
||||
<el-date-picker
|
||||
v-model="searchForm.purchaseDate"
|
||||
type="datetimerange"
|
||||
range-separator="至"
|
||||
start-placeholder="选择日期"
|
||||
end-placeholder="选择日期"
|
||||
@change="dataChange" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
</baseTableHeader>
|
||||
</el-row>
|
||||
<el-card style="margin-top: 8px">
|
||||
<base-table
|
||||
:option="tableOption"
|
||||
ref="table"
|
||||
border
|
||||
show-summary
|
||||
:summary-method="getSummaries">
|
||||
<template #toolsBar>
|
||||
<el-radio-group
|
||||
v-model="searchForm.retailState"
|
||||
size="small"
|
||||
style="margin-left: 15px">
|
||||
<el-radio-button label="未结账" :value="0" />
|
||||
<el-radio-button label="已结账" :value="1" />
|
||||
</el-radio-group>
|
||||
</template>
|
||||
<template #colunm>
|
||||
<el-table-column
|
||||
type="index"
|
||||
width="80"
|
||||
fixed="left"
|
||||
align="center"></el-table-column>
|
||||
<el-table-column
|
||||
prop="retailState"
|
||||
label="结账状态"
|
||||
width="160"
|
||||
fixed="left"
|
||||
align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag
|
||||
:type="
|
||||
row.retailState === 0
|
||||
? 'danger'
|
||||
: row.retailState === 1
|
||||
? 'success'
|
||||
: 'info'
|
||||
">
|
||||
{{
|
||||
row.retailState === 0
|
||||
? "未结账"
|
||||
: row.retailState === 1
|
||||
? "已结账"
|
||||
: "未知"
|
||||
}}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="deceased.name"
|
||||
label="逝者姓名"
|
||||
width="120"
|
||||
fixed="left"
|
||||
align="center" />
|
||||
<el-table-column prop="deceased.gender" label="性别" align="center" />
|
||||
<el-table-column prop="deceased.age" label="年龄" align="center" />
|
||||
<el-table-column
|
||||
prop="deceased.idNumber"
|
||||
label="身份证"
|
||||
align="center"
|
||||
width="180" />
|
||||
<el-table-column
|
||||
prop="deceased.familyPhone"
|
||||
label="购买人电话"
|
||||
align="center"
|
||||
width="150" />
|
||||
<el-table-column
|
||||
prop="salesAmount"
|
||||
:label="'销售金额'"
|
||||
width="150"
|
||||
align="center" />
|
||||
|
||||
<el-table-column
|
||||
v-if="searchForm.retailState === 1"
|
||||
label="现金支付"
|
||||
width="150"
|
||||
prop="paymentRecord.cashAmount"
|
||||
align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.paymentRecord?.cashAmount || "0.00" }} 元
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="paymentRecord.unionPayAmount"
|
||||
label="银联支付"
|
||||
width="150"
|
||||
v-if="searchForm.retailState === 1"
|
||||
align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.paymentRecord?.unionPayAmount || "0.00" }} 元
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
prop="paymentRecord.cardAmount"
|
||||
label="刷卡金额"
|
||||
width="150"
|
||||
v-if="searchForm.retailState === 1"
|
||||
align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.paymentRecord?.cardAmount || "0.00" }} 元
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="paymentRecord.publicTransferAmount"
|
||||
label="对公转账"
|
||||
width="150"
|
||||
v-if="searchForm.retailState === 1"
|
||||
align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.paymentRecord?.publicTransferAmount || "0.00" }} 元
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
prop="paymentRecord.workshopPayment"
|
||||
label="车间支付"
|
||||
v-if="searchForm.retailState === 1"
|
||||
width="150"
|
||||
align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.paymentRecord?.workshopPayment || "0.00" }} 元
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
prop="createDate"
|
||||
:label="searchForm.retailState === 0 ? '录单时间' : '结账时间'"
|
||||
align="center"
|
||||
width="200">
|
||||
<template #default="{ row }">
|
||||
<span v-if="searchForm.retailState === 0">{{
|
||||
dayjs(row.createDate).format("YYYY-MM-DD HH:mm:ss")
|
||||
}}</span>
|
||||
<span v-if="searchForm.retailState === 1">
|
||||
{{
|
||||
dayjs(row.checkoutDate).format("YYYY-MM-DD HH:mm:ss")
|
||||
}}</span
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="deceased.name"
|
||||
label="购买人姓名"
|
||||
align="center"
|
||||
width="150" />
|
||||
|
||||
<el-table-column prop="remark" label="备注" align="center" />
|
||||
<el-table-column
|
||||
width="230"
|
||||
fixed="right"
|
||||
align="center"
|
||||
label="操作">
|
||||
<template #default="{ row }">
|
||||
<div style="display: flex; width: 100%; justify-content: center">
|
||||
<el-button
|
||||
v-if="row.retailState === 0"
|
||||
size="small"
|
||||
type="primary"
|
||||
@click="methods.add(row)">
|
||||
结账登记
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="row.retailState === 1"
|
||||
size="small"
|
||||
type="primary"
|
||||
@click="methods.view(row)">
|
||||
查看
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="row.retailState === 1"
|
||||
size="small"
|
||||
type="default"
|
||||
@click="methods.cancel(row)">
|
||||
作废
|
||||
</el-button>
|
||||
|
||||
<el-button
|
||||
v-if="row.retailState === 1"
|
||||
size="small"
|
||||
type="default"
|
||||
@click="methods.print(row)">
|
||||
打印
|
||||
<template #icon>
|
||||
<img
|
||||
src="/assets/icon/打印机.svg"
|
||||
style="margin-right: 5px"
|
||||
width="20"
|
||||
height="20" />
|
||||
</template>
|
||||
</el-button>
|
||||
|
||||
<el-button
|
||||
v-if="row.retailState === 0"
|
||||
size="small"
|
||||
type="default"
|
||||
@click="methods.print(row)">
|
||||
打印
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</template>
|
||||
</base-table>
|
||||
</el-card>
|
||||
|
||||
<base-curd-dialog
|
||||
v-model="pageVisibleState.show2LevelPage.value"
|
||||
:title="pageVisibleState.dialogTitle.value"
|
||||
width="70%"
|
||||
:before-close="methods.handleDialogClose"
|
||||
@addConfim="methods.addConfim"
|
||||
@editConfim="methods.eidthConfirm"
|
||||
@closeConfirm="methods.handleDialogClose"
|
||||
confirmText="结账"
|
||||
destroy-on-close
|
||||
:showPageType="pageVisibleState.showPageType">
|
||||
<template #content>
|
||||
<checkoutAddOrEdit
|
||||
:executeType="pageVisibleState.executeType.value"
|
||||
:deceased="currentRetail"
|
||||
v-model="currentPayment">
|
||||
</checkoutAddOrEdit>
|
||||
</template>
|
||||
<template #footer>
|
||||
<el-button @click="methods.print">打印</el-button>
|
||||
</template>
|
||||
</base-curd-dialog>
|
||||
|
||||
<base-dialog
|
||||
v-model="cancelState.showDialog"
|
||||
title="账单作废"
|
||||
width="50%"
|
||||
destroy-on-close
|
||||
@closeConfirm="methods.cancleClose">
|
||||
<el-form :model="cancelForm" label-width="120px" style="padding: 20px">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<!-- 注销申请人 -->
|
||||
<el-form-item label="作废申请人">
|
||||
<el-input disabled v-model="cancelForm.cancelPerson" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<!-- 注销日期 -->
|
||||
<el-form-item label="作废日期">
|
||||
<el-date-picker
|
||||
disabled
|
||||
v-model="cancelForm.cancelDate"
|
||||
type="date" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<!-- 注销原因 -->
|
||||
<el-form-item label="作废原因">
|
||||
<el-input
|
||||
v-model="cancelForm.cancelReason"
|
||||
type="textarea"
|
||||
placeholder="请输入作废原因" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="flex-center">
|
||||
<el-button type="primary" @click="methods.submitCancel"
|
||||
>作废</el-button
|
||||
>
|
||||
<el-button @click="methods.resetCancel">取消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</base-dialog>
|
||||
|
||||
<!-- <base-dialog v-model="showPrint" title="打印预览">
|
||||
<printRetailPage v-model="currentData"></printRetailPage>
|
||||
</base-dialog>
|
||||
|
||||
<base-dialog v-model="showPrint1" title="打印预览">
|
||||
<printServicesPage v-model="currentData"></printServicesPage>
|
||||
</base-dialog> -->
|
||||
<PrintRetailPage
|
||||
v-model="showPrint"
|
||||
:deceased="deceased"
|
||||
:serviceUrl="serviceUrl">
|
||||
</PrintRetailPage>
|
||||
|
||||
<printServicesPage
|
||||
v-model="showPrint1"
|
||||
:deceased="deceased"
|
||||
:serviceUrl="serviceUrl">
|
||||
</printServicesPage>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref, onMounted, watch, nextTick } from "vue";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
import { userInfor } from "@/store/user/user";
|
||||
import checkoutAddOrEdit from "./page/checkoutAddOrEdit.vue";
|
||||
import api from "@/lib/request";
|
||||
import pageVisible from "@/components/curdDialog/pageVisibleState";
|
||||
import { tableOptionType } from "@/types/table";
|
||||
import dayjs from "dayjs";
|
||||
import { defaultPaymentForm } from "@/defaultForm/defaultPaymentForm";
|
||||
import { defaultRetail } from "@/defaultForm/defaultRetail";
|
||||
import PrintRetailPage from "@/components/printPage/printRetailPage.vue";
|
||||
import printServicesPage from "@/components/printPage/printServicesPage.vue";
|
||||
|
||||
const pageVisibleState = new pageVisible({
|
||||
add: "结账登记",
|
||||
edit: "登记修改",
|
||||
view: "查看登记",
|
||||
});
|
||||
|
||||
const globaUser = userInfor().userInfor;
|
||||
|
||||
const cancelState = ref({
|
||||
showDialog: false,
|
||||
});
|
||||
const cancelForm = ref({
|
||||
cancelPerson: globaUser.name,
|
||||
cancelDate: dayjs().format(),
|
||||
cancelReason: "",
|
||||
});
|
||||
|
||||
const searchForm = ref({
|
||||
name: "", // 逝者姓名
|
||||
gender: "", // 性别 (male / female / other)
|
||||
checkoutDate: "", // 结账日期 (YYYY-MM-DD)
|
||||
retailState: 0,
|
||||
startDate: "",
|
||||
endDate: "",
|
||||
purchaseDate: ["", ""],
|
||||
});
|
||||
|
||||
let currentRetail = ref<RegisForm>(defaultRetail());
|
||||
|
||||
let showPrint = ref(false);
|
||||
let showPrint1 = ref(false);
|
||||
let deceased = ref();
|
||||
let serviceUrl = ref();
|
||||
|
||||
let table = ref();
|
||||
let currentData = ref();
|
||||
let tableOption = ref<tableOptionType>({
|
||||
url: "/checkout-retail/list?retailState=0",
|
||||
searchUrl: "/checkout-retail/query",
|
||||
searchParams: searchForm,
|
||||
executeType: "list",
|
||||
});
|
||||
|
||||
let currentPayment = ref<PaymentForm>(defaultPaymentForm());
|
||||
|
||||
watch(
|
||||
() => searchForm.value.retailState,
|
||||
(newData) => {
|
||||
tableOption.value.url =
|
||||
"/checkout-retail/list?retailState=" + Number(newData);
|
||||
table.value.methods.setDataType("list");
|
||||
}
|
||||
);
|
||||
|
||||
const methods = {
|
||||
view(row: RegisForm) {
|
||||
currentRetail.value = row;
|
||||
currentData = row;
|
||||
currentPayment.value = row.paymentRecord || defaultPaymentForm();
|
||||
pageVisibleState.showPageType.view = true;
|
||||
pageVisibleState.showPageType.add = false;
|
||||
pageVisibleState.executeType.value = "view";
|
||||
},
|
||||
add(row: RegisForm) {
|
||||
currentData.value = row;
|
||||
currentRetail.value = row;
|
||||
currentPayment.value = row.paymentRecord || defaultPaymentForm();
|
||||
if (row.retailState === 1) {
|
||||
pageVisibleState.showPageType.view = true;
|
||||
} else {
|
||||
pageVisibleState.showPageType.add = true;
|
||||
}
|
||||
pageVisibleState.executeType.value = "add";
|
||||
},
|
||||
|
||||
print(row: RegisForm) {
|
||||
deceased.value = row;
|
||||
serviceUrl.value =
|
||||
"/deceased-retail/selected-service?retailType=0&deceasedId=" +
|
||||
row.deceased.id;
|
||||
if (searchForm.value.retailState === 0) {
|
||||
showPrint1.value = true;
|
||||
} else {
|
||||
showPrint.value = true;
|
||||
}
|
||||
},
|
||||
|
||||
cancleClose() {
|
||||
currentRetail.value = defaultRetail();
|
||||
currentPayment.value = defaultPaymentForm();
|
||||
},
|
||||
|
||||
async addConfim() {
|
||||
await ElMessageBox.confirm("确定结账吗?", { type: "warning" });
|
||||
|
||||
let sendData = {
|
||||
deceasedRetail: {
|
||||
...currentRetail.value,
|
||||
},
|
||||
currentPayment: {
|
||||
...currentPayment.value,
|
||||
},
|
||||
id: currentData.value.id,
|
||||
};
|
||||
|
||||
const res = await api().post("/checkout-retail/confirmCheckout", sendData);
|
||||
if (res.code === 200) {
|
||||
ElMessage.success("结账成功!");
|
||||
pageVisibleState.show2LevelPage.value = false;
|
||||
table.value.methods.setDataType("list");
|
||||
} else {
|
||||
ElMessage.error(res.msg);
|
||||
}
|
||||
},
|
||||
eidthConfirm() {},
|
||||
search() {
|
||||
table.value.methods.setDataType("search");
|
||||
},
|
||||
resetSearch() {
|
||||
let retailState = searchForm.value.retailState;
|
||||
searchForm.value = {
|
||||
name: "", // 逝者姓名
|
||||
gender: "", // 性别 (male / female / other)
|
||||
checkoutDate: "", // 结账日期 (YYYY-MM-DD)
|
||||
startDate: "",
|
||||
endDate: "",
|
||||
purchaseDate: ["", ""],
|
||||
retailState: retailState,
|
||||
};
|
||||
nextTick(() => {
|
||||
table.value.methods.setDataType("reset");
|
||||
});
|
||||
},
|
||||
handleDialogClose() {
|
||||
pageVisibleState.show2LevelPage.value = false;
|
||||
},
|
||||
|
||||
cancel(row: RegisForm) {
|
||||
currentRetail.value = row;
|
||||
cancelState.value.showDialog = true;
|
||||
},
|
||||
async submitCancel() {
|
||||
if (!cancelForm.value.cancelReason) {
|
||||
return ElMessage.error("请输入作废原因");
|
||||
}
|
||||
await ElMessageBox.confirm("确定作废吗?", { type: "warning" });
|
||||
|
||||
let sendData = {
|
||||
deceasedRetailId: currentRetail.value.id,
|
||||
cancelForm: { ...cancelForm.value },
|
||||
cancelType: 0,
|
||||
};
|
||||
|
||||
api()
|
||||
.post("/cancel/cancel", sendData)
|
||||
.then((res) => {
|
||||
if (res.code === 200) {
|
||||
ElMessage.success("作废提交成功!");
|
||||
methods.resetCancel();
|
||||
cancelForm.value = {
|
||||
cancelPerson: globaUser.name,
|
||||
cancelDate: dayjs().format(),
|
||||
cancelReason: "",
|
||||
};
|
||||
table.value.methods.setDataType("list");
|
||||
} else {
|
||||
ElMessage.error(res.msg);
|
||||
}
|
||||
});
|
||||
},
|
||||
resetCancel() {
|
||||
cancelForm.value = {
|
||||
cancelPerson: globaUser.name,
|
||||
cancelDate: dayjs().format(),
|
||||
cancelReason: "",
|
||||
};
|
||||
cancelState.value.showDialog = false;
|
||||
},
|
||||
};
|
||||
function dataChange(val: Date[]) {
|
||||
searchForm.value.startDate = val[0];
|
||||
searchForm.value.endDate = val[1];
|
||||
}
|
||||
|
||||
const getSummaries = (param: { columns: any[]; data: any[] }) => {
|
||||
const { columns, data } = param;
|
||||
const sums: any[] = [];
|
||||
// 需要统计的字段列表
|
||||
const sumKeys = [
|
||||
"salesAmount",
|
||||
"paymentRecord.cashAmount",
|
||||
"paymentRecord.unionPayAmount",
|
||||
"paymentRecord.cardAmount",
|
||||
"paymentRecord.publicTransferAmount",
|
||||
"paymentRecord.workshopPayment",
|
||||
];
|
||||
columns.forEach((column, index) => {
|
||||
if (index === 0) {
|
||||
sums[index] = "合计";
|
||||
return;
|
||||
}
|
||||
if (sumKeys.includes(column.property)) {
|
||||
const values = data.map((item) => {
|
||||
const keys = column.property.split(".");
|
||||
let value = item;
|
||||
for (const key of keys) {
|
||||
value = value?.[key] || 0;
|
||||
}
|
||||
return Number(value) || 0;
|
||||
});
|
||||
|
||||
if (!values.every((value) => isNaN(value))) {
|
||||
const sum = values.reduce((prev, curr) => {
|
||||
return prev + curr;
|
||||
}, 0);
|
||||
sums[index] = `${sum.toFixed(2)}`;
|
||||
} else {
|
||||
sums[index] = "0.00 元";
|
||||
}
|
||||
} else {
|
||||
sums[index] = "";
|
||||
}
|
||||
});
|
||||
|
||||
return sums;
|
||||
};
|
||||
|
||||
onMounted(async () => {});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
/* 添加汇总行样式 */
|
||||
:deep(.el-table__footer) {
|
||||
.cell {
|
||||
font-weight: 600;
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
td {
|
||||
background-color: #f5f7fa !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
303
frontEnd/src/pages/checkout/page/checkoutAddOrEdit.vue
Normal file
@@ -0,0 +1,303 @@
|
||||
<template>
|
||||
<div>
|
||||
<inforCard title="逝者信息">
|
||||
<el-form :model="checkoutForm" label-width="120px" disabled>
|
||||
<el-row :gutter="20" v-if="!deceased.deceased">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="姓名">
|
||||
<el-input
|
||||
:prefix-icon="User"
|
||||
v-model="deceased.name"
|
||||
disabled
|
||||
placeholder="姓名">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="性别">
|
||||
<el-radio-group v-model="deceased.gender" disabled>
|
||||
<el-radio-button value="男" label="男"></el-radio-button>
|
||||
<el-radio-button value="女" label="女"></el-radio-button>
|
||||
</el-radio-group> </el-form-item
|
||||
></el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="证件号码" prop="idNumber">
|
||||
<el-input v-model="deceased.idNumber" disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="年龄">
|
||||
<el-input v-model="deceased.age" disabled placeholder="年龄">
|
||||
</el-input> </el-form-item
|
||||
></el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="购买人" prop="buyer">
|
||||
<el-input v-model="deceased.familyName" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="购买人电话" prop="buyer">
|
||||
<el-input v-model="deceased.familyPhone" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="购买日期" prop="purchaseDate">
|
||||
<el-date-picker
|
||||
v-model="deceased.purchaseDate"
|
||||
type="datetime"
|
||||
format="YYYY-MM-DD: HH:mm:ss" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="销售金额" prop="salesAmount">
|
||||
<el-input v-model.number="deceased.salesAmount" type="number">
|
||||
<template #append>元</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20" v-else">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="姓名">
|
||||
<el-input
|
||||
:prefix-icon="User"
|
||||
v-model="deceased.deceased.name"
|
||||
disabled
|
||||
placeholder="姓名">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="性别">
|
||||
<el-radio-group v-model="deceased.deceased.gender" disabled>
|
||||
<el-radio-button value="男" label="男"></el-radio-button>
|
||||
<el-radio-button value="女" label="女"></el-radio-button>
|
||||
</el-radio-group> </el-form-item
|
||||
></el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="证件号码" prop="idNumber">
|
||||
<el-input v-model="deceased.deceased.idNumber" disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="年龄">
|
||||
<el-input v-model="deceased.deceased.age" disabled placeholder="年龄">
|
||||
</el-input> </el-form-item
|
||||
></el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="购买人" prop="buyer">
|
||||
<el-input v-model="deceased.deceased.familyName" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="购买人电话" prop="buyer">
|
||||
<el-input v-model="deceased.deceased.familyPhone" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="购买日期" prop="purchaseDate">
|
||||
<el-date-picker
|
||||
v-model="deceased.deceased.purchaseDate"
|
||||
type="datetime"
|
||||
format="YYYY-MM-DD: HH:mm:ss" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="销售金额" prop="salesAmount">
|
||||
<el-input v-model.number="deceased.deceased.salesAmount" type="number">
|
||||
<template #append>元</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</inforCard>
|
||||
<inforCard title="已选服务项目">
|
||||
<el-table
|
||||
:data="servicesList"
|
||||
style="max-height: 160px; overflow-y: auto">
|
||||
<el-table-column type="index" label="序号" width="80" />
|
||||
<el-table-column prop="name" label="项目名称" />
|
||||
<el-table-column prop="quantity" label="数量" />
|
||||
<el-table-column prop="unit" label="单位" />
|
||||
<el-table-column prop="price" label="单价">
|
||||
<template #default="{ row }"> {{ row.price }} 元 </template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="price" label="总金额">
|
||||
<template #default="{ row }">
|
||||
{{ row.price * row.quantity }} 元
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="remark" label="备注" />
|
||||
</el-table>
|
||||
</inforCard>
|
||||
<inforCard title="结账列表">
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="checkoutForm"
|
||||
label-width="120px"
|
||||
label-position="right">
|
||||
<el-row :gutter="20">
|
||||
<!-- 第一行 -->
|
||||
<el-col :span="8">
|
||||
<el-form-item label="结账日期" prop="checkoutDate">
|
||||
<el-date-picker
|
||||
v-model="checkoutForm.checkoutDate"
|
||||
type="date"
|
||||
placeholder="结账日期"
|
||||
format="YYYY-MM-DD"
|
||||
disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="8">
|
||||
<el-form-item label="结算日期" prop="settlementDate">
|
||||
<el-date-picker
|
||||
v-model="checkoutForm.settlementDate"
|
||||
type="date"
|
||||
placeholder="选择日期"
|
||||
format="YYYY-MM-DD" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="经办人" prop="handler">
|
||||
<el-input
|
||||
disabled
|
||||
v-model="checkoutForm.handler"
|
||||
placeholder="经办人" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="现金金额" prop="cash">
|
||||
<el-input
|
||||
v-model.number="checkoutForm.cashAmount"
|
||||
type="number"
|
||||
:min="0"
|
||||
@input="caleValue('cashAmount')">
|
||||
<template #append>元</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="银联" prop="unionPay">
|
||||
<el-input
|
||||
v-model.number="checkoutForm.unionPayAmount"
|
||||
type="number"
|
||||
:min="0"
|
||||
@input="caleValue('unionPayAmount')">
|
||||
<template #append>元</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="8">
|
||||
<el-form-item label="银行卡" prop="cardPay">
|
||||
<el-input
|
||||
v-model.number="checkoutForm.cardAmount"
|
||||
type="number"
|
||||
:min="0"
|
||||
@input="caleValue('cardAmount')">
|
||||
<template #append>元</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="8">
|
||||
<el-form-item label="对公" prop="transfer">
|
||||
<el-input
|
||||
v-model.number="checkoutForm.publicTransferAmount"
|
||||
type="number"
|
||||
:min="0"
|
||||
@input="caleValue('publicTransferAmount')">
|
||||
<template #append>元</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="车间支付" prop="transfer">
|
||||
<el-input
|
||||
v-model.number="checkoutForm.workshopPayment"
|
||||
type="number"
|
||||
:min="0"
|
||||
@input="caleValue('workshopPayment')">
|
||||
<template #append>元</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</inforCard>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref, watch } from "vue";
|
||||
// @ts-ignore
|
||||
import { User } from "@element-plus/icons-vue";
|
||||
import dayjs from "dayjs";
|
||||
import { userInfor } from "@/store/user/user";
|
||||
import { defaultRetail } from "@/defaultForm/defaultRetail";
|
||||
import { defaultPaymentForm } from "@/defaultForm/defaultPaymentForm";
|
||||
import request from "@/lib/request";
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
executeType?: string;
|
||||
deceased: RegisForm;
|
||||
}>(),
|
||||
{
|
||||
deceased: () => defaultRetail(),
|
||||
}
|
||||
);
|
||||
|
||||
const emit = defineEmits(["updateData"]);
|
||||
const userInforStore = userInfor().userInfor;
|
||||
|
||||
let checkoutForm = defineModel({ default: defaultPaymentForm() });
|
||||
let servicesList = ref([]);
|
||||
|
||||
onMounted(() => {
|
||||
|
||||
checkoutForm.value.handler =
|
||||
checkoutForm.value.handler || (userInforStore.name as string);
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
let keys = [
|
||||
"cashAmount",
|
||||
"unionPayAmount",
|
||||
"cardAmount",
|
||||
"publicTransferAmount",
|
||||
"workshopPayment",
|
||||
];
|
||||
|
||||
function caleValue(keyVal: string) {
|
||||
let total = 0;
|
||||
let currentVal = checkoutForm.value[keyVal];
|
||||
|
||||
keys.forEach((key) => {
|
||||
if (keyVal !== key) {
|
||||
let tempVal = Number(checkoutForm.value[key]).toFixed(2);
|
||||
|
||||
total = Number(total) + Number(tempVal);
|
||||
}
|
||||
});
|
||||
let salesAmount = Number(props.deceased.salesAmount);
|
||||
|
||||
if (salesAmount - (total + currentVal) < 0) {
|
||||
checkoutForm.value[keyVal] = salesAmount - total;
|
||||
}
|
||||
}
|
||||
request()
|
||||
.get(
|
||||
"/deceased-retail/selected-service?deceasedId=" +
|
||||
props.deceased.deceased.id +
|
||||
"&retailType=0"
|
||||
)
|
||||
.then((res) => {
|
||||
servicesList.value = res.data?.list || [];
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
||||
444
frontEnd/src/pages/funeralRetail/departedSaint/departedSaint.vue
Normal file
@@ -0,0 +1,444 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-row>
|
||||
<baseTableHeader
|
||||
title="逝者零售"
|
||||
@resetSearch="methods.resetSearch"
|
||||
@search="methods.search">
|
||||
<template #content>
|
||||
<el-form :model="searchForm" label-position="right">
|
||||
<el-row :gutter="12">
|
||||
<el-col :span="6">
|
||||
<el-form-item label="逝者姓名">
|
||||
<el-input
|
||||
v-model="searchForm.deceased.name"
|
||||
placeholder="请输入逝者姓名"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="购买人姓名">
|
||||
<el-input
|
||||
v-model="searchForm.retail.familyName"
|
||||
placeholder="请输入购买人姓名"></el-input> </el-form-item
|
||||
></el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="引导员">
|
||||
<GuideList v-model="searchForm.retail.guide"></GuideList>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="10">
|
||||
<el-form-item label="购买日期">
|
||||
<el-date-picker
|
||||
v-model="searchForm.retail.purchaseDate"
|
||||
type="datetimerange"
|
||||
range-separator="至"
|
||||
start-placeholder="选择日期"
|
||||
end-placeholder="选择日期"
|
||||
@change="dataChange" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</template>
|
||||
</baseTableHeader>
|
||||
</el-row>
|
||||
<el-card style="margin-top: 8px">
|
||||
<div style="margin-bottom: 15px">
|
||||
<el-button
|
||||
size="small"
|
||||
type="primary"
|
||||
@click="methods.add"
|
||||
v-if="route.path === '/noDepartedSaint'">
|
||||
<template #icon>
|
||||
<el-icon>
|
||||
<CirclePlus />
|
||||
</el-icon> </template
|
||||
>新增</el-button
|
||||
>
|
||||
</div>
|
||||
<base-table
|
||||
:option="tableOption"
|
||||
ref="table"
|
||||
border
|
||||
show-summary
|
||||
:summary-method="getSummaries">
|
||||
<template #colunm>
|
||||
<el-table-column
|
||||
type="index"
|
||||
width="80"
|
||||
fixed="left"
|
||||
align="center"></el-table-column>
|
||||
<el-table-column
|
||||
prop="name"
|
||||
label="结账"
|
||||
width="120"
|
||||
align="center"
|
||||
fixed="left">
|
||||
<template #default="{ row }">
|
||||
<el-tag type="success" v-if="row.retailState === 1"
|
||||
>已结账</el-tag
|
||||
>
|
||||
<el-tag type="danger" v-if="row.retailState === 0">未结账</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="deceased.name"
|
||||
label="逝者姓名"
|
||||
fixed="left"
|
||||
align="center" />
|
||||
<el-table-column
|
||||
prop="familyName"
|
||||
label="购买人"
|
||||
align="center"
|
||||
fixed="left">
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.deceased.familyName">
|
||||
{{ row.deceased.familyName }}
|
||||
</span>
|
||||
<span v-else>--</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="createDate"
|
||||
label="购买日期"
|
||||
width="200"
|
||||
align="center" />
|
||||
<el-table-column
|
||||
prop="createDate"
|
||||
label="结算日期"
|
||||
width="200"
|
||||
align="center">
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.retailState === 1"> {{ row.checkoutDate }} </span>
|
||||
<span v-else style="color: #999; font-style: italic">--</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="salesAmount"
|
||||
label="销售金额"
|
||||
width="150"
|
||||
align="center" />
|
||||
<el-table-column
|
||||
label="现金支付"
|
||||
width="150"
|
||||
prop="payment.cashAmount"
|
||||
align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.payment?.cashAmount || "0.00" }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="payment.unionPayAmount"
|
||||
label="银联支付"
|
||||
width="150"
|
||||
align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.payment?.unionPayAmount || "0.00" }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
prop="payment.cardAmount"
|
||||
label="刷卡金额"
|
||||
width="150"
|
||||
align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.payment?.cardAmount || "0.00" }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="payment.publicTransferAmount"
|
||||
label="对公转账"
|
||||
width="150"
|
||||
align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.payment?.publicTransferAmount || "0.00" }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
prop="payment.workshopPayment"
|
||||
label="车间支付"
|
||||
width="150"
|
||||
align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.payment?.workshopPayment || "0.00" }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="handler" label="经办人" align="center" />
|
||||
|
||||
<el-table-column label="引导员" align="center">
|
||||
<template #default="{ row }">
|
||||
<span> {{ row.guide ?? row.deceased.guide }} </span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
width="320"
|
||||
label="操作"
|
||||
align="center"
|
||||
fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-row align="middle" justify="center">
|
||||
<el-button
|
||||
v-if="row.retailState !== 1"
|
||||
size="small"
|
||||
type="primary"
|
||||
@click="methods.update(row)">
|
||||
修改</el-button
|
||||
>
|
||||
|
||||
<el-button @click="methods.viewProduct(row)" size="small">
|
||||
零售清单</el-button
|
||||
>
|
||||
<el-button
|
||||
size="small"
|
||||
type="default"
|
||||
@click="methods.print(row)"
|
||||
>打印</el-button
|
||||
>
|
||||
<el-button
|
||||
size="small"
|
||||
type="danger"
|
||||
v-if="row.retailState !== 1"
|
||||
@click="methods.delete(row)">
|
||||
删除</el-button
|
||||
>
|
||||
</el-row>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</template>
|
||||
</base-table>
|
||||
</el-card>
|
||||
|
||||
<retailList v-model="showDialog" :option="retailListTable"></retailList>
|
||||
|
||||
<baseDialog
|
||||
v-model="retailRegisState.showDialog"
|
||||
top="50px"
|
||||
:title="
|
||||
handlerType === 'add'
|
||||
? '新增登记'
|
||||
: handlerType === 'update'
|
||||
? '修改零售登记'
|
||||
: '零售登记'
|
||||
"
|
||||
@close="methods.dialogClose">
|
||||
<retailRegis
|
||||
:retailType="1"
|
||||
v-model="regisForm"
|
||||
type="零售修改"
|
||||
:showList="['逝者信息']"
|
||||
:add="handlerType === 'add'"></retailRegis>
|
||||
<template #footer>
|
||||
<el-row justify="center" align="middle" style="margin-top: 15px">
|
||||
<el-button type="primary" @click="methods.confirmUpdate"
|
||||
>保存</el-button
|
||||
>
|
||||
<el-button type="danger" @click="methods.close">关闭</el-button>
|
||||
</el-row>
|
||||
</template>
|
||||
</baseDialog>
|
||||
|
||||
<printServicesPage
|
||||
v-model="showPrint"
|
||||
:deceased="deceased"
|
||||
:serviceUrl="serviceUrl">
|
||||
</printServicesPage>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref, onMounted, watch } from "vue";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
import { resetParams } from "@/util/globalMethods";
|
||||
import { globalState } from "@/store";
|
||||
import retailRegis from "../publicComponents/retailRegis.vue";
|
||||
import api from "@/lib/request";
|
||||
import { tableOptionType } from "@/types/table";
|
||||
import { useRoute } from "vue-router";
|
||||
import { defaultRetail } from "@/defaultForm/defaultRetail";
|
||||
import PrintRetailPage from "@/components/printPage/printServicesPage.vue";
|
||||
import printServicesPage from "@/components/printPage/printServicesPage.vue";
|
||||
import GuideList from "@/components/guideList/guideList.vue";
|
||||
|
||||
const retailRegisState = ref({
|
||||
showDialog: false,
|
||||
});
|
||||
|
||||
let currentInfor = ref(undefined);
|
||||
let showDialog = ref(false);
|
||||
|
||||
let showPrint = ref(false);
|
||||
let deceased = ref();
|
||||
let serviceUrl = ref();
|
||||
|
||||
const handlerType = ref("");
|
||||
const searchForm = reactive({
|
||||
deceased: {
|
||||
name: "", // 逝者姓名
|
||||
},
|
||||
retail: {
|
||||
guide: "", // 引导员
|
||||
purchaseDate: "", // 购买日期
|
||||
retailType: 1,
|
||||
startDate: "",
|
||||
endDate: "",
|
||||
familyName: "",
|
||||
},
|
||||
});
|
||||
|
||||
const route = useRoute();
|
||||
|
||||
const regisForm = ref<RegisForm>();
|
||||
let table = ref();
|
||||
let tableOption = ref<tableOptionType>({
|
||||
url: "/deceased-retail/list?retailType=1",
|
||||
searchUrl: "/deceased-retail/query",
|
||||
searchParams: searchForm,
|
||||
executeType: "list",
|
||||
});
|
||||
let retailListTable = ref<tableOptionType>({
|
||||
url: "/deceased-retail/selected-service",
|
||||
searchUrl: "",
|
||||
searchParams: {},
|
||||
executeType: "list",
|
||||
});
|
||||
|
||||
const methods = {
|
||||
update(row: RegisForm) {
|
||||
regisForm.value = row;
|
||||
handlerType.value = "update";
|
||||
retailRegisState.value.showDialog = true;
|
||||
},
|
||||
async confirmUpdate() {
|
||||
await ElMessageBox.confirm("确定保存修改吗?", { type: "warning" });
|
||||
let sendData = { ...regisForm.value };
|
||||
api()
|
||||
.post("/deceased-retail/update", sendData)
|
||||
.then((res) => {
|
||||
if (res.code === 200) {
|
||||
ElMessage.success("修改成功");
|
||||
table.value.methods.setDataType("list");
|
||||
retailRegisState.value.showDialog = false;
|
||||
regisForm.value = defaultRetail();
|
||||
}
|
||||
});
|
||||
},
|
||||
async delete(row: RegisForm) {
|
||||
await ElMessageBox.confirm("确定删除该条信息吗?", { type: "warning" });
|
||||
api()
|
||||
.get("/deceased-retail/delete", {
|
||||
params: {
|
||||
id: row.id,
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.code === 200) {
|
||||
ElMessage.success("删除成功");
|
||||
table.value.methods.setDataType("list");
|
||||
}
|
||||
});
|
||||
},
|
||||
add() {
|
||||
retailRegisState.value.showDialog = true;
|
||||
handlerType.value = "add";
|
||||
},
|
||||
async viewProduct(row: RegisForm) {
|
||||
retailListTable.value.url =
|
||||
"/deceased-retail/selected-service?retailType=1&retailId=" +
|
||||
(row.retailId || row.id);
|
||||
showDialog.value = true;
|
||||
},
|
||||
drawerClose() {
|
||||
currentInfor.value = undefined;
|
||||
showDialog.value = false;
|
||||
},
|
||||
|
||||
close() {
|
||||
retailRegisState.value.showDialog = false;
|
||||
},
|
||||
async print(row: RegisForm) {
|
||||
deceased.value = row;
|
||||
showPrint.value = true;
|
||||
|
||||
serviceUrl.value =
|
||||
"/deceased-retail/selected-service?retailType=1&retailId=" +
|
||||
(row.retailId || row.id);
|
||||
},
|
||||
dialogClose() {
|
||||
regisForm.value = defaultRetail();
|
||||
},
|
||||
search() {
|
||||
searchForm.retail.retailType = 1;
|
||||
table.value.methods.setDataType("search");
|
||||
},
|
||||
|
||||
resetSearch() {
|
||||
resetParams(searchForm);
|
||||
table.value.methods.setDataType("reset");
|
||||
},
|
||||
};
|
||||
|
||||
onMounted(async () => {});
|
||||
|
||||
const getSummaries = (param: { columns: any[]; data: any[] }) => {
|
||||
const { columns, data } = param;
|
||||
const sums: any[] = [];
|
||||
// 需要统计的字段列表
|
||||
const sumKeys = [
|
||||
"salesAmount",
|
||||
"payment.cashAmount",
|
||||
"payment.unionPayAmount",
|
||||
"payment.cardAmount",
|
||||
"payment.publicTransferAmount",
|
||||
"payment.workshopPayment",
|
||||
];
|
||||
columns.forEach((column, index) => {
|
||||
if (index === 0) {
|
||||
sums[index] = "合计";
|
||||
return;
|
||||
}
|
||||
if (sumKeys.includes(column.property)) {
|
||||
const values = data.map((item) => {
|
||||
const keys = column.property.split(".");
|
||||
let value = item;
|
||||
for (const key of keys) {
|
||||
value = value?.[key] || 0;
|
||||
}
|
||||
return Number(value) || 0;
|
||||
});
|
||||
|
||||
if (!values.every((value) => isNaN(value))) {
|
||||
const sum = values.reduce((prev, curr) => {
|
||||
return prev + curr;
|
||||
}, 0);
|
||||
sums[index] = `${sum.toFixed(2)}`;
|
||||
} else {
|
||||
sums[index] = "0.00 元";
|
||||
}
|
||||
} else {
|
||||
sums[index] = "";
|
||||
}
|
||||
});
|
||||
|
||||
return sums;
|
||||
};
|
||||
|
||||
function dataChange(val: Date[]) {
|
||||
searchForm.retail.startDate = val[0];
|
||||
searchForm.retail.endDate = val[1];
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
/* 添加汇总行样式 */
|
||||
:deep(.el-table__footer) {
|
||||
.cell {
|
||||
font-weight: 600;
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
td {
|
||||
background-color: #f5f7fa !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
6
frontEnd/src/pages/funeralRetail/funeralRetail.vue
Normal file
@@ -0,0 +1,6 @@
|
||||
<template>
|
||||
<router-view></router-view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup></script>
|
||||
<style lang="scss" scoped></style>
|
||||
@@ -0,0 +1,453 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-row>
|
||||
<baseTableHeader
|
||||
title="无逝者零售"
|
||||
@resetSearch="methods.resetSearch"
|
||||
@search="methods.search">
|
||||
<template #content>
|
||||
<el-form :model="searchForm" label-position="right">
|
||||
<el-row :gutter="12">
|
||||
<el-col :span="6">
|
||||
<el-form-item label="逝者姓名">
|
||||
<el-input
|
||||
v-model="searchForm.deceased.name"
|
||||
placeholder="请输入逝者姓名"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="购买人姓名">
|
||||
<el-input
|
||||
v-model="searchForm.retail.familyName"
|
||||
placeholder="请输入购买人姓名"></el-input> </el-form-item
|
||||
></el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="引导员">
|
||||
<GuideList v-model="searchForm.retail.guide"></GuideList>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="10">
|
||||
<el-form-item label="购买日期">
|
||||
<el-date-picker
|
||||
v-model="searchForm.retail.purchaseDate"
|
||||
type="datetimerange"
|
||||
range-separator="至"
|
||||
start-placeholder="选择日期"
|
||||
end-placeholder="选择日期"
|
||||
@change="dataChange" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</template>
|
||||
</baseTableHeader>
|
||||
</el-row>
|
||||
<el-card style="margin-top: 8px">
|
||||
<base-table
|
||||
:option="tableOption"
|
||||
ref="table"
|
||||
border
|
||||
show-summary
|
||||
:summary-method="getSummaries">
|
||||
<template #toolsBar>
|
||||
<el-button size="small" type="primary" @click="methods.add">
|
||||
<template #icon>
|
||||
<el-icon>
|
||||
<CirclePlus />
|
||||
</el-icon> </template
|
||||
>新增</el-button
|
||||
>
|
||||
</template>
|
||||
<template #colunm>
|
||||
<el-table-column
|
||||
type="index"
|
||||
width="80"
|
||||
fixed="left"
|
||||
align="center"></el-table-column>
|
||||
<el-table-column label="结账" align="center" width="120" fixed="left">
|
||||
<template #default="{ row }">
|
||||
<el-tag type="success" v-if="row.retailState === 1"
|
||||
>已结账</el-tag
|
||||
>
|
||||
<el-tag type="danger" v-if="row.retailState === 0">未结账</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="familyName"
|
||||
label="购买人"
|
||||
align="center"
|
||||
fixed="left">
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.familyName">{{ row.familyName }}</span>
|
||||
<span v-else>--</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
prop="deceasedName"
|
||||
label="逝者姓名"
|
||||
align="center"
|
||||
fixed="left">
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.deceasedName">{{ row.deceasedName }}</span>
|
||||
<span v-else>--</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="createDate"
|
||||
label="购买日期"
|
||||
width="200"
|
||||
align="center" />
|
||||
<el-table-column
|
||||
prop="createDate"
|
||||
label="结算日期"
|
||||
width="200"
|
||||
align="center">
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.retailState === 1"> {{ row.checkoutDate }} </span>
|
||||
<span v-else style="color: #999; font-style: italic">--</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="salesAmount" label="销售金额" align="center" />
|
||||
|
||||
<el-table-column
|
||||
label="现金支付"
|
||||
width="150"
|
||||
prop="payment.cashAmount"
|
||||
align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.payment?.cashAmount || "0.00" }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="payment.unionPayAmount"
|
||||
label="银联支付"
|
||||
width="150"
|
||||
align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.payment?.unionPayAmount || "0.00" }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
prop="payment.cardAmount"
|
||||
label="刷卡金额"
|
||||
width="150"
|
||||
align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.payment?.cardAmount || "0.00" }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="payment.publicTransferAmount"
|
||||
label="对公转账"
|
||||
width="150"
|
||||
align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.payment?.publicTransferAmount || "0.00" }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
prop="payment.workshopPayment"
|
||||
label="车间支付"
|
||||
width="150"
|
||||
align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.payment?.workshopPayment || "0.00" }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="handler" label="经办人" align="center" />
|
||||
<el-table-column prop="guide" label="引导员" align="center" />
|
||||
<el-table-column
|
||||
width="320"
|
||||
label="操作"
|
||||
align="center"
|
||||
fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-row align="middle" justify="center">
|
||||
<el-button
|
||||
v-if="row.retailState === 0"
|
||||
size="small"
|
||||
type="primary"
|
||||
@click="methods.update(row)">
|
||||
修改</el-button
|
||||
>
|
||||
<el-button @click="methods.viewProduct(row)" size="small">
|
||||
零售清单</el-button
|
||||
>
|
||||
|
||||
<el-button
|
||||
size="small"
|
||||
type="default"
|
||||
@click="methods.print(row)"
|
||||
>打印</el-button
|
||||
>
|
||||
<!-- <el-button
|
||||
type="primary"
|
||||
v-if="row.retailState === 0"
|
||||
@click="methods.checkout(row)"
|
||||
>结账</el-button
|
||||
> -->
|
||||
<el-button
|
||||
size="small"
|
||||
type="danger"
|
||||
v-if="row.retailState !== 1"
|
||||
@click="methods.delete(row)">
|
||||
删除</el-button
|
||||
>
|
||||
</el-row>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</template>
|
||||
</base-table>
|
||||
</el-card>
|
||||
|
||||
<retailList v-model="showDialog" :option="retailListTable"></retailList>
|
||||
|
||||
<baseDialog
|
||||
v-model="retailRegisState.showDialog"
|
||||
top="30px"
|
||||
:title="
|
||||
handlerType === 'add'
|
||||
? '新增无逝者零售'
|
||||
: handlerType === 'update'
|
||||
? '修改无逝者登记'
|
||||
: '零售登记'
|
||||
"
|
||||
@close="methods.dialogClose">
|
||||
<retailRegis
|
||||
v-model="regisForm"
|
||||
:add="handlerType === 'add'"
|
||||
:retailType="2"
|
||||
:type="
|
||||
handlerType === 'add'
|
||||
? '新增无逝者零售'
|
||||
: handlerType === 'update'
|
||||
? '修改无逝者登记'
|
||||
: '零售登记'
|
||||
"></retailRegis>
|
||||
<template #footer>
|
||||
<el-row justify="center" align="middle" style="margin-top: 15px">
|
||||
<el-button type="primary" @click="methods.addConfirm">保存</el-button>
|
||||
<el-button type="danger" @click="methods.close">关闭</el-button>
|
||||
</el-row>
|
||||
</template>
|
||||
</baseDialog>
|
||||
|
||||
<printServicesPage
|
||||
v-model="showPrint"
|
||||
:deceased="deceased"
|
||||
:serviceUrl="serviceUrl">
|
||||
</printServicesPage>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref, onMounted, watch } from "vue";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
import { resetParams } from "@/util/globalMethods";
|
||||
import { globalState } from "@/store";
|
||||
import retailRegis from "../publicComponents/retailRegis.vue";
|
||||
import api from "@/lib/request";
|
||||
import { tableOptionType } from "@/types/table";
|
||||
import { defaultRetail } from "@/defaultForm/defaultRetail";
|
||||
import printServicesPage from "@/components/printPage/printServicesPage.vue";
|
||||
import GuideList from "@/components/guideList/guideList.vue";
|
||||
|
||||
let retailListTable = ref<tableOptionType>({
|
||||
url: "/deceased-retail/selected-service",
|
||||
searchUrl: "",
|
||||
searchParams: {},
|
||||
executeType: "list",
|
||||
});
|
||||
|
||||
let showPrint = ref(false);
|
||||
let deceased = ref();
|
||||
let serviceUrl = ref();
|
||||
|
||||
const retailRegisState = ref({
|
||||
showDialog: false,
|
||||
});
|
||||
|
||||
let currentInfor = ref(undefined);
|
||||
let showDialog = ref(false);
|
||||
|
||||
const handlerType = ref("新增无逝者零售");
|
||||
const searchForm = reactive({
|
||||
deceased: {
|
||||
name: "",
|
||||
},
|
||||
retail: {
|
||||
guide: "", // 引导员
|
||||
purchaseDate: "", // 购买日期
|
||||
retailType: 2,
|
||||
familyName: "",
|
||||
},
|
||||
});
|
||||
|
||||
const regisForm = ref<RegisForm>();
|
||||
|
||||
let table = ref();
|
||||
let tableOption = ref<tableOptionType>({
|
||||
url: "/deceased-retail/list?retailType=2",
|
||||
searchUrl: "/deceased-retail/query",
|
||||
searchParams: searchForm,
|
||||
executeType: "list",
|
||||
});
|
||||
const methods = {
|
||||
update(row: RegisForm) {
|
||||
regisForm.value = row;
|
||||
handlerType.value = "update";
|
||||
retailRegisState.value.showDialog = true;
|
||||
},
|
||||
async delete(row: RegisForm) {
|
||||
await ElMessageBox.confirm("确定删除该条信息吗?", { type: "warning" });
|
||||
const res = await api().get("deceased-retail/delete", {
|
||||
params: {
|
||||
id: row.id,
|
||||
},
|
||||
});
|
||||
if (res.code === 200) {
|
||||
ElMessage.success("删除成功");
|
||||
table.value.methods.setDataType("list");
|
||||
} else {
|
||||
ElMessage.error(res);
|
||||
}
|
||||
},
|
||||
add() {
|
||||
retailRegisState.value.showDialog = true;
|
||||
handlerType.value = "add";
|
||||
},
|
||||
viewProduct(row: RegisForm) {
|
||||
retailListTable.value.url =
|
||||
"/deceased-retail/selected-service?retailType=2&retailId=" + row.id;
|
||||
showDialog.value = true;
|
||||
},
|
||||
drawerClose() {
|
||||
currentInfor.value = undefined;
|
||||
showDialog.value = false;
|
||||
},
|
||||
async addConfirm() {
|
||||
let url = "/no-deceased-retail/add";
|
||||
if (handlerType.value === "update") url = "/no-deceased-retail/update";
|
||||
await ElMessageBox.confirm("确定保存吗?", {
|
||||
type: "warning",
|
||||
});
|
||||
let sendData = { ...regisForm.value };
|
||||
api()
|
||||
.post(url, sendData)
|
||||
.then((res) => {
|
||||
if (res.code === 200) {
|
||||
ElMessage.success("保存成功!");
|
||||
retailRegisState.value.showDialog = false;
|
||||
table.value.methods.setDataType("list");
|
||||
} else {
|
||||
ElMessage.error(res.msg);
|
||||
}
|
||||
});
|
||||
},
|
||||
async checkout(row: RegisForm) {
|
||||
await ElMessageBox.confirm("确定结账吗?", { type: "warning" });
|
||||
|
||||
api()
|
||||
.get("/no-deceased-retail/checkout", {
|
||||
params: {
|
||||
id: Number(row.id),
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.code === 200) {
|
||||
ElMessage.success("结账成功!");
|
||||
retailRegisState.value.showDialog = false;
|
||||
table.value.methods.setDataType("list");
|
||||
} else {
|
||||
ElMessage.error(res.msg);
|
||||
}
|
||||
});
|
||||
},
|
||||
close() {
|
||||
retailRegisState.value.showDialog = false;
|
||||
},
|
||||
async print(row: any) {
|
||||
deceased.value = row;
|
||||
showPrint.value = true;
|
||||
|
||||
serviceUrl.value =
|
||||
"/deceased-retail/selected-service?retailType=2&retailId=" + row.id;
|
||||
},
|
||||
dialogClose() {
|
||||
regisForm.value = defaultRetail();
|
||||
},
|
||||
search() {
|
||||
searchForm.retail.retailType = 2;
|
||||
table.value.methods.setDataType("search");
|
||||
},
|
||||
|
||||
resetSearch() {
|
||||
resetParams(searchForm);
|
||||
table.value.methods.setDataType("reset");
|
||||
},
|
||||
};
|
||||
|
||||
const getSummaries = (param: { columns: any[]; data: any[] }) => {
|
||||
const { columns, data } = param;
|
||||
const sums: any[] = [];
|
||||
// 需要统计的字段列表
|
||||
const sumKeys = [
|
||||
"salesAmount",
|
||||
"payment.cashAmount",
|
||||
"payment.unionPayAmount",
|
||||
"payment.cardAmount",
|
||||
"payment.publicTransferAmount",
|
||||
"payment.workshopPayment",
|
||||
];
|
||||
columns.forEach((column, index) => {
|
||||
if (index === 0) {
|
||||
sums[index] = "合计";
|
||||
return;
|
||||
}
|
||||
if (sumKeys.includes(column.property)) {
|
||||
const values = data.map((item) => {
|
||||
const keys = column.property.split(".");
|
||||
let value = item;
|
||||
for (const key of keys) {
|
||||
value = value?.[key] || 0;
|
||||
}
|
||||
return Number(value) || 0;
|
||||
});
|
||||
|
||||
if (!values.every((value) => isNaN(value))) {
|
||||
const sum = values.reduce((prev, curr) => {
|
||||
return prev + curr;
|
||||
}, 0);
|
||||
sums[index] = `${sum.toFixed(2)}`;
|
||||
} else {
|
||||
sums[index] = "0.00 元";
|
||||
}
|
||||
} else {
|
||||
sums[index] = "";
|
||||
}
|
||||
});
|
||||
|
||||
return sums;
|
||||
};
|
||||
|
||||
function dataChange(val: Date[]) {
|
||||
searchForm.retail.startDate = val[0];
|
||||
searchForm.retail.endDate = val[1];
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
/* 添加汇总行样式 */
|
||||
:deep(.el-table__footer) {
|
||||
.cell {
|
||||
font-weight: 600;
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
td {
|
||||
background-color: #f5f7fa !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,512 @@
|
||||
<template>
|
||||
<el-form
|
||||
style="max-height: 72vh; overflow-y: auto"
|
||||
ref="formRef"
|
||||
:model="regisForm"
|
||||
label-width="120px"
|
||||
label-position="right">
|
||||
<inforCard title="逝者信息" v-if="showList.includes('逝者信息')">
|
||||
<el-row :gutter="20" v-if="!regisForm.deceased">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="逝者姓名" prop="name">
|
||||
<el-input
|
||||
v-model="regisForm.name"
|
||||
:disabled="
|
||||
props.type !== '服务修改' && props.type !== '服务登记'
|
||||
" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="8">
|
||||
<el-form-item label="证件号码" prop="idNumber">
|
||||
<el-input
|
||||
v-model="regisForm.idNumber"
|
||||
:disabled="
|
||||
props.type !== '服务修改' && props.type !== '服务登记'
|
||||
" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="性别" prop="gender">
|
||||
<el-radio-group
|
||||
v-model="regisForm.gender"
|
||||
:disabled="
|
||||
props.type !== '服务修改' && props.type !== '服务登记'
|
||||
">
|
||||
<el-radio-button label="男" value="男"></el-radio-button>
|
||||
<el-radio-button label="女" value="女"></el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="8">
|
||||
<el-form-item label="年龄" prop="age">
|
||||
<el-input
|
||||
v-model="regisForm.age"
|
||||
:disabled="
|
||||
props.type !== '服务修改' && props.type !== '服务登记'
|
||||
" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20" v-else>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="逝者姓名" prop="name">
|
||||
<el-input
|
||||
v-model="regisForm.deceased.name"
|
||||
:disabled="
|
||||
props.type !== '服务修改' && props.type !== '服务登记'
|
||||
" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="8">
|
||||
<el-form-item label="证件号码" prop="idNumber">
|
||||
<el-input
|
||||
v-model="regisForm.deceased.idNumber"
|
||||
:disabled="
|
||||
props.type !== '服务修改' && props.type !== '服务登记'
|
||||
" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="性别" prop="gender">
|
||||
<el-radio-group
|
||||
v-model="regisForm.deceased.gender"
|
||||
:disabled="
|
||||
props.type !== '服务修改' && props.type !== '服务登记'
|
||||
">
|
||||
<el-radio-button label="男" value="男"></el-radio-button>
|
||||
<el-radio-button label="女" value="女"></el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="8">
|
||||
<el-form-item label="年龄" prop="age">
|
||||
<el-input
|
||||
v-model="regisForm.deceased.age"
|
||||
:disabled="
|
||||
props.type !== '服务修改' && props.type !== '服务登记'
|
||||
" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</inforCard>
|
||||
|
||||
<inforCard title="购买信息">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8" v-if="props.retailType === 2">
|
||||
<el-form-item label="逝者姓名" prop="deceasedName">
|
||||
<el-input
|
||||
v-model="regisForm.deceasedName"
|
||||
placeholder="请输入逝者姓名" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form v-model="regisForm"></el-form>
|
||||
<el-form-item label="引导员" prop="guide">
|
||||
<GuideList v-model="regisForm.guide"></GuideList>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="8">
|
||||
<el-form-item label="购买人" prop="buyer">
|
||||
<el-input
|
||||
:disabled="
|
||||
props.type !== '服务修改' &&
|
||||
props.type !== '服务登记' &&
|
||||
props.type !== '新增无逝者零售' &&
|
||||
props.type !== '修改无逝者登记'
|
||||
"
|
||||
v-model="regisForm.familyName"
|
||||
placeholder="请输入购买人姓名" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="购买人联系电话" prop="buyer">
|
||||
<el-input
|
||||
:disabled="
|
||||
props.type !== '服务修改' &&
|
||||
props.type !== '服务登记' &&
|
||||
props.type !== '新增无逝者零售' &&
|
||||
props.type !== '修改无逝者登记'
|
||||
"
|
||||
v-model="regisForm.familyPhone"
|
||||
placeholder="请输入购买人电话" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="8">
|
||||
<el-form-item label="所在区域">
|
||||
<el-cascader
|
||||
:disabled="
|
||||
props.type !== '服务修改' &&
|
||||
props.type !== '服务登记' &&
|
||||
props.type !== '新增无逝者零售' &&
|
||||
props.type !== '修改无逝者登记'
|
||||
"
|
||||
:options="pcaTextArrData"
|
||||
v-model="selectedOptions"
|
||||
@change="methods.pcaChange"></el-cascader> </el-form-item
|
||||
></el-col>
|
||||
|
||||
<el-col :span="8">
|
||||
<el-form-item label="详细地址">
|
||||
<el-input
|
||||
v-model="regisForm.address"
|
||||
:disabled="
|
||||
props.type !== '服务修改' &&
|
||||
props.type !== '服务登记' &&
|
||||
props.type !== '新增无逝者零售' &&
|
||||
props.type !== '修改无逝者登记'
|
||||
"
|
||||
placeholder="请输入你的地址"></el-input> </el-form-item
|
||||
></el-col>
|
||||
|
||||
<el-col :span="8">
|
||||
<el-form-item label="购买日期" prop="purchaseDate">
|
||||
<el-date-picker
|
||||
v-model="regisForm.purchaseDate"
|
||||
type="datetime"
|
||||
placeholder="选择日期"
|
||||
format="YYYY-MM-DD: HH:mm:ss" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="8">
|
||||
<el-form-item label="经办人" prop="handler">
|
||||
<el-input
|
||||
v-model="regisForm.handler"
|
||||
disabled
|
||||
placeholder="请输入经办人" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="销售金额" prop="salesAmount">
|
||||
<el-input
|
||||
v-model.number="regisForm.salesAmount"
|
||||
disabled
|
||||
type="number">
|
||||
<template #append>元</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</inforCard>
|
||||
|
||||
<inforCard title="已选服务项目">
|
||||
<div style="display: flex; align-items: center">
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
@click="methods.addServiceItem"
|
||||
v-if="props.type !== '零售结算'"
|
||||
>新增项目</el-button
|
||||
>
|
||||
<el-button
|
||||
type="default"
|
||||
size="small"
|
||||
@click="methods.customInput"
|
||||
v-if="props.type !== '零售结算'"
|
||||
>手工录入</el-button
|
||||
>
|
||||
</div>
|
||||
|
||||
<el-table
|
||||
:data="regisForm.services"
|
||||
:style="{ marginTop: (props.type !== '零售结算' ? 15 : 0) + 'px' }">
|
||||
<el-table-column type="index" label="序号" width="80" />
|
||||
<el-table-column prop="name" label="项目名称" />
|
||||
<el-table-column prop="quantity" label="数量" width="80">
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.name === '殡仪定制服务'">
|
||||
<el-input v-model="row.quantity"></el-input>
|
||||
</span>
|
||||
<span v-else>{{ row.quantity }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="unit" label="单位" width="80">
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.name === '殡仪定制服务'">
|
||||
<el-input v-model="row.unit"></el-input>
|
||||
</span>
|
||||
<span v-else>{{ row.unit }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="price" label="单价(元)">
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.name === '殡仪定制服务'">
|
||||
<el-input v-model="row.price"></el-input>
|
||||
</span>
|
||||
<span v-else>
|
||||
{{ row.price }}
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="price" label="总金额">
|
||||
<template #default="{ row }">
|
||||
{{ row.price * row.quantity }} 元
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="remark" width="200" label="备注">
|
||||
<template #default="{ row }">
|
||||
<el-tooltip
|
||||
class="box-item"
|
||||
effect="dark"
|
||||
:content="row.remark"
|
||||
placement="top">
|
||||
<p
|
||||
style="
|
||||
white-space: nowrap; /* 强制不换行 */
|
||||
overflow: hidden; /* 隐藏溢出内容 */
|
||||
text-overflow: ellipsis; /* 显示省略号 */
|
||||
">
|
||||
{{ row.remark }}
|
||||
</p>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column>
|
||||
<template #default="{ row }">
|
||||
<el-button
|
||||
type="danger"
|
||||
size="small"
|
||||
v-if="props.showServiceDelBtn"
|
||||
@click="methods.removeProduct(row)"
|
||||
>删除</el-button
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</inforCard>
|
||||
|
||||
<base-curd-dialog
|
||||
v-model="customServiceState.show2LevelPage.value"
|
||||
title="手工录入服务"
|
||||
width="50%"
|
||||
@addConfim="addConfim"
|
||||
@closeConfirm="handleDialogClose"
|
||||
:showPageType="customServiceState.showPageType">
|
||||
<template #content>
|
||||
<serviceListaddOrEdit
|
||||
type="手工录入服务"
|
||||
:executeType="customServiceState.executeType.value"
|
||||
v-model="currentServiceItem"></serviceListaddOrEdit>
|
||||
</template>
|
||||
<template #footer>
|
||||
<el-button type="primary" @click="methods.confirmCustomService"
|
||||
>确定</el-button
|
||||
>
|
||||
</template>
|
||||
</base-curd-dialog>
|
||||
<el-drawer
|
||||
v-model="serviceItemState.showDrawer"
|
||||
size="50%"
|
||||
:with-header="false">
|
||||
<serviceItemSelect v-model="regisForm.services"></serviceItemSelect>
|
||||
</el-drawer>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, nextTick, onMounted, ref, watch } from "vue";
|
||||
import { userInfor } from "@/store/user/user";
|
||||
import serviceItemSelect from "./serviceItemSelect.vue";
|
||||
import dayjs from "dayjs";
|
||||
import api from "@/lib/request";
|
||||
import pageVisible from "@/components/curdDialog/pageVisibleState";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
import serviceListaddOrEdit from "../../serviceList/serviceItem/page/addOrEdit.vue";
|
||||
import { defaultRetail } from "@/defaultForm/defaultRetail";
|
||||
import { defaultServiceItem } from "@/defaultForm/defaultSerivceItem";
|
||||
import { pcaTextArr } from "element-china-area-data";
|
||||
import GuideList from "@/components/guideList/guideList.vue";
|
||||
|
||||
const formRef = ref();
|
||||
const userStoreState = userInfor();
|
||||
const serviceItemState = ref({
|
||||
showDrawer: false,
|
||||
});
|
||||
|
||||
const customServiceState = new pageVisible({
|
||||
add: "新增服务项目",
|
||||
edit: "服务项目编辑",
|
||||
view: "服务项目查看",
|
||||
});
|
||||
|
||||
// 表单数据
|
||||
const regisForm = defineModel<RegisForm>({
|
||||
default: defaultRetail(),
|
||||
});
|
||||
|
||||
const selectedOptions = ref([
|
||||
regisForm.value.province,
|
||||
regisForm.value.city,
|
||||
regisForm.value.area,
|
||||
]);
|
||||
|
||||
const pcaTextArrData = ref(pcaTextArr);
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
add?: boolean;
|
||||
type?: RegistrationType;
|
||||
showServiceDelBtn?: boolean;
|
||||
retailType?: number;
|
||||
showList?: string[];
|
||||
}>(),
|
||||
{
|
||||
add: false,
|
||||
showServiceDelBtn: true,
|
||||
type: "服务登记",
|
||||
retailType: 0,
|
||||
showList: () => [],
|
||||
}
|
||||
);
|
||||
|
||||
if (["零售登记", "服务登记"].includes(props.type)) {
|
||||
regisForm.value.serviceItems = "";
|
||||
regisForm.value.services = [];
|
||||
}
|
||||
|
||||
const methods = {
|
||||
addServiceItem() {
|
||||
if (!regisForm.value.services?.length) {
|
||||
regisForm.value.services = [];
|
||||
}
|
||||
serviceItemState.value.showDrawer = true;
|
||||
},
|
||||
removeProduct(row: Product) {
|
||||
let index = regisForm.value.services?.findIndex(
|
||||
(item: any) => item.name === row.name
|
||||
);
|
||||
regisForm.value.services = regisForm.value.services?.filter(
|
||||
(_, i) => i !== index
|
||||
);
|
||||
},
|
||||
customInput() {
|
||||
customServiceState.show2LevelPage.value = true;
|
||||
},
|
||||
async confirmCustomService() {
|
||||
if (!currentServiceItem.value.name)
|
||||
return ElMessage.warning("服务项目名称不能为空!");
|
||||
if (
|
||||
currentServiceItem.value.price <= 0 ||
|
||||
currentServiceItem.value.quantity <= 0
|
||||
) {
|
||||
await ElMessageBox.confirm(
|
||||
"该商品售价或商品数量为0,是否继续?",
|
||||
"提示",
|
||||
{
|
||||
type: "warning",
|
||||
}
|
||||
);
|
||||
if (!regisForm.value.services) regisForm.value.services = [];
|
||||
regisForm.value.services.push({ ...currentServiceItem.value });
|
||||
customServiceState.show2LevelPage.value = false;
|
||||
|
||||
currentServiceItem.value = defaultServiceItem();
|
||||
return;
|
||||
}
|
||||
await ElMessageBox.confirm("确定新增该条信息吗?", "提示", {
|
||||
type: "warning",
|
||||
});
|
||||
|
||||
if (!regisForm.value.services) regisForm.value.services = [];
|
||||
regisForm.value.services.push({ ...currentServiceItem.value });
|
||||
customServiceState.show2LevelPage.value = false;
|
||||
|
||||
currentServiceItem.value = defaultServiceItem();
|
||||
},
|
||||
pcaChange(data: { [key: string]: any }) {
|
||||
regisForm.value.province = data[0];
|
||||
regisForm.value.city = data[1];
|
||||
regisForm.value.area = data[2];
|
||||
},
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
if (
|
||||
!["零售登记", "服务登记"].includes(props.type) &&
|
||||
(regisForm.value.deceasedId || regisForm.value.id)
|
||||
) {
|
||||
let url =
|
||||
"/deceased-retail/selected-service?deceasedId=" +
|
||||
(regisForm.value.deceasedId || regisForm.value.id) +
|
||||
"&retailType=" +
|
||||
props.retailType;
|
||||
|
||||
if (regisForm.value.id && props.retailType === 2) {
|
||||
url =
|
||||
"/deceased-retail/selected-service?retailId=" +
|
||||
regisForm.value.id +
|
||||
"&retailType=" +
|
||||
props.retailType;
|
||||
}
|
||||
|
||||
if (["零售修改", "零售结算"].includes(props.type)) {
|
||||
url =
|
||||
"/deceased-retail/selected-service?retailId=" +
|
||||
regisForm.value.id +
|
||||
"&retailType=" +
|
||||
props.retailType;
|
||||
}
|
||||
|
||||
const selectedService = await api().get(url);
|
||||
|
||||
regisForm.value.services = selectedService.data.list;
|
||||
}
|
||||
|
||||
watch(
|
||||
() => regisForm.value.services,
|
||||
(newVal) => {
|
||||
if (newVal) {
|
||||
regisForm.value.salesAmount = 0;
|
||||
newVal?.forEach(
|
||||
(item) => (regisForm.value.salesAmount += item.price * item.quantity)
|
||||
);
|
||||
|
||||
if (props.type === "服务登记") {
|
||||
regisForm.value.serviceItems = newVal
|
||||
.map((item) => item.id)
|
||||
.join(",");
|
||||
}
|
||||
}
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
regisForm.value = {
|
||||
...regisForm.value,
|
||||
handler: regisForm.value.handler || userStoreState.userInfor.name || "",
|
||||
purchaseDate:
|
||||
regisForm.value.purchaseDate ||
|
||||
dayjs(new Date()).format("YYYY-MM-DD HH:mm:ss"),
|
||||
};
|
||||
});
|
||||
let currentServiceItem = ref<ServiceItemType>(defaultServiceItem());
|
||||
async function addConfim() {
|
||||
await ElMessageBox.confirm("确定新增该条信息吗?", "提示", {
|
||||
type: "warning",
|
||||
});
|
||||
if (!regisForm.value.services) regisForm.value.services = [];
|
||||
regisForm.value.services.push({ ...currentServiceItem.value });
|
||||
|
||||
// await ElMessageBox.confirm("确定新增该条信息吗?", "提示", {
|
||||
// type: "warning",
|
||||
// });
|
||||
// let res = await api().post("/service-item/add", currentServiceItem.value);
|
||||
// if (res.code === 200) {
|
||||
// ElMessage.success("添加成功");
|
||||
// customServiceState.show2LevelPage.value = false;
|
||||
// } else {
|
||||
// ElMessage.error(res.msg);
|
||||
// }
|
||||
}
|
||||
|
||||
function handleDialogClose() {
|
||||
customServiceState.show2LevelPage.value = false;
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
||||
@@ -0,0 +1,353 @@
|
||||
<template>
|
||||
<div class="service-selection">
|
||||
<!-- 标题 -->
|
||||
<h2 class="title">服务项目选择</h2>
|
||||
<!-- 搜索框 -->
|
||||
|
||||
<el-form>
|
||||
<el-row :gutter="15" style="margin-top: 15px">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="商品名称">
|
||||
<el-input
|
||||
v-model="searchKeyword"
|
||||
placeholder="请输入商品名称"
|
||||
clearable />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="16">
|
||||
<el-form-item label="价格">
|
||||
<el-input-number
|
||||
v-model="price"
|
||||
:min="0"
|
||||
clearable
|
||||
placeholder="请输入价格"
|
||||
type="number"></el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<el-divider style="margin: 8px 0; margin-bottom: 30px" />
|
||||
<!-- 两列布局 -->
|
||||
<div
|
||||
class="content"
|
||||
v-loading="lodaing"
|
||||
element-loading-text="数据加载中....">
|
||||
<!-- 左侧树结构 -->
|
||||
<div class="left">
|
||||
<el-tree
|
||||
ref="tree"
|
||||
:data="categoryTree"
|
||||
:props="treeProps"
|
||||
show-checkbox
|
||||
check-strictly
|
||||
@check="getCheckedKeys" />
|
||||
</div>
|
||||
|
||||
<!-- 右侧商品列表 -->
|
||||
<div class="right">
|
||||
<div
|
||||
v-for="(item, index) in categoryServiceList"
|
||||
:key="index"
|
||||
class="item">
|
||||
<!-- 商品信息 -->
|
||||
<div class="item-info">
|
||||
<div class="item-name">商品名称:{{ item.name }}</div>
|
||||
<div class="item-group">
|
||||
所属分类:{{
|
||||
categoryTreeAll.find((fitem) => fitem.id === item.parentId)
|
||||
?.name || "无"
|
||||
}}
|
||||
</div>
|
||||
<div class="item-price">
|
||||
{{ item.price }} 元 / {{ item.unit || "(暂无单位)" }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 添加/删除按钮 -->
|
||||
<div class="item-actions">
|
||||
<!-- <el-button
|
||||
v-if="!item.quantity || item.quantity === 0"
|
||||
type="primary"
|
||||
@click="addItem(item)">
|
||||
<span style="color: #fff">+ 添加</span>
|
||||
</el-button>
|
||||
<div v-else class="quantity-control">
|
||||
<el-button type="danger" @click="removeItem(item)">-</el-button>
|
||||
<span class="quantity">{{ item.quantity }}</span>
|
||||
<el-button type="primary" @click="addItem(item)">+ </el-button>
|
||||
</div> -->
|
||||
|
||||
<el-input-number
|
||||
style="margin-top: 5px"
|
||||
v-model="item.quantity"
|
||||
:min="0"
|
||||
@change="methods.quantityChange(item)" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 底部悬浮框 -->
|
||||
<div class="footer">
|
||||
<div class="footer-item">
|
||||
<span>总金额:</span>
|
||||
<span
|
||||
><span class="red-font">{{ totalAmount }} </span>元</span
|
||||
>
|
||||
</div>
|
||||
<!-- <div class="footer-item">
|
||||
<span>减免金额:</span>
|
||||
<span
|
||||
><span class="green-font">
|
||||
{{ discountAmount }}
|
||||
</span>
|
||||
元</span
|
||||
>
|
||||
</div>
|
||||
<div class="footer-item">
|
||||
<span>实收金额:</span>
|
||||
<span
|
||||
><span class="red-font">
|
||||
{{ actualAmount }}
|
||||
</span>
|
||||
元</span
|
||||
>
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted, watch } from "vue";
|
||||
import api from "@/lib/request";
|
||||
|
||||
const emits = defineEmits(["selectedProduct"]);
|
||||
const products = defineModel<Product[]>();
|
||||
|
||||
// 搜索关键词
|
||||
const searchKeyword = ref("");
|
||||
const price = ref(0);
|
||||
|
||||
const lodaing = ref(false);
|
||||
|
||||
// 分类树数据
|
||||
const categoryTree = ref([]);
|
||||
const categoryTreeAll = ref([]);
|
||||
const categoryServiceAll = ref<Product[]>([]);
|
||||
const selectedCategory = ref([]);
|
||||
const tree = ref();
|
||||
|
||||
const categoryServiceList = computed(() => {
|
||||
let resData: Product[] = [];
|
||||
selectedCategory.value.forEach((item) => {
|
||||
let findData = categoryServiceAll.value.filter(
|
||||
(fitem) => fitem.parentId === item.id
|
||||
);
|
||||
if (findData) {
|
||||
resData = [...resData, ...findData];
|
||||
}
|
||||
});
|
||||
let res = selectedCategory.value.length ? resData : categoryServiceAll.value;
|
||||
|
||||
if (searchKeyword.value) {
|
||||
res = res.filter((item) => item.name.includes(searchKeyword.value));
|
||||
let includeCategory = categoryTreeAll.value.filter((category) =>
|
||||
category.name.includes(searchKeyword.value)
|
||||
);
|
||||
categoryServiceAll.value.forEach((item) => {
|
||||
includeCategory.forEach((iitem) => {
|
||||
if (
|
||||
item.parentId === iitem.id &&
|
||||
!res.find((fitem) => fitem.name === item.name)
|
||||
) {
|
||||
res.unshift(item);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
if (price.value && price.value !== 0) {
|
||||
res = res.filter((fitem) => Number(fitem.price) === price.value);
|
||||
}
|
||||
return res;
|
||||
});
|
||||
|
||||
// 树结构配置
|
||||
const treeProps = {
|
||||
children: "children",
|
||||
label: "name",
|
||||
};
|
||||
|
||||
const syncProductsWithCategoryServiceAll = () => {
|
||||
if (!products.value) return; // 防止 products 为空时报错
|
||||
|
||||
categoryServiceAll.value.forEach((item) => {
|
||||
const findItem = products.value?.find(
|
||||
(newItem) => newItem.name === item.name
|
||||
);
|
||||
if (findItem) {
|
||||
item.quantity = findItem.quantity;
|
||||
} else {
|
||||
item.quantity = 0;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
watch(
|
||||
() => products.value,
|
||||
(newVal) => {
|
||||
syncProductsWithCategoryServiceAll();
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
immediate: true,
|
||||
}
|
||||
);
|
||||
|
||||
// 总金额
|
||||
const totalAmount = computed(() => {
|
||||
return categoryServiceAll.value.reduce(
|
||||
(sum, item) => sum + item.price * (item.quantity || 0),
|
||||
0
|
||||
);
|
||||
});
|
||||
|
||||
const methods = {
|
||||
quantityChange(item: any) {
|
||||
let findData = products.value?.find(
|
||||
(findItem) => findItem.name === item.name
|
||||
);
|
||||
if (!findData) {
|
||||
products.value?.push(item);
|
||||
} else {
|
||||
findData.quantity = item.quantity;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
const getCheckedKeys = (data: any) => {
|
||||
selectedCategory.value = tree.value.getCheckedNodes();
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
lodaing.value = true;
|
||||
let treeList = await api().get("/service-category/list");
|
||||
let allTreeList = await api().get("/service-category/list", {
|
||||
params: { all: true },
|
||||
});
|
||||
let allService = await api().get("/service-item/list", {
|
||||
params: { all: true },
|
||||
});
|
||||
|
||||
categoryTree.value = treeList.data.list;
|
||||
categoryServiceAll.value = allService.data.list;
|
||||
categoryTreeAll.value = allTreeList.data.list;
|
||||
|
||||
syncProductsWithCategoryServiceAll();
|
||||
|
||||
lodaing.value = false;
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.service-selection {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
.title {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.search-box {
|
||||
margin-bottom: 20px;
|
||||
width: 50%;
|
||||
}
|
||||
.left {
|
||||
width: 200px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.right {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding-bottom: 30px;
|
||||
max-height: calc(100vh - 150px);
|
||||
flex-wrap: wrap;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
}
|
||||
.content {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
.item {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
width: calc(50% - 10px);
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
padding: 10px;
|
||||
border: 1px solid #eee;
|
||||
border-radius: 4px;
|
||||
flex-direction: column;
|
||||
// .item-image {
|
||||
// width: 100px;
|
||||
// height: 100px;
|
||||
// margin-right: 10px;
|
||||
// }
|
||||
.item-info {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.item-name {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.item-category,
|
||||
.item-group,
|
||||
.item-price {
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
}
|
||||
.item-actions {
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.quantity-control {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.quantity {
|
||||
margin: 0 10px;
|
||||
}
|
||||
|
||||
.footer {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
width: 50%;
|
||||
z-index: 10;
|
||||
background: #fff;
|
||||
padding: 10px 20px;
|
||||
border-top: 1px solid #eee;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1);
|
||||
.footer-item {
|
||||
font-size: 14px;
|
||||
}
|
||||
.red-font,
|
||||
.green-font {
|
||||
font-size: 18px;
|
||||
color: #f04b22;
|
||||
font-weight: bold;
|
||||
padding-right: 8px;
|
||||
}
|
||||
.green-font {
|
||||
color: #67c23a;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,307 @@
|
||||
<template>
|
||||
<div>
|
||||
<inforCard title="逝者信息">
|
||||
<el-form :model="checkoutForm" label-width="120px" disabled>
|
||||
<el-row :gutter="20" v-if="deceased.deceased">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="姓名">
|
||||
<el-input
|
||||
:prefix-icon="User"
|
||||
v-model="deceased.deceased.name"
|
||||
disabled
|
||||
placeholder="姓名">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="性别">
|
||||
<el-radio-group v-model="deceased.deceased.gender" disabled>
|
||||
<el-radio-button value="男" label="男"></el-radio-button>
|
||||
<el-radio-button value="女" label="女"></el-radio-button>
|
||||
</el-radio-group> </el-form-item
|
||||
></el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="证件号码" prop="idNumber">
|
||||
<el-input v-model="deceased.deceased.idNumber" disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="年龄">
|
||||
<el-input
|
||||
v-model="deceased.deceased.age"
|
||||
disabled
|
||||
placeholder="年龄">
|
||||
</el-input> </el-form-item
|
||||
></el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="购买人名" prop="buyer">
|
||||
<el-input v-model="deceased.deceased.familyName" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="购买人电话" prop="buyer">
|
||||
<el-input v-model="deceased.deceased.familyPhone" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="购买日期" prop="purchaseDate">
|
||||
<el-date-picker
|
||||
v-model="deceased.purchaseDate"
|
||||
type="datetime"
|
||||
format="YYYY-MM-DD: HH:mm:ss" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="销售金额" prop="salesAmount">
|
||||
<el-input v-model.number="deceased.salesAmount" type="number">
|
||||
<template #append>元</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20" v-else>
|
||||
<!-- <el-col :span="8">
|
||||
<el-form-item label="姓名">
|
||||
<el-input
|
||||
:prefix-icon="User"
|
||||
v-model="deceased.name"
|
||||
disabled
|
||||
placeholder="姓名">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="性别">
|
||||
<el-radio-group v-model="deceased.gender" disabled>
|
||||
<el-radio-button value="男" label="男"></el-radio-button>
|
||||
<el-radio-button value="女" label="女"></el-radio-button>
|
||||
</el-radio-group> </el-form-item
|
||||
></el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="证件号码" prop="idNumber">
|
||||
<el-input v-model="deceased.idNumber" disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="年龄">
|
||||
<el-input v-model="deceased.age" disabled placeholder="年龄">
|
||||
</el-input> </el-form-item
|
||||
></el-col> -->
|
||||
<el-col :span="8">
|
||||
<el-form-item label="购买人姓名" prop="buyer">
|
||||
<el-input v-model="deceased.familyName" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="购买人电话" prop="buyer">
|
||||
<el-input v-model="deceased.familyPhone" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="购买日期" prop="purchaseDate">
|
||||
<el-date-picker
|
||||
v-model="deceased.purchaseDate"
|
||||
type="datetime"
|
||||
format="YYYY-MM-DD: HH:mm:ss" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="销售金额" prop="salesAmount">
|
||||
<el-input v-model.number="deceased.salesAmount" type="number">
|
||||
<template #append>元</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</inforCard>
|
||||
<inforCard title="已选服务项目">
|
||||
<el-table
|
||||
:data="servicesList"
|
||||
style="max-height: 160px; overflow-y: auto">
|
||||
<el-table-column type="index" label="序号" width="80" />
|
||||
<el-table-column prop="name" label="项目名称" />
|
||||
<el-table-column prop="quantity" label="数量" />
|
||||
<el-table-column prop="unit" label="单位" />
|
||||
<el-table-column prop="price" label="单价">
|
||||
<template #default="{ row }"> {{ row.price }} 元 </template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="price" label="总金额">
|
||||
<template #default="{ row }">
|
||||
{{ row.price * row.quantity }} 元
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="remark" label="备注" />
|
||||
</el-table>
|
||||
</inforCard>
|
||||
<inforCard title="结账列表">
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="checkoutForm"
|
||||
label-width="120px"
|
||||
label-position="right">
|
||||
<el-row :gutter="20">
|
||||
<!-- 第一行 -->
|
||||
<el-col :span="8">
|
||||
<el-form-item label="结账日期" prop="checkoutDate">
|
||||
<el-date-picker
|
||||
v-model="checkoutForm.checkoutDate"
|
||||
type="date"
|
||||
placeholder="结账日期"
|
||||
format="YYYY-MM-DD"
|
||||
disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="8">
|
||||
<el-form-item label="结算日期" prop="settlementDate">
|
||||
<el-date-picker
|
||||
v-model="checkoutForm.settlementDate"
|
||||
type="date"
|
||||
placeholder="选择日期"
|
||||
format="YYYY-MM-DD" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="经办人" prop="handler">
|
||||
<el-input
|
||||
disabled
|
||||
v-model="checkoutForm.handler"
|
||||
placeholder="经办人" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="现金金额" prop="cash">
|
||||
<el-input
|
||||
v-model.number="checkoutForm.cashAmount"
|
||||
type="number"
|
||||
:min="0"
|
||||
@input="caleValue('cashAmount')">
|
||||
<template #append>元</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="银联" prop="unionPay">
|
||||
<el-input
|
||||
v-model.number="checkoutForm.unionPayAmount"
|
||||
type="number"
|
||||
:min="0"
|
||||
@input="caleValue('unionPayAmount')">
|
||||
<template #append>元</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="8">
|
||||
<el-form-item label="银行卡" prop="cardPay">
|
||||
<el-input
|
||||
v-model.number="checkoutForm.cardAmount"
|
||||
type="number"
|
||||
:min="0"
|
||||
@input="caleValue('cardAmount')">
|
||||
<template #append>元</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="8">
|
||||
<el-form-item label="对公" prop="transfer">
|
||||
<el-input
|
||||
v-model.number="checkoutForm.publicTransferAmount"
|
||||
type="number"
|
||||
:min="0"
|
||||
@input="caleValue('publicTransferAmount')">
|
||||
<template #append>元</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="车间支付" prop="transfer">
|
||||
<el-input
|
||||
v-model.number="checkoutForm.workshopPayment"
|
||||
type="number"
|
||||
:min="0"
|
||||
@input="caleValue('workshopPayment')">
|
||||
<template #append>元</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</inforCard>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref, watch } from "vue";
|
||||
// @ts-ignore
|
||||
import { User } from "@element-plus/icons-vue";
|
||||
import dayjs from "dayjs";
|
||||
import { userInfor } from "@/store/user/user";
|
||||
import { defaultRetail } from "@/defaultForm/defaultRetail";
|
||||
import { defaultPaymentForm } from "@/defaultForm/defaultPaymentForm";
|
||||
import request from "@/lib/request";
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
executeType?: string;
|
||||
deceased: RegisForm;
|
||||
}>(),
|
||||
{
|
||||
deceased: () => {
|
||||
return {
|
||||
...defaultRetail(),
|
||||
deceased: {},
|
||||
};
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const emit = defineEmits(["updateData"]);
|
||||
const userInforStore = userInfor().userInfor;
|
||||
|
||||
let checkoutForm = defineModel({ default: defaultPaymentForm() });
|
||||
let servicesList = ref([]);
|
||||
|
||||
onMounted(() => {
|
||||
checkoutForm.value.handler =
|
||||
checkoutForm.value.handler || (userInforStore.name as string);
|
||||
request()
|
||||
.get(
|
||||
"/deceased-retail/selected-service?retailId=" +
|
||||
props.deceased.id +
|
||||
"&retailType=" +
|
||||
props.deceased.retailType
|
||||
)
|
||||
.then((res) => {
|
||||
servicesList.value = res.data?.list || [];
|
||||
});
|
||||
});
|
||||
|
||||
let keys = [
|
||||
"cashAmount",
|
||||
"unionPayAmount",
|
||||
"cardAmount",
|
||||
"publicTransferAmount",
|
||||
"workshopPayment",
|
||||
];
|
||||
|
||||
function caleValue(keyVal: string) {
|
||||
let total = 0;
|
||||
let currentVal = checkoutForm.value[keyVal];
|
||||
|
||||
keys.forEach((key) => {
|
||||
if (keyVal !== key) {
|
||||
let tempVal = Number(checkoutForm.value[key]).toFixed(2);
|
||||
total = Number(total) + Number(tempVal);
|
||||
}
|
||||
});
|
||||
let salesAmount = Number(props.deceased.salesAmount);
|
||||
|
||||
if (salesAmount - (total + currentVal) < 0) {
|
||||
checkoutForm.value[keyVal] = salesAmount - total;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
||||
643
frontEnd/src/pages/funeralRetail/saintCheckout/saintCheckout.vue
Normal file
@@ -0,0 +1,643 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-row>
|
||||
<baseTableHeader
|
||||
title="零售结算"
|
||||
@resetSearch="methods.resetSearch"
|
||||
@search="methods.search">
|
||||
<template #content>
|
||||
<el-form :model="searchForm" label-position="right">
|
||||
<el-row :gutter="12">
|
||||
<el-col :span="6">
|
||||
<el-form-item label="逝者姓名">
|
||||
<el-input
|
||||
v-model="searchForm.deceased.name"
|
||||
placeholder="请输入逝者姓名"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="购买人姓名">
|
||||
<el-input
|
||||
v-model="searchForm.retail.familyName"
|
||||
placeholder="请输入购买人姓名"></el-input> </el-form-item
|
||||
></el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="引导员">
|
||||
<GuideList
|
||||
v-model="
|
||||
searchForm.retail.guide
|
||||
"></GuideList> </el-form-item
|
||||
></el-col>
|
||||
|
||||
<el-col :span="8">
|
||||
<el-form-item label="购买日期">
|
||||
<el-date-picker
|
||||
v-model="searchForm.retail.purchaseDate"
|
||||
type="datetimerange"
|
||||
range-separator="至"
|
||||
start-placeholder="选择日期"
|
||||
end-placeholder="选择日期"
|
||||
@change="dataChange" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</template>
|
||||
</baseTableHeader>
|
||||
</el-row>
|
||||
<el-card style="margin-top: 8px">
|
||||
<div style="margin-bottom: 15px">
|
||||
<el-button
|
||||
size="small"
|
||||
type="primary"
|
||||
@click="methods.add"
|
||||
v-if="route.path === '/noDepartedSaint'">
|
||||
<template #icon>
|
||||
<el-icon>
|
||||
<CirclePlus />
|
||||
</el-icon> </template
|
||||
>新增</el-button
|
||||
>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<base-table
|
||||
:option="tableOption"
|
||||
ref="table"
|
||||
border
|
||||
show-summary
|
||||
:summary-method="getSummaries">
|
||||
<template #toolsBar>
|
||||
<el-radio-group
|
||||
v-model="searchForm.retail.retailType"
|
||||
size="small"
|
||||
style="margin-left: 15px">
|
||||
<el-radio-button label="逝者零售" :value="1" />
|
||||
<el-radio-button label="无逝者零售" :value="2" />
|
||||
</el-radio-group>
|
||||
</template>
|
||||
<template #colunm>
|
||||
<el-table-column
|
||||
type="index"
|
||||
width="80"
|
||||
fixed="left"
|
||||
align="center"></el-table-column>
|
||||
|
||||
<el-table-column
|
||||
prop="deceased.name"
|
||||
label="逝者姓名"
|
||||
width="100"
|
||||
fixed="left"
|
||||
v-if="searchForm.retail.retailType === 1"
|
||||
align="center">
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="name"
|
||||
label="结账"
|
||||
width="100"
|
||||
fixed="left"
|
||||
align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag
|
||||
:type="
|
||||
row.retailState === 0
|
||||
? 'danger'
|
||||
: row.retailState === 1
|
||||
? 'success'
|
||||
: 'info'
|
||||
">
|
||||
{{
|
||||
row.retailState === 0
|
||||
? "未结账"
|
||||
: row.retailState === 1
|
||||
? "已结账"
|
||||
: "未知"
|
||||
}}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="购买人" align="center" fixed="left">
|
||||
<template #default="{ row }">
|
||||
<span>{{ row.familyName || row.deceased?.name }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="familyPhone"
|
||||
label="购买人电话"
|
||||
width="120"
|
||||
align="center">
|
||||
<template #default="{ row }">
|
||||
<span>{{ row.deceased?.familyPhone || row.familyPhone }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
prop="purchaseDate"
|
||||
label="购买日期"
|
||||
width="200"
|
||||
align="center" />
|
||||
<el-table-column
|
||||
prop="checkoutDate"
|
||||
label="结算日期"
|
||||
width="200"
|
||||
align="center">
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.retailState === 1">
|
||||
{{ row.checkoutDate }}
|
||||
</span>
|
||||
<span v-else>--</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="handler" label="经办人" align="center" />
|
||||
<el-table-column
|
||||
width="100"
|
||||
prop="salesAmount"
|
||||
label="销售金额"
|
||||
align="center" />
|
||||
|
||||
<el-table-column
|
||||
label="现金支付"
|
||||
prop="payment.cashAmount"
|
||||
width="100"
|
||||
align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.payment?.cashAmount || "0.00" }} 元
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="payment.unionPayAmount"
|
||||
label="银联支付"
|
||||
width="100"
|
||||
align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.payment?.unionPayAmount || "0.00" }} 元
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
prop="payment.cardAmount"
|
||||
label="刷卡金额"
|
||||
width="100"
|
||||
align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.payment?.cardAmount || "0.00" }} 元
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="payment.publicTransferAmount"
|
||||
label="对公转账"
|
||||
width="100"
|
||||
align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.payment?.publicTransferAmount || "0.00" }} 元
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
prop="payment.workshopPayment"
|
||||
label="车间支付"
|
||||
width="100"
|
||||
align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.payment?.workshopPayment || "0.00" }} 元
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="guide" label="引导员" align="center" />
|
||||
<el-table-column
|
||||
width="300"
|
||||
label="操作"
|
||||
align="center"
|
||||
fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-row align="middle" justify="center">
|
||||
<el-button
|
||||
size="small"
|
||||
type="primary"
|
||||
v-if="row.retailState === 1"
|
||||
@click="methods.hanlderView(row)">
|
||||
查看</el-button
|
||||
>
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
@click="methods.checkout(row)"
|
||||
v-if="row.retailState === 0"
|
||||
>结账</el-button
|
||||
>
|
||||
<el-button
|
||||
v-if="row.retailState === 1"
|
||||
size="small"
|
||||
type="default"
|
||||
@click="methods.cancel(row)">
|
||||
作废
|
||||
</el-button>
|
||||
<el-button @click="methods.viewProduct(row)" size="small">
|
||||
零售清单</el-button
|
||||
>
|
||||
<el-button @click="methods.print(row)" size="small"
|
||||
>打印</el-button
|
||||
>
|
||||
</el-row>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</template>
|
||||
</base-table>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<retailList v-model="showDialog" :option="retailListTable"></retailList>
|
||||
|
||||
<baseDialog
|
||||
v-model="retailRegisState.showDialog"
|
||||
top="50px"
|
||||
title="零售结算">
|
||||
<retailRegis
|
||||
v-model="regisForm"
|
||||
:retailType="searchForm.retail.retailType"
|
||||
:showServiceDelBtn="handlerType !== 'view'"
|
||||
:add="handlerType === 'add'"
|
||||
type="零售结算"></retailRegis>
|
||||
<template #footer>
|
||||
<el-row justify="center" align="middle" style="margin-top: 15px">
|
||||
<el-button type="danger" @click="methods.close">关闭</el-button>
|
||||
</el-row>
|
||||
</template>
|
||||
</baseDialog>
|
||||
<base-curd-dialog
|
||||
v-model="pageVisibleState.show2LevelPage.value"
|
||||
:title="pageVisibleState.dialogTitle.value"
|
||||
width="70%"
|
||||
:before-close="methods.handleDialogClose"
|
||||
@addConfim="methods.addConfim"
|
||||
@closeConfirm="methods.handleDialogClose"
|
||||
confirmText="结账"
|
||||
destroy-on-close
|
||||
:showPageType="pageVisibleState.showPageType">
|
||||
<template #content>
|
||||
<checkoutAddOrEdit
|
||||
:executeType="pageVisibleState.executeType.value"
|
||||
:deceased="currentData"
|
||||
v-model="currentPayment">
|
||||
</checkoutAddOrEdit>
|
||||
</template>
|
||||
<template #footer>
|
||||
<el-button type="primary" @click="methods.addConfim"
|
||||
>确定结账</el-button
|
||||
></template
|
||||
>
|
||||
</base-curd-dialog>
|
||||
|
||||
<printServicesPage
|
||||
v-model="showPrint"
|
||||
:deceased="deceased"
|
||||
:serviceUrl="serviceUrl">
|
||||
</printServicesPage>
|
||||
|
||||
<base-dialog
|
||||
v-model="cancelState.showDialog"
|
||||
title="账单作废"
|
||||
width="50%"
|
||||
@closeConfirm="methods.cancleClose">
|
||||
<el-form :model="cancelForm" label-width="120px" style="padding: 20px">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<!-- 注销申请人 -->
|
||||
<el-form-item label="作废申请人">
|
||||
<el-input disabled v-model="cancelForm.cancelPerson" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<!-- 注销日期 -->
|
||||
<el-form-item label="作废日期">
|
||||
<el-date-picker
|
||||
disabled
|
||||
v-model="cancelForm.cancelDate"
|
||||
type="date" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<!-- 注销原因 -->
|
||||
<el-form-item label="作废原因">
|
||||
<el-input
|
||||
v-model="cancelForm.cancelReason"
|
||||
type="textarea"
|
||||
placeholder="请输入作废原因" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="flex-center">
|
||||
<el-button type="primary" @click="methods.submitCancel"
|
||||
>作废</el-button
|
||||
>
|
||||
<el-button @click="methods.resetCancel">取消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</base-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref, onMounted, watch, nextTick } from "vue";
|
||||
import { dayjs, ElMessage, ElMessageBox } from "element-plus";
|
||||
import { resetParams } from "@/util/globalMethods";
|
||||
import { globalState } from "@/store";
|
||||
import retailRegis from "../publicComponents/retailRegis.vue";
|
||||
import api from "@/lib/request";
|
||||
import { tableOptionType } from "@/types/table";
|
||||
import { useRoute } from "vue-router";
|
||||
import pageVisible from "@/components/curdDialog/pageVisibleState";
|
||||
import { defaultPaymentForm } from "@/defaultForm/defaultPaymentForm";
|
||||
import checkoutAddOrEdit from "./page/checkoutAddOrEdit.vue";
|
||||
import printServicesPage from "@/components/printPage/printServicesPage.vue";
|
||||
import { defaultRetail } from "@/defaultForm/defaultRetail";
|
||||
import { userInfor } from "@/store/user/user";
|
||||
import GuideList from "@/components/guideList/guideList.vue";
|
||||
|
||||
const pageVisibleState = new pageVisible({
|
||||
add: "结账登记",
|
||||
edit: "登记修改",
|
||||
view: "查看登记",
|
||||
});
|
||||
|
||||
let retailListTable = ref<tableOptionType>({
|
||||
url: "/deceased-retail/selected-service",
|
||||
searchUrl: "",
|
||||
searchParams: {},
|
||||
executeType: "list",
|
||||
});
|
||||
|
||||
const retailRegisState = ref({
|
||||
showDialog: false,
|
||||
});
|
||||
|
||||
let currentRetail = ref<RegisForm>(defaultRetail());
|
||||
|
||||
let currentInfor = ref(undefined);
|
||||
let showDialog = ref(false);
|
||||
|
||||
let showPrint = ref(false);
|
||||
let deceased = ref();
|
||||
let serviceUrl = ref();
|
||||
|
||||
const handlerType = ref("");
|
||||
const searchForm = ref({
|
||||
retail: {
|
||||
guide: "", // 引导员
|
||||
startDate: "",
|
||||
endDate: "",
|
||||
purchaseDate: ["", ""],
|
||||
retailType: 1,
|
||||
familyName: "",
|
||||
},
|
||||
deceased: {
|
||||
name: "", // 逝者姓名
|
||||
familyName: "",
|
||||
},
|
||||
});
|
||||
|
||||
let currentPayment = ref<PaymentForm>(defaultPaymentForm());
|
||||
let currentData = ref();
|
||||
|
||||
const route = useRoute();
|
||||
|
||||
const regisForm = ref<RegisForm>();
|
||||
const cancelState = ref({
|
||||
showDialog: false,
|
||||
});
|
||||
const globaUser = userInfor().userInfor;
|
||||
const cancelForm = ref({
|
||||
cancelPerson: globaUser.name,
|
||||
cancelDate: dayjs().format(),
|
||||
cancelReason: "",
|
||||
});
|
||||
|
||||
let table = ref();
|
||||
let tableOption = ref<tableOptionType>({
|
||||
url: "/deceased-retail/list?retailType=" + searchForm.value.retail.retailType,
|
||||
searchUrl: "/deceased-retail/query",
|
||||
searchParams: searchForm.value,
|
||||
executeType: "list",
|
||||
});
|
||||
const methods = {
|
||||
add() {
|
||||
retailRegisState.value.showDialog = true;
|
||||
handlerType.value = "add";
|
||||
},
|
||||
cancel(row: RegisForm) {
|
||||
currentRetail.value = row;
|
||||
cancelState.value.showDialog = true;
|
||||
},
|
||||
viewProduct(row: RegisForm) {
|
||||
retailListTable.value.url =
|
||||
"/deceased-retail/selected-service?retailId=" + row.id;
|
||||
showDialog.value = true;
|
||||
},
|
||||
drawerClose() {
|
||||
currentInfor.value = undefined;
|
||||
showDialog.value = false;
|
||||
},
|
||||
async checkout(row: RegisForm) {
|
||||
currentData.value = row;
|
||||
pageVisibleState.dialogTitle.value = "零售结算";
|
||||
|
||||
pageVisibleState.show2LevelPage.value = true;
|
||||
},
|
||||
async hanlderView(row: RegisForm) {
|
||||
// await ElMessageBox.confirm("确定结账吗?");
|
||||
regisForm.value = row;
|
||||
retailRegisState.value.showDialog = true;
|
||||
handlerType.value = "view";
|
||||
|
||||
pageVisibleState.dialogTitle.value = "零售查看";
|
||||
},
|
||||
close() {
|
||||
retailRegisState.value.showDialog = false;
|
||||
},
|
||||
async cancle() {
|
||||
await ElMessageBox.confirm("确定作废该条吗?", { type: "error" });
|
||||
retailRegisState.value.showDialog = false;
|
||||
ElMessage.success("作废成功!");
|
||||
},
|
||||
print(row: RegisForm) {
|
||||
deceased.value = row;
|
||||
serviceUrl.value = `/deceased-retail/selected-service?retailType=${searchForm.value.retail.retailType}&retailId=${row.id}`;
|
||||
|
||||
nextTick(() => {
|
||||
showPrint.value = true;
|
||||
});
|
||||
},
|
||||
search() {
|
||||
table.value.methods.setDataType("search");
|
||||
},
|
||||
|
||||
resetSearch() {
|
||||
searchForm.value = {
|
||||
retail: {
|
||||
guide: "", // 引导员
|
||||
startDate: "",
|
||||
endDate: "",
|
||||
purchaseDate: ["", ""],
|
||||
retailType: 1,
|
||||
familyName: "",
|
||||
},
|
||||
deceased: {
|
||||
name: "", // 逝者姓名
|
||||
familyName: "",
|
||||
},
|
||||
};
|
||||
tableOption.value.searchParams = searchForm.value;
|
||||
nextTick(() => {
|
||||
table.value.methods.setDataType("search");
|
||||
});
|
||||
},
|
||||
|
||||
async addConfim() {
|
||||
await ElMessageBox.confirm("确定结账吗?", { type: "warning" });
|
||||
|
||||
let sendData = {
|
||||
deceased: {
|
||||
...currentData.value,
|
||||
},
|
||||
currentPayment: {
|
||||
...currentPayment.value,
|
||||
},
|
||||
id: currentData.value.id,
|
||||
};
|
||||
let url = "/checkout/deceasedCheckout";
|
||||
|
||||
const res = await api().post(url, sendData);
|
||||
if (res.code === 200) {
|
||||
ElMessage.success("结账成功!");
|
||||
pageVisibleState.show2LevelPage.value = false;
|
||||
nextTick(() => {
|
||||
table.value.methods.setDataType("search");
|
||||
currentPayment.value = defaultPaymentForm();
|
||||
currentData.value = undefined;
|
||||
});
|
||||
} else {
|
||||
ElMessage.error(res.msg);
|
||||
}
|
||||
},
|
||||
|
||||
handleDialogClose() {
|
||||
pageVisibleState.show2LevelPage.value = false;
|
||||
currentData.value = undefined;
|
||||
currentPayment.value = defaultPaymentForm();
|
||||
},
|
||||
cancleClose() {
|
||||
cancelForm.value = {
|
||||
cancelPerson: globaUser.name,
|
||||
cancelDate: dayjs().format(),
|
||||
cancelReason: "",
|
||||
};
|
||||
},
|
||||
|
||||
async submitCancel() {
|
||||
if (!cancelForm.value.cancelReason) {
|
||||
return ElMessage.error("请输入作废原因");
|
||||
}
|
||||
await ElMessageBox.confirm("确定作废吗?", { type: "warning" });
|
||||
|
||||
let sendData = {
|
||||
deceasedRetailId: currentRetail.value.id,
|
||||
cancelForm: { ...cancelForm.value },
|
||||
cancelType: 0,
|
||||
};
|
||||
|
||||
api()
|
||||
.post("/cancel/cancel", sendData)
|
||||
.then((res) => {
|
||||
if (res.code === 200) {
|
||||
ElMessage.success("作废提交成功!");
|
||||
methods.resetCancel();
|
||||
cancelForm.value = {
|
||||
cancelPerson: globaUser.name,
|
||||
cancelDate: dayjs().format(),
|
||||
cancelReason: "",
|
||||
};
|
||||
table.value.methods.setDataType("search");
|
||||
} else {
|
||||
ElMessage.error(res.msg);
|
||||
}
|
||||
});
|
||||
},
|
||||
resetCancel() {
|
||||
cancelForm.value = {
|
||||
cancelPerson: globaUser.name,
|
||||
cancelDate: dayjs().format(),
|
||||
cancelReason: "",
|
||||
};
|
||||
cancelState.value.showDialog = false;
|
||||
},
|
||||
};
|
||||
|
||||
watch(
|
||||
() => searchForm.value.retail.retailType,
|
||||
() => {
|
||||
table.value.methods.setDataType("search");
|
||||
}
|
||||
);
|
||||
|
||||
function dataChange(val: Date[]) {
|
||||
searchForm.value.retail.startDate = val[0];
|
||||
searchForm.value.retail.endDate = val[1];
|
||||
}
|
||||
|
||||
const getSummaries = (param: { columns: any[]; data: any[] }) => {
|
||||
const { columns, data } = param;
|
||||
const sums: any[] = [];
|
||||
// 需要统计的字段列表
|
||||
const sumKeys = [
|
||||
"salesAmount",
|
||||
"payment.cashAmount",
|
||||
"payment.unionPayAmount",
|
||||
"payment.cardAmount",
|
||||
"payment.publicTransferAmount",
|
||||
"payment.workshopPayment",
|
||||
];
|
||||
columns.forEach((column, index) => {
|
||||
if (index === 0) {
|
||||
sums[index] = "合计";
|
||||
return;
|
||||
}
|
||||
if (sumKeys.includes(column.property)) {
|
||||
const values = data.map((item) => {
|
||||
const keys = column.property.split(".");
|
||||
let value = item;
|
||||
for (const key of keys) {
|
||||
value = value?.[key] || 0;
|
||||
}
|
||||
return Number(value) || 0;
|
||||
});
|
||||
|
||||
if (!values.every((value) => isNaN(value))) {
|
||||
const sum = values.reduce((prev, curr) => {
|
||||
return prev + curr;
|
||||
}, 0);
|
||||
sums[index] = `${sum.toFixed(2)}`;
|
||||
} else {
|
||||
sums[index] = "0.00 元";
|
||||
}
|
||||
} else {
|
||||
sums[index] = "";
|
||||
}
|
||||
});
|
||||
|
||||
return sums;
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
/* 添加汇总行样式 */
|
||||
:deep(.el-table__footer) {
|
||||
.cell {
|
||||
font-weight: 600;
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
td {
|
||||
background-color: #f5f7fa !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
460
frontEnd/src/pages/funeralServices/funeralServices.vue
Normal file
@@ -0,0 +1,460 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-row>
|
||||
<baseTableHeader
|
||||
title="殡仪服务"
|
||||
@resetSearch="resetSearch"
|
||||
@search="search">
|
||||
<template #content>
|
||||
<el-form
|
||||
:model="searchForm"
|
||||
:inline="true"
|
||||
label-position="right"
|
||||
label-width="80px">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="6">
|
||||
<el-form-item label="逝者姓名">
|
||||
<el-input
|
||||
v-model="searchForm.name"
|
||||
placeholder="请输入逝者姓名"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="性别">
|
||||
<el-radio-group v-model="searchForm.gender">
|
||||
<el-radio-button value="男" label="男"></el-radio-button>
|
||||
<el-radio-button value="女" label="女"></el-radio-button>
|
||||
</el-radio-group> </el-form-item
|
||||
></el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="购买人">
|
||||
<el-input
|
||||
v-model="searchForm.familyName"
|
||||
placeholder="请输入购买人姓名"></el-input> </el-form-item
|
||||
></el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="购买人手机号">
|
||||
<el-input
|
||||
v-model="searchForm.familyPhone"
|
||||
placeholder="请输入购买人手机号"></el-input> </el-form-item
|
||||
></el-col>
|
||||
<el-col :span="6"
|
||||
><el-form-item label="引导员">
|
||||
<GuideList
|
||||
v-model="searchForm.guide"></GuideList> </el-form-item
|
||||
></el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="录单日期">
|
||||
<el-date-picker
|
||||
v-model="searchForm.createDate"
|
||||
type="date"
|
||||
value-format="YYYY-MM-DD"
|
||||
placeholder="录单日期" /> </el-form-item
|
||||
></el-col>
|
||||
<!-- <el-col :span="6">
|
||||
<el-form-item label="结账日期">
|
||||
<el-date-picker
|
||||
v-model="searchForm.checkoutDate"
|
||||
type="date"
|
||||
placeholder="结账日期" /></el-form-item
|
||||
></el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="录单日期">
|
||||
<el-date-picker
|
||||
v-model="searchForm.purchaseDate"
|
||||
type="datetime"
|
||||
placeholder="录单日期" /></el-form-item
|
||||
></el-col> -->
|
||||
</el-row>
|
||||
</el-form>
|
||||
</template>
|
||||
</baseTableHeader>
|
||||
</el-row>
|
||||
<el-card style="margin-top: 8px">
|
||||
<base-table :option="tableOption" ref="table" border>
|
||||
<template #toolsBar>
|
||||
<el-button size="small" type="primary" @click="methods.handleService">
|
||||
服务办理</el-button
|
||||
>
|
||||
</template>
|
||||
<template #colunm>
|
||||
<el-table-column
|
||||
type="index"
|
||||
width="60"
|
||||
label="序号"
|
||||
align="center" />
|
||||
<el-table-column
|
||||
prop="deceased.name"
|
||||
label="逝者姓名"
|
||||
align="center" />
|
||||
<el-table-column prop="deceased.gender" label="性别" align="center" />
|
||||
<el-table-column
|
||||
prop="deceased.age"
|
||||
label="年龄"
|
||||
width="80"
|
||||
align="center" />
|
||||
<el-table-column
|
||||
prop="deceased.familyName"
|
||||
label="购买人姓名"
|
||||
align="center" />
|
||||
<el-table-column
|
||||
prop="deceased.familyPhone"
|
||||
label="购买人手机号"
|
||||
width="180"
|
||||
align="center" />
|
||||
<el-table-column prop="deceased.name" label="购买人" align="center" />
|
||||
<el-table-column
|
||||
prop="retail.purchaseDate"
|
||||
label="录单日期"
|
||||
width="180"
|
||||
align="center" />
|
||||
<el-table-column prop="handler" label="经办人" align="center" />
|
||||
<el-table-column
|
||||
prop="retail.salesAmount"
|
||||
label="销售金额"
|
||||
align="center"
|
||||
width="180">
|
||||
<template #default="{ row }">
|
||||
{{ row.retail.salesAmount || 0 }} 元
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="guide"
|
||||
label="引导员"
|
||||
width="120"
|
||||
align="center" />
|
||||
<el-table-column
|
||||
label="操作"
|
||||
align="center"
|
||||
width="350"
|
||||
fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button
|
||||
size="small"
|
||||
type="primary"
|
||||
@click="methods.addRetailRegis(row)">
|
||||
零售登记
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="row.retail?.retailState !== 1"
|
||||
size="small"
|
||||
type="primary"
|
||||
@click="methods.update(row)">
|
||||
修改</el-button
|
||||
>
|
||||
|
||||
<el-button @click="methods.viewProduct(row)" size="small">
|
||||
服务清单</el-button
|
||||
>
|
||||
<el-button size="small" type="default" @click="methods.print(row)"
|
||||
>打印</el-button
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</template>
|
||||
</base-table>
|
||||
</el-card>
|
||||
|
||||
<baseDialog
|
||||
v-model="retailRegisState.showAddRetial"
|
||||
top="50px"
|
||||
:title="retailTitle"
|
||||
@close="methods.addRetialClose">
|
||||
<retailRegis
|
||||
v-model="retailRegisForm"
|
||||
:type="retailRegisState.type"
|
||||
:showList="['逝者信息']"></retailRegis>
|
||||
<template #footer>
|
||||
<el-row justify="center" align="middle" style="margin-top: 15px">
|
||||
<el-button type="primary" @click="methods.addConfim">保存</el-button>
|
||||
<el-button type="danger" @click="methods.addClose">关闭</el-button>
|
||||
</el-row>
|
||||
</template>
|
||||
</baseDialog>
|
||||
|
||||
<baseDialog
|
||||
v-model="retailRegisState.showUpdateDialog"
|
||||
top="50px"
|
||||
:title="retailRegisState.title"
|
||||
@close="methods.resetRegisForm">
|
||||
<div
|
||||
v-loading="retailRegisState.showLoding"
|
||||
element-loading-text="正在处理...">
|
||||
<retailRegis
|
||||
v-model="regisForm"
|
||||
:type="retailRegisState.type"
|
||||
:showList="['逝者信息']"></retailRegis>
|
||||
|
||||
<el-row :justify="'center'">
|
||||
<el-button type="primary" @click="methods.addConfim">确定</el-button>
|
||||
<el-button type="warning" @click="methods.updateClose"
|
||||
>关闭</el-button
|
||||
>
|
||||
</el-row>
|
||||
</div>
|
||||
</baseDialog>
|
||||
|
||||
<PrintRetailPage
|
||||
v-model="showPrint"
|
||||
:deceased="deceased"
|
||||
:serviceUrl="serviceUrl">
|
||||
</PrintRetailPage>
|
||||
|
||||
<retailList
|
||||
v-model="showRetailList"
|
||||
title="服务清单"
|
||||
:option="retailListTable"></retailList>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref, onMounted, watch } from "vue";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
import { resetParams } from "@/util/globalMethods";
|
||||
import retailRegis from "../funeralRetail/publicComponents/retailRegis.vue";
|
||||
import api from "@/lib/request";
|
||||
import { tableOptionType } from "@/types/table";
|
||||
import { defaultRetail } from "@/defaultForm/defaultRetail";
|
||||
import PrintRetailPage from "@/components/printPage/printRetailPage.vue";
|
||||
import GuideList from "@/components/guideList/guideList.vue";
|
||||
|
||||
interface deceasedForm extends RegisForm {
|
||||
deceased: RegisForm;
|
||||
retailType: number;
|
||||
}
|
||||
|
||||
const retailRegisState = ref({
|
||||
showAddRetial: false,
|
||||
title: "服务登记",
|
||||
type: "服务登记" as RegistrationType,
|
||||
showLoding: false,
|
||||
showUpdateDialog: false,
|
||||
});
|
||||
const serviceState = ref({
|
||||
showDialog: false,
|
||||
});
|
||||
|
||||
let showRetailList = ref(false);
|
||||
|
||||
let retailTitle = ref("服务登记");
|
||||
|
||||
let showPrint = ref(false);
|
||||
let deceased = ref();
|
||||
let serviceUrl = ref();
|
||||
|
||||
let retailListTable = ref<tableOptionType>({
|
||||
url: "/deceased-retail/selected-service",
|
||||
searchUrl: "",
|
||||
searchParams: {},
|
||||
executeType: "list",
|
||||
});
|
||||
|
||||
const searchForm = reactive({
|
||||
name: "", // 逝者姓名
|
||||
gender: "", // 性别
|
||||
phone: "", // 手机号
|
||||
guide: "", // 引导员
|
||||
purchaseDate: "", // 购买日期
|
||||
createDate: "",
|
||||
familyName: "",
|
||||
familyPhone: "",
|
||||
});
|
||||
|
||||
const regisForm = ref<deceasedForm>(defaultRetail());
|
||||
const retailRegisForm = ref<RegisForm>(defaultRetail());
|
||||
|
||||
let table = ref();
|
||||
const tableOption = ref<tableOptionType>({
|
||||
url: "/deceased/list", // 获取列表数据的接口
|
||||
searchUrl: "/deceased/query", // 搜索接口
|
||||
searchParams: searchForm, // 搜索表单数据
|
||||
executeType: "list", // 默认执行类型
|
||||
});
|
||||
|
||||
const methods = {
|
||||
// 零售登记
|
||||
addRetailRegis(item: RegisForm) {
|
||||
retailRegisForm.value = {
|
||||
...regisForm.value,
|
||||
...item,
|
||||
serviceItems: [],
|
||||
services: [],
|
||||
};
|
||||
retailRegisState.value.title = "零售登记";
|
||||
retailRegisState.value.type = "零售登记";
|
||||
retailRegisState.value.showAddRetial = true;
|
||||
retailTitle.value = "零售登记";
|
||||
},
|
||||
|
||||
async print(row: any) {
|
||||
deceased.value = row;
|
||||
showPrint.value = true;
|
||||
|
||||
serviceUrl.value =
|
||||
"/deceased-retail/selected-service?retailType=0&deceasedId=" + row.id;
|
||||
},
|
||||
drawerClose() {
|
||||
showRetailList.value = false;
|
||||
},
|
||||
|
||||
async viewProduct(row: RegisForm) {
|
||||
retailListTable.value.url =
|
||||
"/deceased-retail/selected-service?retailType=0&deceasedId=" + row.id;
|
||||
showRetailList.value = true;
|
||||
},
|
||||
|
||||
update(row: RegisForm) {
|
||||
regisForm.value = row;
|
||||
retailTitle.value = "服务修改";
|
||||
retailRegisState.value.title = "服务修改";
|
||||
retailRegisState.value.type = "服务修改";
|
||||
retailRegisState.value.showUpdateDialog = true;
|
||||
},
|
||||
|
||||
// 服务办理
|
||||
handleService() {
|
||||
retailRegisForm.value = defaultRetail();
|
||||
serviceState.value.showDialog = true;
|
||||
retailRegisState.value.showAddRetial = true;
|
||||
retailRegisState.value.title = "服务登记";
|
||||
retailRegisState.value.type = "服务登记";
|
||||
retailTitle.value = "服务登记";
|
||||
},
|
||||
|
||||
// 重置登记表单
|
||||
resetRegisForm() {
|
||||
regisForm.value = defaultRetail();
|
||||
},
|
||||
|
||||
// 取消操作
|
||||
cancle() {
|
||||
retailRegisState.value.showAddRetial = false;
|
||||
methods.resetRegisForm();
|
||||
},
|
||||
|
||||
updateClose() {
|
||||
retailRegisState.value.showUpdateDialog = false;
|
||||
},
|
||||
addClose() {
|
||||
retailRegisState.value.showAddRetial = false;
|
||||
regisForm.value = defaultRetail();
|
||||
},
|
||||
|
||||
async confirmUpdate() {
|
||||
await ElMessageBox.confirm("确定保存修改吗?", { type: "warning" });
|
||||
let sendData = { ...regisForm.value };
|
||||
api()
|
||||
.post("/deceased-retail/update", sendData)
|
||||
.then((res) => {
|
||||
if (res.code === 200) {
|
||||
ElMessage.success("修改成功");
|
||||
table.value.methods.setDataType("list");
|
||||
retailRegisState.value.showAddRetial = false;
|
||||
regisForm.value = defaultRetail();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
async addConfim() {
|
||||
if (retailRegisState.value.type === "服务登记") {
|
||||
if (!retailRegisForm.value.idNumber || !retailRegisForm.value.name) {
|
||||
return ElMessage.error("逝者姓名和证件号码不能为空!");
|
||||
}
|
||||
}
|
||||
|
||||
let confirmContent = "";
|
||||
if (retailRegisState.value.type === "服务登记")
|
||||
confirmContent = "确定登记该服务吗?";
|
||||
if (retailRegisState.value.type === "零售登记")
|
||||
confirmContent = "确定登记该信息吗?";
|
||||
if (retailRegisState.value.type === "服务修改")
|
||||
confirmContent = "确定修改该信息吗?";
|
||||
|
||||
await ElMessageBox.confirm(confirmContent, "提示", {
|
||||
type: "warning",
|
||||
});
|
||||
|
||||
if (retailRegisState.value.type === "服务登记") {
|
||||
let sendData = { ...retailRegisForm.value };
|
||||
sendData.retailType = 0;
|
||||
api()
|
||||
.post("/deceased/add", sendData) // 修改为 Deceased 的接口
|
||||
.then((res) => {
|
||||
if (res.code === 200) {
|
||||
ElMessage.success("新增成功!");
|
||||
table.value.methods.setDataType("list");
|
||||
retailRegisState.value.showAddRetial = false;
|
||||
retailRegisState.value.showLoding = false;
|
||||
methods.resetRegisForm();
|
||||
} else {
|
||||
ElMessage.error(res.msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (retailRegisState.value.type === "零售登记") {
|
||||
let sendData = { ...retailRegisForm.value };
|
||||
sendData.retailType = 1;
|
||||
|
||||
sendData.deceasedId = sendData.id;
|
||||
|
||||
let url = "/deceased-retail/add?type=1";
|
||||
|
||||
api()
|
||||
.post(url, sendData) // 修改为 Deceased 的接口
|
||||
.then((res) => {
|
||||
if (res.code === 200) {
|
||||
ElMessage.success("新增成功!");
|
||||
table.value.methods.setDataType("list");
|
||||
retailRegisState.value.showAddRetial = false;
|
||||
retailRegisState.value.showLoding = false;
|
||||
methods.resetRegisForm();
|
||||
} else {
|
||||
ElMessage.error(res.msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (retailRegisState.value.type === "服务修改") {
|
||||
let sendData = { ...regisForm.value };
|
||||
sendData.retailType = 0;
|
||||
sendData.deceased.familyName = sendData.familyName;
|
||||
sendData.deceased.familyPhone = sendData.familyPhone;
|
||||
sendData.deceased.address = sendData.address;
|
||||
sendData.deceased.area = sendData.area;
|
||||
sendData.deceased.province = sendData.province;
|
||||
sendData.deceased.city = sendData.city;
|
||||
sendData.deceased.guide = sendData.guide;
|
||||
api()
|
||||
.post("/deceased-retail/updateRetail", sendData) // 修改为 Deceased 的接口
|
||||
.then((res) => {
|
||||
if (res.code === 200) {
|
||||
ElMessage.success("修改成功!");
|
||||
table.value.methods.setDataType("list");
|
||||
retailRegisState.value.showAddRetial = false;
|
||||
retailRegisState.value.showLoding = false;
|
||||
retailRegisState.value.showUpdateDialog = false;
|
||||
|
||||
methods.resetRegisForm();
|
||||
} else {
|
||||
ElMessage.error(res.msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
addRetialClose() {
|
||||
retailRegisState.value.showAddRetial = false;
|
||||
regisForm.value = defaultRetail();
|
||||
},
|
||||
};
|
||||
|
||||
onMounted(async () => {});
|
||||
|
||||
function search() {
|
||||
table.value.methods.setDataType("search");
|
||||
}
|
||||
|
||||
function resetSearch() {
|
||||
resetParams(searchForm);
|
||||
table.value.methods.setDataType("reset");
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
||||
143
frontEnd/src/pages/funeralServices/page/userAddOrEdit.vue
Normal file
@@ -0,0 +1,143 @@
|
||||
<template>
|
||||
<el-form
|
||||
:model="user"
|
||||
label-width="100px"
|
||||
:inline="true"
|
||||
label-suffix=":"
|
||||
v-loading="loading"
|
||||
element-loading-text="正在初始化数据...">
|
||||
<el-form-item label="姓名">
|
||||
<el-input :prefix-icon="User" v-model="user.name" placeholder="姓名">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="性别">
|
||||
<el-radio-group v-model="user.sex">
|
||||
<el-radio value="男">男</el-radio>
|
||||
<el-radio value="女">女</el-radio>
|
||||
<el-radio value="保密">保密</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="电话">
|
||||
<el-input
|
||||
:prefix-icon="Iphone"
|
||||
v-model="user.phone"
|
||||
placeholder="电话"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="所属角色">
|
||||
<el-select
|
||||
v-model="user.role"
|
||||
clearable
|
||||
filterable
|
||||
placeholder="请选择角色"
|
||||
style="width: 230px">
|
||||
<el-option
|
||||
v-for="item in roleList"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="String(item.id)"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="生日">
|
||||
<el-date-picker
|
||||
format="YYYYH-MM-DD"
|
||||
v-model="user.birthday"
|
||||
type="date"
|
||||
placeholder="生日"
|
||||
size="large" />
|
||||
</el-form-item>
|
||||
<el-form-item label="所在区域">
|
||||
<el-cascader
|
||||
:options="pcaTextArrData"
|
||||
v-model="selectedOptions"
|
||||
@change="pcaChange"></el-cascader>
|
||||
</el-form-item>
|
||||
<el-form-item label="详细地址">
|
||||
<el-input
|
||||
:prefix-icon="Location"
|
||||
v-model="user.address"
|
||||
placeholder="请输入详细地址"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="账号状态">
|
||||
<el-switch
|
||||
v-model="user.userState"
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
active-text="启用"
|
||||
width="65px"
|
||||
inline-prompt
|
||||
inactive-text="禁用"></el-switch>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref, watch } from "vue";
|
||||
import { userType } from "@/types/user";
|
||||
// @ts-ignore
|
||||
import { pcaTextArr } from "element-china-area-data";
|
||||
import { Avatar, Location, Iphone, User } from "@element-plus/icons-vue";
|
||||
import { roleType } from "@/types/role";
|
||||
import { roleDataList } from "@/lib/api/publicApiList";
|
||||
|
||||
const pcaTextArrData = ref(pcaTextArr);
|
||||
const selectedOptions = ref([]);
|
||||
const props = defineProps<{
|
||||
data?: userType;
|
||||
executeType?: string;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits(["updateData"]);
|
||||
|
||||
let loading = ref(true);
|
||||
let roleList = ref<roleType[]>();
|
||||
let user = ref<userType>({
|
||||
createDate: "",
|
||||
name: "",
|
||||
sex: "男",
|
||||
phone: "",
|
||||
userState: 1,
|
||||
role: "",
|
||||
birthday: "",
|
||||
province: "",
|
||||
city: "",
|
||||
area: "",
|
||||
address: "",
|
||||
});
|
||||
|
||||
onMounted(async () => {
|
||||
roleList.value = await roleDataList();
|
||||
|
||||
watch(
|
||||
() => user,
|
||||
(newVal) => {
|
||||
emit("updateData", newVal);
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
loading.value = false;
|
||||
});
|
||||
|
||||
if (props.executeType === "edit") {
|
||||
user.value = { ...props.data };
|
||||
selectedOptions.value = [
|
||||
user.value.province as never,
|
||||
user.value.city as never,
|
||||
user.value.area as never,
|
||||
];
|
||||
}
|
||||
|
||||
function pcaChange(data: { [key: string]: any }) {
|
||||
user.value.province = data[0];
|
||||
user.value.city = data[1];
|
||||
user.value.area = data[2];
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
:deep(.el-input) {
|
||||
width: 230px;
|
||||
}
|
||||
:deep(.el-form-item) {
|
||||
margin-right: 0;
|
||||
}
|
||||
</style>
|
||||
374
frontEnd/src/pages/invalidReview/invalidReview.vue
Normal file
@@ -0,0 +1,374 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-row>
|
||||
<baseTableHeader
|
||||
title="作废审核"
|
||||
@resetSearch="resetSearch"
|
||||
@search="search">
|
||||
<template #content>
|
||||
<el-form
|
||||
:model="searchForm"
|
||||
label-position="right"
|
||||
label-width="90px">
|
||||
<el-row :gutter="15">
|
||||
<!-- 逝者姓名 -->
|
||||
<el-col :span="8">
|
||||
<el-form-item label="逝者姓名">
|
||||
<el-input
|
||||
v-model="searchForm.name"
|
||||
placeholder="请输入逝者姓名" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<!-- 作废申请人 -->
|
||||
<el-col :span="8">
|
||||
<el-form-item label="作废申请人" style="width: 100%">
|
||||
<el-select
|
||||
v-model="searchForm.cancelPerson"
|
||||
placeholder="请选择申请人">
|
||||
<el-option
|
||||
v-for="item in guideOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<!-- 结账时间 -->
|
||||
<!-- <el-col :span="6">
|
||||
<el-form-item label="结账时间">
|
||||
<el-date-picker
|
||||
value-format="YYYY-MM-DD"
|
||||
v-model="searchForm.checkoutDate"
|
||||
type="date"
|
||||
placeholder="选择结账时间"
|
||||
format="YYYY-MM-DD" />
|
||||
</el-form-item>
|
||||
</el-col> -->
|
||||
|
||||
<!-- 申请时间 -->
|
||||
<el-col :span="8">
|
||||
<el-form-item label="申请时间">
|
||||
<el-date-picker
|
||||
value-format="YYYY-MM-DD"
|
||||
v-model="searchForm.cancelDate"
|
||||
type="date"
|
||||
placeholder="选择申请时间"
|
||||
format="YYYY-MM-DD" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</template>
|
||||
</baseTableHeader>
|
||||
</el-row>
|
||||
<el-card style="margin-top: 8px">
|
||||
<base-table :option="tableOption" ref="table" border>
|
||||
<template #toolsBar>
|
||||
<el-radio-group v-model="searchForm.examineState" size="small">
|
||||
<el-radio-button :value="0" label="未处理"></el-radio-button>
|
||||
<el-radio-button :value="1" label="已通过"></el-radio-button>
|
||||
<!-- <el-radio-button :value="2" label="已拒绝"></el-radio-button> -->
|
||||
</el-radio-group>
|
||||
</template>
|
||||
<template #colunm>
|
||||
<!-- 序号 -->
|
||||
<el-table-column
|
||||
type="index"
|
||||
label="序号"
|
||||
width="80"
|
||||
align="center" />
|
||||
|
||||
<!-- 状态 -->
|
||||
<el-table-column label="状态" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag type="primary" v-if="row.examineState === 0"
|
||||
>未审核</el-tag
|
||||
>
|
||||
<el-tag type="success" v-if="row.examineState === 1"
|
||||
>已审核</el-tag
|
||||
>
|
||||
<el-tag type="success" v-if="row.examineState === 2"
|
||||
>已拒绝</el-tag
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="逝者姓名" align="center">
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.retail.retailType !== 2">
|
||||
{{ row.deceased.name }}</span
|
||||
>
|
||||
<span v-else> {{ row.retail.familyName }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="deceased.gender" label="性别" align="center">
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.retail.retailType !== 2">
|
||||
{{ row.deceased.gender }}</span
|
||||
>
|
||||
<span v-else> {{ row.retail.gender || "无" }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="deceased.age"
|
||||
label="年龄"
|
||||
width="80"
|
||||
align="center">
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.retail.retailType !== 2">
|
||||
{{ row.deceased.age }}</span
|
||||
>
|
||||
<span v-else> {{ row.retail.age || "无" }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="cancelReason"
|
||||
label="作废原因"
|
||||
width="200"
|
||||
align="center" />
|
||||
<el-table-column
|
||||
prop="cancelPerson"
|
||||
label="作废申请人"
|
||||
align="center" />
|
||||
<el-table-column
|
||||
prop="cancelDate"
|
||||
label="申请时间"
|
||||
align="center"
|
||||
width="180" />
|
||||
<el-table-column
|
||||
prop="retail.checkoutDate"
|
||||
label="结账时间"
|
||||
width="180"
|
||||
align="center" />
|
||||
<el-table-column
|
||||
prop="payment.cashAmount"
|
||||
label="现金支付"
|
||||
width="100"
|
||||
align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.payment?.cashAmount || "0.00" }} 元
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="payment.unionPayAmount"
|
||||
label="银联支付"
|
||||
width="100"
|
||||
align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.payment?.unionPayAmount || "0.00" }} 元
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
prop="payment.cardAmount"
|
||||
label="刷卡金额"
|
||||
width="100"
|
||||
align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.payment?.cardAmount || "0.00" }} 元
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="payment.publicTransferAmount"
|
||||
label="对公转账"
|
||||
width="100"
|
||||
align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.payment?.publicTransferAmount || "0.00" }} 元
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="payment.workshopPayment"
|
||||
label="车间支付"
|
||||
width="100"
|
||||
align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.payment?.workshopPayment || "0.00" }} 元
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
width="200"
|
||||
label="操作"
|
||||
align="center"
|
||||
fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button
|
||||
size="small"
|
||||
type="primary"
|
||||
v-if="row.examineState === 0"
|
||||
@click="methods.invalid(row)">
|
||||
审核</el-button
|
||||
>
|
||||
|
||||
<el-button
|
||||
size="small"
|
||||
type="primary"
|
||||
v-if="row.examineState === 1"
|
||||
@click="methods.view(row)">
|
||||
查看</el-button
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</template>
|
||||
</base-table>
|
||||
</el-card>
|
||||
|
||||
<baseDialog
|
||||
v-model="invalidReviewState.showDialog"
|
||||
top="50px"
|
||||
:title="invalidReviewState.title"
|
||||
@close="methods.resetRegisForm">
|
||||
<div
|
||||
v-loading="invalidReviewState.showLoding"
|
||||
element-loading-text="正在处理...">
|
||||
<reviewDetails v-model="currentData"></reviewDetails>
|
||||
|
||||
<el-row :justify="'center'">
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="methods.confirm"
|
||||
v-if="invalidReviewState.title !== '作废查看'"
|
||||
>确定</el-button
|
||||
>
|
||||
<el-button
|
||||
type="primary"
|
||||
v-if="invalidReviewState.title !== '作废查看'"
|
||||
@click="methods.cancel"
|
||||
>拒绝</el-button
|
||||
>
|
||||
<el-button type="danger" @click="methods.close">关闭</el-button>
|
||||
</el-row>
|
||||
</div>
|
||||
</baseDialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref, onMounted, watch } from "vue";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
import { resetParams } from "@/util/globalMethods";
|
||||
import { globalState } from "@/store";
|
||||
import reviewDetails from "./reviewDetails.vue";
|
||||
import { tableOptionType } from "@/types/table";
|
||||
import { defaultRetail } from "@/defaultForm/defaultRetail";
|
||||
import { defaultPaymentForm } from "@/defaultForm/defaultPaymentForm";
|
||||
import api from "@/lib/request";
|
||||
|
||||
const invalidReviewState = ref({
|
||||
showDialog: false,
|
||||
title: "作废审核",
|
||||
type: "服务登记" as RegistrationType,
|
||||
showLoding: false,
|
||||
});
|
||||
|
||||
const guideOptions = ref<guideOption[]>([]);
|
||||
|
||||
const searchForm = reactive({
|
||||
examineState: 0, // 状态
|
||||
name: "", // 逝者姓名
|
||||
cancelPerson: "", // 作废申请人
|
||||
checkoutDate: "", // 结账时间
|
||||
cancelDate: "", // 申请时间
|
||||
});
|
||||
|
||||
const currentData = ref({
|
||||
payment: defaultPaymentForm(),
|
||||
deceased: {},
|
||||
retail: defaultRetail(),
|
||||
});
|
||||
|
||||
const regisForm = ref<RegisForm>(defaultRetail());
|
||||
|
||||
let table = ref();
|
||||
let tableOption = ref<tableOptionType>({
|
||||
url: "/cancel/list",
|
||||
searchUrl: "/cancel/query",
|
||||
searchParams: searchForm,
|
||||
executeType: "list",
|
||||
});
|
||||
const methods = {
|
||||
resetRegisForm() {
|
||||
regisForm.value = defaultRetail();
|
||||
},
|
||||
async confirm() {
|
||||
let confirmContent = "确定【通过】该信息吗?";
|
||||
|
||||
await ElMessageBox.confirm(confirmContent, "提示", {
|
||||
type: "warning",
|
||||
});
|
||||
|
||||
let sendData = { ...currentData.value };
|
||||
sendData.examineState = 1;
|
||||
api()
|
||||
.post("/cancel/examine", sendData)
|
||||
.then((res) => {
|
||||
if (res.code === 200) {
|
||||
invalidReviewState.value.showDialog = false;
|
||||
ElMessage.success("成功通过!");
|
||||
table.value.methods.setDataType("list");
|
||||
} else {
|
||||
ElMessage.error(res.msg);
|
||||
}
|
||||
});
|
||||
},
|
||||
invalid(row: any) {
|
||||
currentData.value = row;
|
||||
invalidReviewState.value.showDialog = true;
|
||||
invalidReviewState.value.title = "作废审核";
|
||||
},
|
||||
async cancel() {
|
||||
let confirmContent = "确定【拒绝】该信息吗?";
|
||||
await ElMessageBox.confirm(confirmContent, { type: "warning" });
|
||||
|
||||
let sendData = { ...currentData.value };
|
||||
sendData.examineState = 2;
|
||||
api()
|
||||
.post("/cancel/examine", sendData)
|
||||
.then((res) => {
|
||||
if (res.code === 200) {
|
||||
invalidReviewState.value.showDialog = false;
|
||||
ElMessage.success("成功拒绝!");
|
||||
table.value.methods.setDataType("list");
|
||||
} else {
|
||||
ElMessage.error(res.msg);
|
||||
}
|
||||
});
|
||||
},
|
||||
close() {
|
||||
invalidReviewState.value.showDialog = false;
|
||||
invalidReviewState.value.title = "";
|
||||
methods.resetRegisForm();
|
||||
},
|
||||
|
||||
view(row: any) {
|
||||
invalidReviewState.value.showDialog = true;
|
||||
currentData.value = row;
|
||||
invalidReviewState.value.title = "作废查看";
|
||||
},
|
||||
};
|
||||
api()
|
||||
.get("public/guide")
|
||||
.then((res) => {
|
||||
guideOptions.value = res.data;
|
||||
});
|
||||
onMounted(async () => {});
|
||||
|
||||
watch(
|
||||
() => searchForm.examineState,
|
||||
(newData) => {
|
||||
table.value.methods.setDataType("search");
|
||||
}
|
||||
);
|
||||
|
||||
function search() {
|
||||
table.value.methods.setDataType("search");
|
||||
}
|
||||
|
||||
function resetSearch() {
|
||||
resetParams(searchForm);
|
||||
table.value.methods.setDataType("reset");
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
||||
259
frontEnd/src/pages/invalidReview/reviewDetails.vue
Normal file
@@ -0,0 +1,259 @@
|
||||
<template>
|
||||
<el-form
|
||||
style="max-height: 72vh; overflow-y: auto"
|
||||
ref="formRef"
|
||||
:model="formData"
|
||||
label-width="120px"
|
||||
label-position="right">
|
||||
<inforCard title="逝者信息">
|
||||
<el-form :model="formData" label-width="120px" disabled>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="姓名">
|
||||
<el-input
|
||||
v-model="formData.deceased.name"
|
||||
disabled
|
||||
placeholder="姓名">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="性别">
|
||||
<el-radio-group v-model="formData.deceased.gender" disabled>
|
||||
<el-radio-button value="男" label="男"></el-radio-button>
|
||||
<el-radio-button value="女" label="女"></el-radio-button>
|
||||
</el-radio-group> </el-form-item
|
||||
></el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="证件号码" prop="idNumber">
|
||||
<el-input v-model="formData.deceased.idNumber" disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="年龄">
|
||||
<el-input
|
||||
v-model="formData.deceased.age"
|
||||
disabled
|
||||
placeholder="年龄">
|
||||
</el-input> </el-form-item
|
||||
></el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="购买人姓名" prop="buyer">
|
||||
<el-input v-model="formData.deceased.familyName" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="购买人电话" prop="buyer">
|
||||
<el-input v-model="formData.deceased.familyPhone" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="购买日期" prop="purchaseDate">
|
||||
<el-date-picker
|
||||
v-model="formData.deceased.purchaseDate"
|
||||
type="datetime"
|
||||
format="YYYY-MM-DD: HH:mm:ss" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</inforCard>
|
||||
|
||||
<inforCard title="结账列表">
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="formData"
|
||||
label-width="120px"
|
||||
label-position="right">
|
||||
<el-row :gutter="20">
|
||||
<!-- 第一行 -->
|
||||
<el-col :span="8">
|
||||
<el-form-item label="结账日期" prop="checkoutDate">
|
||||
<el-date-picker
|
||||
v-model="formData.payment.checkoutDate"
|
||||
type="date"
|
||||
placeholder="结账日期"
|
||||
format="YYYY-MM-DD"
|
||||
disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="8">
|
||||
<el-form-item label="结算日期" prop="settlementDate">
|
||||
<el-date-picker
|
||||
v-model="formData.payment.settlementDate"
|
||||
type="date"
|
||||
disabled
|
||||
placeholder="选择日期"
|
||||
format="YYYY-MM-DD" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="经办人" prop="handler">
|
||||
<el-input
|
||||
disabled
|
||||
v-model="formData.payment.handler"
|
||||
placeholder="经办人" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="现金金额" prop="cash">
|
||||
<el-input
|
||||
disabled
|
||||
v-model="formData.payment.cashAmount"
|
||||
:min="0"
|
||||
@change="caleValue('cashAmount')"
|
||||
type="number">
|
||||
<template #append>元</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="银联" prop="unionPay">
|
||||
<el-input
|
||||
disabled
|
||||
v-model="formData.payment.unionPayAmount"
|
||||
:min="0"
|
||||
@change="caleValue('cashAmount')"
|
||||
type="number">
|
||||
<template #append>元</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="8">
|
||||
<el-form-item label="银行卡" prop="cardPay">
|
||||
<el-input
|
||||
disabled
|
||||
v-model="formData.payment.cardAmount"
|
||||
:min="0"
|
||||
@change="caleValue('cashAmount')"
|
||||
type="number">
|
||||
<template #append>元</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="8">
|
||||
<el-form-item label="对公" prop="transfer">
|
||||
<el-input
|
||||
disabled
|
||||
v-model="formData.payment.publicTransferAmount"
|
||||
:min="0"
|
||||
@change="caleValue('cashAmount')"
|
||||
type="number">
|
||||
<template #append>元</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="车间支付" prop="transfer">
|
||||
<el-input
|
||||
disabled
|
||||
v-model="formData.payment.workshopPayment"
|
||||
:min="0"
|
||||
@change="caleValue('cashAmount')"
|
||||
type="number">
|
||||
<template #append>元</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</inforCard>
|
||||
|
||||
<inforCard title="作废信息">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="作废申请人">
|
||||
<el-input
|
||||
disabled
|
||||
v-model="formData.cancelPerson"
|
||||
placeholder="请输入作废申请人" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="作废时间">
|
||||
<el-date-picker
|
||||
disabled
|
||||
v-model="formData.cancelDate"
|
||||
type="datetime"
|
||||
placeholder="选择作废时间" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="作废原因">
|
||||
<el-input
|
||||
disabled
|
||||
v-model="formData.cancelReason"
|
||||
type="textarea"
|
||||
placeholder="请输入作废原因" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</inforCard>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref } from "vue";
|
||||
import { defaultPaymentForm } from "@/defaultForm/defaultPaymentForm";
|
||||
import { defaultRetail } from "@/defaultForm/defaultRetail";
|
||||
|
||||
const formRef = ref();
|
||||
|
||||
// 表单数据
|
||||
const formData = defineModel<any>({
|
||||
default: {
|
||||
payment: defaultPaymentForm(),
|
||||
deceased: {},
|
||||
retail: defaultRetail(),
|
||||
},
|
||||
});
|
||||
|
||||
if (!formData.value.payment) {
|
||||
formData.value.payment = defaultPaymentForm();
|
||||
}
|
||||
if (!formData.value.deceased) {
|
||||
formData.value.deceased = { ...formData.value.retail };
|
||||
}
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
add?: boolean;
|
||||
type?: "审核" | "申请";
|
||||
}>(),
|
||||
{
|
||||
add: false,
|
||||
type: "审核",
|
||||
}
|
||||
);
|
||||
|
||||
onMounted(() => {});
|
||||
|
||||
let keys = [
|
||||
"cashAmount",
|
||||
"unionPayAmount",
|
||||
"cardAmount",
|
||||
"publicTransferAmount",
|
||||
"workshopPayment",
|
||||
];
|
||||
|
||||
function caleValue(keyVal: string) {
|
||||
let total = 0;
|
||||
let currentVal = formData.value.payment[keyVal];
|
||||
|
||||
keys.forEach((key) => {
|
||||
if (keyVal !== key) {
|
||||
let tempVal = Number(formData.value.payment[key]).toFixed(2);
|
||||
total = Number(total) + Number(tempVal);
|
||||
}
|
||||
});
|
||||
let salesAmount = Number(formData.value.deceased.salesAmount);
|
||||
|
||||
if (salesAmount - (total + currentVal) < 0) {
|
||||
formData.value[keyVal] = salesAmount - total;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
||||
BIN
frontEnd/src/pages/login/img/login-bck.jpg
Normal file
|
After Width: | Height: | Size: 758 KiB |
123
frontEnd/src/pages/login/login.vue
Normal file
@@ -0,0 +1,123 @@
|
||||
<template>
|
||||
<div
|
||||
class="logon-main-content"
|
||||
v-loading="loading"
|
||||
:element-loading-text="'正在登录...'">
|
||||
<div class="login">
|
||||
<h2 class="title">欢迎使用德孝善延伸服务系统</h2>
|
||||
<el-form :model="data.loginForm" class="login-form">
|
||||
<el-form-item>
|
||||
<el-input
|
||||
v-model="data.loginForm.name"
|
||||
placeholder="请输入账户"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-input
|
||||
v-model="data.loginForm.pwd"
|
||||
type="password"
|
||||
placeholder="请输入密码"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="">
|
||||
<el-button class="login-btn" type="default" @click="login"
|
||||
>登陆</el-button
|
||||
>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, onBeforeMount, onMounted, ref } from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
import { userInfor } from "@/store/user/user";
|
||||
import MD5 from "js-md5";
|
||||
import api from "@/lib/request";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
|
||||
const data = reactive({
|
||||
name: "测试",
|
||||
loginForm: {
|
||||
name: "",
|
||||
pwd: "",
|
||||
},
|
||||
});
|
||||
|
||||
let loading = ref(false);
|
||||
|
||||
const router = useRouter();
|
||||
const userInforState = userInfor();
|
||||
|
||||
onBeforeMount(() => {});
|
||||
|
||||
onMounted(() => {});
|
||||
|
||||
function login() {
|
||||
loading.value = true;
|
||||
api()
|
||||
.post("/login", {
|
||||
name: data.loginForm.name,
|
||||
pwd: MD5.md5(data.loginForm.pwd).toLocaleUpperCase(),
|
||||
})
|
||||
.then((res: any) => {
|
||||
if (res.code === 200) {
|
||||
userInforState.setLoginState(res.data.user);
|
||||
ElMessage.success("登录成功!");
|
||||
let userRouter: [] = res.data.user.routerMenue;
|
||||
let noChildren = userRouter.find((item) => !item.children.length);
|
||||
|
||||
router.replace({ name: noChildren.name });
|
||||
userInforState.setToken(res.data.token);
|
||||
userInforState.setRefToken(res.data.refreshToken);
|
||||
} else {
|
||||
ElMessage.error(res.msg || res);
|
||||
}
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.logon-main-content {
|
||||
background-image: url("./img/login-bck.jpg");
|
||||
background-size: 100% 100%;
|
||||
background-repeat: no-repeat;
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
.login {
|
||||
width: 40%;
|
||||
height: 60%;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
background-image: linear-gradient(135deg, #5efce8 10%, #736efe 100%);
|
||||
|
||||
.title {
|
||||
margin: 30px 0;
|
||||
font-size: 30px;
|
||||
}
|
||||
.copy-info {
|
||||
text-align: center;
|
||||
p {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.login-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-content: center;
|
||||
.login-btn {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
167
frontEnd/src/pages/main/index.vue
Normal file
@@ -0,0 +1,167 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-row class="width-100" justify="space-between">
|
||||
<el-row :gutter="20" class="width-100">
|
||||
<el-col :span="6">
|
||||
<el-card>
|
||||
<template #header>
|
||||
<el-row :gutter="15" justify="space-between">
|
||||
<el-col :span="12">
|
||||
<h2>框架访问人数</h2>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<h1>100</h1>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</template>
|
||||
今天的天气也很好呀
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-card>
|
||||
<template #header>
|
||||
<el-row :gutter="15" justify="space-between">
|
||||
<el-col :span="12">
|
||||
<h2>留言总数</h2>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<h1>3205</h1>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</template>
|
||||
每一天都有希望
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-card>
|
||||
<template #header>
|
||||
<el-row :gutter="15" justify="space-between">
|
||||
<el-col :span="12">
|
||||
<h2>用户数量</h2>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<h1>421</h1>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</template>
|
||||
期待美好的事情发生
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-card>
|
||||
<template #header>
|
||||
<el-row :gutter="15" justify="space-between">
|
||||
<el-col :span="12">
|
||||
<h2>总文章数</h2>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<h1>421</h1>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</template>
|
||||
明天将会发生什么呢
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-row>
|
||||
|
||||
<el-row style="margin-top: 15px" :gutter="20" class="width-100">
|
||||
<el-col :span="18" style="height: 500px">
|
||||
<el-card class="height-100" body-style="height:100%">
|
||||
<baseEcharts></baseEcharts>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-card style="height: 500px; overflow-y: auto">
|
||||
<template #header> 更新动态 </template>
|
||||
<p v-for="i in 20" :key="i">今天这里是第{{ i }}篇文章</p>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="24" style="margin-top: 15px">
|
||||
<el-card>
|
||||
<baseEcharts :option="lineStack" style="height: 500px"></baseEcharts>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive } from "vue";
|
||||
import baseEcharts from "@/components/baseEcharts/baseEcharts.vue";
|
||||
|
||||
const data = reactive({});
|
||||
const lineStack = reactive({
|
||||
title: {
|
||||
text: "Stacked Line",
|
||||
},
|
||||
tooltip: {
|
||||
trigger: "axis",
|
||||
},
|
||||
legend: {
|
||||
data: ["Email", "Union Ads", "Video Ads", "Direct", "Search Engine"],
|
||||
},
|
||||
grid: {
|
||||
left: "3%",
|
||||
right: "4%",
|
||||
bottom: "3%",
|
||||
containLabel: true,
|
||||
},
|
||||
toolbox: {
|
||||
feature: {
|
||||
saveAsImage: {},
|
||||
},
|
||||
},
|
||||
xAxis: {
|
||||
type: "category",
|
||||
boundaryGap: false,
|
||||
data: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
|
||||
},
|
||||
yAxis: {
|
||||
type: "value",
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: "Email",
|
||||
type: "line",
|
||||
stack: "Total",
|
||||
data: [120, 132, 101, 134, 90, 230, 210],
|
||||
},
|
||||
{
|
||||
name: "Union Ads",
|
||||
type: "line",
|
||||
stack: "Total",
|
||||
data: [220, 182, 191, 234, 290, 330, 310],
|
||||
},
|
||||
{
|
||||
name: "Video Ads",
|
||||
type: "line",
|
||||
stack: "Total",
|
||||
data: [150, 232, 201, 154, 190, 330, 410],
|
||||
},
|
||||
{
|
||||
name: "Direct",
|
||||
type: "line",
|
||||
stack: "Total",
|
||||
data: [320, 332, 301, 334, 390, 330, 320],
|
||||
},
|
||||
{
|
||||
name: "Search Engine",
|
||||
type: "line",
|
||||
stack: "Total",
|
||||
data: [820, 932, 901, 934, 1290, 1330, 1320],
|
||||
},
|
||||
],
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.el-carousel__item h3 {
|
||||
display: flex;
|
||||
color: #475669;
|
||||
opacity: 0.75;
|
||||
line-height: 300px;
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
104
frontEnd/src/pages/publicPages/user/userView.vue
Normal file
@@ -0,0 +1,104 @@
|
||||
<template>
|
||||
<el-descriptions
|
||||
title="个人信息"
|
||||
style="padding: 15px"
|
||||
border
|
||||
size="large"
|
||||
:column="2"
|
||||
v-loading="loading"
|
||||
element-loading-text="正在初始化数据...">
|
||||
<el-descriptions-item>
|
||||
<template #label>
|
||||
<el-icon>
|
||||
<User />
|
||||
</el-icon>
|
||||
姓名 </template
|
||||
>{{ user.name }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item>
|
||||
<template #label>
|
||||
<el-icon>
|
||||
<Female v-if="user.sex === 0 || user.sex === '女'" />
|
||||
<Male v-if="user.sex === 1 || user.sex === '男'" />
|
||||
</el-icon>
|
||||
性别 </template
|
||||
>{{ user.sex }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item>
|
||||
<template #label>
|
||||
<el-icon>
|
||||
<Iphone />
|
||||
</el-icon>
|
||||
电话 </template
|
||||
>{{ user.phone }}</el-descriptions-item
|
||||
>
|
||||
<el-descriptions-item>
|
||||
<template #label>
|
||||
<el-icon> <Avatar /> </el-icon>状态
|
||||
</template>
|
||||
<el-tag type="success" v-if="user.userState || user.userState === 1"
|
||||
>正常</el-tag
|
||||
>
|
||||
<el-tag type="danger" v-if="!user.userState || user.userState === 0"
|
||||
>未启用</el-tag
|
||||
>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item>
|
||||
<template #label>
|
||||
<el-icon> <UserFilled /> </el-icon>角色
|
||||
</template>
|
||||
<el-tag>
|
||||
{{
|
||||
roles.find((item) => Number(item.id) === Number(user.role))?.name ||
|
||||
"无"
|
||||
}}
|
||||
</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item>
|
||||
<template #label>
|
||||
<el-icon> <TakeawayBox /> </el-icon>生日 </template
|
||||
>{{ dayjs(user.birthday).format("YYYYH-MM-DD") }}</el-descriptions-item
|
||||
>
|
||||
<!-- <el-descriptions-item label="年龄">{{ user.age }}</el-descriptions-item> -->
|
||||
<el-descriptions-item>
|
||||
<template #label>
|
||||
<el-icon> <OfficeBuilding /> </el-icon>所在省市区
|
||||
</template>
|
||||
{{ user.province + "/" + user.city + "/" + user.area }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item>
|
||||
<template #label>
|
||||
<el-icon><LocationInformation /></el-icon>详细地址
|
||||
</template>
|
||||
{{ user.address }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, onMounted } from "vue";
|
||||
import { userType } from "@/types/user";
|
||||
import dayjs from "dayjs";
|
||||
import { roleDataList } from "@/lib/api/publicApiList";
|
||||
import { roleType } from "@/types/role";
|
||||
const props = defineProps<{
|
||||
data: userType;
|
||||
}>();
|
||||
const user = props.data;
|
||||
let roles = ref<roleType[]>([]);
|
||||
let loading = ref(true);
|
||||
|
||||
onMounted(async () => {
|
||||
roles.value = await roleDataList();
|
||||
loading.value = false;
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
:deep(.el-descriptions__label) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.el-icon {
|
||||
margin: 0 5px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,65 @@
|
||||
<template>
|
||||
<el-form
|
||||
:model="formData"
|
||||
label-width="100px"
|
||||
inline
|
||||
style="padding-bottom: 20px">
|
||||
<el-form-item label="服务分类名称">
|
||||
<el-input
|
||||
v-model="formData.name"
|
||||
placeholder="请输入服务分类名称"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注">
|
||||
<el-input v-model="formData.remark" placeholder="请输入备注"></el-input>
|
||||
</el-form-item>
|
||||
<el-row>
|
||||
<el-form-item label="分类" style="width: 100%">
|
||||
<el-tree-select
|
||||
check-strictly
|
||||
:check-on-click-node="true"
|
||||
v-model="formData.parentId"
|
||||
:props="{ label: 'name', value: 'id' }"
|
||||
:data="categoryOptions"
|
||||
:render-after-expand="false"
|
||||
style="width: 240px" />
|
||||
</el-form-item>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, onMounted } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
import api from "@/lib/request";
|
||||
|
||||
// 表单数据
|
||||
const formData = defineModel({
|
||||
default: {
|
||||
name: "", // 服务项目名称
|
||||
remark: "", // 备注
|
||||
parentId: 0, // 分类ID
|
||||
},
|
||||
});
|
||||
|
||||
// 分类选项数据
|
||||
const categoryOptions = ref<{ id: number; name: string }[]>([]);
|
||||
|
||||
// 获取分类树并转换为下拉框选项
|
||||
const loadCategoryTree = async () => {
|
||||
try {
|
||||
const res = await api().get("/service-category/list");
|
||||
if (res.data.list.length) {
|
||||
categoryOptions.value = [{ id: 0, name: "无" }, ...res.data.list];
|
||||
} else {
|
||||
categoryOptions.value = [{ id: 0, name: "无" }];
|
||||
}
|
||||
} catch (err) {
|
||||
ElMessage.error("获取分类树失败");
|
||||
}
|
||||
};
|
||||
|
||||
// 页面加载时获取分类树
|
||||
onMounted(() => {
|
||||
loadCategoryTree();
|
||||
});
|
||||
</script>
|
||||
20
frontEnd/src/pages/serviceList/serviceCategory/page/view.vue
Normal file
@@ -0,0 +1,20 @@
|
||||
<template>
|
||||
<el-descriptions title="服务项目详情" border style="margin-bottom: 30px">
|
||||
<el-descriptions-item label="服务项目名称">{{
|
||||
data.name
|
||||
}}</el-descriptions-item>
|
||||
<el-descriptions-item label="数量">{{
|
||||
data.quantity
|
||||
}}</el-descriptions-item>
|
||||
<el-descriptions-item label="单位">{{ data.unit }}</el-descriptions-item>
|
||||
<el-descriptions-item label="售价">{{ data.price }}</el-descriptions-item>
|
||||
<el-descriptions-item label="备注">{{ data.remark }}</el-descriptions-item>
|
||||
<el-descriptions-item label="分类">{{
|
||||
data.category
|
||||
}}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
const data = defineModel<ServiceItemType>({ required: true });
|
||||
</script>
|
||||
@@ -0,0 +1,215 @@
|
||||
<template>
|
||||
<div>
|
||||
<baseTableHeader
|
||||
title="服务分类"
|
||||
@resetSearch="resetSearch"
|
||||
@search="search">
|
||||
<template #content>
|
||||
<el-form :model="searchForm" :inline="true" label-position="right">
|
||||
<el-form-item label="分类名称:">
|
||||
<el-input
|
||||
v-model="searchForm.name"
|
||||
placeholder="请输入分类名称"></el-input>
|
||||
</el-form-item>
|
||||
<!-- <el-form-item label="分类:">
|
||||
<el-input
|
||||
v-model="searchForm.category"
|
||||
placeholder="请输入分类"></el-input>
|
||||
</el-form-item> -->
|
||||
</el-form>
|
||||
</template>
|
||||
<template #operateBtns>
|
||||
<el-button type="primary" @click="add" size="small"
|
||||
><el-icon> <CirclePlus /> </el-icon>新增</el-button
|
||||
>
|
||||
</template>
|
||||
</baseTableHeader>
|
||||
<el-card style="margin-top: 8px">
|
||||
<base-table
|
||||
:option="tableOption"
|
||||
ref="table"
|
||||
style="width: 100%"
|
||||
:tree-props="{ children: 'children' }"
|
||||
row-key="id"
|
||||
:indent="30"
|
||||
:showPagination="false"
|
||||
@addConfim="addConfim"
|
||||
@editConfim="editConfim">
|
||||
<template #colunm>
|
||||
<el-table-column prop="name" label="服务分类名称" />
|
||||
<el-table-column prop="remark" label="备注" align="center" />
|
||||
<el-table-column
|
||||
#default="{ row }"
|
||||
label="操作"
|
||||
align="center"
|
||||
fixed="right"
|
||||
width="250">
|
||||
<!-- <el-button size="small" type="primary" @click="examine(row)"
|
||||
>查看</el-button
|
||||
> -->
|
||||
<el-button size="small" type="warning" @click="update(row)"
|
||||
>修改</el-button
|
||||
>
|
||||
<el-button size="small" type="danger" @click="deleteData(row)"
|
||||
>删除</el-button
|
||||
>
|
||||
</el-table-column>
|
||||
</template>
|
||||
</base-table>
|
||||
|
||||
<base-curd-dialog
|
||||
v-model="pageVisibleState.show2LevelPage.value"
|
||||
:title="pageVisibleState.dialogTitle.value"
|
||||
width="50%"
|
||||
:before-close="handleDialogClose"
|
||||
@addConfim="addConfim"
|
||||
@editConfim="editConfim"
|
||||
@closeConfirm="handleDialogClose"
|
||||
:showPageType="pageVisibleState.showPageType">
|
||||
<template #content>
|
||||
<addOrEdit
|
||||
:executeType="pageVisibleState.executeType.value"
|
||||
v-model="currentServiceItem"
|
||||
v-if="
|
||||
pageVisibleState.showPageType.edit ||
|
||||
pageVisibleState.showPageType.add
|
||||
"></addOrEdit>
|
||||
<serviceItemView
|
||||
v-if="pageVisibleState.showPageType.view"
|
||||
v-model="currentServiceItem"></serviceItemView>
|
||||
</template>
|
||||
</base-curd-dialog>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, onMounted, ref, watch } from "vue";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
import { resetParams } from "@/util/globalMethods";
|
||||
import addOrEdit from "./page/addOrEdit.vue";
|
||||
import serviceItemView from "./page/view.vue";
|
||||
import pageVisible from "@/components/curdDialog/pageVisibleState";
|
||||
|
||||
import api from "@/lib/request";
|
||||
import { tableOptionType } from "@/types/table";
|
||||
|
||||
const pageVisibleState = new pageVisible({
|
||||
add: "新增服务项目",
|
||||
edit: "服务项目编辑",
|
||||
view: "服务项目查看",
|
||||
});
|
||||
const searchForm = reactive({
|
||||
name: "",
|
||||
category: 0,
|
||||
});
|
||||
|
||||
let currentServiceItem = ref<ServiceItemType>({
|
||||
name: "",
|
||||
remark: "",
|
||||
parentId: 0,
|
||||
});
|
||||
|
||||
watch(
|
||||
() => pageVisibleState.show2LevelPage,
|
||||
(newVal) => {
|
||||
if (newVal.value === false) {
|
||||
resetServiceItem();
|
||||
}
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
}
|
||||
);
|
||||
|
||||
let table = ref();
|
||||
let tableOption = ref<tableOptionType>({
|
||||
url: "/service-category/list",
|
||||
searchUrl: "/service-category/query",
|
||||
searchParams: searchForm,
|
||||
executeType: "list",
|
||||
});
|
||||
|
||||
function add() {
|
||||
pageVisibleState.show2LevelPage.value = true;
|
||||
pageVisibleState.showPageType.add = true;
|
||||
}
|
||||
|
||||
function examine(row: ServiceItemType) {
|
||||
currentServiceItem.value = row;
|
||||
pageVisibleState.show2LevelPage.value = true;
|
||||
pageVisibleState.showPageType.view = true;
|
||||
}
|
||||
function update(row: ServiceItemType) {
|
||||
currentServiceItem.value = { ...row };
|
||||
pageVisibleState.show2LevelPage.value = true;
|
||||
pageVisibleState.showPageType.edit = true;
|
||||
}
|
||||
async function deleteData(row: ServiceItemType) {
|
||||
await ElMessageBox.confirm("确定要删除该服务分类吗?", {
|
||||
type: "error",
|
||||
});
|
||||
let respone = await api().get("/service-category/delete?id=" + row.id);
|
||||
if (respone.code === 200) {
|
||||
ElMessage.success("服务项目删除成功!");
|
||||
table.value.methods.setDataType("list");
|
||||
} else {
|
||||
ElMessage.error(respone.msg);
|
||||
}
|
||||
}
|
||||
function search() {
|
||||
table.value.methods.setDataType("search");
|
||||
}
|
||||
function resetSearch() {
|
||||
resetParams(searchForm);
|
||||
table.value.methods.setDataType("list");
|
||||
ElMessage.success("重置成功!");
|
||||
}
|
||||
|
||||
function handleDialogClose() {
|
||||
pageVisibleState.show2LevelPage.value = false;
|
||||
}
|
||||
async function addConfim() {
|
||||
await ElMessageBox.confirm("确定新增该分类吗?", "提示", {
|
||||
type: "warning",
|
||||
});
|
||||
let res = await api().post("/service-category/add", currentServiceItem.value);
|
||||
if (res.code === 200) {
|
||||
ElMessage.success("添加成功");
|
||||
pageVisibleState.show2LevelPage.value = false;
|
||||
table.value.methods.setDataType("list");
|
||||
} else {
|
||||
ElMessage.error(res.msg);
|
||||
}
|
||||
}
|
||||
|
||||
async function editConfim() {
|
||||
ElMessageBox.confirm("确认修改该条信息吗?", "提示", {
|
||||
type: "warning",
|
||||
}).then(async () => {
|
||||
let respone = await api().post(
|
||||
"/service-category/update",
|
||||
currentServiceItem.value
|
||||
);
|
||||
if (respone.code == 200) {
|
||||
ElMessage.success("修改成功!");
|
||||
pageVisibleState.show2LevelPage.value = false;
|
||||
table.value.methods.setDataType("list");
|
||||
} else {
|
||||
ElMessage.error(respone.msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function resetServiceItem() {
|
||||
currentServiceItem.value = {
|
||||
name: "",
|
||||
quantity: 0,
|
||||
category: 0,
|
||||
unit: "",
|
||||
price: 0,
|
||||
remark: "",
|
||||
};
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
||||
@@ -0,0 +1,57 @@
|
||||
<template>
|
||||
<el-form
|
||||
:model="formData"
|
||||
label-width="100px"
|
||||
inline
|
||||
style="padding-bottom: 20px">
|
||||
<el-form-item label="服务项目名称">
|
||||
<el-input
|
||||
v-model="formData.name"
|
||||
placeholder="请输入服务项目名称"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="单位">
|
||||
<el-input v-model="formData.unit" placeholder="请输入单位"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="售价">
|
||||
<el-input v-model="formData.price" placeholder="请输入售价"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="数量" v-if="props.type === '手工录入服务'">
|
||||
<el-input v-model="formData.quantity" placeholder="请输入数量"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注">
|
||||
<el-input v-model="formData.remark" placeholder="请输入备注"></el-input>
|
||||
</el-form-item>
|
||||
<el-row v-if="props.type !== '手工录入服务'">
|
||||
<el-form-item label="分类" style="width: 100%">
|
||||
<serviceSelect v-model="formData.parentId"></serviceSelect>
|
||||
</el-form-item>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, onMounted, watch } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
import api from "@/lib/request";
|
||||
|
||||
let props = defineProps<{
|
||||
type: "手工录入服务";
|
||||
}>();
|
||||
// 表单数据
|
||||
const formData = defineModel({
|
||||
default: {
|
||||
name: "", // 服务项目名称
|
||||
quantity: 1, // 数量
|
||||
unit: "", // 单位
|
||||
price: 0, // 售价
|
||||
remark: "", // 备注
|
||||
parentId: 0, // 分类ID
|
||||
},
|
||||
});
|
||||
|
||||
// 分类选项数据
|
||||
const categoryOptions = ref<{ id: number; name: string }[]>([]);
|
||||
|
||||
// 页面加载时获取分类树
|
||||
onMounted(() => {});
|
||||
</script>
|
||||
20
frontEnd/src/pages/serviceList/serviceItem/page/view.vue
Normal file
@@ -0,0 +1,20 @@
|
||||
<template>
|
||||
<el-descriptions title="服务项目详情" border style="margin-bottom: 30px">
|
||||
<el-descriptions-item label="服务项目名称">{{
|
||||
data.name
|
||||
}}</el-descriptions-item>
|
||||
<el-descriptions-item label="数量">{{
|
||||
data.quantity
|
||||
}}</el-descriptions-item>
|
||||
<el-descriptions-item label="单位">{{ data.unit }}</el-descriptions-item>
|
||||
<el-descriptions-item label="售价">{{ data.price }}</el-descriptions-item>
|
||||
<el-descriptions-item label="备注">{{ data.remark }}</el-descriptions-item>
|
||||
<el-descriptions-item label="分类">{{
|
||||
data.category
|
||||
}}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
const data = defineModel<ServiceItemType>({ required: true });
|
||||
</script>
|
||||
247
frontEnd/src/pages/serviceList/serviceItem/serviceItemList.vue
Normal file
@@ -0,0 +1,247 @@
|
||||
<template>
|
||||
<div>
|
||||
<baseTableHeader
|
||||
title="服务项目"
|
||||
@resetSearch="resetSearch"
|
||||
@search="search">
|
||||
<template #content>
|
||||
<el-form :model="searchForm" :inline="true" label-position="right">
|
||||
<el-form-item label="服务项目名称:">
|
||||
<el-input
|
||||
v-model="searchForm.name"
|
||||
placeholder="请输入服务项目名称"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="分类:">
|
||||
<serviceSelect v-model="searchForm.category"></serviceSelect>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
<template #operateBtns>
|
||||
<el-button type="primary" @click="add" size="small"
|
||||
><el-icon> <CirclePlus /> </el-icon>新增</el-button
|
||||
>
|
||||
</template>
|
||||
</baseTableHeader>
|
||||
<el-card style="margin-top: 8px">
|
||||
<base-table
|
||||
:option="tableOption"
|
||||
ref="table"
|
||||
style="width: 100%"
|
||||
border
|
||||
@addConfim="addConfim"
|
||||
@editConfim="editConfim">
|
||||
<template #colunm>
|
||||
<el-table-column
|
||||
type="index"
|
||||
label="序号"
|
||||
width="80"
|
||||
align="center"></el-table-column>
|
||||
<el-table-column prop="name" label="服务项目名称" align="center" />
|
||||
<!-- <el-table-column
|
||||
prop="quantity"
|
||||
label="数量"
|
||||
align="center"
|
||||
width="80" /> -->
|
||||
<el-table-column prop="unit" label="单位" align="center" width="80" />
|
||||
<el-table-column
|
||||
prop="price"
|
||||
label="售价"
|
||||
align="center"
|
||||
width="120" />
|
||||
<el-table-column prop="remark" label="备注" align="center" />
|
||||
<el-table-column prop="parentId" label="分类" align="center">
|
||||
<template #default="{ row }">
|
||||
{{
|
||||
serviceCaregoryOptions.find((item) => item.id === row.parentId)
|
||||
?.name
|
||||
}}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
#default="{ row }"
|
||||
label="操作"
|
||||
align="center"
|
||||
fixed="right"
|
||||
width="250">
|
||||
<el-button size="small" type="primary" @click="examine(row)"
|
||||
>查看</el-button
|
||||
>
|
||||
<el-button size="small" type="warning" @click="update(row)"
|
||||
>修改</el-button
|
||||
>
|
||||
<el-button size="small" type="danger" @click="deleteData(row)"
|
||||
>删除</el-button
|
||||
>
|
||||
</el-table-column>
|
||||
</template>
|
||||
</base-table>
|
||||
|
||||
<base-curd-dialog
|
||||
v-model="pageVisibleState.show2LevelPage.value"
|
||||
:title="pageVisibleState.dialogTitle.value"
|
||||
width="50%"
|
||||
:before-close="handleDialogClose"
|
||||
@addConfim="addConfim"
|
||||
@editConfim="editConfim"
|
||||
@closeConfirm="handleDialogClose"
|
||||
:showPageType="pageVisibleState.showPageType">
|
||||
<template #content>
|
||||
<addOrEdit
|
||||
:executeType="pageVisibleState.executeType.value"
|
||||
v-model="currentServiceItem"
|
||||
v-if="
|
||||
pageVisibleState.showPageType.edit ||
|
||||
pageVisibleState.showPageType.add
|
||||
"></addOrEdit>
|
||||
<serviceItemView
|
||||
v-if="pageVisibleState.showPageType.view"
|
||||
v-model="currentServiceItem"></serviceItemView>
|
||||
</template>
|
||||
</base-curd-dialog>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, onMounted, ref, watch } from "vue";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
import { resetParams } from "@/util/globalMethods";
|
||||
import addOrEdit from "./page/addOrEdit.vue";
|
||||
import serviceItemView from "./page/view.vue";
|
||||
import pageVisible from "@/components/curdDialog/pageVisibleState";
|
||||
import serviceSelect from "@/components/serviceSelect/serviceSelect.vue";
|
||||
|
||||
import api from "@/lib/request";
|
||||
import { tableOptionType } from "@/types/table";
|
||||
|
||||
const pageVisibleState = new pageVisible({
|
||||
add: "新增服务项目",
|
||||
edit: "服务项目编辑",
|
||||
view: "服务项目查看",
|
||||
});
|
||||
const searchForm = reactive({
|
||||
name: "",
|
||||
category: 0,
|
||||
});
|
||||
|
||||
let currentServiceItem = ref<ServiceItemType>({
|
||||
name: "",
|
||||
quantity: 0,
|
||||
category: 0,
|
||||
unit: "",
|
||||
price: 0,
|
||||
remark: "",
|
||||
});
|
||||
|
||||
const serviceCaregoryOptions = ref<{ id: number; name: string }[]>([]);
|
||||
|
||||
onMounted(async () => {
|
||||
const res = await api().get("/service-category/list");
|
||||
|
||||
serviceCaregoryOptions.value = [{ id: 0, name: "无" }, ...res.data.list];
|
||||
});
|
||||
|
||||
watch(
|
||||
() => pageVisibleState.show2LevelPage,
|
||||
(newVal) => {
|
||||
if (newVal.value === false) {
|
||||
resetServiceItem();
|
||||
}
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
}
|
||||
);
|
||||
|
||||
let table = ref();
|
||||
let tableOption = ref<tableOptionType>({
|
||||
url: "/service-item/list",
|
||||
searchUrl: "/service-item/query",
|
||||
searchParams: searchForm,
|
||||
executeType: "list",
|
||||
});
|
||||
|
||||
function add() {
|
||||
pageVisibleState.show2LevelPage.value = true;
|
||||
pageVisibleState.showPageType.add = true;
|
||||
}
|
||||
|
||||
function examine(row: ServiceItemType) {
|
||||
currentServiceItem.value = row;
|
||||
pageVisibleState.show2LevelPage.value = true;
|
||||
pageVisibleState.showPageType.view = true;
|
||||
}
|
||||
function update(row: ServiceItemType) {
|
||||
currentServiceItem.value = { ...row };
|
||||
|
||||
pageVisibleState.show2LevelPage.value = true;
|
||||
pageVisibleState.showPageType.edit = true;
|
||||
}
|
||||
async function deleteData(row: ServiceItemType) {
|
||||
await ElMessageBox.confirm("确定要删除该服务项目吗?", {
|
||||
type: "error",
|
||||
});
|
||||
let respone = await api().get("/service-item/delete?id=" + row.id);
|
||||
if (respone.code === 200) {
|
||||
ElMessage.success("服务项目删除成功!");
|
||||
table.value.methods.setDataType("list");
|
||||
} else {
|
||||
ElMessage.error(respone.msg);
|
||||
}
|
||||
}
|
||||
function search() {
|
||||
table.value.methods.setDataType("search");
|
||||
}
|
||||
function resetSearch() {
|
||||
resetParams(searchForm);
|
||||
table.value.methods.setDataType("list");
|
||||
ElMessage.success("重置成功!");
|
||||
}
|
||||
|
||||
function handleDialogClose() {
|
||||
pageVisibleState.show2LevelPage.value = false;
|
||||
}
|
||||
async function addConfim() {
|
||||
await ElMessageBox.confirm("确定新增该条信息吗?", "提示", {
|
||||
type: "warning",
|
||||
});
|
||||
let res = await api().post("/service-item/add", currentServiceItem.value);
|
||||
if (res.code === 200) {
|
||||
ElMessage.success("添加成功");
|
||||
pageVisibleState.show2LevelPage.value = false;
|
||||
table.value.methods.setDataType("list");
|
||||
} else {
|
||||
ElMessage.error(res.msg);
|
||||
}
|
||||
}
|
||||
|
||||
async function editConfim() {
|
||||
ElMessageBox.confirm("确认修改该条信息吗?", "提示", {
|
||||
type: "warning",
|
||||
}).then(async () => {
|
||||
let respone = await api().post(
|
||||
"/service-item/update",
|
||||
currentServiceItem.value
|
||||
);
|
||||
if (respone.code == 200) {
|
||||
ElMessage.success("修改成功!");
|
||||
pageVisibleState.show2LevelPage.value = false;
|
||||
table.value.methods.setDataType("list");
|
||||
} else {
|
||||
ElMessage.error(respone.msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function resetServiceItem() {
|
||||
currentServiceItem.value = {
|
||||
name: "",
|
||||
quantity: 0,
|
||||
category: 0,
|
||||
unit: "",
|
||||
price: 0,
|
||||
remark: "",
|
||||
};
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
||||
20
frontEnd/src/pages/serviceList/serviceList.vue
Normal file
@@ -0,0 +1,20 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-tabs type="border-card">
|
||||
<el-tab-pane>
|
||||
<template #label>服务项目</template>
|
||||
<serviceItemList></serviceItemList>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane>
|
||||
<template #label> 服务分类 </template>
|
||||
<serviceCategory> </serviceCategory>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import serviceItemList from "./serviceItem/serviceItemList.vue";
|
||||
import serviceCategory from "./serviceCategory/serviceCategory.vue";
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
||||
713
frontEnd/src/pages/statistics/dayIncome/dayIncome.vue
Normal file
@@ -0,0 +1,713 @@
|
||||
<template>
|
||||
<div style="background-color: #fff; padding: 15px">
|
||||
<baseTableHeader
|
||||
title="公司日收入统计"
|
||||
@resetSearch="reset"
|
||||
@search="query">
|
||||
<template #content>
|
||||
<el-form v-model="searchForm">
|
||||
<el-row :gutter="15">
|
||||
<el-col>
|
||||
<el-form-item label="购买日期">
|
||||
<el-date-picker
|
||||
v-model="searchForm.purchaseDate"
|
||||
type="datetimerange"
|
||||
range-separator="至"
|
||||
start-placeholder="选择日期"
|
||||
end-placeholder="选择日期"
|
||||
@change="dataChange" />
|
||||
</el-form-item>
|
||||
<!-- <div>
|
||||
<el-button
|
||||
type="primary"
|
||||
style="margin-left: 15px"
|
||||
@click="query"
|
||||
>查询</el-button
|
||||
><el-button
|
||||
type="warning"
|
||||
style="margin-left: 15px"
|
||||
@click="reset"
|
||||
>重置</el-button
|
||||
>
|
||||
<el-button v-print="print">打印单据</el-button>
|
||||
</div> -->
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</template>
|
||||
<template #operateBtns>
|
||||
<el-button v-print="print"
|
||||
><img
|
||||
src="/assets/icon/打印机.svg"
|
||||
style="margin-right: 5px"
|
||||
width="20"
|
||||
height="20" />打印单据</el-button
|
||||
>
|
||||
<el-button @click="exportFile"
|
||||
><img
|
||||
src="/assets/images/Excel.svg"
|
||||
alt=""
|
||||
width="20"
|
||||
height="20" />导出</el-button
|
||||
>
|
||||
</template>
|
||||
</baseTableHeader>
|
||||
|
||||
<div id="print-container">
|
||||
<h2
|
||||
style="
|
||||
color: #000;
|
||||
text-align: center;
|
||||
font-size: 20pt;
|
||||
padding: 15px;
|
||||
font-weight: bold;
|
||||
">
|
||||
殡仪服务公司日收入统计表
|
||||
</h2>
|
||||
<table
|
||||
id="print-table"
|
||||
class=""
|
||||
style="
|
||||
font-family: 仿宋;
|
||||
table-layout: fixed;
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td
|
||||
colspan="4"
|
||||
class="l"
|
||||
style="
|
||||
text-align: left;
|
||||
|
||||
font-weight: bold;
|
||||
font-size: 25px;
|
||||
font-family: 宋体;
|
||||
">
|
||||
<span>
|
||||
统计时间:{{
|
||||
dayjs(searchForm.startDate).format("YYYY-MM-DD HH:mm:ss")
|
||||
}}
|
||||
至
|
||||
{{ dayjs(searchForm.endDate).format("YYYY-MM-DD HH:mm:ss") }}
|
||||
</span>
|
||||
<!-- <span v-else>
|
||||
开始时间:{{ dayjs(searchForm.startDate).format("YYYY-MM-DD") }}
|
||||
</span> -->
|
||||
</td>
|
||||
<td
|
||||
colspan="2"
|
||||
class="l"
|
||||
style="
|
||||
text-align: left;
|
||||
|
||||
font-weight: bold;
|
||||
font-size: 25px;
|
||||
font-family: 宋体;
|
||||
">
|
||||
单位:元
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td
|
||||
style="
|
||||
height: 30px;
|
||||
|
||||
border: 1px solid black;
|
||||
text-align: center;
|
||||
">
|
||||
<b></b>
|
||||
</td>
|
||||
<td
|
||||
style="
|
||||
height: 30px;
|
||||
|
||||
border: 1px solid black;
|
||||
text-align: center;
|
||||
">
|
||||
<b>小计</b>
|
||||
</td>
|
||||
<td
|
||||
colspan="2"
|
||||
style="height: 30px; border: 1px solid black; text-align: center">
|
||||
<b>总计</b>
|
||||
</td>
|
||||
<td
|
||||
colspan="2"
|
||||
style="
|
||||
height: 30px;
|
||||
|
||||
border: 1px solid black;
|
||||
text-align: center;
|
||||
">
|
||||
<b>备注</b>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td
|
||||
style="
|
||||
height: 30px;
|
||||
|
||||
border: 1px solid black;
|
||||
text-align: center;
|
||||
">
|
||||
现金
|
||||
</td>
|
||||
<td
|
||||
style="
|
||||
height: 30px;
|
||||
|
||||
border: 1px solid black;
|
||||
text-align: center;
|
||||
">
|
||||
{{ statsData.service.cashAmount + statsData.retail.cashAmount }}
|
||||
</td>
|
||||
<td
|
||||
rowspan="6"
|
||||
colspan="2"
|
||||
style="
|
||||
height: 30px;
|
||||
|
||||
border: 1px solid black;
|
||||
text-align: center;
|
||||
">
|
||||
{{
|
||||
statsData.service.cashAmount +
|
||||
statsData.service.unionPayAmount +
|
||||
statsData.service.cardAmount +
|
||||
statsData.service.publicTransferAmount +
|
||||
statsData.service.workshopPayment +
|
||||
statsData.retail.cashAmount +
|
||||
statsData.retail.unionPayAmount +
|
||||
statsData.retail.cardAmount +
|
||||
statsData.retail.publicTransferAmount +
|
||||
statsData.retail.workshopPayment
|
||||
}}
|
||||
</td>
|
||||
|
||||
<td
|
||||
colspan="2"
|
||||
style="
|
||||
height: 30px;
|
||||
|
||||
border: 1px solid black;
|
||||
text-align: center;
|
||||
"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td
|
||||
style="
|
||||
height: 30px;
|
||||
|
||||
border: 1px solid black;
|
||||
text-align: center;
|
||||
">
|
||||
银联
|
||||
</td>
|
||||
<td
|
||||
style="
|
||||
height: 30px;
|
||||
|
||||
border: 1px solid black;
|
||||
text-align: center;
|
||||
">
|
||||
{{
|
||||
statsData.service.unionPayAmount +
|
||||
statsData.retail.unionPayAmount
|
||||
}}
|
||||
</td>
|
||||
|
||||
<td
|
||||
colspan="2"
|
||||
style="
|
||||
height: 30px;
|
||||
|
||||
border: 1px solid black;
|
||||
text-align: center;
|
||||
"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td
|
||||
style="
|
||||
height: 30px;
|
||||
|
||||
border: 1px solid black;
|
||||
text-align: center;
|
||||
">
|
||||
银行卡
|
||||
</td>
|
||||
<td
|
||||
style="
|
||||
height: 30px;
|
||||
|
||||
border: 1px solid black;
|
||||
text-align: center;
|
||||
">
|
||||
{{ statsData.service.cardAmount + statsData.retail.cardAmount }}
|
||||
</td>
|
||||
|
||||
<td
|
||||
colspan="2"
|
||||
style="
|
||||
height: 30px;
|
||||
|
||||
border: 1px solid black;
|
||||
text-align: center;
|
||||
"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td
|
||||
style="
|
||||
height: 30px;
|
||||
|
||||
border: 1px solid black;
|
||||
text-align: center;
|
||||
">
|
||||
车间支付
|
||||
</td>
|
||||
<td
|
||||
style="
|
||||
height: 30px;
|
||||
|
||||
border: 1px solid black;
|
||||
text-align: center;
|
||||
">
|
||||
{{
|
||||
statsData.service.workshopPayment +
|
||||
statsData.retail.workshopPayment
|
||||
}}
|
||||
</td>
|
||||
|
||||
<td
|
||||
colspan="2"
|
||||
style="
|
||||
height: 30px;
|
||||
|
||||
border: 1px solid black;
|
||||
text-align: center;
|
||||
"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td
|
||||
style="
|
||||
height: 30px;
|
||||
|
||||
border: 1px solid black;
|
||||
text-align: center;
|
||||
">
|
||||
对公转账
|
||||
</td>
|
||||
<td
|
||||
style="
|
||||
height: 30px;
|
||||
|
||||
border: 1px solid black;
|
||||
text-align: center;
|
||||
">
|
||||
{{
|
||||
statsData.service.publicTransferAmount +
|
||||
statsData.retail.publicTransferAmount
|
||||
}}
|
||||
</td>
|
||||
|
||||
<td
|
||||
colspan="2"
|
||||
style="
|
||||
height: 30px;
|
||||
|
||||
border: 1px solid black;
|
||||
text-align: center;
|
||||
"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td
|
||||
style="
|
||||
height: 30px;
|
||||
|
||||
border: 1px solid black;
|
||||
text-align: center;
|
||||
"></td>
|
||||
<td
|
||||
style="
|
||||
height: 30px;
|
||||
|
||||
border: 1px solid black;
|
||||
text-align: center;
|
||||
"></td>
|
||||
|
||||
<td
|
||||
colspan="2"
|
||||
style="
|
||||
height: 30px;
|
||||
|
||||
border: 1px solid black;
|
||||
text-align: center;
|
||||
"></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td
|
||||
style="
|
||||
height: 30px;
|
||||
|
||||
border: 1px solid black;
|
||||
text-align: center;
|
||||
">
|
||||
<b>现金合计</b>
|
||||
</td>
|
||||
<td
|
||||
style="
|
||||
height: 30px;
|
||||
|
||||
border: 1px solid black;
|
||||
text-align: center;
|
||||
">
|
||||
<b>微信合计</b>
|
||||
</td>
|
||||
<td
|
||||
colspan="2"
|
||||
style="
|
||||
height: 30px;
|
||||
|
||||
border: 1px solid black;
|
||||
text-align: center;
|
||||
">
|
||||
<b>银行卡合计</b>
|
||||
</td>
|
||||
<td
|
||||
style="
|
||||
height: 30px;
|
||||
|
||||
border: 1px solid black;
|
||||
text-align: center;
|
||||
">
|
||||
<b>车间支付合计</b>
|
||||
</td>
|
||||
<td
|
||||
style="
|
||||
height: 30px;
|
||||
|
||||
border: 1px solid black;
|
||||
text-align: center;
|
||||
">
|
||||
<b>对公转账合计</b>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td
|
||||
style="
|
||||
height: 30px;
|
||||
|
||||
border: 1px solid black;
|
||||
text-align: center;
|
||||
">
|
||||
{{ statsData.total.cashAmount }}
|
||||
</td>
|
||||
<td
|
||||
style="
|
||||
height: 30px;
|
||||
|
||||
border: 1px solid black;
|
||||
text-align: center;
|
||||
">
|
||||
{{ statsData.total.unionPayAmount }}
|
||||
</td>
|
||||
|
||||
<td
|
||||
colspan="2"
|
||||
style="
|
||||
height: 30px;
|
||||
|
||||
border: 1px solid black;
|
||||
text-align: center;
|
||||
">
|
||||
{{ statsData.total.cardAmount }}
|
||||
</td>
|
||||
<td
|
||||
style="
|
||||
height: 30px;
|
||||
|
||||
border: 1px solid black;
|
||||
text-align: center;
|
||||
">
|
||||
{{ statsData.total.workshopPayment }}
|
||||
</td>
|
||||
<td
|
||||
style="
|
||||
height: 30px;
|
||||
|
||||
border: 1px solid black;
|
||||
text-align: center;
|
||||
">
|
||||
{{ statsData.total.publicTransferAmount }}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td
|
||||
style="
|
||||
height: 30px;
|
||||
|
||||
border: 1px solid black;
|
||||
text-align: center;
|
||||
">
|
||||
<b>总合计:</b>
|
||||
</td>
|
||||
<td
|
||||
colspan="5"
|
||||
style="
|
||||
height: 30px;
|
||||
|
||||
border: 1px solid black;
|
||||
text-align: center;
|
||||
">
|
||||
{{
|
||||
statsData.total.cashAmount +
|
||||
statsData.total.unionPayAmount +
|
||||
statsData.total.cardAmount +
|
||||
statsData.total.workshopPayment +
|
||||
statsData.total.publicTransferAmount
|
||||
}}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { nextTick, ref } from "vue";
|
||||
import request from "@/lib/request";
|
||||
import dayjs from "dayjs";
|
||||
import ExcelJS from "exceljs";
|
||||
|
||||
export type PaymentStats = {
|
||||
cashAmount: number;
|
||||
unionPayAmount: number;
|
||||
cardAmount: number;
|
||||
publicTransferAmount: number;
|
||||
workshopPayment: number;
|
||||
};
|
||||
|
||||
// 完整响应类型
|
||||
export type StatsResponse = {
|
||||
retail: PaymentStats;
|
||||
service: PaymentStats;
|
||||
total: PaymentStats;
|
||||
};
|
||||
|
||||
let searchForm = ref({
|
||||
startDate: dayjs().startOf("day").toDate(),
|
||||
endDate: new Date(),
|
||||
purchaseDate: [dayjs().startOf("day").toDate(), new Date()],
|
||||
});
|
||||
|
||||
let statsData = ref<StatsResponse>({
|
||||
retail: {
|
||||
cashAmount: 0,
|
||||
unionPayAmount: 0,
|
||||
cardAmount: 0,
|
||||
publicTransferAmount: 0,
|
||||
workshopPayment: 0,
|
||||
},
|
||||
service: {
|
||||
cashAmount: 0,
|
||||
unionPayAmount: 0,
|
||||
cardAmount: 0,
|
||||
publicTransferAmount: 0,
|
||||
workshopPayment: 0,
|
||||
},
|
||||
total: {
|
||||
cashAmount: 0,
|
||||
unionPayAmount: 0,
|
||||
cardAmount: 0,
|
||||
publicTransferAmount: 0,
|
||||
workshopPayment: 0,
|
||||
},
|
||||
});
|
||||
let searched = ref(false);
|
||||
|
||||
request()
|
||||
.get("/stats/dayIncome", {
|
||||
params: {
|
||||
startDate: dayjs().startOf("day").toDate(),
|
||||
endDate: new Date(),
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
statsData.value = res.data;
|
||||
});
|
||||
|
||||
const print = {
|
||||
id: "print-container",
|
||||
};
|
||||
|
||||
function query() {
|
||||
searched.value = false;
|
||||
request()
|
||||
.get("/stats/dayIncome", {
|
||||
params: {
|
||||
startDate: dayjs(searchForm.value.startDate).format(
|
||||
"YYYY-MM-DD HH:mm:ss"
|
||||
),
|
||||
endDate: dayjs(searchForm.value.endDate).format("YYYY-MM-DD HH:mm:ss"),
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
statsData.value = res.data;
|
||||
});
|
||||
}
|
||||
|
||||
function reset() {
|
||||
searchForm.value = {
|
||||
startDate: dayjs().startOf("day").toDate(),
|
||||
endDate: new Date(),
|
||||
purchaseDate: [dayjs().startOf("day").toDate(), new Date()],
|
||||
};
|
||||
query();
|
||||
}
|
||||
|
||||
function dataChange(val: Date[]) {
|
||||
searchForm.value.startDate = val[0];
|
||||
searchForm.value.endDate = val[1];
|
||||
}
|
||||
|
||||
async function exportFile() {
|
||||
try {
|
||||
// 获取模板文件
|
||||
const response = await fetch("/excelTemple/日收入统计.xlsx");
|
||||
const buffer = await response.arrayBuffer();
|
||||
|
||||
const workbook = new ExcelJS.Workbook();
|
||||
await workbook.xlsx.load(buffer);
|
||||
const sheet = workbook.getWorksheet(1); // 默认第一个工作表
|
||||
|
||||
const startDate = dayjs(searchForm.value.startDate).format(
|
||||
"YYYY-MM-DD HH:mm:ss"
|
||||
);
|
||||
const endDate = dayjs(searchForm.value.endDate).format(
|
||||
"YYYY-MM-DD HH:mm:ss"
|
||||
);
|
||||
|
||||
// 工具函数:填充值并保留样式
|
||||
const setCellValueWithStyle = (cellAddress, value) => {
|
||||
const cell = sheet.getCell(cellAddress);
|
||||
const style = { ...cell.style };
|
||||
cell.value = value;
|
||||
cell.style = style;
|
||||
};
|
||||
|
||||
// 填充各项内容(保持样式)
|
||||
setCellValueWithStyle("C2", `${startDate} 至 ${endDate}`);
|
||||
|
||||
setCellValueWithStyle("B4", statsData.value.total.cashAmount);
|
||||
|
||||
setCellValueWithStyle("B5", statsData.value.total.unionPayAmount);
|
||||
setCellValueWithStyle("B6", statsData.value.total.cardAmount);
|
||||
setCellValueWithStyle("B7", statsData.value.total.workshopPayment);
|
||||
setCellValueWithStyle("B8", statsData.value.total.publicTransferAmount);
|
||||
|
||||
const total =
|
||||
statsData.value.service.cashAmount +
|
||||
statsData.value.service.unionPayAmount +
|
||||
statsData.value.service.cardAmount +
|
||||
statsData.value.service.publicTransferAmount +
|
||||
statsData.value.service.workshopPayment +
|
||||
statsData.value.retail.cashAmount +
|
||||
statsData.value.retail.unionPayAmount +
|
||||
statsData.value.retail.cardAmount +
|
||||
statsData.value.retail.publicTransferAmount +
|
||||
statsData.value.retail.workshopPayment;
|
||||
setCellValueWithStyle("C4", total);
|
||||
|
||||
setCellValueWithStyle("A11", statsData.value.total.cashAmount);
|
||||
setCellValueWithStyle("B11", statsData.value.total.unionPayAmount);
|
||||
setCellValueWithStyle("C11", statsData.value.total.cardAmount);
|
||||
setCellValueWithStyle("D11", statsData.value.total.workshopPayment);
|
||||
setCellValueWithStyle("E11", statsData.value.total.publicTransferAmount);
|
||||
|
||||
const grandTotal =
|
||||
statsData.value.total.cashAmount +
|
||||
statsData.value.total.unionPayAmount +
|
||||
statsData.value.total.cardAmount +
|
||||
statsData.value.total.workshopPayment +
|
||||
statsData.value.total.publicTransferAmount;
|
||||
setCellValueWithStyle("B12", grandTotal);
|
||||
|
||||
// 导出文件
|
||||
const newBuffer = await workbook.xlsx.writeBuffer();
|
||||
const blob = new Blob([newBuffer], {
|
||||
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||
});
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement("a");
|
||||
a.href = url;
|
||||
a.download = "日收入统计.xlsx";
|
||||
a.click();
|
||||
URL.revokeObjectURL(url);
|
||||
} catch (error) {
|
||||
console.error("导出 Excel 文件时出错:", error);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
tr,
|
||||
td {
|
||||
font-size: 14px !important;
|
||||
}
|
||||
|
||||
#print-container {
|
||||
width: 100% !important;
|
||||
margin: 0 !important;
|
||||
padding: 0 5mm !important;
|
||||
font-size: 14pt;
|
||||
color: #000 !important;
|
||||
font-family: Microsoft YaHei, "SimSun", serif !important;
|
||||
|
||||
/* 添加表格布局优化 */
|
||||
table {
|
||||
width: 100% !important;
|
||||
table-layout: fixed;
|
||||
border-collapse: collapse !important;
|
||||
|
||||
td,
|
||||
th {
|
||||
padding: 5px 2mm !important;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media print {
|
||||
/* 重置body和html的布局方式 */
|
||||
body,
|
||||
html {
|
||||
display: block !important;
|
||||
height: auto !important;
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
@page {
|
||||
margin: 15pt;
|
||||
}
|
||||
|
||||
#print-container {
|
||||
min-height: 297mm; /* A4纸高度 */
|
||||
width: 100% !important;
|
||||
vertical-align: top !important;
|
||||
position: relative;
|
||||
top: 0;
|
||||
transform: none !important;
|
||||
}
|
||||
|
||||
/* 隐藏不需要打印的元素 */
|
||||
.el-form,
|
||||
.el-button {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,6 @@
|
||||
<template>
|
||||
<div>引导员销售统计</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup></script>
|
||||
<style lang="scss" scoped></style>
|
||||
452
frontEnd/src/pages/statistics/saleDetail/saleDetail.vue
Normal file
@@ -0,0 +1,452 @@
|
||||
<template>
|
||||
<div style="background-color: #fff; padding: 15px">
|
||||
<baseTableHeader title="公司销售明细" @resetSearch="reset" @search="query">
|
||||
<template #content>
|
||||
<el-form v-model="searchForm" label-width="100">
|
||||
<el-row :gutter="25">
|
||||
<el-col :span="10">
|
||||
<el-form-item label="统计日期">
|
||||
<el-date-picker
|
||||
v-model="searchForm.dateRange"
|
||||
type="datetimerange"
|
||||
range-separator="至"
|
||||
start-placeholder="选择开始日期"
|
||||
end-placeholder="选择结束日期"
|
||||
value-format="YYYY-MM-DD HH:mm:ss"
|
||||
@change="dateChange" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="逝者姓名">
|
||||
<el-input
|
||||
v-model="searchForm.deceasedName"
|
||||
placeholder="输入逝者名称" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="购买人">
|
||||
<el-input
|
||||
v-model="searchForm.familyName"
|
||||
placeholder="输入购买人" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="服务名称">
|
||||
<el-input
|
||||
v-model="searchForm.serviceName"
|
||||
placeholder="输入服务名称" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6" label="引导员">
|
||||
<el-form-item label="引导员">
|
||||
<guideList v-model="searchForm.guide"></guideList>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</template>
|
||||
<template #operateBtns>
|
||||
<el-button @click="exportSalesDetailsExcel('当前')"
|
||||
><img
|
||||
src="/assets/images/Excel.svg"
|
||||
alt=""
|
||||
width="20"
|
||||
height="20" />导出当前</el-button
|
||||
>
|
||||
<el-button @click="exportSalesDetailsExcel('所有')"
|
||||
><img
|
||||
src="/assets/images/Excel.svg"
|
||||
alt=""
|
||||
width="20"
|
||||
height="20" />导出所有</el-button
|
||||
>
|
||||
</template>
|
||||
</baseTableHeader>
|
||||
<el-card style="margin-top: 8px">
|
||||
<base-table
|
||||
:option="tableOption"
|
||||
ref="table"
|
||||
border
|
||||
show-summary
|
||||
:summary-method="getSummaries">
|
||||
<template #colunm>
|
||||
<el-table-column
|
||||
type="index"
|
||||
width="80"
|
||||
fixed="left"
|
||||
label="序号"
|
||||
align="center"></el-table-column>
|
||||
<el-table-column
|
||||
width="120"
|
||||
fixed="left"
|
||||
prop="deceasedRetail.checkoutDate"
|
||||
label="结账日期"
|
||||
align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.deceasedRetail.checkoutDate.split(" ")[0] }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="deceased.name"
|
||||
label="逝者姓名"
|
||||
width="120"
|
||||
fixed="left"
|
||||
align="center">
|
||||
<template #default="{ row }">
|
||||
<span>{{
|
||||
row.deceased.name ||
|
||||
row.deceased.familyName ||
|
||||
row.deceasedRetail.deceasedName
|
||||
}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="deceasedRetail.guide"
|
||||
label="引导员"
|
||||
fixed="left"
|
||||
align="center" />
|
||||
<el-table-column prop="deceased.gender" label="性别" align="center" />
|
||||
<el-table-column prop="deceased.age" label="年龄" align="center" />
|
||||
<el-table-column
|
||||
prop="deceased.idNumber"
|
||||
label="身份证"
|
||||
align="center"
|
||||
width="180" />
|
||||
<el-table-column label="地址" align="center" width="280">
|
||||
<template #default="{ row }">
|
||||
<div style="text-align: left">
|
||||
<span
|
||||
v-if="row.deceased.province || row.deceasedRetail.province"
|
||||
>{{
|
||||
row.deceased.province || row.deceasedRetail.province
|
||||
}}/</span
|
||||
>
|
||||
<span v-if="row.deceased.city || row.deceasedRetail.city"
|
||||
>{{ row.deceased.city || row.deceasedRetail.city }}/</span
|
||||
>
|
||||
<span
|
||||
v-if="row.deceased.address || row.deceasedRetail.address"
|
||||
>{{
|
||||
row.deceased.address || row.deceasedRetail.address
|
||||
}}</span
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="deceased.name"
|
||||
label="购买人姓名"
|
||||
align="center"
|
||||
width="120">
|
||||
<template #default="{ row }">
|
||||
<span>{{
|
||||
row.deceased.familyName || row.deceasedRetail.deceasedName
|
||||
}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="deceased.familyPhone"
|
||||
label="购买人电话"
|
||||
align="center"
|
||||
width="150" />
|
||||
<el-table-column
|
||||
prop="name"
|
||||
label="项目名称"
|
||||
align="center"
|
||||
width="150" />
|
||||
<el-table-column
|
||||
prop="price"
|
||||
label="单价"
|
||||
align="center"
|
||||
width="150" />
|
||||
<el-table-column
|
||||
prop="quantity"
|
||||
label="数量"
|
||||
align="center"
|
||||
width="150" />
|
||||
<el-table-column prop="sum" label="金额" align="center" width="150">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
prop="remark"
|
||||
label="备注"
|
||||
width="280"
|
||||
align="center" />
|
||||
</template>
|
||||
</base-table>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import request from "@/lib/request";
|
||||
import { tableOptionType } from "@/types/table";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { nextTick, onMounted, ref } from "vue";
|
||||
import ExcelJS from "exceljs";
|
||||
|
||||
const categories = ref<Array<{ id: number; name: string }>>([]);
|
||||
let searchForm = ref({
|
||||
dateRange: [],
|
||||
serviceName: "",
|
||||
categoryName: "",
|
||||
categories: "",
|
||||
startDate: "",
|
||||
endDate: "",
|
||||
deceasedName: "",
|
||||
guide: "",
|
||||
familyName: "",
|
||||
});
|
||||
|
||||
let tableOption = ref<tableOptionType>({
|
||||
url: "/stats/salesDetails",
|
||||
searchUrl: "/stats/salesDetails",
|
||||
searchParams: searchForm,
|
||||
executeType: "list",
|
||||
});
|
||||
let table = ref();
|
||||
const fetchCategories = async () => {
|
||||
try {
|
||||
const res = await request().get("/public/service-categories");
|
||||
categories.value = res.data.map((item: any) => ({
|
||||
id: item.value,
|
||||
name: item.label,
|
||||
}));
|
||||
} catch (error) {
|
||||
ElMessage.error("分类加载失败");
|
||||
}
|
||||
};
|
||||
const getSummaries = (param: { columns: any[]; data: any[] }) => {
|
||||
const { columns, data } = param;
|
||||
const sums: any[] = [];
|
||||
// 需要统计的字段列表
|
||||
const sumKeys = ["price", "quantity", "sum"];
|
||||
columns.forEach((column, index) => {
|
||||
if (index === 0) {
|
||||
sums[index] = "合计";
|
||||
return;
|
||||
}
|
||||
if (sumKeys.includes(column.property)) {
|
||||
const values = data.map((item) => {
|
||||
const keys = column.property.split(".");
|
||||
let value = item;
|
||||
for (const key of keys) {
|
||||
value = value?.[key] || 0;
|
||||
}
|
||||
return Number(value) || 0;
|
||||
});
|
||||
|
||||
if (!values.every((value) => isNaN(value))) {
|
||||
const sum = values.reduce((prev, curr) => {
|
||||
return prev + curr;
|
||||
}, 0);
|
||||
sums[index] = `${sum.toFixed(2)}`;
|
||||
} else {
|
||||
sums[index] = "0.00 元";
|
||||
}
|
||||
} else {
|
||||
sums[index] = "";
|
||||
}
|
||||
});
|
||||
|
||||
return sums;
|
||||
};
|
||||
|
||||
const dateChange = (val: string[]) => {
|
||||
if (val?.length === 2) {
|
||||
searchForm.value.dateRange = val;
|
||||
searchForm.value.startDate = val[0];
|
||||
searchForm.value.endDate = val[1];
|
||||
}
|
||||
};
|
||||
|
||||
function reset() {
|
||||
searchForm.value = {
|
||||
dateRange: [],
|
||||
serviceName: "",
|
||||
categoryName: "",
|
||||
categories: "",
|
||||
startDate: "",
|
||||
endDate: "",
|
||||
deceasedName: "",
|
||||
familyName: "",
|
||||
};
|
||||
table.value.methods.setDataType("reset");
|
||||
}
|
||||
|
||||
function query() {
|
||||
table.value.methods.setDataType("search");
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
fetchCategories();
|
||||
});
|
||||
|
||||
async function exportSalesDetailsExcel(type: "当前" | "所有") {
|
||||
try {
|
||||
let list = [];
|
||||
|
||||
if (type === "当前") {
|
||||
list = table.value.tableData.data;
|
||||
} else {
|
||||
// 1. 获取所有数据
|
||||
const res = await request().post("/stats/salesDetails", {
|
||||
pageSize: 999999999,
|
||||
pageNumber: 1,
|
||||
dateRange: [],
|
||||
serviceName: "",
|
||||
categoryName: "",
|
||||
categories: "",
|
||||
startDate: "",
|
||||
endDate: "",
|
||||
deceasedName: "",
|
||||
guide: "",
|
||||
familyName: "",
|
||||
});
|
||||
list = res.data?.list;
|
||||
}
|
||||
|
||||
// 2. 获取模板文件
|
||||
const templateRes = await fetch("/excelTemple/销售明细.xlsx");
|
||||
const buffer = await templateRes.arrayBuffer();
|
||||
|
||||
// 3. 加载 Excel 模板
|
||||
const workbook = new ExcelJS.Workbook();
|
||||
await workbook.xlsx.load(buffer);
|
||||
const sheet = workbook.getWorksheet(1); // 默认取第一个 sheet
|
||||
|
||||
// 4. 从第 3 行开始填充数据
|
||||
list.forEach((item, index) => {
|
||||
const row = sheet.getRow(index + 2); // 第3行开始
|
||||
const deceased = item.deceased || {};
|
||||
const retail = item.deceasedRetail || {};
|
||||
|
||||
row.getCell(1).value = index + 1;
|
||||
row.getCell(2).value = retail.checkoutDate || "";
|
||||
row.getCell(3).value = deceased.name || "";
|
||||
row.getCell(4).value = retail.guide || "";
|
||||
row.getCell(5).value = deceased.gender || "";
|
||||
row.getCell(6).value = deceased.age || "";
|
||||
row.getCell(7).value = deceased.idNumber || "";
|
||||
row.getCell(8).value = deceased.address || "";
|
||||
row.getCell(9).value = deceased.familyName || "";
|
||||
row.getCell(10).value = deceased.familyPhone || "";
|
||||
row.getCell(11).value = item.name || "";
|
||||
row.getCell(12).value = item.price || "";
|
||||
row.getCell(13).value = item.quantity || "";
|
||||
row.getCell(14).value = item.sum || "";
|
||||
row.getCell(15).value = item.remark || "";
|
||||
row.eachCell((cell) => {
|
||||
cell.alignment = { vertical: "middle", horizontal: "center" };
|
||||
});
|
||||
row.commit(); // 应用修改
|
||||
});
|
||||
|
||||
// 5. 导出为 blob
|
||||
const blob = await workbook.xlsx.writeBuffer();
|
||||
const file = new Blob([blob], {
|
||||
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||
});
|
||||
|
||||
// 6. 触发下载
|
||||
const url = URL.createObjectURL(file);
|
||||
const a = document.createElement("a");
|
||||
a.href = url;
|
||||
a.download = "销售明细.xlsx";
|
||||
a.click();
|
||||
URL.revokeObjectURL(url);
|
||||
} catch (error) {
|
||||
console.error("导出销售明细失败:", error);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.loading-mask {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
.is-loading {
|
||||
animation: rotating 2s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes rotating {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
th,
|
||||
td {
|
||||
border: 1px solid #000;
|
||||
padding: 8px;
|
||||
font-size: 14px;
|
||||
text-align: center !important;
|
||||
}
|
||||
@media print {
|
||||
/* 移除全局布局影响 */
|
||||
body,
|
||||
html {
|
||||
display: block !important;
|
||||
height: auto !important;
|
||||
margin: 2mm !important; /* 添加安全边距 */
|
||||
}
|
||||
|
||||
#print-container {
|
||||
width: auto !important; /* 改为自动宽度 */
|
||||
margin: 0 auto !important; /* 居中显示 */
|
||||
font-size: 12pt !important; /* 调整字号 */
|
||||
min-height: 297mm;
|
||||
}
|
||||
|
||||
table {
|
||||
table-layout: fixed;
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
/* 优化单元格内边距 */
|
||||
td,
|
||||
th {
|
||||
padding: 4px 2mm !important;
|
||||
line-height: 1.4 !important;
|
||||
}
|
||||
}
|
||||
|
||||
tr,
|
||||
td {
|
||||
font-size: 14px !important;
|
||||
}
|
||||
|
||||
#print-container {
|
||||
width: 100% !important;
|
||||
margin: 0 !important;
|
||||
padding: 0 5mm !important;
|
||||
font-size: 14pt;
|
||||
color: #000 !important;
|
||||
font-family: Microsoft YaHei, "SimSun", serif !important;
|
||||
}
|
||||
/* 添加表格布局优化 */
|
||||
table {
|
||||
width: 100% !important;
|
||||
table-layout: fixed;
|
||||
border-collapse: collapse !important;
|
||||
|
||||
td,
|
||||
th {
|
||||
padding: 10px 2mm !important;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
498
frontEnd/src/pages/statistics/sales/sales.vue
Normal file
@@ -0,0 +1,498 @@
|
||||
<template>
|
||||
<div style="background-color: #fff; padding: 15px">
|
||||
<baseTableHeader title="销售统计报表" @resetSearch="reset" @search="query">
|
||||
<template #content>
|
||||
<el-form v-model="searchForm">
|
||||
<el-row :gutter="25">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="统计日期">
|
||||
<el-date-picker
|
||||
v-model="searchForm.dateRange"
|
||||
type="datetimerange"
|
||||
range-separator="至"
|
||||
start-placeholder="选择开始日期"
|
||||
end-placeholder="选择结束日期"
|
||||
value-format="YYYY-MM-DD HH:mm:ss"
|
||||
@change="dateChange" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="服务名称">
|
||||
<el-input
|
||||
v-model="searchForm.serviceName"
|
||||
placeholder="输入服务名称" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="项目分类">
|
||||
<el-select
|
||||
v-model="searchForm.categoryName"
|
||||
placeholder="选择分类"
|
||||
clearable>
|
||||
<el-option
|
||||
v-for="category in categories"
|
||||
:key="category.id"
|
||||
:label="category.name"
|
||||
:value="category.name" />
|
||||
<el-option label="其他服务" value="其他服务" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<!-- <div>
|
||||
<el-button
|
||||
type="primary"
|
||||
style="margin-left: 15px"
|
||||
@click="query"
|
||||
:loading="loading">
|
||||
查询
|
||||
</el-button>
|
||||
<el-button type="warning" @click="reset">重置</el-button>
|
||||
</div> -->
|
||||
</el-row>
|
||||
</el-form>
|
||||
</template>
|
||||
<template #operateBtns>
|
||||
<el-button size="small" v-print="print"
|
||||
><img
|
||||
src="/assets/icon/打印机.svg"
|
||||
style="margin-right: 5px"
|
||||
width="20"
|
||||
height="20" />打印单据</el-button
|
||||
>
|
||||
<el-button @click="exportTableToExcel"
|
||||
><img
|
||||
src="/assets/images/Excel.svg"
|
||||
alt=""
|
||||
width="20"
|
||||
height="20" />导出</el-button
|
||||
>
|
||||
</template>
|
||||
</baseTableHeader>
|
||||
|
||||
<!-- 加载状态 -->
|
||||
<div v-if="loading" class="loading-mask">
|
||||
<el-icon class="is-loading" color="#409EFC" :size="30">
|
||||
<Loading />
|
||||
</el-icon>
|
||||
<span style="margin-left: 10px">数据加载中...</span>
|
||||
</div>
|
||||
<div id="print-container">
|
||||
<h2
|
||||
style="
|
||||
color: #000;
|
||||
text-align: center;
|
||||
font-size: 20pt;
|
||||
padding: 15px;
|
||||
font-weight: bold;
|
||||
">
|
||||
销售统计报表
|
||||
</h2>
|
||||
<table
|
||||
v-show="!loading"
|
||||
style="
|
||||
table-layout: fixed;
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-family: 宋体;
|
||||
">
|
||||
<!-- 表头 -->
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="border: 1px solid #000; padding: 8px">序号</th>
|
||||
<th style="border: 1px solid #000; padding: 8px">服务项目</th>
|
||||
<th style="border: 1px solid #000; padding: 8px">单价(元)</th>
|
||||
<th style="border: 1px solid #000; padding: 8px">数量</th>
|
||||
<th style="border: 1px solid #000; padding: 8px">小计(元)</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<!-- 新增空状态 -->
|
||||
<tr v-if="showEmpty">
|
||||
<td
|
||||
colspan="4"
|
||||
style="text-align: center; color: #999; padding: 20px">
|
||||
未查询到相关数据
|
||||
</td>
|
||||
</tr>
|
||||
<!-- 分类数据 -->
|
||||
<template
|
||||
v-for="category in statsData.categories"
|
||||
:key="category.categoryName">
|
||||
<tr>
|
||||
<td
|
||||
colspan="5"
|
||||
style="font-weight: bold; padding: 8px; text-align: center">
|
||||
{{ category.categoryName }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr
|
||||
v-for="(service, index) in category.services"
|
||||
:key="service.serviceName">
|
||||
<td style="padding: 8px">{{ index + 1 }}</td>
|
||||
<td style="border: 1px solid #000; padding: 8px">
|
||||
{{ service.serviceName }}
|
||||
</td>
|
||||
<td
|
||||
style="border: 1px solid #000; text-align: right; padding: 8px">
|
||||
{{ service.price.toFixed(2) }}
|
||||
</td>
|
||||
<td
|
||||
style="border: 1px solid #000; text-align: right; padding: 8px">
|
||||
{{ service.quantity }}
|
||||
</td>
|
||||
<td
|
||||
style="border: 1px solid #000; text-align: right; padding: 8px">
|
||||
{{ service.subtotal.toFixed(2) }}
|
||||
</td>
|
||||
</tr>
|
||||
<!-- <tr style="font-weight: bold">
|
||||
<td colspan="2" style="border: 1px solid #000; padding: 8px">
|
||||
分类合计
|
||||
</td>
|
||||
<td
|
||||
style="border: 1px solid #000; text-align: right; padding: 8px">
|
||||
{{ category.totalQuantity }}
|
||||
</td>
|
||||
<td
|
||||
style="border: 1px solid #000; text-align: right; padding: 8px">
|
||||
{{ category.totalAmount.toFixed(2) }}
|
||||
</td>
|
||||
</tr> -->
|
||||
</template>
|
||||
|
||||
<!-- 其他服务 -->
|
||||
<tr v-if="statsData.otherCategory.services.length">
|
||||
<td colspan="5" style="font-weight: bold; padding: 8px">
|
||||
{{ statsData.otherCategory.categoryName }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr
|
||||
v-if="statsData.otherCategory.services.length"
|
||||
v-for="(service, index) in statsData.otherCategory.services"
|
||||
:key="'other-' + service.serviceName">
|
||||
<td style="padding: 8px">{{ index + 1 }}</td>
|
||||
<td style="border: 1px solid #000; padding: 8px">
|
||||
{{ service.serviceName }}
|
||||
</td>
|
||||
<td style="border: 1px solid #000; text-align: right; padding: 8px">
|
||||
{{ service.price.toFixed(2) }}
|
||||
</td>
|
||||
<td style="border: 1px solid #000; text-align: right; padding: 8px">
|
||||
{{ service.quantity }}
|
||||
</td>
|
||||
<td style="border: 1px solid #000; text-align: right; padding: 8px">
|
||||
{{ service.subtotal.toFixed(2) }}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- 总计行 -->
|
||||
<tr>
|
||||
<td
|
||||
colspan="3"
|
||||
style="
|
||||
border: 1px solid #000;
|
||||
padding: 8px;
|
||||
font-weight: bold;
|
||||
font-size: 20px;
|
||||
">
|
||||
数量和金额总计
|
||||
</td>
|
||||
<td
|
||||
style="
|
||||
border: 1px solid #000;
|
||||
text-align: right;
|
||||
padding: 8px;
|
||||
font-weight: bold;
|
||||
font-size: 20px;
|
||||
">
|
||||
{{ statsData.grandTotalQuantity }}
|
||||
</td>
|
||||
<td
|
||||
style="
|
||||
border: 1px solid #000;
|
||||
text-align: right;
|
||||
padding: 8px;
|
||||
font-weight: bold;
|
||||
font-size: 20px;
|
||||
">
|
||||
{{ statsData.grandTotalAmount.toFixed(2) }} 元
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, onMounted } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { Loading } from "@element-plus/icons-vue";
|
||||
import request from "@/lib/request";
|
||||
import dayjs from "dayjs";
|
||||
import * as XLSX from "xlsx";
|
||||
|
||||
interface ServiceStatsItem {
|
||||
serviceName: string;
|
||||
price: number;
|
||||
unit: string;
|
||||
quantity: number;
|
||||
subtotal: number;
|
||||
}
|
||||
|
||||
interface CategoryStats {
|
||||
categoryName: string;
|
||||
services: ServiceStatsItem[];
|
||||
totalQuantity: number;
|
||||
totalAmount: number;
|
||||
}
|
||||
|
||||
interface StatsResponse {
|
||||
categories: CategoryStats[];
|
||||
otherCategory: CategoryStats;
|
||||
grandTotalQuantity: number;
|
||||
grandTotalAmount: number;
|
||||
}
|
||||
const print = {
|
||||
id: "print-container",
|
||||
};
|
||||
// 保持原有响应式数据结构
|
||||
const loading = ref(false);
|
||||
const searchForm = ref({
|
||||
dateRange: [
|
||||
dayjs().startOf("day").format("YYYY-MM-DD 00:00:00"),
|
||||
dayjs(new Date()).format("YYYY-MM-DD HH:mm:ss"),
|
||||
] as string[],
|
||||
serviceName: "",
|
||||
categoryName: "",
|
||||
});
|
||||
|
||||
const statsData = ref<StatsResponse>({
|
||||
categories: [],
|
||||
otherCategory: {
|
||||
categoryName: "其他服务",
|
||||
services: [],
|
||||
totalQuantity: 0,
|
||||
totalAmount: 0,
|
||||
},
|
||||
grandTotalQuantity: 0,
|
||||
grandTotalAmount: 0,
|
||||
});
|
||||
|
||||
const categories = ref<Array<{ id: number; name: string }>>([]);
|
||||
const showEmpty = computed(
|
||||
() =>
|
||||
statsData.value?.categories?.length === 0 &&
|
||||
statsData.value.otherCategory.services.length === 0
|
||||
);
|
||||
|
||||
onMounted(async () => {
|
||||
try {
|
||||
await fetchCategories();
|
||||
await query();
|
||||
} catch (error) {
|
||||
handleError(error);
|
||||
}
|
||||
});
|
||||
|
||||
const fetchCategories = async () => {
|
||||
try {
|
||||
const res = await request().get("/public/service-categories");
|
||||
categories.value = res.data.map((item: any) => ({
|
||||
id: item.value,
|
||||
name: item.label,
|
||||
}));
|
||||
} catch (error) {
|
||||
ElMessage.error("分类加载失败");
|
||||
}
|
||||
};
|
||||
|
||||
const query = async () => {
|
||||
try {
|
||||
loading.value = true;
|
||||
|
||||
const params = {
|
||||
startDate: searchForm.value.dateRange[0],
|
||||
endDate: searchForm.value.dateRange[1],
|
||||
serviceName: searchForm.value.serviceName,
|
||||
categoryName: searchForm.value.categoryName,
|
||||
};
|
||||
|
||||
const res = await request().get("/stats/servicesStats", { params });
|
||||
statsData.value = res.data || res;
|
||||
} catch (error) {
|
||||
ElMessage.error(`查询失败: ${(error as Error).message}`);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const reset = () => {
|
||||
searchForm.value = {
|
||||
dateRange: [
|
||||
dayjs().startOf("day").format("YYYY-MM-DD 00:00:00"),
|
||||
dayjs().format("YYYY-MM-DD 23:59:59"),
|
||||
],
|
||||
serviceName: "",
|
||||
categoryName: "",
|
||||
};
|
||||
query();
|
||||
};
|
||||
|
||||
const dateChange = (val: string[]) => {
|
||||
if (val?.length === 2) {
|
||||
searchForm.value.dateRange = val;
|
||||
}
|
||||
};
|
||||
|
||||
const handleError = (error: unknown) => {
|
||||
ElMessage({
|
||||
type: "error",
|
||||
message: "系统异常,请稍后重试",
|
||||
duration: 3000,
|
||||
});
|
||||
};
|
||||
|
||||
function exportTableToExcel() {
|
||||
const table = document.querySelector(
|
||||
"#print-container table"
|
||||
) as HTMLTableElement;
|
||||
if (!table) {
|
||||
console.error("找不到表格");
|
||||
return;
|
||||
}
|
||||
|
||||
// 将 HTML 表格转换为 worksheet
|
||||
const worksheet = XLSX.utils.table_to_sheet(table, {
|
||||
raw: true,
|
||||
});
|
||||
|
||||
// 获取范围
|
||||
const range = XLSX.utils.decode_range(worksheet["!ref"]!);
|
||||
|
||||
// 遍历每个单元格,设置样式
|
||||
for (let R = range.s.r; R <= range.e.r; ++R) {
|
||||
for (let C = range.s.c; C <= range.e.c; ++C) {
|
||||
const cellAddress = XLSX.utils.encode_cell({ r: R, c: C });
|
||||
const cell = worksheet[cellAddress];
|
||||
if (!cell || !cell.v) continue;
|
||||
|
||||
// 是否是最后一行(数量和金额总计行)
|
||||
const isLastRow = R === range.e.r;
|
||||
|
||||
cell.s = {
|
||||
alignment: {
|
||||
horizontal: "center",
|
||||
vertical: "center",
|
||||
wrapText: true,
|
||||
},
|
||||
font: {
|
||||
bold: isLastRow, // 最后一行加粗
|
||||
sz: 12,
|
||||
},
|
||||
border: {
|
||||
top: { style: "thin", color: { rgb: "000000" } },
|
||||
bottom: { style: "thin", color: { rgb: "000000" } },
|
||||
left: { style: "thin", color: { rgb: "000000" } },
|
||||
right: { style: "thin", color: { rgb: "000000" } },
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// 创建工作簿并导出
|
||||
const workbook = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(workbook, worksheet, "销售统计");
|
||||
XLSX.writeFile(workbook, "销售统计报表.xlsx");
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.loading-mask {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
.is-loading {
|
||||
animation: rotating 2s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes rotating {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
th,
|
||||
td {
|
||||
border: 1px solid #000;
|
||||
padding: 8px;
|
||||
font-size: 14px;
|
||||
text-align: center !important;
|
||||
}
|
||||
@media print {
|
||||
/* 移除全局布局影响 */
|
||||
body,
|
||||
html {
|
||||
display: block !important;
|
||||
height: auto !important;
|
||||
margin: 2mm !important; /* 添加安全边距 */
|
||||
}
|
||||
|
||||
#print-container {
|
||||
width: auto !important; /* 改为自动宽度 */
|
||||
margin: 0 auto !important; /* 居中显示 */
|
||||
font-size: 12pt !important; /* 调整字号 */
|
||||
min-height: 297mm;
|
||||
}
|
||||
|
||||
table {
|
||||
table-layout: fixed;
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
/* 优化单元格内边距 */
|
||||
td,
|
||||
th {
|
||||
padding: 4px 2mm !important;
|
||||
line-height: 1.4 !important;
|
||||
}
|
||||
}
|
||||
|
||||
tr,
|
||||
td {
|
||||
font-size: 14px !important;
|
||||
}
|
||||
|
||||
#print-container {
|
||||
width: 100% !important;
|
||||
margin: 0 !important;
|
||||
padding: 0 5mm !important;
|
||||
font-size: 14pt;
|
||||
color: #000 !important;
|
||||
font-family: Microsoft YaHei, "SimSun", serif !important;
|
||||
}
|
||||
/* 添加表格布局优化 */
|
||||
table {
|
||||
width: 100% !important;
|
||||
table-layout: fixed;
|
||||
border-collapse: collapse !important;
|
||||
|
||||
td,
|
||||
th {
|
||||
padding: 10px 2mm !important;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
218
frontEnd/src/pages/system/menue/index.vue
Normal file
@@ -0,0 +1,218 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-row>
|
||||
<baseTableHeader
|
||||
title="菜单管理"
|
||||
@resetSearch="resetSearch"
|
||||
@search="search">
|
||||
<template #content>
|
||||
<el-form :model="searchForm" :inline="true" label-position="right">
|
||||
<el-form-item label="菜单名:">
|
||||
<el-input
|
||||
v-model="searchForm.name"
|
||||
placeholder="请输入菜单名"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="菜单路径:">
|
||||
<el-input
|
||||
v-model="searchForm.path"
|
||||
placeholder="请输入菜单路径"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
<template #operateBtns>
|
||||
<el-button type="primary" @click="add" size="small"
|
||||
><el-icon> <CirclePlus /> </el-icon>新增</el-button
|
||||
>
|
||||
</template>
|
||||
</baseTableHeader>
|
||||
</el-row>
|
||||
<el-card style="margin-top: 8px">
|
||||
<base-table
|
||||
:option="tableOption"
|
||||
ref="table"
|
||||
style="width: 100%"
|
||||
row-key="id"
|
||||
:indent="30"
|
||||
@addConfim="addConfim"
|
||||
@editConfim="editConfim"
|
||||
:tree-props="{ children: 'children' }">
|
||||
<template #colunm>
|
||||
<el-table-column
|
||||
prop="name"
|
||||
label="菜单名"
|
||||
align="center"
|
||||
width="180" />
|
||||
<el-table-column
|
||||
prop="createDate"
|
||||
label="创建时间"
|
||||
width="180"
|
||||
align="center" />
|
||||
<el-table-column label="图标" width="180" align="center">
|
||||
<template #default="scope">
|
||||
<el-icon>
|
||||
<component :is="scope.row.icon"></component>
|
||||
</el-icon>
|
||||
<span style="padding: 0 15px">{{ scope.row.icon }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="path"
|
||||
label="路径"
|
||||
width="180"
|
||||
align="center" />
|
||||
<el-table-column label="是否显示" align="center">
|
||||
<template #default="scope">
|
||||
<el-switch
|
||||
v-model="scope.row.show"
|
||||
size="large"
|
||||
width="65px"
|
||||
inline-prompt
|
||||
active-text="是"
|
||||
inactive-text="否" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
#default="scope"
|
||||
width="300"
|
||||
label="操作"
|
||||
align="center">
|
||||
<el-button size="small" type="primary" @click="examine(scope.row)"
|
||||
>查看</el-button
|
||||
>
|
||||
<el-button size="small" type="warning" @click="update(scope.row)"
|
||||
>修改</el-button
|
||||
>
|
||||
<el-button size="small" type="danger" @click="deleteData(scope.row)"
|
||||
>删除</el-button
|
||||
>
|
||||
</el-table-column>
|
||||
</template>
|
||||
</base-table>
|
||||
|
||||
<base-curd-dialog
|
||||
v-model="pageVisibleState.show2LevelPage.value"
|
||||
:title="pageVisibleState.dialogTitle.value"
|
||||
width="50%"
|
||||
:before-close="handleDialogClose"
|
||||
@addConfim="addConfim"
|
||||
@editConfim="editConfim"
|
||||
@closeConfirm="handleDialogClose"
|
||||
:showPageType="pageVisibleState.showPageType">
|
||||
<template #content>
|
||||
<addOrEdit
|
||||
:executeType="pageVisibleState.executeType.value"
|
||||
:data="currentMenue"
|
||||
@updateData="getUserData"
|
||||
v-if="
|
||||
pageVisibleState.showPageType.edit ||
|
||||
pageVisibleState.showPageType.add
|
||||
"></addOrEdit>
|
||||
<menueView
|
||||
v-if="pageVisibleState.showPageType.view"
|
||||
:data="currentMenue"></menueView>
|
||||
</template>
|
||||
</base-curd-dialog>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, onMounted, ref } from "vue";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
import { resetParams } from "@/util/globalMethods";
|
||||
import addOrEdit from "./page/addOrEdit/addOrEdit.vue";
|
||||
import menueView from "./page/view/view.vue";
|
||||
import pageVisible from "@/components/curdDialog/pageVisibleState";
|
||||
import { systemMenueType } from "@/types/systemMenue";
|
||||
import api from "@/lib/request";
|
||||
import { tableOptionType } from "@/types/table";
|
||||
|
||||
const pageVisibleState = new pageVisible({
|
||||
add: "新增菜单",
|
||||
edit: "菜单编辑",
|
||||
view: "菜单查看",
|
||||
});
|
||||
const searchForm = reactive({
|
||||
name: "",
|
||||
path: "",
|
||||
});
|
||||
|
||||
let currentMenue = ref<systemMenueType>({});
|
||||
|
||||
let table = ref();
|
||||
let tableOption = ref<tableOptionType>({
|
||||
url: "/system-menue/list",
|
||||
searchUrl: "/system-menue/query",
|
||||
searchParams: searchForm,
|
||||
executeType: "list",
|
||||
});
|
||||
|
||||
function add() {
|
||||
pageVisibleState.show2LevelPage.value = true;
|
||||
pageVisibleState.showPageType.add = true;
|
||||
}
|
||||
|
||||
function examine(row: systemMenueType) {
|
||||
currentMenue.value = row;
|
||||
pageVisibleState.show2LevelPage.value = true;
|
||||
pageVisibleState.showPageType.view = true;
|
||||
}
|
||||
function update(row: systemMenueType) {
|
||||
currentMenue.value = row;
|
||||
pageVisibleState.show2LevelPage.value = true;
|
||||
pageVisibleState.showPageType.edit = true;
|
||||
}
|
||||
async function deleteData(row: systemMenueType) {
|
||||
ElMessageBox.confirm("确定要删除该菜单吗?", "警告", {
|
||||
type: "error",
|
||||
}).then(async () => {
|
||||
let respone = await api().get("/system-menue/delete?id=" + row.id);
|
||||
if (respone.code === 200) {
|
||||
ElMessage.success("菜单删除成功!");
|
||||
table.value.methods.setDataType("list");
|
||||
} else {
|
||||
ElMessage.error(respone.msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
function search() {
|
||||
table.value.methods.setDataType("search");
|
||||
}
|
||||
function resetSearch() {
|
||||
resetParams(searchForm);
|
||||
table.value.methods.setDataType("list");
|
||||
ElMessage.success("重置成功!");
|
||||
}
|
||||
|
||||
function handleDialogClose() {
|
||||
pageVisibleState.show2LevelPage.value = false;
|
||||
}
|
||||
function addConfim() {
|
||||
ElMessageBox.confirm("确定新增该条信息吗?", "提示", {
|
||||
type: "warning",
|
||||
}).then(async () => {
|
||||
let res = await api().post("/system-menue/add", currentMenue.value);
|
||||
if (res.code === 200) {
|
||||
ElMessage.success("添加成功");
|
||||
pageVisibleState.show2LevelPage.value = false;
|
||||
table.value.methods.setDataType("list");
|
||||
}
|
||||
});
|
||||
}
|
||||
function getUserData(newVal: systemMenueType) {
|
||||
currentMenue.value = { ...newVal };
|
||||
}
|
||||
async function editConfim() {
|
||||
ElMessageBox.confirm("确认该条信息吗?", "提示", {
|
||||
type: "warning",
|
||||
}).then(async () => {
|
||||
let respone = await api().post("/system-menue/update", currentMenue.value);
|
||||
if (respone.code == 200) {
|
||||
ElMessage.success("修改成功!");
|
||||
pageVisibleState.show2LevelPage.value = false;
|
||||
table.value.methods.setDataType("list");
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
||||
81
frontEnd/src/pages/system/menue/page/addOrEdit/addOrEdit.vue
Normal file
@@ -0,0 +1,81 @@
|
||||
<template>
|
||||
<el-form
|
||||
v-loading="loading"
|
||||
element-loading-text="初始化数据中..."
|
||||
:model="menueForm"
|
||||
:inline="true"
|
||||
label-suffix=":"
|
||||
label-width="80px">
|
||||
<el-form-item label="菜单名">
|
||||
<el-input v-model="menueForm.name"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="路径">
|
||||
<el-input v-model="menueForm.path"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="所属">
|
||||
<el-select v-model="menueForm.parentId">
|
||||
<el-option label="顶级" :value="0"></el-option>
|
||||
<el-option
|
||||
:label="item.name"
|
||||
:value="((item.id) as number)"
|
||||
v-for="(item, index) in menues"
|
||||
:key="index">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="图标">
|
||||
<el-input v-model="menueForm.icon"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否显示">
|
||||
<el-switch v-model="menueForm.show"></el-switch>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref, watch } from "vue";
|
||||
import { systemMenueType } from "@/types/systemMenue";
|
||||
import api from "@/lib/request";
|
||||
|
||||
const props = defineProps<{
|
||||
data?: systemMenueType;
|
||||
executeType?: string;
|
||||
}>();
|
||||
const emits = defineEmits(["updateData"]);
|
||||
let menues = ref<systemMenueType[]>([]);
|
||||
let loading = ref(true);
|
||||
let menueForm = ref<systemMenueType>({
|
||||
name: "",
|
||||
path: "",
|
||||
parentId: 0,
|
||||
icon: "",
|
||||
show: true,
|
||||
});
|
||||
|
||||
if (props.executeType === "edit") {
|
||||
menueForm.value = { ...props.data };
|
||||
}
|
||||
|
||||
watch(
|
||||
() => menueForm,
|
||||
(newVal) => {
|
||||
emits("updateData", newVal.value);
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
onMounted(async () => {
|
||||
let respone = await api().get("/system-menue/list?all=true");
|
||||
menues.value = respone.data.list;
|
||||
|
||||
loading.value = false;
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.el-input__wrapper {
|
||||
width: 200px;
|
||||
}
|
||||
.el-select {
|
||||
width: 192px;
|
||||
}
|
||||
</style>
|
||||
47
frontEnd/src/pages/system/menue/page/view/view.vue
Normal file
@@ -0,0 +1,47 @@
|
||||
<template>
|
||||
<el-descriptions
|
||||
title="个人信息"
|
||||
style="padding: 15px"
|
||||
border
|
||||
size="large"
|
||||
:column="2">
|
||||
<el-descriptions-item>
|
||||
<template #label> 菜单名 </template>{{ menue.name }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item>
|
||||
<template #label> 路径 </template>{{ menue.path }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item>
|
||||
<template #label> 所属菜单 </template
|
||||
>{{ menue.parentId }}</el-descriptions-item
|
||||
>
|
||||
<el-descriptions-item>
|
||||
<template #label> 图标 </template>
|
||||
<el-icon>
|
||||
<component :is="menue.icon" />
|
||||
</el-icon>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item>
|
||||
<template #label>是否显示 </template>
|
||||
<el-tag type="success" v-if="menue.show">显示</el-tag>
|
||||
<el-tag type="danger" v-else>隐藏</el-tag>
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { systemMenueType } from "@/types/systemMenue";
|
||||
const props = defineProps<{
|
||||
data: systemMenueType;
|
||||
}>();
|
||||
const menue = props.data;
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
:deep(.el-descriptions__label) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.el-icon {
|
||||
margin: 0 5px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
212
frontEnd/src/pages/system/role/index.vue
Normal file
@@ -0,0 +1,212 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-row>
|
||||
<baseTableHeader
|
||||
title="角色管理"
|
||||
@resetSearch="resetSearch"
|
||||
@search="search">
|
||||
<template #content>
|
||||
<el-form
|
||||
:model="searchForm"
|
||||
:inline="true"
|
||||
label-position="right"
|
||||
:label-suffix="':'">
|
||||
<!-- <el-form-item label="所属角色">
|
||||
<el-select
|
||||
v-model="searchForm.roleValue"
|
||||
clearable
|
||||
filterable
|
||||
placeholder="请选择角色"
|
||||
style="width: 150px">
|
||||
<el-option
|
||||
v-for="item in menues"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="String(item.id)">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item> -->
|
||||
<el-form-item label="角色名">
|
||||
<el-input
|
||||
v-model="searchForm.name"
|
||||
placeholder="请输入角色名"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
<template #operateBtns>
|
||||
<el-button size="small" type="primary" @click="add">
|
||||
<el-icon> <CirclePlus /> </el-icon>新增
|
||||
</el-button>
|
||||
</template>
|
||||
</baseTableHeader>
|
||||
</el-row>
|
||||
<el-card style="margin-top: 8px">
|
||||
<base-table :option="tableOption" ref="table">
|
||||
<el-table-column type="index"></el-table-column>
|
||||
<el-table-column prop="name" label="角色名" align="center" />
|
||||
<el-table-column prop="createDate" label="创建时间" align="center" />
|
||||
<el-table-column
|
||||
prop="updateData"
|
||||
label="最后更改时间"
|
||||
align="center" />
|
||||
<!-- <el-table-column label="角色状态" align="center">
|
||||
<template #default="scope">
|
||||
<el-switch
|
||||
v-model="scope.row.roleState"
|
||||
size="large"
|
||||
width="65px"
|
||||
inline-prompt
|
||||
active-text="启用"
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
@change="roleStateChange"
|
||||
inactive-text="禁用" />
|
||||
</template>
|
||||
</el-table-column> -->
|
||||
<el-table-column #default="scope" label="操作" align="center">
|
||||
<el-button size="small" type="primary" @click="examine(scope.row)"
|
||||
>查看</el-button
|
||||
>
|
||||
<el-button size="small" type="warning" @click="update(scope.row)"
|
||||
>修改</el-button
|
||||
>
|
||||
<el-button size="small" type="danger" @click="deleteData(scope.row)"
|
||||
>删除</el-button
|
||||
>
|
||||
</el-table-column>
|
||||
</base-table>
|
||||
</el-card>
|
||||
<base-curd-dialog
|
||||
v-model="pageVisibleState.show2LevelPage.value"
|
||||
:title="pageVisibleState.dialogTitle.value"
|
||||
width="50%"
|
||||
:before-close="handleDialogClose"
|
||||
@addConfim="addConfim"
|
||||
@editConfim="editConfim"
|
||||
@closeConfirm="handleDialogClose"
|
||||
:showPageType="pageVisibleState.showPageType">
|
||||
<template #content>
|
||||
<addOrEdite
|
||||
:data="currentRole"
|
||||
@updateData="getRoleData"
|
||||
:executeType="pageVisibleState.executeType.value"
|
||||
v-if="
|
||||
pageVisibleState.showPageType.edit ||
|
||||
pageVisibleState.showPageType.add
|
||||
"></addOrEdite>
|
||||
<roleView :data="currentRole" v-if="pageVisibleState.showPageType.view">
|
||||
</roleView>
|
||||
</template>
|
||||
</base-curd-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, onMounted, ref } from "vue";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
import pageVisible from "@/components/curdDialog/pageVisibleState";
|
||||
import api from "@/lib/request";
|
||||
import { roleType } from "@/types/role";
|
||||
import roleView from "./page/view.vue";
|
||||
import addOrEdite from "./page/addOrEdit.vue";
|
||||
import { systemMenueType } from "@/types/systemMenue";
|
||||
import { tableOptionType } from "@/types/table";
|
||||
|
||||
const pageVisibleState = new pageVisible({
|
||||
add: "新增角色",
|
||||
edit: "角色编辑",
|
||||
view: "角色查看",
|
||||
});
|
||||
|
||||
let currentRole = ref<roleType>({});
|
||||
let menues = ref<systemMenueType[]>();
|
||||
|
||||
const searchForm = reactive({
|
||||
roleValue: "",
|
||||
name: "",
|
||||
});
|
||||
let table = ref();
|
||||
let tableOption = ref<tableOptionType>({
|
||||
url: "/role/list",
|
||||
searchUrl: "/role/query",
|
||||
searchParams: searchForm,
|
||||
executeType: "list",
|
||||
});
|
||||
|
||||
onMounted(async () => {
|
||||
let respone = await api().get("/system-menue/list?all=true");
|
||||
menues.value = respone.data.list;
|
||||
});
|
||||
|
||||
function examine(row: roleType) {
|
||||
currentRole.value = row;
|
||||
pageVisibleState.show2LevelPage.value = true;
|
||||
pageVisibleState.showPageType.view = true;
|
||||
}
|
||||
function update(row: roleType) {
|
||||
currentRole.value = row;
|
||||
pageVisibleState.show2LevelPage.value = true;
|
||||
pageVisibleState.showPageType.edit = true;
|
||||
}
|
||||
async function deleteData(row: roleType) {
|
||||
ElMessageBox.confirm("确定要删除该用户吗?", "警告", {
|
||||
type: "error",
|
||||
}).then(async () => {
|
||||
let respone = await api().get("/role/delete?id=" + row.id);
|
||||
if (respone.code === 200) {
|
||||
ElMessage.success("角色删除成功!");
|
||||
table.value.methods.setDataType("list");
|
||||
} else {
|
||||
ElMessage.error(respone.msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
function search() {
|
||||
table.value.methods.setDataType("search");
|
||||
}
|
||||
function resetSearch() {
|
||||
searchForm.roleValue = "";
|
||||
searchForm.name = "";
|
||||
table.value.methods.setDataType("list");
|
||||
ElMessage.success("重置成功!");
|
||||
}
|
||||
function handleDialogClose() {
|
||||
pageVisibleState.show2LevelPage.value = false;
|
||||
}
|
||||
function addConfim() {
|
||||
ElMessageBox.confirm("确定增加数据吗?", "提示", { type: "warning" }).then(
|
||||
async () => {
|
||||
let res = await api().post("/role/add", currentRole.value);
|
||||
if (res.code === 200) {
|
||||
ElMessage.success("添加成功");
|
||||
pageVisibleState.show2LevelPage.value = false;
|
||||
table.value.methods.setDataType("list");
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
function editConfim() {
|
||||
ElMessageBox.confirm("确定要修改数据吗?", "提示", { type: "warning" }).then(
|
||||
async () => {
|
||||
let respone = await api().post("/role/update", currentRole.value);
|
||||
if (respone.code == 200) {
|
||||
ElMessage.success("修改成功!");
|
||||
pageVisibleState.show2LevelPage.value = false;
|
||||
table.value.methods.setDataType("list");
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function getRoleData(newVal: roleType) {
|
||||
currentRole.value = { ...newVal };
|
||||
}
|
||||
|
||||
function add() {
|
||||
pageVisibleState.show2LevelPage.value = true;
|
||||
pageVisibleState.showPageType.add = true;
|
||||
}
|
||||
|
||||
function roleStateChange(state: any) {}
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
||||
75
frontEnd/src/pages/system/role/page/addOrEdit.vue
Normal file
@@ -0,0 +1,75 @@
|
||||
<template>
|
||||
<el-form v-loading="loading" element-loading-text="初始化数据中..." :model="roleForm" :inline="true" label-suffix=":"
|
||||
label-width="80px">
|
||||
<el-form-item label="角色名">
|
||||
<el-input v-model="roleForm.name"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否启用">
|
||||
<el-switch v-model="roleForm.roleState" :active-value="1" :inactive-value="0"></el-switch>
|
||||
</el-form-item>
|
||||
<el-form-item style="width: 100%;" label="权限">
|
||||
<el-tree :data="roles" :props="treeProps" show-checkbox default-expand-all node-key="id"
|
||||
:default-checked-keys="roleForm.values?.split(',')" @check="handleCheckChange" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref, watch } from "vue";
|
||||
import { systemMenueType } from "@/types/systemMenue";
|
||||
import api from "@/lib/request";
|
||||
import { roleType } from "@/types/role";
|
||||
|
||||
const props = defineProps<{
|
||||
data?: roleType;
|
||||
executeType?: string;
|
||||
}>();
|
||||
const emits = defineEmits(["updateData"]);
|
||||
let roles = ref<systemMenueType[]>([]);
|
||||
let loading = ref(true);
|
||||
let treeProps = { label: "name", children: "children" };
|
||||
let auths = ref<string[]>([]);
|
||||
|
||||
let roleForm = ref<roleType>({
|
||||
name: "",
|
||||
roleState: 1,
|
||||
values: ''
|
||||
});
|
||||
|
||||
onMounted(async () => {
|
||||
let respone = await api().get('/system-menue/list');
|
||||
roles.value = respone.data.list;
|
||||
|
||||
loading.value = false;
|
||||
|
||||
if (props.executeType === "edit") {
|
||||
roleForm.value = { ...props.data };
|
||||
auths.value = roleForm.value.values?.split(',') as string[];
|
||||
}
|
||||
|
||||
watch(
|
||||
() => roleForm,
|
||||
(newVal) => {
|
||||
emits("updateData", newVal.value);
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
})
|
||||
|
||||
function handleCheckChange(val: string[], checkVal: any) {
|
||||
auths.value = checkVal.checkedKeys.filter(item => String(item));
|
||||
roleForm.value.values = auths.value.join(',');
|
||||
}
|
||||
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.el-input__wrapper {
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
.el-select {
|
||||
width: 192px;
|
||||
}
|
||||
</style>
|
||||
@/types/systemMenue
|
||||
61
frontEnd/src/pages/system/role/page/view.vue
Normal file
@@ -0,0 +1,61 @@
|
||||
<template>
|
||||
<el-descriptions
|
||||
title="角色信息"
|
||||
style="padding: 15px"
|
||||
border
|
||||
size="large"
|
||||
:column="2">
|
||||
<el-descriptions-item>
|
||||
<template #label> 角色名 </template>{{ theRoleInfo.name }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item>
|
||||
<template #label>是否启用 </template>
|
||||
<el-tag type="success" v-if="theRoleInfo.roleState">启用</el-tag>
|
||||
<el-tag type="danger" v-else>禁用</el-tag>
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<el-row>
|
||||
<el-col>
|
||||
<label>角色权限:</label>
|
||||
<el-tree
|
||||
:data="roles"
|
||||
:props="treeProps"
|
||||
show-checkbox
|
||||
node-key="id"
|
||||
:default-checked-keys="theRoleInfo.values?.split(',')"
|
||||
default-expand-all />
|
||||
</el-col>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { systemMenueType } from "@/types/systemMenue";
|
||||
import { roleType } from "@/types/role";
|
||||
import { ref, onMounted } from "vue";
|
||||
import api from "@/lib/request";
|
||||
const props = defineProps<{
|
||||
data: roleType;
|
||||
}>();
|
||||
const role = props.data;
|
||||
let roles = ref<systemMenueType[]>([]);
|
||||
let loading = ref(true);
|
||||
let treeProps = { label: "name", children: "children" };
|
||||
let theRoleInfo = ref<roleType>({});
|
||||
|
||||
theRoleInfo.value = { ...props.data };
|
||||
|
||||
onMounted(async () => {
|
||||
let respone = await api().get("/system-menue/list");
|
||||
roles.value = respone.data.list;
|
||||
loading.value = false;
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
:deep(.el-descriptions__label) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.el-icon {
|
||||
margin: 0 5px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
279
frontEnd/src/pages/system/user/index.vue
Normal file
@@ -0,0 +1,279 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-row>
|
||||
<baseTableHeader
|
||||
title="用户管理"
|
||||
@resetSearch="resetSearch"
|
||||
@search="search">
|
||||
<template #content>
|
||||
<el-form :model="searchForm" :inline="true" label-position="right">
|
||||
<el-form-item label="姓名:">
|
||||
<el-input
|
||||
v-model="searchForm.name"
|
||||
placeholder="请输入姓名"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="性别:">
|
||||
<el-radio-group v-model="searchForm.sex">
|
||||
<el-radio value="男">男</el-radio>
|
||||
<el-radio value="女">女</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="手机号:">
|
||||
<el-input
|
||||
v-model="searchForm.phone"
|
||||
placeholder="请输入手机号"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
<template #operateBtns>
|
||||
<el-button size="small" type="primary" @click="add">
|
||||
<template #icon>
|
||||
<el-icon>
|
||||
<CirclePlus />
|
||||
</el-icon> </template
|
||||
>新增</el-button
|
||||
>
|
||||
</template>
|
||||
</baseTableHeader>
|
||||
</el-row>
|
||||
<el-card style="margin-top: 8px">
|
||||
<base-table :option="tableOption" ref="table">
|
||||
<template #colunm>
|
||||
<el-table-column type="index" width="50"></el-table-column>
|
||||
<el-table-column
|
||||
prop="name"
|
||||
label="姓名"
|
||||
width="180"
|
||||
align="center" />
|
||||
<el-table-column prop="sex" label="性别" align="center" />
|
||||
<el-table-column prop="role" label="所属角色" align="center">
|
||||
<template #default="scope">
|
||||
{{
|
||||
roleList?.find(
|
||||
(item) => Number(item.id) === Number(scope.row.role)
|
||||
)?.name || "无"
|
||||
}}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="账户状态" align="center">
|
||||
<template #default="scope">
|
||||
<el-switch
|
||||
v-model="scope.row.userState"
|
||||
size="large"
|
||||
width="65px"
|
||||
inline-prompt
|
||||
active-text="启用"
|
||||
@change="stateVal => userStatChange(stateVal as boolean, scope.row)"
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
inactive-text="禁用" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="phone" label="手机号" align="center" />
|
||||
<el-table-column
|
||||
prop="createDate"
|
||||
label="创建时间"
|
||||
width="180"
|
||||
align="center" />
|
||||
<el-table-column #default="scope" width="300">
|
||||
<el-button size="small" type="primary" @click="view(scope.row)"
|
||||
>查看</el-button
|
||||
>
|
||||
<el-button size="small" type="warning" @click="edit(scope.row)"
|
||||
>修改</el-button
|
||||
>
|
||||
<el-button size="small" type="danger" @click="deleteData(scope.row)"
|
||||
>删除</el-button
|
||||
>
|
||||
<el-button size="small" type="danger" @click="resetPwd(scope.row)"
|
||||
>重置密码</el-button
|
||||
>
|
||||
</el-table-column>
|
||||
</template>
|
||||
</base-table>
|
||||
</el-card>
|
||||
|
||||
<base-curd-dialog
|
||||
v-model="pageVisibleState.show2LevelPage.value"
|
||||
:title="pageVisibleState.dialogTitle.value"
|
||||
width="50%"
|
||||
:before-close="handleDialogClose"
|
||||
@addConfim="addConfim"
|
||||
@editConfim="editConfim"
|
||||
@closeConfirm="handleDialogClose"
|
||||
:showPageType="pageVisibleState.showPageType">
|
||||
<template #content>
|
||||
<userAddOrEdit
|
||||
:executeType="pageVisibleState.executeType.value"
|
||||
v-if="
|
||||
pageVisibleState.showPageType.edit ||
|
||||
pageVisibleState.showPageType.add
|
||||
"
|
||||
:data="(currentUser as userType)"
|
||||
@updateData="getUserData">
|
||||
</userAddOrEdit>
|
||||
<userView
|
||||
v-if="pageVisibleState.showPageType.view"
|
||||
:data="(currentUser as userType)">
|
||||
</userView>
|
||||
</template>
|
||||
</base-curd-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref, onMounted, watch } from "vue";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
import { resetParams } from "@/util/globalMethods";
|
||||
import { userType } from "@/types/user";
|
||||
import { globalState } from "@/store";
|
||||
import userAddOrEdit from "./page/userAddOrEdit.vue";
|
||||
import userView from "@/pages/publicPages/user/userView.vue";
|
||||
import api from "@/lib/request";
|
||||
import pageVisible from "@/components/curdDialog/pageVisibleState";
|
||||
import { roleDataList } from "@/lib/api/publicApiList";
|
||||
import { roleType } from "@/types/role";
|
||||
import { tableOptionType } from "@/types/table";
|
||||
const pageVisibleState = new pageVisible({
|
||||
add: "新增用户",
|
||||
edit: "用户编辑",
|
||||
view: "信息查看",
|
||||
});
|
||||
|
||||
const globalStateStore = globalState();
|
||||
const searchForm = reactive({
|
||||
name: "",
|
||||
sex: "",
|
||||
phone: "",
|
||||
});
|
||||
|
||||
let currentUser = ref<userType>({});
|
||||
let roleList = ref<roleType[]>();
|
||||
let table = ref();
|
||||
let tableOption = ref<tableOptionType>({
|
||||
url: "/user/list",
|
||||
searchUrl: "/user/query",
|
||||
searchParams: searchForm,
|
||||
executeType: "list",
|
||||
});
|
||||
|
||||
onMounted(async () => {
|
||||
roleList.value = await roleDataList();
|
||||
});
|
||||
|
||||
function view(row: userType) {
|
||||
pageVisibleState.showPageType.view = true;
|
||||
currentUser.value = row;
|
||||
}
|
||||
function edit(row: userType) {
|
||||
pageVisibleState.showPageType.edit = true;
|
||||
|
||||
currentUser.value = row;
|
||||
}
|
||||
function add() {
|
||||
pageVisibleState.showPageType.add = true;
|
||||
}
|
||||
|
||||
function addConfim() {
|
||||
ElMessageBox.confirm("确定新增该条信息吗?", "提示", {
|
||||
type: "warning",
|
||||
}).then(() => {
|
||||
globalStateStore.setGlobalLoadingShow(true, "正在提交信息...");
|
||||
api()
|
||||
.post("/user/add", { ...currentUser.value })
|
||||
.then((res) => {
|
||||
if (res.code === 200) {
|
||||
pageVisibleState.showPageType.add = false;
|
||||
pageVisibleState.show2LevelPage.value = false;
|
||||
ElMessage.success("新增成功!");
|
||||
table.value.methods.setDataType("list");
|
||||
} else {
|
||||
ElMessage.error(res.msg);
|
||||
}
|
||||
globalStateStore.setGlobalLoadingShow(false);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function getUserData(newVal: any) {
|
||||
currentUser.value = { ...newVal.value };
|
||||
}
|
||||
|
||||
function editConfim() {
|
||||
ElMessageBox.confirm("确定更改数据吗?", "提示", { type: "warning" }).then(
|
||||
() => {
|
||||
api()
|
||||
.post("/user/update", currentUser.value)
|
||||
.then((res) => {
|
||||
if (res.code === 200) {
|
||||
ElMessage.success("更改成功!");
|
||||
pageVisibleState.show2LevelPage.value = false;
|
||||
table.value.methods.setDataType("list");
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function deleteData(row: userType) {
|
||||
ElMessageBox.confirm("确定要删除该用户吗?", "警告", {
|
||||
type: "error",
|
||||
}).then(() => {
|
||||
api()
|
||||
.get("/user/delete?id=" + row.id)
|
||||
.then((res) => {
|
||||
if (res.code === 200) {
|
||||
ElMessage.success(` ${row.name} 删除成功!`);
|
||||
table.value.methods.setDataType("list");
|
||||
} else {
|
||||
ElMessage.warning(res.msg);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
function search() {
|
||||
table.value.methods.setDataType("search");
|
||||
}
|
||||
|
||||
function resetSearch() {
|
||||
resetParams(searchForm);
|
||||
table.value.methods.setDataType("reset");
|
||||
ElMessage.success("重置成功!");
|
||||
}
|
||||
|
||||
function resetPwd(row: userType) {
|
||||
ElMessageBox.confirm("确定要重置该用户的密码吗?", "警告", {
|
||||
type: "error",
|
||||
}).then(() => {
|
||||
api()
|
||||
.get("/user/resetPwd?id=" + row.id)
|
||||
.then((res) => {
|
||||
if (res.code === 200) {
|
||||
ElMessageBox.confirm(
|
||||
` ${row.name} 的密码重置成功为123456,请告知用户!`,
|
||||
"提示",
|
||||
{ type: "success" }
|
||||
);
|
||||
} else {
|
||||
ElMessage.error(res.msg);
|
||||
}
|
||||
});
|
||||
ElMessage.success("密码重置成功!");
|
||||
});
|
||||
}
|
||||
function handleDialogClose() {
|
||||
pageVisibleState.show2LevelPage.value = false;
|
||||
}
|
||||
function userStatChange(state: boolean, data: userType) {
|
||||
api()
|
||||
.post("/user/update", {
|
||||
userState: state ? 1 : 0,
|
||||
id: data.id,
|
||||
})
|
||||
.then(() => {
|
||||
ElMessage.success("用户状态更改成功!");
|
||||
table.value.methods.setDataType("list");
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
||||
143
frontEnd/src/pages/system/user/page/userAddOrEdit.vue
Normal file
@@ -0,0 +1,143 @@
|
||||
<template>
|
||||
<el-form
|
||||
:model="user"
|
||||
label-width="100px"
|
||||
:inline="true"
|
||||
label-suffix=":"
|
||||
v-loading="loading"
|
||||
element-loading-text="正在初始化数据...">
|
||||
<el-form-item label="姓名">
|
||||
<el-input :prefix-icon="User" v-model="user.name" placeholder="姓名">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="性别">
|
||||
<el-radio-group v-model="user.sex">
|
||||
<el-radio value="男">男</el-radio>
|
||||
<el-radio value="女">女</el-radio>
|
||||
<el-radio value="保密">保密</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="电话">
|
||||
<el-input
|
||||
:prefix-icon="Iphone"
|
||||
v-model="user.phone"
|
||||
placeholder="电话"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="所属角色">
|
||||
<el-select
|
||||
v-model="user.role"
|
||||
clearable
|
||||
filterable
|
||||
placeholder="请选择角色"
|
||||
style="width: 230px">
|
||||
<el-option
|
||||
v-for="item in roleList"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="String(item.id)"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="生日">
|
||||
<el-date-picker
|
||||
format="YYYYH-MM-DD"
|
||||
v-model="user.birthday"
|
||||
type="date"
|
||||
placeholder="生日"
|
||||
size="large" />
|
||||
</el-form-item>
|
||||
<el-form-item label="所在区域">
|
||||
<el-cascader
|
||||
:options="pcaTextArrData"
|
||||
v-model="selectedOptions"
|
||||
@change="pcaChange"></el-cascader>
|
||||
</el-form-item>
|
||||
<el-form-item label="详细地址">
|
||||
<el-input
|
||||
:prefix-icon="Location"
|
||||
v-model="user.address"
|
||||
placeholder="请输入详细地址"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="账号状态">
|
||||
<el-switch
|
||||
v-model="user.userState"
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
active-text="启用"
|
||||
width="65px"
|
||||
inline-prompt
|
||||
inactive-text="禁用"></el-switch>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref, watch } from "vue";
|
||||
import { userType } from "@/types/user";
|
||||
// @ts-ignore
|
||||
import { pcaTextArr } from "element-china-area-data";
|
||||
import { Avatar, Location, Iphone, User } from "@element-plus/icons-vue";
|
||||
import { roleType } from "@/types/role";
|
||||
import { roleDataList } from "@/lib/api/publicApiList";
|
||||
|
||||
const pcaTextArrData = ref(pcaTextArr);
|
||||
const selectedOptions = ref([]);
|
||||
const props = defineProps<{
|
||||
data?: userType;
|
||||
executeType?: string;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits(["updateData"]);
|
||||
|
||||
let loading = ref(true);
|
||||
let roleList = ref<roleType[]>();
|
||||
let user = ref<userType>({
|
||||
createDate: "",
|
||||
name: "",
|
||||
sex: "男",
|
||||
phone: "",
|
||||
userState: 1,
|
||||
role: "",
|
||||
birthday: "",
|
||||
province: "",
|
||||
city: "",
|
||||
area: "",
|
||||
address: "",
|
||||
});
|
||||
|
||||
onMounted(async () => {
|
||||
roleList.value = await roleDataList();
|
||||
|
||||
watch(
|
||||
() => user,
|
||||
(newVal) => {
|
||||
emit("updateData", newVal);
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
loading.value = false;
|
||||
});
|
||||
|
||||
if (props.executeType === "edit") {
|
||||
user.value = { ...props.data };
|
||||
selectedOptions.value = [
|
||||
user.value.province as never,
|
||||
user.value.city as never,
|
||||
user.value.area as never,
|
||||
];
|
||||
}
|
||||
|
||||
function pcaChange(data: { [key: string]: any }) {
|
||||
user.value.province = data[0];
|
||||
user.value.city = data[1];
|
||||
user.value.area = data[2];
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
:deep(.el-input) {
|
||||
width: 230px;
|
||||
}
|
||||
:deep(.el-form-item) {
|
||||
margin-right: 0;
|
||||
}
|
||||
</style>
|
||||
267
frontEnd/src/pages/system/user/personal.vue
Normal file
@@ -0,0 +1,267 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-row :gutter="15">
|
||||
<!-- <el-col :span="12">
|
||||
<el-card style="height: 500px" class="info-show">
|
||||
<ul class="info-list">
|
||||
<li class="infor-list-item">
|
||||
<label for="">姓名:</label>
|
||||
<span>{{ userInforStore.userInfor.name }}</span>
|
||||
</li>
|
||||
<li class="infor-list-item">
|
||||
<label for="">性别:</label>
|
||||
<span>{{ userInforStore.userInfor.sex }}</span>
|
||||
</li>
|
||||
<li class="infor-list-item">
|
||||
<label for="">手机号:</label>
|
||||
<span>{{ userInforStore.userInfor.phone }}</span>
|
||||
</li>
|
||||
<li class="infor-list-item">
|
||||
<label for="">生日:</label>
|
||||
<span>{{
|
||||
dayjs(userInforStore.userInfor.birthday).format("YYYY-MM-DD")
|
||||
}}</span>
|
||||
</li>
|
||||
<li class="infor-list-item">
|
||||
<label for="">地址:</label>
|
||||
<span>{{
|
||||
userInforStore.userInfor.province +
|
||||
"/" +
|
||||
userInforStore.userInfor.city +
|
||||
"/" +
|
||||
userInforStore.userInfor.area +
|
||||
"/" +
|
||||
userInforStore.userInfor.address
|
||||
}}</span>
|
||||
</li>
|
||||
</ul>
|
||||
<el-divider />
|
||||
</el-card>
|
||||
</el-col> -->
|
||||
<el-col :span="24" v-loading="loading">
|
||||
<el-form :model="tempUserInfor" label-width="120px">
|
||||
<el-form-item label="姓名:">
|
||||
<el-input
|
||||
v-model="tempUserInfor.name"
|
||||
placeholder="请输入你的姓名"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="性别:">
|
||||
<el-radio-group v-model="tempUserInfor.sex">
|
||||
<el-radio value="男">男</el-radio>
|
||||
<el-radio value="女">女</el-radio>
|
||||
<el-radio value="保密">保密</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="生日:">
|
||||
<el-date-picker
|
||||
v-model="tempUserInfor.birthday"
|
||||
type="date"
|
||||
placeholder="选择你的生日呀"
|
||||
size="large" />
|
||||
</el-form-item>
|
||||
<el-form-item label="手机号:">
|
||||
<el-input
|
||||
v-model="tempUserInfor.phone"
|
||||
placeholder="请输入你的手机号"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="所在区域">
|
||||
<el-cascader
|
||||
:options="pcaTextArrData"
|
||||
v-model="selectedOptions"
|
||||
@change="pcaChange"></el-cascader>
|
||||
</el-form-item>
|
||||
<el-form-item label="详细地址:">
|
||||
<el-input
|
||||
v-model="tempUserInfor.address"
|
||||
placeholder="请输入你的地址"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="密码:">
|
||||
<el-input
|
||||
v-model="tempUserInfor.pwd"
|
||||
placeholder="请输入你的新密码"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button
|
||||
type="primary"
|
||||
size="large"
|
||||
style="width: 60%"
|
||||
@click="updatePersonInfo"
|
||||
>更新我的信息</el-button
|
||||
>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-col>
|
||||
<!-- <el-col :span="24" style="margin-top: 15px">
|
||||
<el-card>
|
||||
<baseEcharts :option="lineStack" style="height: 300px"></baseEcharts>
|
||||
</el-card>
|
||||
</el-col> -->
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, onMounted, ref } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { userInfor } from "@/store/user/user";
|
||||
import dayjs from "dayjs";
|
||||
import { pcaTextArr } from "element-china-area-data";
|
||||
import { userType } from "@/types/user";
|
||||
import api from "@/lib/request";
|
||||
import { md5 } from "js-md5";
|
||||
|
||||
const userInforStore = userInfor();
|
||||
const pcaTextArrData = ref(pcaTextArr);
|
||||
let tempUserInfor = ref<userType>({ ...userInforStore.userInfor, pwd: "" });
|
||||
const selectedOptions = ref([
|
||||
tempUserInfor.value.province,
|
||||
tempUserInfor.value.city,
|
||||
tempUserInfor.value.area,
|
||||
]);
|
||||
|
||||
const lineStack = reactive({
|
||||
title: {
|
||||
text: "Stacked Line",
|
||||
},
|
||||
tooltip: {
|
||||
trigger: "axis",
|
||||
},
|
||||
legend: {
|
||||
data: ["Email", "Union Ads", "Video Ads", "Direct", "Search Engine"],
|
||||
},
|
||||
grid: {
|
||||
left: "3%",
|
||||
right: "4%",
|
||||
bottom: "3%",
|
||||
containLabel: true,
|
||||
},
|
||||
toolbox: {
|
||||
feature: {
|
||||
saveAsImage: {},
|
||||
},
|
||||
},
|
||||
xAxis: {
|
||||
type: "category",
|
||||
boundaryGap: false,
|
||||
data: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
|
||||
},
|
||||
yAxis: {
|
||||
type: "value",
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: "Email",
|
||||
type: "line",
|
||||
stack: "Total",
|
||||
data: [120, 132, 101, 134, 90, 230, 210],
|
||||
},
|
||||
{
|
||||
name: "Union Ads",
|
||||
type: "line",
|
||||
stack: "Total",
|
||||
data: [220, 182, 191, 234, 290, 330, 310],
|
||||
},
|
||||
{
|
||||
name: "Video Ads",
|
||||
type: "line",
|
||||
stack: "Total",
|
||||
data: [150, 232, 201, 154, 190, 330, 410],
|
||||
},
|
||||
{
|
||||
name: "Direct",
|
||||
type: "line",
|
||||
stack: "Total",
|
||||
data: [320, 332, 301, 334, 390, 330, 320],
|
||||
},
|
||||
{
|
||||
name: "Search Engine",
|
||||
type: "line",
|
||||
stack: "Total",
|
||||
data: [820, 932, 901, 934, 1290, 1330, 1320],
|
||||
},
|
||||
],
|
||||
});
|
||||
const loading = ref(false);
|
||||
const infoList = ref([
|
||||
{
|
||||
label: "姓名",
|
||||
value: "李嘉图",
|
||||
},
|
||||
{
|
||||
label: "性别",
|
||||
value: "男",
|
||||
},
|
||||
{
|
||||
label: "生日",
|
||||
value: "1996/08/17",
|
||||
},
|
||||
{
|
||||
label: "手机号",
|
||||
value: "1823079420",
|
||||
},
|
||||
{
|
||||
label: "地址",
|
||||
value: "中国贵州省贵阳市",
|
||||
},
|
||||
]);
|
||||
|
||||
function updatePersonInfo() {
|
||||
loading.value = true;
|
||||
let sendData = { ...tempUserInfor.value };
|
||||
|
||||
if (tempUserInfor.value.pwd) {
|
||||
sendData.pwd = md5(tempUserInfor.value.pwd).toLocaleUpperCase();
|
||||
}
|
||||
|
||||
api()
|
||||
.post("/user/update", sendData)
|
||||
.then((res) => {
|
||||
if (res.code === 200) {
|
||||
userInfor().setLoginState(res.data.userInfo);
|
||||
loading.value = false;
|
||||
ElMessage.success("用户信息更新成功!");
|
||||
} else {
|
||||
loading.value = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function pcaChange(data: { [key: string]: any }) {
|
||||
tempUserInfor.value.province = data[0];
|
||||
tempUserInfor.value.city = data[1];
|
||||
tempUserInfor.value.area = data[2];
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.info-show {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
.info-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
.infor-list-item {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
label {
|
||||
width: 30%;
|
||||
text-align: right;
|
||||
}
|
||||
span {
|
||||
width: 70%;
|
||||
}
|
||||
}
|
||||
}
|
||||
.sign {
|
||||
display: inline-block;
|
||||
color: rgba($color: #000000, $alpha: 0.5);
|
||||
// transform: scale(0.8);
|
||||
font-size: 0.7rem;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
:deep(.el-divider--horizontal) {
|
||||
margin: 8px 0;
|
||||
}
|
||||
</style>
|
||||