forked from admin/deShanXiao
初始版本,目前线上可用
This commit is contained in:
14
frontEnd/src/App.vue
Normal file
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
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
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
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
1
frontEnd/src/assets/css/aliIcon/iconfont.js
Normal file
File diff suppressed because one or more lines are too long
205
frontEnd/src/assets/css/aliIcon/iconfont.json
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.ttf
Normal file
Binary file not shown.
BIN
frontEnd/src/assets/css/aliIcon/iconfont.woff
Normal file
BIN
frontEnd/src/assets/css/aliIcon/iconfont.woff
Normal file
Binary file not shown.
BIN
frontEnd/src/assets/css/aliIcon/iconfont.woff2
Normal file
BIN
frontEnd/src/assets/css/aliIcon/iconfont.woff2
Normal file
Binary file not shown.
73
frontEnd/src/assets/css/default.scss
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
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
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
BIN
frontEnd/src/assets/images/index.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 91 KiB |
52
frontEnd/src/components/baseEcharts/baseEcharts.vue
Normal file
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
BIN
frontEnd/src/pages/login/img/login-bck.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 758 KiB |
123
frontEnd/src/pages/login/login.vue
Normal file
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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>
|
||||
266
frontEnd/src/routers/index.ts
Normal file
266
frontEnd/src/routers/index.ts
Normal file
@@ -0,0 +1,266 @@
|
||||
import {
|
||||
createRouter,
|
||||
createWebHashHistory,
|
||||
createWebHistory,
|
||||
RouteRecordRaw,
|
||||
} from "vue-router";
|
||||
|
||||
const routes: Array<RouteRecordRaw> = [
|
||||
{
|
||||
path: "/login",
|
||||
name: "登陆",
|
||||
component: () => import("@/pages/login/login.vue"),
|
||||
},
|
||||
{
|
||||
path: "/:cathAll(.*)",
|
||||
name: "未找到",
|
||||
component: () => import("@/pages/404/404.vue"),
|
||||
},
|
||||
{
|
||||
path: "/",
|
||||
name: "主页",
|
||||
redirect: "main",
|
||||
component: () => import("@/layout/index.vue"),
|
||||
children: [
|
||||
{
|
||||
path: "/main",
|
||||
name: "首页",
|
||||
meta: {
|
||||
icon: {
|
||||
type: "elem",
|
||||
value: "House",
|
||||
},
|
||||
},
|
||||
component: () => import("@/pages/main/index.vue"),
|
||||
},
|
||||
{
|
||||
path: "/system",
|
||||
name: "系统设置",
|
||||
meta: {
|
||||
icon: {
|
||||
type: "elem",
|
||||
value: "Setting",
|
||||
},
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: "/account",
|
||||
name: "用户管理",
|
||||
meta: {
|
||||
icon: {
|
||||
type: "elem",
|
||||
value: "User",
|
||||
},
|
||||
},
|
||||
component: () => import("@/pages/system/user/index.vue"),
|
||||
},
|
||||
{
|
||||
path: "/role",
|
||||
name: "角色管理",
|
||||
meta: {
|
||||
icon: {
|
||||
type: "elem",
|
||||
value: "Avatar",
|
||||
},
|
||||
},
|
||||
component: () => import("@/pages/system/role/index.vue"),
|
||||
},
|
||||
{
|
||||
path: "/menue",
|
||||
name: "菜单管理",
|
||||
meta: {
|
||||
icon: {
|
||||
type: "elem",
|
||||
value: "Menu",
|
||||
},
|
||||
},
|
||||
component: () => import("@/pages/system/menue/index.vue"),
|
||||
},
|
||||
{
|
||||
path: "/personal",
|
||||
name: "个人中心",
|
||||
meta: {
|
||||
icon: {
|
||||
type: "elem",
|
||||
value: "UserFilled",
|
||||
},
|
||||
},
|
||||
component: () => import("@/pages/system/user/personal.vue"),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "/serviceList",
|
||||
name: "服务项目",
|
||||
meta: {
|
||||
icon: {
|
||||
type: "elem",
|
||||
},
|
||||
},
|
||||
component: () => import("@/pages/serviceList/serviceList.vue"),
|
||||
},
|
||||
{
|
||||
path: "/funeralRetail",
|
||||
name: "殡仪零售",
|
||||
meta: {
|
||||
icon: {
|
||||
type: "svg",
|
||||
value: "零售",
|
||||
},
|
||||
},
|
||||
component: () => import("@/pages/funeralRetail/funeralRetail.vue"),
|
||||
},
|
||||
{
|
||||
path: "/funeralServices",
|
||||
name: "殡仪服务",
|
||||
meta: {
|
||||
icon: {
|
||||
type: "svg",
|
||||
value: "服务.svg",
|
||||
},
|
||||
},
|
||||
component: () => import("@/pages/funeralServices/funeralServices.vue"),
|
||||
},
|
||||
{
|
||||
path: "/checkout",
|
||||
name: "结账处理",
|
||||
meta: {
|
||||
icon: {
|
||||
type: "svg",
|
||||
value: "结账.svg",
|
||||
},
|
||||
},
|
||||
component: () => import("@/pages/checkout/checkout.vue"),
|
||||
},
|
||||
{
|
||||
path: "/invalidReview",
|
||||
name: "作废审核",
|
||||
meta: {
|
||||
icon: {
|
||||
type: "svg",
|
||||
value: "作废.svg",
|
||||
},
|
||||
},
|
||||
component: () => import("@/pages/invalidReview/invalidReview.vue"),
|
||||
},
|
||||
{
|
||||
path: "/funeralRetail",
|
||||
name: "零售管理",
|
||||
meta: {
|
||||
icon: {
|
||||
type: "svg",
|
||||
value: "零售.svg",
|
||||
},
|
||||
},
|
||||
component: () => import("@/pages/funeralRetail/funeralRetail.vue"),
|
||||
children: [
|
||||
{
|
||||
path: "/departedSaint",
|
||||
name: "逝者零售管理",
|
||||
meta: {
|
||||
icon: {
|
||||
type: "svg",
|
||||
value: "零售管理.svg",
|
||||
},
|
||||
},
|
||||
component: () =>
|
||||
import("@/pages/funeralRetail/departedSaint/departedSaint.vue"),
|
||||
},
|
||||
{
|
||||
path: "/noDepartedSaint",
|
||||
name: "无逝者零售登记",
|
||||
meta: {
|
||||
icon: {
|
||||
type: "svg",
|
||||
value: "登记.svg",
|
||||
},
|
||||
},
|
||||
component: () =>
|
||||
import(
|
||||
"@/pages/funeralRetail/noDepartedSaint/noDepartedSaint.vue"
|
||||
),
|
||||
},
|
||||
{
|
||||
path: "/saintCheckout",
|
||||
name: "零售结算",
|
||||
meta: {
|
||||
icon: {
|
||||
type: "svg",
|
||||
value: "结算.svg",
|
||||
},
|
||||
},
|
||||
component: () =>
|
||||
import("@/pages/funeralRetail/saintCheckout/saintCheckout.vue"),
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
path: "/statistics",
|
||||
name: "后台统计",
|
||||
meta: {
|
||||
icon: {
|
||||
type: "svg",
|
||||
value: "统计.svg",
|
||||
},
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: "/sales",
|
||||
name: "销售统计报表",
|
||||
meta: {
|
||||
icon: {
|
||||
type: "svg",
|
||||
value: "销售统计.svg",
|
||||
},
|
||||
},
|
||||
component: () => import("@/pages/statistics/sales/sales.vue"),
|
||||
},
|
||||
{
|
||||
path: "/saleDetail",
|
||||
name: "公司销售明细",
|
||||
meta: {
|
||||
icon: {
|
||||
type: "svg",
|
||||
value: "销售明细.svg",
|
||||
},
|
||||
},
|
||||
component: () =>
|
||||
import("@/pages/statistics/saleDetail/saleDetail.vue"),
|
||||
},
|
||||
// {
|
||||
// path: "/guideDetail",
|
||||
// name: "引导员销售统计表",
|
||||
// meta: {
|
||||
// icon: {
|
||||
// type: "elem",
|
||||
// value: "Menu",
|
||||
// },
|
||||
// },
|
||||
// component: () =>
|
||||
// import("@/pages/statistics/guideDetail/guideDetail.vue"),
|
||||
// },
|
||||
{
|
||||
path: "/dayIncome",
|
||||
name: "公司日收入统计表",
|
||||
meta: {
|
||||
icon: {
|
||||
type: "svg",
|
||||
value: "日收入.svg",
|
||||
},
|
||||
},
|
||||
component: () =>
|
||||
import("@/pages/statistics/dayIncome/dayIncome.vue"),
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHashHistory(),
|
||||
routes,
|
||||
});
|
||||
|
||||
export default router;
|
||||
46
frontEnd/src/store/index.ts
Normal file
46
frontEnd/src/store/index.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import { defineStore } from "pinia"
|
||||
import { RouteRecordRaw } from "vue-router";
|
||||
|
||||
interface globalState {
|
||||
loadingShow: boolean;
|
||||
globalLodingShow: boolean;
|
||||
globalLodingShowText: string;
|
||||
currentMenue: RouteRecordRaw | null;
|
||||
historyRouterPath: string;
|
||||
loadingText: string
|
||||
}
|
||||
export const globalState = defineStore('globalState', {
|
||||
state(): globalState{
|
||||
return {
|
||||
loadingShow: false,
|
||||
loadingText: '',
|
||||
currentMenue: null,
|
||||
historyRouterPath: '/',
|
||||
globalLodingShow: false,
|
||||
globalLodingShowText: ""
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
setLoadingShow(state: boolean, showText = '请稍候...' ) {
|
||||
this.loadingShow = state;
|
||||
this.loadingText = showText;
|
||||
},
|
||||
toggleLoadingShow() {
|
||||
this.loadingShow = !this.loadingShow;
|
||||
},
|
||||
setSelectMenue(menue: RouteRecordRaw) {
|
||||
this.currentMenue = menue;
|
||||
},
|
||||
setHistoryRouterPath(path: string) {
|
||||
this.historyRouterPath = path;
|
||||
localStorage.setItem('historyRouterPath', path);
|
||||
},
|
||||
setLoadingText(text:string) {
|
||||
this.loadingText = text;
|
||||
},
|
||||
setGlobalLoadingShow(state: boolean, showText = '请稍候...') {
|
||||
this.globalLodingShow = state;
|
||||
this.globalLodingShowText = showText;
|
||||
}
|
||||
}
|
||||
})
|
||||
44
frontEnd/src/store/user/user.ts
Normal file
44
frontEnd/src/store/user/user.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import { defineStore } from "pinia";
|
||||
import { userType } from "@/types/user";
|
||||
|
||||
interface user {
|
||||
userInfor: userType;
|
||||
token: string | undefined;
|
||||
refreshToken: string | undefined;
|
||||
}
|
||||
|
||||
export const userInfor = defineStore("userInfor", {
|
||||
state(): user {
|
||||
return {
|
||||
userInfor: {
|
||||
name: "",
|
||||
},
|
||||
token: "",
|
||||
refreshToken: "",
|
||||
};
|
||||
},
|
||||
actions: {
|
||||
setLoginState(userData: userType) {
|
||||
this.userInfor = userData;
|
||||
localStorage.setItem("userInfor", JSON.stringify(userData));
|
||||
},
|
||||
removeLoginState() {
|
||||
localStorage.removeItem("userInfor");
|
||||
},
|
||||
setToken(token: string) {
|
||||
this.token = token;
|
||||
localStorage.setItem("token", token);
|
||||
},
|
||||
setRefToken(toekn: string) {
|
||||
this.refreshToken = toekn;
|
||||
localStorage.setItem("refreshToken", toekn);
|
||||
},
|
||||
removeToken() {
|
||||
this.token = undefined;
|
||||
this.refreshToken = undefined;
|
||||
localStorage.removeItem("token");
|
||||
localStorage.removeItem("refreshToken");
|
||||
localStorage.removeItem("historyRouterPath");
|
||||
},
|
||||
},
|
||||
});
|
||||
82
frontEnd/src/style.css
Normal file
82
frontEnd/src/style.css
Normal file
@@ -0,0 +1,82 @@
|
||||
:root {
|
||||
font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
font-weight: 400;
|
||||
|
||||
color-scheme: light dark;
|
||||
color: rgba(255, 255, 255, 0.87);
|
||||
background-color: #242424;
|
||||
|
||||
font-synthesis: none;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
* {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
box-sizing: border-box;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
ul {
|
||||
list-style: none;
|
||||
}
|
||||
a {
|
||||
font-weight: 500;
|
||||
color: #646cff;
|
||||
text-decoration: inherit;
|
||||
}
|
||||
a:hover {
|
||||
color: #535bf2;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
display: flex;
|
||||
place-items: center;
|
||||
min-width: 320px;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 3.2em;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: 8px;
|
||||
border: 1px solid transparent;
|
||||
padding: 0.6em 1.2em;
|
||||
font-size: 1em;
|
||||
font-weight: 500;
|
||||
font-family: inherit;
|
||||
background-color: #1a1a1a;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.25s;
|
||||
}
|
||||
button:hover {
|
||||
border-color: #646cff;
|
||||
}
|
||||
button:focus,
|
||||
button:focus-visible {
|
||||
outline: 4px auto -webkit-focus-ring-color;
|
||||
}
|
||||
|
||||
.card {
|
||||
padding: 2em;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
:root {
|
||||
color: #213547;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
a:hover {
|
||||
color: #747bff;
|
||||
}
|
||||
button {
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
}
|
||||
101
frontEnd/src/types/global.ts
Normal file
101
frontEnd/src/types/global.ts
Normal file
@@ -0,0 +1,101 @@
|
||||
declare global {
|
||||
interface Product {
|
||||
id?: number; // 商品ID
|
||||
name: string; // 商品名称
|
||||
parentId?: string; // 商品分类
|
||||
group?: string; // 商品分组
|
||||
price: number; // 商品价格
|
||||
unit: string; // 计量单位
|
||||
image?: string; // 商品图片路径
|
||||
quantity: number; // 商品数量
|
||||
remark?: string; // 标注
|
||||
}
|
||||
|
||||
interface RegisForm {
|
||||
id?: number;
|
||||
deceasedId?: number;
|
||||
name: string; // 逝者姓名
|
||||
idNumber: string; // 证件号码
|
||||
gender: string; // 性别
|
||||
age: number; // 年龄
|
||||
buyer: string; // 购买人
|
||||
purchaseDate: string; // 购买日期 (格式为 YYYY-MM-DD)
|
||||
handler: string; // 经办人 (数据库字段为 handler,不是 handler)
|
||||
salesAmount: number; // 销售金额
|
||||
guide: string; // 引导员
|
||||
familyName: string;
|
||||
familyPhone: string;
|
||||
services?: ServiceItemType[];
|
||||
retailState?: number;
|
||||
province?: string; // 所在省
|
||||
city?: string; // 所在市
|
||||
area?: string; // 所在区域
|
||||
address?: string; // 详细地址
|
||||
serviceItems: ServiceItemType[] | string; // 服务项目列表 (数据库字段为 service_items)
|
||||
type: number;
|
||||
retailId?: number;
|
||||
deceasedName?: string;
|
||||
}
|
||||
|
||||
type RegistrationType =
|
||||
| "服务登记"
|
||||
| "零售登记"
|
||||
| "修改登记"
|
||||
| "零售结账"
|
||||
| "服务修改";
|
||||
|
||||
interface PaymentForm {
|
||||
checkoutDate: string; // 结账日期
|
||||
handler: string; // 经办人
|
||||
settlementDate: string; // 结算日期
|
||||
cashAmount: number; // 现金金额
|
||||
unionPayAmount: number; // 银联支付金额
|
||||
cardAmount: number; // 刷卡金额
|
||||
publicTransferAmount: number; // 对公转账金额
|
||||
workshopPayment: NumberConstructor; // 车间支付
|
||||
}
|
||||
|
||||
interface ServiceItemType {
|
||||
name: string; // 服务项目名称
|
||||
quantity: number; // 数量
|
||||
unit: string; // 单位
|
||||
price: number; // 售价
|
||||
remark: string; // 备注
|
||||
category: number; // 关联的分类信息
|
||||
createDate?: string; // 创建时间
|
||||
updateDate?: string; // 更新时间
|
||||
}
|
||||
|
||||
export interface DeceasedRetail {
|
||||
/** 逝者ID */
|
||||
deceased: number;
|
||||
|
||||
/** 购买人 */
|
||||
buyer: string;
|
||||
|
||||
/** 购买日期(格式化为 YYYY-MM-DD HH:mm:ss) */
|
||||
purchaseDate: string;
|
||||
|
||||
/** 经办人 */
|
||||
handler: string;
|
||||
|
||||
/** 销售金额(精确到小数点后两位) */
|
||||
salesAmount: number;
|
||||
|
||||
/** 引导员 */
|
||||
guide: string;
|
||||
|
||||
/** 服务项目列表 */
|
||||
serviceItems: string[];
|
||||
|
||||
/** 结账状态(0:未结账,1:已结账) */
|
||||
retailState: number;
|
||||
}
|
||||
|
||||
interface guideOption {
|
||||
value: number;
|
||||
label: string;
|
||||
}
|
||||
}
|
||||
|
||||
export {};
|
||||
7
frontEnd/src/types/role.ts
Normal file
7
frontEnd/src/types/role.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
export type roleType = {
|
||||
name?: string;
|
||||
roleState?: number;
|
||||
values?: string;
|
||||
createDate?:string;
|
||||
id?:number;
|
||||
}
|
||||
9
frontEnd/src/types/systemMenue.ts
Normal file
9
frontEnd/src/types/systemMenue.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
export type systemMenueType = {
|
||||
name?: string;
|
||||
path?: string;
|
||||
parentId?: number;
|
||||
icon?: string;
|
||||
show?: boolean;
|
||||
id?:number;
|
||||
children?: systemMenueType[];
|
||||
}
|
||||
17
frontEnd/src/types/table.ts
Normal file
17
frontEnd/src/types/table.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { userType } from "./user";
|
||||
|
||||
export type tableDataType = {
|
||||
data: Array<userType | any>;
|
||||
total: number;
|
||||
pageNumber: number;
|
||||
pageSize: number;
|
||||
}
|
||||
|
||||
export type tableOptionType = {
|
||||
url: string;
|
||||
showPagination?: boolean;
|
||||
searchParams: object;
|
||||
searchUrl: string;
|
||||
resizeTable?: boolean;
|
||||
executeType?: "reset" | "list" | "search";
|
||||
};
|
||||
18
frontEnd/src/types/user.ts
Normal file
18
frontEnd/src/types/user.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { systemMenueType } from "./systemMenue";
|
||||
export type userType = {
|
||||
id?: number;
|
||||
name?: string; // 姓名
|
||||
sex?: string | number | undefined;
|
||||
phone?: string;
|
||||
createDate?: string;
|
||||
userState?: boolean | number; // 账户状态
|
||||
role?: number | string; // 角色
|
||||
birthday?: string; // 生日
|
||||
age?: number | string; // 年龄
|
||||
province?: string; // 所在省
|
||||
city?: string; // 所在市
|
||||
area?: string; // 所在区域
|
||||
address?: string; // 详细地址
|
||||
routerMenue?: systemMenueType[];
|
||||
pwd?: string;
|
||||
};
|
||||
11
frontEnd/src/util/globalComponents.ts
Normal file
11
frontEnd/src/util/globalComponents.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { App, defineAsyncComponent, defineComponent } from "vue"
|
||||
|
||||
const modulesComponent = import.meta.glob('../components/**/**.vue');
|
||||
|
||||
const install = (app: App) => {
|
||||
for(const [key , value] of Object.entries(modulesComponent)) {
|
||||
const name = key.slice(key.lastIndexOf('/') + 1, key.lastIndexOf('.'));
|
||||
app.component(name, defineAsyncComponent(value))
|
||||
}
|
||||
}
|
||||
export default install
|
||||
15
frontEnd/src/util/globalMethods.ts
Normal file
15
frontEnd/src/util/globalMethods.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
//重置对象属性
|
||||
export function resetParams(params: { [key: string]: any }) {
|
||||
Object.keys(params).forEach((key: string) => {
|
||||
let keyVal = params[key];
|
||||
let type = typeof keyVal;
|
||||
if (type === "undefined") params[key] = undefined;
|
||||
if (type === "string") params[key] = "";
|
||||
if (type === "number") params[key] = 0;
|
||||
if (type === "object") {
|
||||
if (Array.isArray(keyVal)) params[key] = [];
|
||||
if (Object.prototype.toString.call(keyVal) === "[object Object]")
|
||||
params[key] = {};
|
||||
}
|
||||
});
|
||||
}
|
||||
7
frontEnd/src/vite-env.d.ts
vendored
Normal file
7
frontEnd/src/vite-env.d.ts
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
/// <reference types="vite/client" />
|
||||
|
||||
declare module '*.vue' {
|
||||
import type { DefineComponent } from 'vue'
|
||||
const component: DefineComponent<{}, {}, any>
|
||||
export default component
|
||||
}
|
||||
Reference in New Issue
Block a user