mirror of
https://gitee.com/beijing_hongye_huicheng/lilishop-ui.git
synced 2026-06-21 17:40:25 +08:00
Merge branch 'master' of gitee.com:beijing_hongye_huicheng/lilishop-ui
This commit is contained in:
73
README.md
73
README.md
@@ -1,16 +1,12 @@
|
||||
## Lilishop B2B2C商城系统
|
||||
|
||||
#### 欢迎交流需求,交流业务,交流技术(基础问题自行解决,其他问题先看文档后提问)
|
||||
|
||||
#### 不用削尖脑袋往老群里加,老群活跃度较低,很多潜水党,新群相对而言活跃一些 :tw-1f606: :tw-1f606: :tw-1f606: :tw-1f606: :tw-1f606: :tw-1f606:
|
||||
|
||||
#### PS: **演示站点所有环境均部署master分支。如果有演示站点问题,可以反馈,如果演示站点没问题本地运行有问题,需自行处理**
|
||||
|
||||
##### 交流 qq 1群 961316482(已满)
|
||||
##### 交流 qq 2群 875294241(已满)
|
||||
##### 交流 qq 3群 263785057(已满)
|
||||
##### 交流 qq 4群 674617534 (已满)
|
||||
##### 交流 qq 5群 594675235
|
||||
- **[在线客服](https://work.weixin.qq.com/kfid/kfc4d8dc24a73c15f44)**
|
||||
- **微信交流1群(已满)**
|
||||
- **微信交流2群**:
|
||||

|
||||
|
||||
##### 体验 公众号/小程序/APP 体验,扫描二维码
|
||||
|
||||
@@ -19,6 +15,41 @@
|
||||
[](https://gitee.com/beijing_hongye_huicheng/lilishop/stargazers)
|
||||

|
||||
|
||||
## 2025-10-10日更新
|
||||
兼容更高的node版本16
|
||||
|
||||
这里我用的是node版本 v16.20.2
|
||||
|
||||
npm版本 8.19.4
|
||||
|
||||
使用yarn install 然后执行 yarn dev
|
||||
|
||||
yarn 安装/启动
|
||||
```
|
||||
// 如果没有 yarn 安装yarn
|
||||
npm install yarn -g
|
||||
|
||||
// 切换源
|
||||
yarn config set registry https://registry.npmmirror.com
|
||||
|
||||
// 以buyer项目为例
|
||||
cd buyer
|
||||
|
||||
yarn install
|
||||
|
||||
yarn dev
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
没有二开过的项目直接拉最新代码即可,二开项目可以跟着提交记录一起同步修改 install出现问题检查的话删除 "package-lock.json" 重新install
|
||||
|
||||
Q&A 为什么不升级更高的node版本? :因为高node版本 OpenSSL 改动 导致旧版本 Webpack 插件会失效 试了好几次如果兼容的话 需要升级Webpack5以及其他的插件 升级内容较多 为了更稳定的还是尽量少动为主
|
||||
|
||||
****
|
||||
|
||||
|
||||
## 如何在本地环境运行lilishop-ui部署视频
|
||||
https://www.bilibili.com/video/BV1B28EeJEnP/
|
||||
|
||||
@@ -29,8 +60,11 @@ https://www.bilibili.com/video/BV1WD87eoE9F/
|
||||
## 开发项目
|
||||
|
||||
#### 安装Node.js
|
||||
|
||||
保证`node`版本`14`,推荐 14.17.0
|
||||
|
||||
2025-10-10日拉的代码之后不限制于node版本为14,这里只是以14版本为例子
|
||||
|
||||
可以使用 `yarn` 或者 `npm` 进行安装
|
||||
|
||||
#### yarn 安装/启动
|
||||
@@ -49,17 +83,6 @@ yarn install
|
||||
yarn dev
|
||||
```
|
||||
|
||||
#### npm 安装/启动
|
||||
```
|
||||
npm config set registry https://registry.npmmirror.com
|
||||
|
||||
// 以buyer项目为例
|
||||
cd buyer
|
||||
|
||||
npm run install
|
||||
|
||||
npm run dev
|
||||
```
|
||||
|
||||
#### FAQ
|
||||
|
||||
@@ -223,19 +246,9 @@ PS:手机验证码为 ‘111111’
|
||||
|
||||
4.限制商用,如果需要商业使用请联系我们。QQ3409056806.或者加入qq群联系群主。
|
||||
|
||||
|
||||
|
||||
### 交流群
|
||||
|
||||
##### 交流 qq 1群 961316482(已满)
|
||||
##### 交流 qq 2群 875294241(已满)
|
||||
##### 交流 qq 3群 263785057(已满)
|
||||
##### 交流 qq 4群 674617534(已满)
|
||||
##### 交流 qq 5群 594675235
|
||||
|
||||
### 附录
|
||||
有人有自己的学习视频、学习记录文档、希望宣传关联开源项目等均可以私聊仓库所有者。
|
||||
|
||||
类似:
|
||||
|
||||
清晨敲代码同学的分析: https://blog.csdn.net/vaevaevae233/category_12103567.html
|
||||
清晨敲代码同学的分析: https://blog.csdn.net/vaevaevae233/category_12103567.html
|
||||
|
||||
1
buyer/.npmrc
Normal file
1
buyer/.npmrc
Normal file
@@ -0,0 +1 @@
|
||||
engine-strict=false
|
||||
1
buyer/.yarnrc
Normal file
1
buyer/.yarnrc
Normal file
@@ -0,0 +1 @@
|
||||
--ignore-engines true
|
||||
@@ -1,19 +0,0 @@
|
||||
# new
|
||||
|
||||
## Project setup
|
||||
```
|
||||
npm install
|
||||
```
|
||||
|
||||
### Compiles and hot-reloads for development
|
||||
```
|
||||
npm run serve
|
||||
```
|
||||
|
||||
### Compiles and minifies for production
|
||||
```
|
||||
npm run build
|
||||
```
|
||||
|
||||
### Customize configuration
|
||||
See [Configuration Reference](https://cli.vuejs.org/config/).
|
||||
|
||||
@@ -3,9 +3,12 @@
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vue-cli-service serve",
|
||||
"serve": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build"
|
||||
"build": "vue-cli-service build",
|
||||
"dev": "vue-cli-service serve"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"dependencies": {
|
||||
"@amap/amap-jsapi-loader": "0.0.7",
|
||||
@@ -15,11 +18,10 @@
|
||||
"less": "^2.7.0",
|
||||
"less-loader": "^5.0.0",
|
||||
"mv-count-down": "^0.1.15",
|
||||
"node-sass": "^4.14.1",
|
||||
"postcss-loader": "^7.0.1",
|
||||
"sass": "^1.63.6",
|
||||
"postcss-loader": "^4.3.0",
|
||||
"psl": "^1.8.0",
|
||||
"qs": "^6.9.4",
|
||||
"sass-loader": "^7.3.1",
|
||||
"uuid": "^8.3.2",
|
||||
"view-design": "^4.3.2",
|
||||
"vue": "^2.6.11",
|
||||
@@ -32,7 +34,7 @@
|
||||
"devDependencies": {
|
||||
"@vue/cli-service": "~4.5.0",
|
||||
"compression-webpack-plugin": "^5.0.0",
|
||||
"sass-loader": "^7.3.1",
|
||||
"sass-loader": "^10.4.1",
|
||||
"uglifyjs-webpack-plugin": "^2.2.0",
|
||||
"vue-template-compiler": "^2.6.11"
|
||||
},
|
||||
@@ -40,5 +42,10 @@
|
||||
"> 1%",
|
||||
"last 2 versions",
|
||||
"not dead"
|
||||
]
|
||||
],
|
||||
"resolutions": {
|
||||
"minimatch": "^3.1.2",
|
||||
"node-sass": "npm:sass@^1.63.6",
|
||||
"@achrinza/node-ipc": "9.2.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,6 +69,32 @@ export function loginCallback (uuid) {
|
||||
});
|
||||
}
|
||||
|
||||
export function getThirdAccountBindList () {
|
||||
return request({
|
||||
url: '/buyer/passport/connect/bind/list',
|
||||
method: Method.GET,
|
||||
needToken: true
|
||||
});
|
||||
}
|
||||
|
||||
export function bindThirdAccount (data) {
|
||||
return request({
|
||||
url: '/buyer/passport/connect/bind',
|
||||
method: Method.POST,
|
||||
needToken: true,
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
export function unbindThirdAccount (data) {
|
||||
return request({
|
||||
url: '/buyer/passport/connect/bind/unbind',
|
||||
method: Method.POST,
|
||||
needToken: true,
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 忘记密码 验证手机验证码
|
||||
*/
|
||||
@@ -109,3 +135,12 @@ export function sCLogin(token,params) {
|
||||
params
|
||||
});
|
||||
}
|
||||
|
||||
export function getWechatH5QrCode (params) {
|
||||
return request({
|
||||
url: '/buyer/other/wechat/h5/qrcode',
|
||||
method: Method.GET,
|
||||
needToken: true,
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
@@ -180,6 +180,15 @@ export function receiptList () {
|
||||
});
|
||||
}
|
||||
|
||||
// 发票详情
|
||||
export function receiptDetail (id) {
|
||||
return request({
|
||||
url: `/buyer/trade/receipt/${id}`,
|
||||
method: Method.GET,
|
||||
needToken: true
|
||||
});
|
||||
}
|
||||
|
||||
// 保存发票信息
|
||||
export function saveReceipt (params) {
|
||||
return request({
|
||||
@@ -480,6 +489,31 @@ export function memberPointHistory (params) {
|
||||
params
|
||||
});
|
||||
}
|
||||
|
||||
export function memberGradeCurrent (params) {
|
||||
return request({
|
||||
url: `/buyer/member/memberGrade/current`,
|
||||
method: Method.GET,
|
||||
needToken: true,
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
export function memberGradeRules () {
|
||||
return request({
|
||||
url: `/buyer/member/memberGrade/rules`,
|
||||
method: Method.GET,
|
||||
needToken: true
|
||||
})
|
||||
}
|
||||
|
||||
export function memberGradeList () {
|
||||
return request({
|
||||
url: `/buyer/member/memberGrade/list`,
|
||||
method: Method.GET,
|
||||
needToken: true
|
||||
})
|
||||
}
|
||||
/**
|
||||
* 分页获取会员站内信
|
||||
* @param {Object} params 请求参数,包括pageNumber、pageSize、status
|
||||
|
||||
@@ -173,7 +173,7 @@ export default {
|
||||
border-radius: 18.9px;
|
||||
|
||||
|
||||
/deep/ .ivu-input.ivu-input-large {
|
||||
::v-deep .ivu-input.ivu-input-large {
|
||||
border: 1.4px solid $theme_color;
|
||||
box-sizing: border-box;
|
||||
border-radius: 19.6px;
|
||||
@@ -188,7 +188,7 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
/deep/ .ivu-input-group-append {
|
||||
::v-deep .ivu-input-group-append {
|
||||
border-radius: 19.6px !important;
|
||||
cursor: pointer;
|
||||
box-sizing: border-box;
|
||||
|
||||
@@ -113,12 +113,12 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
/deep/ .ivu-card, .ivu-card-head, ._Card {
|
||||
::v-deep .ivu-card, .ivu-card-head, ._Card {
|
||||
margin-bottom: 20px;
|
||||
@include white_background_color();
|
||||
}
|
||||
|
||||
/deep/ .ivu-card-head {
|
||||
::v-deep .ivu-card-head {
|
||||
position: relative;
|
||||
padding: 0 14px;
|
||||
height: 50px;
|
||||
@@ -140,7 +140,7 @@ export default {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/deep/ .ivu-card-body {
|
||||
::v-deep .ivu-card-body {
|
||||
padding: 0 !important;
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -147,11 +147,11 @@ export default {
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
/deep/.popup .ivu-drawer-body{
|
||||
::v-deep.popup .ivu-drawer-body{
|
||||
padding: 0!important;
|
||||
background-color: #eee;
|
||||
}
|
||||
/deep/.popup .ivu-drawer-wrap{
|
||||
::v-deep.popup .ivu-drawer-wrap{
|
||||
z-index: 3001;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -87,14 +87,12 @@
|
||||
</div>
|
||||
</TabPane>
|
||||
<TabPane label="商品参数">
|
||||
<template v-if="detail.goodsParamsDTOList && detail.goodsParamsDTOList.length">
|
||||
<div class="goods-params" style="height:inherit;" v-for="item in detail.goodsParamsDTOList" :key="item.groupId">
|
||||
<span class="ml_10">{{item.groupName}}</span>
|
||||
<table class="mb_10" cellpadding='0' cellspacing="0" >
|
||||
<tr v-for="param in item.goodsParamsItemDTOList" :key="param.paramId">
|
||||
<td style="text-align: center">{{param.paramName}}</td><td>{{param.paramValue}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
<template v-if="goodsParamsList.length">
|
||||
<div class="item-param-container">
|
||||
<div class="item-param-box" v-for="param in goodsParamsList" :key="param.paramId || param.paramName">
|
||||
<span class="item-param-title">{{ param.paramName }}:</span>
|
||||
<span class="item-param-content">{{ param.paramValue || '-' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<div v-else>暂无商品参数</div>
|
||||
@@ -134,6 +132,29 @@ export default {
|
||||
// 商品详情
|
||||
skuDetail () {
|
||||
return this.detail.data;
|
||||
},
|
||||
goodsParamsList () {
|
||||
const list = this.detail && Array.isArray(this.detail.goodsParamsDTOList) ? this.detail.goodsParamsDTOList : [];
|
||||
const flat = [];
|
||||
|
||||
list.forEach((item) => {
|
||||
if (!item) return;
|
||||
if (Array.isArray(item.goodsParamsItemDTOList)) {
|
||||
flat.push(...item.goodsParamsItemDTOList);
|
||||
} else {
|
||||
flat.push(item);
|
||||
}
|
||||
});
|
||||
|
||||
const cleaned = flat.filter((p) => p && (p.paramName || p.paramId));
|
||||
const hasSort = cleaned.some((p) => p && p.sort !== undefined && p.sort !== null);
|
||||
if (!hasSort) return cleaned;
|
||||
|
||||
return cleaned.slice().sort((a, b) => {
|
||||
const sa = Number(a && a.sort) || 0;
|
||||
const sb = Number(b && b.sort) || 0;
|
||||
return sa - sb;
|
||||
});
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -326,7 +347,7 @@ export default {
|
||||
.item-intro-img {
|
||||
width: 100%;
|
||||
min-height: 300px;
|
||||
/deep/ img{
|
||||
::v-deep img{
|
||||
margin:0 auto;
|
||||
}
|
||||
}
|
||||
@@ -336,14 +357,12 @@ export default {
|
||||
/************* 商品参数 *************/
|
||||
.item-param-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
flex-direction: column;
|
||||
}
|
||||
.item-param-box {
|
||||
padding: 5px;
|
||||
padding-left: 30px;
|
||||
width: 240px;
|
||||
width: 100%;
|
||||
height: 36px;
|
||||
font-size: 14px;
|
||||
}
|
||||
@@ -472,7 +491,7 @@ export default {
|
||||
.ivu-tabs-ink-bar {
|
||||
background-color: $theme_color !important;
|
||||
}
|
||||
/deep/.ivu-tabs-bar{
|
||||
::v-deep.ivu-tabs-bar{
|
||||
border: none;
|
||||
}
|
||||
.item-tabs > .ivu-tabs > .ivu-tabs-bar .ivu-tabs-tab{
|
||||
|
||||
@@ -84,10 +84,10 @@ export default {
|
||||
border-top: 1.4px solid #e2e2e2;
|
||||
}
|
||||
&:hover {
|
||||
/deep/ .goods-name {
|
||||
::v-deep .goods-name {
|
||||
color: $theme_color;
|
||||
}
|
||||
/deep/ .goods-desc {
|
||||
::v-deep .goods-desc {
|
||||
color: $theme_color;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,39 +1,83 @@
|
||||
<template>
|
||||
<div class="invoice-modal">
|
||||
<Modal v-model="invoiceAvailable" width="600" footer-hide>
|
||||
<Modal v-model="invoiceAvailable" width="640" footer-hide>
|
||||
<p slot="header">
|
||||
<span>发票信息</span>
|
||||
</p>
|
||||
<!-- 普通发票 -->
|
||||
<div class="nav-content">
|
||||
<Form :model="invoiceForm" ref="form" label-position="left" :rules="ruleInline" :label-width="110">
|
||||
<Form :model="invoiceForm" ref="form" label-position="left" :rules="formRules" :label-width="118">
|
||||
<FormItem label="发票类型">
|
||||
<RadioGroup v-model="invoice" type="button" button-style="solid">
|
||||
<Radio @on-change="changeInvoice" :label="1">电子普通发票</Radio>
|
||||
<Radio :label="2" :disabled="true">增值税专用发票</Radio>
|
||||
</RadioGroup>
|
||||
</FormItem>
|
||||
<FormItem label="发票抬头">
|
||||
<RadioGroup v-model="type" @on-change="changeInvoice" type="button" button-style="solid">
|
||||
<Radio :label="1">个人</Radio>
|
||||
<Radio :label="2">单位</Radio>
|
||||
</RadioGroup>
|
||||
</FormItem>
|
||||
<FormItem label="个人名称" v-if="type === 1" prop="receiptTitle">
|
||||
<i-input v-model="invoiceForm.receiptTitle"></i-input>
|
||||
</FormItem>
|
||||
<FormItem label="单位名称" v-if="type === 2" prop="receiptTitle">
|
||||
<i-input v-model="invoiceForm.receiptTitle"></i-input>
|
||||
</FormItem>
|
||||
<FormItem label="纳税人识别号" v-if="type === 2" prop="taxpayerId">
|
||||
<i-input v-model="invoiceForm.taxpayerId"></i-input>
|
||||
</FormItem>
|
||||
<FormItem label="发票内容">
|
||||
<RadioGroup v-model="invoiceForm.receiptContent" type="button" button-style="solid">
|
||||
<Radio label="商品明细">商品明细</Radio>
|
||||
<Radio label="商品类别">商品类别</Radio>
|
||||
<RadioGroup v-model="invoice" type="button" button-style="solid" @on-change="onInvoiceKindChange">
|
||||
<Radio :label="1">电子普通发票</Radio>
|
||||
<Radio :label="2">增值税专用发票</Radio>
|
||||
</RadioGroup>
|
||||
</FormItem>
|
||||
|
||||
<!-- 电子普通发票 -->
|
||||
<div v-if="invoice === 1" key="invoice-normal">
|
||||
<FormItem label="发票抬头">
|
||||
<RadioGroup v-model="type" type="button" button-style="solid" @on-change="onHeaderTypeChange">
|
||||
<Radio :label="1">个人</Radio>
|
||||
<Radio :label="2">单位</Radio>
|
||||
</RadioGroup>
|
||||
</FormItem>
|
||||
<FormItem :label="type === 1 ? '个人名称' : '单位名称'" :prop="type === 1 ? 'personalName' : 'companyName'">
|
||||
<i-input v-if="type === 1" v-model="invoiceForm.personalName"></i-input>
|
||||
<i-input v-else v-model="invoiceForm.companyName"></i-input>
|
||||
</FormItem>
|
||||
|
||||
<FormItem label="纳税人识别号" v-if="type === 2" prop="taxpayerId">
|
||||
<i-input v-model="invoiceForm.taxpayerId"></i-input>
|
||||
</FormItem>
|
||||
<FormItem label="发票内容">
|
||||
<RadioGroup v-model="invoiceForm.receiptContent" type="button" button-style="solid">
|
||||
<Radio label="商品明细">商品明细</Radio>
|
||||
<Radio label="商品类别">商品类别</Radio>
|
||||
</RadioGroup>
|
||||
</FormItem>
|
||||
<FormItem label="收票人手机" prop="receiptPhone">
|
||||
<i-input v-model="invoiceForm.receiptPhone"></i-input>
|
||||
</FormItem>
|
||||
<FormItem label="收票人邮箱" prop="receiptEmail">
|
||||
<i-input v-model="invoiceForm.receiptEmail" placeholder="可选"></i-input>
|
||||
</FormItem>
|
||||
</div>
|
||||
|
||||
<!-- 增值税专用发票(固定为单位) -->
|
||||
<div v-else key="invoice-vat">
|
||||
<FormItem label="发票抬头">
|
||||
<span class="inv-title-fixed">单位</span>
|
||||
</FormItem>
|
||||
<FormItem label="单位名称" prop="companyName">
|
||||
<i-input v-model="invoiceForm.companyName" placeholder="与营业执照一致"></i-input>
|
||||
</FormItem>
|
||||
<FormItem label="纳税人识别号" prop="taxpayerId">
|
||||
<i-input v-model="invoiceForm.taxpayerId"></i-input>
|
||||
</FormItem>
|
||||
<FormItem label="单位地址" prop="companyAddress">
|
||||
<i-input v-model="invoiceForm.companyAddress" placeholder="注册地址"></i-input>
|
||||
</FormItem>
|
||||
<FormItem label="单位电话" prop="companyPhone">
|
||||
<i-input v-model="invoiceForm.companyPhone" placeholder="固话或手机"></i-input>
|
||||
</FormItem>
|
||||
<FormItem label="开户银行" prop="bankName">
|
||||
<i-input v-model="invoiceForm.bankName"></i-input>
|
||||
</FormItem>
|
||||
<FormItem label="银行账号" prop="bankAccount">
|
||||
<i-input v-model="invoiceForm.bankAccount"></i-input>
|
||||
</FormItem>
|
||||
<FormItem label="发票内容">
|
||||
<RadioGroup v-model="invoiceForm.receiptContent" type="button" button-style="solid">
|
||||
<Radio label="商品明细">商品明细</Radio>
|
||||
</RadioGroup>
|
||||
</FormItem>
|
||||
<FormItem label="收票人手机" prop="receiptPhone">
|
||||
<i-input v-model="invoiceForm.receiptPhone"></i-input>
|
||||
</FormItem>
|
||||
<FormItem label="收票人邮箱" prop="receiptEmail">
|
||||
<i-input v-model="invoiceForm.receiptEmail" placeholder="可选"></i-input>
|
||||
</FormItem>
|
||||
</div>
|
||||
</Form>
|
||||
<div style="text-align: center">
|
||||
<Button type="primary" :loading="loading" @click="submit">保存发票信息</Button>
|
||||
@@ -45,106 +89,209 @@
|
||||
</template>
|
||||
<script>
|
||||
import { receiptSelect } from '@/api/cart.js';
|
||||
import { TINumber } from '@/plugins/RegExp.js';
|
||||
import { mobile, email } from '@/plugins/RegExp.js';
|
||||
|
||||
export default {
|
||||
name: 'invoiceModal',
|
||||
data () {
|
||||
return {
|
||||
invoice: 1, // 发票类型
|
||||
invoiceAvailable: false, // 模态框显隐
|
||||
loading: false, // 提交状态
|
||||
invoice: 1, // 1 电子普通发票 2 增值税专用发票
|
||||
invoiceAvailable: false,
|
||||
loading: false,
|
||||
invoiceForm: {
|
||||
// 普票表单
|
||||
receiptTitle: '', // 发票抬头
|
||||
taxpayerId: '', // 纳税人识别号
|
||||
receiptContent: '商品明细' // 发票内容
|
||||
receiptTitle: '',
|
||||
personalName: '',
|
||||
companyName: '',
|
||||
taxpayerId: '',
|
||||
receiptContent: '商品明细',
|
||||
receiptPhone: '',
|
||||
receiptEmail: '',
|
||||
companyAddress: '',
|
||||
companyPhone: '',
|
||||
bankName: '',
|
||||
bankAccount: ''
|
||||
},
|
||||
type: 1, // 1 个人 2 单位
|
||||
ruleInline: {
|
||||
taxpayerId: [
|
||||
{ required: true, message: '请填写纳税人识别号' },
|
||||
{ pattern: TINumber, message: '请填写正确的纳税人识别号' }
|
||||
]
|
||||
}
|
||||
type: 1
|
||||
};
|
||||
},
|
||||
props: ['invoiceData'],
|
||||
computed: {
|
||||
formRules () {
|
||||
const receiptPhoneRules = [
|
||||
{ required: true, message: '请填写收票人手机', trigger: 'blur' },
|
||||
{ pattern: mobile, message: '请填写正确的手机号码', trigger: 'blur' }
|
||||
];
|
||||
// 收票人邮箱可选:仅校验格式;提示文案须与手机区分,避免误用「请填写收票人手机」
|
||||
const receiptEmailRules = [
|
||||
{
|
||||
validator (rule, val, cb) {
|
||||
const s = val != null ? String(val).trim() : '';
|
||||
if (!s) {
|
||||
cb();
|
||||
return;
|
||||
}
|
||||
if (!email.test(s)) {
|
||||
cb(new Error('请填写正确的收票人邮箱'));
|
||||
return;
|
||||
}
|
||||
cb();
|
||||
},
|
||||
trigger: 'blur'
|
||||
}
|
||||
];
|
||||
|
||||
if (this.invoice === 2) {
|
||||
return {
|
||||
companyName: [{ required: true, message: '请填写单位名称', trigger: 'blur' }],
|
||||
taxpayerId: [{ required: true, message: '请填写纳税人识别号', trigger: 'blur' }],
|
||||
companyAddress: [{ required: true, message: '请填写单位地址', trigger: 'blur' }],
|
||||
companyPhone: [{ required: true, message: '请填写单位电话', trigger: 'blur' }],
|
||||
bankName: [{ required: true, message: '请填写开户银行', trigger: 'blur' }],
|
||||
bankAccount: [{ required: true, message: '请填写银行账号', trigger: 'blur' }],
|
||||
receiptPhone: receiptPhoneRules,
|
||||
receiptEmail: receiptEmailRules
|
||||
};
|
||||
}
|
||||
|
||||
const rules = {
|
||||
receiptPhone: receiptPhoneRules,
|
||||
receiptEmail: receiptEmailRules
|
||||
};
|
||||
if (this.type === 1) {
|
||||
rules.personalName = [{ required: true, message: '请填写个人名称', trigger: 'blur' }];
|
||||
} else {
|
||||
rules.companyName = [{ required: true, message: '请填写单位名称', trigger: 'blur' }];
|
||||
rules.taxpayerId = [{ required: true, message: '请填写纳税人识别号', trigger: 'blur' }];
|
||||
}
|
||||
return rules;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
// 回显的发票信息
|
||||
invoiceData: {
|
||||
handler (val) {
|
||||
this.invoiceForm = { ...val };
|
||||
if (!val) return;
|
||||
this.invoiceForm = { ...this.invoiceForm, ...val };
|
||||
if (!this.invoiceForm.receiptPhone) this.invoiceForm.receiptPhone = '';
|
||||
if (!this.invoiceForm.receiptEmail) this.invoiceForm.receiptEmail = '';
|
||||
if (!this.invoiceForm.receiptContent) this.invoiceForm.receiptContent = '商品明细';
|
||||
if (!this.invoiceForm.companyAddress) this.invoiceForm.companyAddress = '';
|
||||
if (!this.invoiceForm.companyPhone) this.invoiceForm.companyPhone = '';
|
||||
if (!this.invoiceForm.bankName) this.invoiceForm.bankName = '';
|
||||
if (!this.invoiceForm.bankAccount) this.invoiceForm.bankAccount = '';
|
||||
if (!this.invoiceForm.personalName) this.invoiceForm.personalName = '';
|
||||
if (!this.invoiceForm.companyName) this.invoiceForm.companyName = '';
|
||||
|
||||
if (val.taxpayerId) {
|
||||
const rt = val.receiptType;
|
||||
if (rt === 2 || rt === '2' || val.invoiceKind === 'VAT_SPECIAL') {
|
||||
this.invoice = 2;
|
||||
this.type = 2;
|
||||
} else {
|
||||
this.type = 1;
|
||||
this.invoice = 1;
|
||||
if (val.taxpayerId) this.type = 2;
|
||||
else this.type = 1;
|
||||
}
|
||||
// 兼容后端 receiptTitle 存「个人/单位」,实际名称在 personalName/companyName;旧数据名称可能只在 receiptTitle
|
||||
const titleAsName = (t) => (t && t !== '个人' && t !== '单位' ? t : '');
|
||||
if (this.invoice === 2) {
|
||||
this.invoiceForm.companyName = val.companyName || titleAsName(val.receiptTitle) || '';
|
||||
} else if (this.type === 2) {
|
||||
this.invoiceForm.companyName = val.companyName || titleAsName(val.receiptTitle) || '';
|
||||
this.invoiceForm.personalName = val.personalName || '';
|
||||
} else {
|
||||
this.invoiceForm.personalName = val.personalName || titleAsName(val.receiptTitle) || '';
|
||||
this.invoiceForm.companyName = val.companyName || '';
|
||||
}
|
||||
if (this.invoice === 1) {
|
||||
this.invoiceForm.companyAddress = '';
|
||||
this.invoiceForm.companyPhone = '';
|
||||
this.invoiceForm.bankName = '';
|
||||
this.invoiceForm.bankAccount = '';
|
||||
}
|
||||
if (this.invoice === 2) {
|
||||
this.invoiceForm.personalName = '';
|
||||
}
|
||||
},
|
||||
deep: true,
|
||||
immeadite: true
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 选择发票抬头
|
||||
*/
|
||||
changeInvoice (val) {
|
||||
onHeaderTypeChange (val) {
|
||||
if (this.invoice === 1 && val === 1 && this.invoiceForm.personalName === '个人') {
|
||||
this.invoiceForm.personalName = '';
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
this.type = val;
|
||||
if (this.$refs.form) this.$refs.form.clearValidate();
|
||||
});
|
||||
},
|
||||
onInvoiceKindChange (val) {
|
||||
this.type = val === 2 ? 2 : 1;
|
||||
this.invoiceForm = {
|
||||
receiptTitle: '',
|
||||
personalName: '',
|
||||
companyName: '',
|
||||
taxpayerId: '',
|
||||
receiptContent: '商品明细',
|
||||
receiptPhone: '',
|
||||
receiptEmail: '',
|
||||
companyAddress: '',
|
||||
companyPhone: '',
|
||||
bankName: '',
|
||||
bankAccount: ''
|
||||
};
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.form) this.$refs.form.clearValidate();
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 保存判断
|
||||
*/
|
||||
save () {
|
||||
let flage = true;
|
||||
|
||||
// 保存分为两种类型,个人以及企业
|
||||
const { receiptTitle } = JSON.parse(
|
||||
JSON.stringify(this.invoiceForm)
|
||||
);
|
||||
// 判断是否填写发票抬头
|
||||
if (!receiptTitle) {
|
||||
this.$Message.error('请填写发票抬头!');
|
||||
flage = false;
|
||||
return false;
|
||||
async save () {
|
||||
if (this.invoice === 2) {
|
||||
this.invoiceForm.receiptContent = '商品明细';
|
||||
}
|
||||
|
||||
if (this.type === 2) {
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (!valid) {
|
||||
flage = false;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
delete this.invoiceForm.taxpayerId;
|
||||
}
|
||||
|
||||
return flage;
|
||||
return await new Promise(resolve => {
|
||||
this.$refs.form.validate(valid => resolve(valid));
|
||||
});
|
||||
},
|
||||
// 保存发票信息
|
||||
async submit () {
|
||||
if (this.save()) {
|
||||
this.loading = true;
|
||||
let submit = {
|
||||
way: this.$route.query.way,
|
||||
...this.invoiceForm
|
||||
};
|
||||
let receipt = await receiptSelect(submit);
|
||||
if (receipt.success) {
|
||||
this.$emit('change', true);
|
||||
}
|
||||
|
||||
this.loading = false;
|
||||
async submit () {
|
||||
if (!await this.save()) return;
|
||||
this.loading = true;
|
||||
const raw = JSON.parse(JSON.stringify(this.invoiceForm));
|
||||
if (this.invoice === 1) {
|
||||
delete raw.companyAddress;
|
||||
delete raw.companyPhone;
|
||||
delete raw.bankName;
|
||||
delete raw.bankAccount;
|
||||
delete raw.invoiceAddress;
|
||||
if (this.type === 1) {
|
||||
delete raw.taxpayerId;
|
||||
}
|
||||
} else {
|
||||
delete raw.personalName;
|
||||
}
|
||||
const isCompanyTitle = this.invoice === 2 || this.type === 2;
|
||||
const titleName = isCompanyTitle
|
||||
? (raw.companyName != null ? String(raw.companyName).trim() : '')
|
||||
: (raw.personalName != null ? String(raw.personalName).trim() : '');
|
||||
const submit = {
|
||||
way: this.$route.query.way,
|
||||
...raw,
|
||||
receiptType: this.invoice,
|
||||
receiptTitle: isCompanyTitle ? '单位' : '个人',
|
||||
personalName: isCompanyTitle ? '' : titleName,
|
||||
companyName: isCompanyTitle ? titleName : ''
|
||||
};
|
||||
let receipt = await receiptSelect(submit);
|
||||
if (receipt.success) {
|
||||
this.$emit('change', true);
|
||||
}
|
||||
this.loading = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
/** 普票 */
|
||||
.inv-type {
|
||||
text-align: center;
|
||||
}
|
||||
@@ -158,7 +305,12 @@ export default {
|
||||
}
|
||||
|
||||
.nav-content {
|
||||
width: 500px;
|
||||
width: 520px;
|
||||
margin: 10px auto;
|
||||
}
|
||||
|
||||
.inv-title-fixed {
|
||||
line-height: 32px;
|
||||
color: #515a6e;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -25,11 +25,11 @@ export default {
|
||||
//携带商品Id,在IM可以发送商品信息
|
||||
if(goodsId && skuId){
|
||||
window.open(
|
||||
this.IMLink + "?token=" + accessToken + "&id=" + id || this.storeMsg.storeId + "&goodsId=" + goodsId + "&skuId=" + skuId
|
||||
this.IMLink + "?token=" + accessToken + "&id=" + (id || this.storeMsg.storeId) + "&goodsId=" + goodsId + "&skuId=" + skuId
|
||||
);
|
||||
}else{
|
||||
window.open(
|
||||
this.IMLink + "?token=" + accessToken + "&id=" + id || this.storeMsg.storeId
|
||||
this.IMLink + "?token=" + accessToken + "&id=" + (id || this.storeMsg.storeId)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -15,21 +15,112 @@
|
||||
<Button @click="modifyPwd">修改密码</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<Row class="safeItem">
|
||||
<Col :span="2">
|
||||
<Icon size="40" type="md-link" />
|
||||
</Col>
|
||||
<Col :span="16">
|
||||
<div class="setDivItem">第三方账户绑定</div>
|
||||
<div class="setDivItem theme">绑定后可使用第三方账号快捷登录。</div>
|
||||
<div class="connectList">
|
||||
<div class="connectRow">
|
||||
<div class="connectRowLeft">
|
||||
<span class="connectName">{{ wechatConnect.label }}</span>
|
||||
<Tag v-if="isBound(wechatConnect.type)" color="success">已绑定</Tag>
|
||||
<Tag v-else>未绑定</Tag>
|
||||
</div>
|
||||
</div>
|
||||
<Spin size="large" fix v-if="connectLoading"></Spin>
|
||||
</div>
|
||||
</Col>
|
||||
<Col :span="4">
|
||||
<Button v-if="!isBound(wechatConnect.type)" type="primary" @click="openBindModal(wechatConnect)">绑定</Button>
|
||||
<Button v-else @click="confirmUnbind(wechatConnect)">解绑</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
|
||||
<Modal
|
||||
v-model="bindModalVisible"
|
||||
title="绑定第三方账户"
|
||||
:mask-closable="false"
|
||||
:footer-hide="bindForm.type === 'WECHAT'"
|
||||
:ok-text="bindModalOkText"
|
||||
:loading="bindSubmitLoading"
|
||||
@on-ok="submitBind"
|
||||
@on-cancel="resetBindForm"
|
||||
>
|
||||
<Form :label-width="110">
|
||||
<FormItem label="类型">
|
||||
<Input v-model="bindForm.typeLabel" disabled />
|
||||
</FormItem>
|
||||
|
||||
<FormItem v-if="bindForm.type === 'WECHAT'" label="公众号二维码">
|
||||
<div class="wechatQrBox">
|
||||
<div class="wechatQrImgBox">
|
||||
<Spin fix v-if="qrCodeLoading"></Spin>
|
||||
<img v-if="qrCodeSrc" class="wechatQrImg" :src="qrCodeSrc" alt="微信公众号二维码" />
|
||||
<div v-else class="wechatQrEmpty">二维码获取失败,请刷新重试</div>
|
||||
</div>
|
||||
<div class="wechatQrActions">
|
||||
<Button @click="fetchWechatQrCode">刷新二维码</Button>
|
||||
<Button type="primary" @click="submitBind">我已完成绑定</Button>
|
||||
</div>
|
||||
<div class="wechatQrTip">请使用微信扫码关注/授权,完成后点击“我已完成绑定”检测绑定状态</div>
|
||||
</div>
|
||||
</FormItem>
|
||||
|
||||
<FormItem v-if="bindForm.type !== 'WECHAT'" label="OpenID/UnionID">
|
||||
<Input v-model="bindForm.unionID" placeholder="请输入 OpenID/UnionID" />
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getPwdStatus } from '@/api/account';
|
||||
// import { getPwdStatus } from '@/api/account';
|
||||
import storage from '@/plugins/storage'
|
||||
import { bindThirdAccount, getThirdAccountBindList, getWechatH5QrCode, unbindThirdAccount } from '@/api/login.js'
|
||||
export default {
|
||||
name: 'AccountSafe',
|
||||
data () {
|
||||
return {
|
||||
pwdStatus: '' // 密码状态
|
||||
pwdStatus: '',
|
||||
connectLoading: false,
|
||||
bindModalVisible: false,
|
||||
bindSubmitLoading: false,
|
||||
connectBoundTypes: [],
|
||||
thirdAccountTypes: [
|
||||
{ type: 'WECHAT', label: '微信' }
|
||||
],
|
||||
qrCodeLoading: false,
|
||||
qrCodeBase64: '',
|
||||
bindForm: {
|
||||
type: '',
|
||||
typeLabel: '',
|
||||
unionID: ''
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
wechatConnect () {
|
||||
return this.thirdAccountTypes[0]
|
||||
},
|
||||
qrCodeSrc () {
|
||||
if (!this.qrCodeBase64) return ''
|
||||
if (this.qrCodeBase64.startsWith('data:image')) return this.qrCodeBase64
|
||||
return `data:image/png;base64,${this.qrCodeBase64}`
|
||||
},
|
||||
bindModalOkText () {
|
||||
if (this.bindForm.type === 'WECHAT') return '我已完成绑定'
|
||||
return '确定'
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.getPwdStatus()
|
||||
this.refreshConnectBinds()
|
||||
},
|
||||
methods: {
|
||||
// 设置支付密码
|
||||
@@ -40,21 +131,140 @@ export default {
|
||||
this.$router.push({name: 'ModifyPwd', query: { status: 1 }})
|
||||
},
|
||||
// 获取密码状态
|
||||
getPwdStatus () {
|
||||
getPwdStatus().then(res => {
|
||||
if (res) {
|
||||
this.pwdStatus = '修改密码'
|
||||
} else {
|
||||
this.pwdStatus = '设置密码'
|
||||
getPwdStatus () {},
|
||||
// getPwdStatus () {
|
||||
// getPwdStatus().then(res => {
|
||||
// if (res) {
|
||||
// this.pwdStatus = '修改密码'
|
||||
// } else {
|
||||
// this.pwdStatus = '设置密码'
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
isBound (type) {
|
||||
return this.connectBoundTypes.includes(type)
|
||||
},
|
||||
refreshConnectBinds () {
|
||||
this.connectLoading = true
|
||||
return getThirdAccountBindList()
|
||||
.then(res => {
|
||||
if (res && res.success) {
|
||||
this.connectBoundTypes = Array.isArray(res.result) ? res.result : []
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.connectLoading = false
|
||||
})
|
||||
},
|
||||
openBindModal (item) {
|
||||
this.bindForm.type = item.type
|
||||
this.bindForm.typeLabel = item.label
|
||||
this.bindForm.unionID = ''
|
||||
this.qrCodeBase64 = ''
|
||||
this.bindModalVisible = true
|
||||
if (item.type === 'WECHAT') {
|
||||
this.fetchWechatQrCode()
|
||||
}
|
||||
},
|
||||
resetBindForm () {
|
||||
this.bindForm.type = ''
|
||||
this.bindForm.typeLabel = ''
|
||||
this.bindForm.unionID = ''
|
||||
this.qrCodeLoading = false
|
||||
this.qrCodeBase64 = ''
|
||||
this.bindSubmitLoading = false
|
||||
},
|
||||
fetchWechatQrCode () {
|
||||
if (this.bindForm.type !== 'WECHAT') return
|
||||
const rawUserInfo = storage.getItem('userInfo')
|
||||
const userInfo = rawUserInfo ? JSON.parse(rawUserInfo) : null
|
||||
const userId = userInfo && userInfo.id ? String(userInfo.id) : ''
|
||||
if (!userId) {
|
||||
this.qrCodeBase64 = ''
|
||||
this.$Message.error('未获取到当前用户ID,请重新登录后重试')
|
||||
return
|
||||
}
|
||||
this.qrCodeLoading = true
|
||||
getWechatH5QrCode({ scene: userId })
|
||||
.then(res => {
|
||||
if (res && res.success) {
|
||||
this.qrCodeBase64 = res.result || ''
|
||||
return
|
||||
}
|
||||
this.qrCodeBase64 = ''
|
||||
this.$Message.error((res && res.message) || '二维码获取失败')
|
||||
})
|
||||
.catch(() => {
|
||||
this.qrCodeBase64 = ''
|
||||
})
|
||||
.finally(() => {
|
||||
this.qrCodeLoading = false
|
||||
})
|
||||
},
|
||||
submitBind () {
|
||||
if (this.bindSubmitLoading) return
|
||||
if (this.bindForm.type === 'WECHAT' && !this.bindForm.unionID) {
|
||||
this.bindSubmitLoading = true
|
||||
this.refreshConnectBinds()
|
||||
.then(() => {
|
||||
if (this.isBound(this.bindForm.type)) {
|
||||
this.$Message.success('绑定成功')
|
||||
this.bindModalVisible = false
|
||||
this.resetBindForm()
|
||||
return
|
||||
}
|
||||
this.$Message.warning('暂未检测到绑定,请扫码后重试')
|
||||
this.$nextTick(() => {
|
||||
this.bindModalVisible = true
|
||||
})
|
||||
})
|
||||
.finally(() => {
|
||||
this.bindSubmitLoading = false
|
||||
})
|
||||
return
|
||||
}
|
||||
if (!this.bindForm.type) {
|
||||
this.$Message.error('绑定类型不能为空')
|
||||
return
|
||||
}
|
||||
if (!this.bindForm.unionID) {
|
||||
this.$Message.error('OpenID/UnionID 不能为空')
|
||||
this.$nextTick(() => {
|
||||
this.bindModalVisible = true
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
this.bindSubmitLoading = true
|
||||
bindThirdAccount({ unionID: this.bindForm.unionID, type: this.bindForm.type })
|
||||
.then(() => {
|
||||
this.$Message.success('绑定成功')
|
||||
this.bindModalVisible = false
|
||||
this.resetBindForm()
|
||||
this.refreshConnectBinds()
|
||||
})
|
||||
.finally(() => {
|
||||
this.bindSubmitLoading = false
|
||||
})
|
||||
},
|
||||
confirmUnbind (item) {
|
||||
this.$Modal.confirm({
|
||||
title: '解绑确认',
|
||||
content: `<p>确定解绑 ${item.label} 吗?</p>`,
|
||||
onOk: () => {
|
||||
unbindThirdAccount({ type: item.type }).then(() => {
|
||||
this.$Message.success('解绑成功')
|
||||
this.refreshConnectBinds()
|
||||
})
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
/deep/ .ivu-col-span-2, .ivu-col-span-4 {
|
||||
::v-deep .ivu-col-span-2, .ivu-col-span-4 {
|
||||
text-align: center;
|
||||
color: $theme_color;
|
||||
}
|
||||
@@ -71,9 +281,72 @@ export default {
|
||||
border-bottom: 1px solid $border_color;
|
||||
padding: 16px 0;
|
||||
|
||||
/deep/ .ivu-col {
|
||||
::v-deep .ivu-col {
|
||||
padding: 8px 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.connectList {
|
||||
position: relative;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.connectRow {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 6px 0;
|
||||
}
|
||||
|
||||
.connectRowLeft {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.connectName {
|
||||
color: $title_color;
|
||||
}
|
||||
|
||||
.wechatQrBox {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.wechatQrImgBox {
|
||||
position: relative;
|
||||
width: 180px;
|
||||
height: 180px;
|
||||
border: 1px solid $border_color;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.wechatQrImg {
|
||||
width: 168px;
|
||||
height: 168px;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.wechatQrEmpty {
|
||||
color: $light_sub_color;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
padding: 0 8px;
|
||||
}
|
||||
|
||||
.wechatQrActions {
|
||||
margin-top: 10px;
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.wechatQrTip {
|
||||
margin-top: 10px;
|
||||
color: $light_sub_color;
|
||||
font-size: 12px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -584,7 +584,7 @@ export default {
|
||||
margin-left: 25px;
|
||||
margin-top: 5px
|
||||
}
|
||||
/deep/ .ivu-alert-message {
|
||||
::v-deep .ivu-alert-message {
|
||||
p {
|
||||
margin: 4px 0;
|
||||
}
|
||||
|
||||
431
buyer/src/pages/home/memberCenter/MemberGrade.vue
Normal file
431
buyer/src/pages/home/memberCenter/MemberGrade.vue
Normal file
@@ -0,0 +1,431 @@
|
||||
<template>
|
||||
<div class="memberGrade">
|
||||
<card _Title="我的等级"/>
|
||||
<div class="summary">
|
||||
<div class="gradeCard">
|
||||
<div class="gradeLeft">
|
||||
<img v-if="currentGrade.gradeImage" class="gradeIcon" :src="currentGrade.gradeImage" alt="等级图标" />
|
||||
<div class="gradeInfo">
|
||||
<div class="gradeNameRow">
|
||||
<span class="gradeNameText">{{ currentGrade.gradeName || '暂无等级' }}</span>
|
||||
<span v-if="currentGradeBenefits.length" class="benefitTagsInline">
|
||||
<Tag v-for="b in currentGradeBenefits" :key="b.id" class="benefitTag" color="blue">{{ b.benefitName || '-' }}</Tag>
|
||||
</span>
|
||||
</div>
|
||||
<div class="gradeExp">
|
||||
当前经验值:<span class="num">{{ currentExperience || 0 }}</span>
|
||||
</div>
|
||||
<div class="gradeNext" v-if="nextGrade">
|
||||
距 {{ nextGrade.gradeName }} 还差 <span class="num">{{ diffExperience }}</span> 经验值
|
||||
</div>
|
||||
<div class="gradeNext" v-else>已达最高等级</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Tabs value="rules">
|
||||
<TabPane label="获取经验值方式" name="rules">
|
||||
<Table :columns="ruleColumns" :data="ruleList" :loading="rulesLoading">
|
||||
<template slot-scope="{ row }" slot="ruleItem">
|
||||
<div class="ruleItem">
|
||||
<div class="ruleTop">
|
||||
<div class="ruleName">
|
||||
<span>{{ row.ruleName || row.ruleKey || '-' }}</span>
|
||||
</div>
|
||||
<Tag v-if="row.completed === true" color="success">已完成</Tag>
|
||||
<Tag v-else color="default">未完成</Tag>
|
||||
</div>
|
||||
<div class="ruleDesc">{{ getRuleDesc(row.ruleKey) }}</div>
|
||||
<div class="ruleMeta">
|
||||
<span class="metaItem">单次获得:<b>+{{ row.value == null ? 0 : row.value }}</b></span>
|
||||
<span v-if="row.maxValue != null && Number(row.maxValue) > 0" class="metaItem">限额:<b>{{ row.maxValue }}</b></span>
|
||||
<span class="metaItem">已获得:<b>{{ row.gainedExperience == null ? 0 : row.gainedExperience }}</b></span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</Table>
|
||||
<div class="rulesDesc" v-if="rulesDescription">{{ rulesDescription }}</div>
|
||||
</TabPane>
|
||||
<TabPane label="经验值记录" name="logs">
|
||||
<Table :columns="logColumns" :data="experienceLogs.records || []" :loading="logLoading">
|
||||
<template slot-scope="{ row }" slot="rule">
|
||||
<span>{{ getRuleName(row.ruleKey) }}</span>
|
||||
</template>
|
||||
<template slot-scope="{ row }" slot="delta">
|
||||
<div :style="{color: getLogDeltaColor(row)}">
|
||||
<span v-if="getLogDeltaSign(row) === '+'">+</span>{{ getLogDeltaAbsValue(row) }}
|
||||
</div>
|
||||
</template>
|
||||
</Table>
|
||||
<Page
|
||||
style="float:right;margin-top:10px"
|
||||
:current="params.pageNumber"
|
||||
:total="experienceLogs.total || 0"
|
||||
:page-size="params.pageSize"
|
||||
@on-change="changePage"
|
||||
@on-page-size-change="changePageSize"
|
||||
:page-size-opts="[10, 20, 50]"
|
||||
size="small"
|
||||
show-total
|
||||
show-elevator
|
||||
></Page>
|
||||
</TabPane>
|
||||
</Tabs>
|
||||
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { memberGradeCurrent, memberGradeList, memberGradeRules } from '@/api/member.js'
|
||||
|
||||
export default {
|
||||
name: 'MemberGrade',
|
||||
data () {
|
||||
return {
|
||||
ruleList: [],
|
||||
rulesLoading: false,
|
||||
rulesDescription: '',
|
||||
/** 接口返回 List MemberGradeDetailVO,每项 { grade, benefits } */
|
||||
gradeDetails: [],
|
||||
gradeList: [],
|
||||
currentGrade: {},
|
||||
currentExperience: 0,
|
||||
currentGradeId: '',
|
||||
selectedRuleKey: '',
|
||||
logLoading: false,
|
||||
gradeLoading: false,
|
||||
params: {
|
||||
pageNumber: 1,
|
||||
pageSize: 10
|
||||
},
|
||||
experienceLogs: {},
|
||||
ruleColumns: [
|
||||
{
|
||||
title: '获取方式',
|
||||
slot: 'ruleItem',
|
||||
minWidth: 720
|
||||
}
|
||||
],
|
||||
logColumns: [
|
||||
{
|
||||
title: '时间',
|
||||
key: 'createTime',
|
||||
align: 'center',
|
||||
minWidth: 160
|
||||
},
|
||||
{
|
||||
title: '规则',
|
||||
slot: 'rule',
|
||||
align: 'center',
|
||||
minWidth: 160
|
||||
},
|
||||
{
|
||||
title: '变动值',
|
||||
slot: 'delta',
|
||||
align: 'center',
|
||||
minWidth: 120
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
rulesMap () {
|
||||
const map = {}
|
||||
this.ruleList.forEach(item => {
|
||||
map[item.ruleKey] = item.ruleName
|
||||
})
|
||||
return map
|
||||
},
|
||||
sortedGradeList () {
|
||||
const list = Array.isArray(this.gradeList) ? this.gradeList.slice() : []
|
||||
list.sort((a, b) => {
|
||||
const sa = a && a.gradeSort != null ? Number(a.gradeSort) : 0
|
||||
const sb = b && b.gradeSort != null ? Number(b.gradeSort) : 0
|
||||
if (sa !== sb) return sa - sb
|
||||
const ea = a && a.requiredExperience != null ? Number(a.requiredExperience) : 0
|
||||
const eb = b && b.requiredExperience != null ? Number(b.requiredExperience) : 0
|
||||
return ea - eb
|
||||
})
|
||||
return list
|
||||
},
|
||||
currentGradeIndex () {
|
||||
if (!this.currentGradeId) return -1
|
||||
return this.sortedGradeList.findIndex(g => g && g.id === this.currentGradeId)
|
||||
},
|
||||
nextGrade () {
|
||||
const idx = this.currentGradeIndex
|
||||
if (idx < 0) return null
|
||||
return this.sortedGradeList[idx + 1] || null
|
||||
},
|
||||
diffExperience () {
|
||||
if (!this.nextGrade || this.nextGrade.requiredExperience == null) return 0
|
||||
const diff = Number(this.nextGrade.requiredExperience) - Number(this.currentExperience || 0)
|
||||
return diff > 0 ? diff : 0
|
||||
},
|
||||
/** 当前等级在列表详情中对应的启用权益(顺序与后台 benefits 一致) */
|
||||
currentGradeBenefits () {
|
||||
const id = this.currentGradeId
|
||||
if (!id || !Array.isArray(this.gradeDetails) || !this.gradeDetails.length) return []
|
||||
const detail = this.gradeDetails.find(
|
||||
(d) => d && d.grade && String(d.grade.id) === String(id)
|
||||
)
|
||||
const list = detail && Array.isArray(detail.benefits) ? detail.benefits : []
|
||||
return list.filter((b) => b && b.benefitState === 'OPEN')
|
||||
},
|
||||
},
|
||||
mounted () {
|
||||
this.init()
|
||||
},
|
||||
methods: {
|
||||
init () {
|
||||
this.loadRules()
|
||||
this.loadGradeList()
|
||||
this.loadCurrent()
|
||||
},
|
||||
loadRules () {
|
||||
this.rulesLoading = true
|
||||
memberGradeRules()
|
||||
.then(res => {
|
||||
if (res && res.success) {
|
||||
const items = res.result && Array.isArray(res.result.items) ? res.result.items : []
|
||||
this.rulesDescription = (res.result && res.result.description) || ''
|
||||
this.ruleList = items
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.rulesLoading = false
|
||||
})
|
||||
},
|
||||
loadGradeList () {
|
||||
this.gradeLoading = true
|
||||
memberGradeList()
|
||||
.then(res => {
|
||||
if (res && res.success) {
|
||||
const raw = Array.isArray(res.result) ? res.result : []
|
||||
this.gradeDetails = raw
|
||||
.map((item) => {
|
||||
if (!item) return null
|
||||
if (item.grade != null) {
|
||||
return {
|
||||
grade: item.grade,
|
||||
benefits: Array.isArray(item.benefits) ? item.benefits : []
|
||||
}
|
||||
}
|
||||
return { grade: item, benefits: [] }
|
||||
})
|
||||
.filter(Boolean)
|
||||
this.gradeList = this.gradeDetails.map((d) => d.grade).filter(Boolean)
|
||||
} else {
|
||||
this.gradeDetails = []
|
||||
this.gradeList = []
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.gradeLoading = false
|
||||
})
|
||||
},
|
||||
loadCurrent () {
|
||||
this.logLoading = true
|
||||
const params = {
|
||||
pageNumber: this.params.pageNumber,
|
||||
pageSize: this.params.pageSize
|
||||
}
|
||||
if (this.selectedRuleKey) params.ruleKey = this.selectedRuleKey
|
||||
memberGradeCurrent(params)
|
||||
.then(res => {
|
||||
if (res && res.success && res.result) {
|
||||
this.currentGrade = res.result.grade || {}
|
||||
this.currentExperience = res.result.experience || 0
|
||||
this.currentGradeId = res.result.gradeId || (this.currentGrade && this.currentGrade.id) || ''
|
||||
this.experienceLogs = res.result.experienceLogs || {}
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.logLoading = false
|
||||
})
|
||||
},
|
||||
selectRule (ruleKey) {
|
||||
this.selectedRuleKey = ruleKey || ''
|
||||
this.params.pageNumber = 1
|
||||
this.loadCurrent()
|
||||
},
|
||||
changePage (val) {
|
||||
this.params.pageNumber = val
|
||||
this.loadCurrent()
|
||||
},
|
||||
changePageSize (val) {
|
||||
this.params.pageSize = val
|
||||
this.params.pageNumber = 1
|
||||
this.loadCurrent()
|
||||
},
|
||||
getRuleName (ruleKey) {
|
||||
if (!ruleKey) return '-'
|
||||
return this.rulesMap[ruleKey] || ruleKey
|
||||
},
|
||||
getRuleDesc (ruleKey) {
|
||||
const map = {
|
||||
CONSUME: '客户消费1元可获取经验值,向下取整',
|
||||
REGISTER: '会员注册成功后可获取经验值',
|
||||
SIGN_IN: '客户每日签到后可获取的经验值',
|
||||
COMMENT: '对已购买商品完成发表评价获取经验值;仅针对评论字数大于30字的评论进行发放',
|
||||
SHARE: '会员分享商城页面可获取的经验值',
|
||||
PROFILE: '完善个人基本信息可获得经验值,每个会员仅可获得一次',
|
||||
FOLLOW_STORE: '关注店铺可获得经验值,每个客户ID同店铺仅第一次关注可进行获得',
|
||||
BIND_WECHAT: '绑定微信成功后获得经验值,每个会员仅可获得一次',
|
||||
ADD_ADDRESS: '添加收货地址可获得经验值,每个会员仅可获得一次',
|
||||
SHARE_REGISTER: '仅被注册成功后可获得相应奖励经验值',
|
||||
SHARE_BUY: '仅被购买成功后可获得相应奖励经验值'
|
||||
}
|
||||
if (!ruleKey) return '-'
|
||||
return map[ruleKey] || '-'
|
||||
},
|
||||
getLogDeltaRaw (row) {
|
||||
if (!row) return 0
|
||||
const candidate = row.variableExperience != null ? row.variableExperience : (row.changeExperience != null ? row.changeExperience : (row.experience != null ? row.experience : row.value))
|
||||
if (candidate == null) return 0
|
||||
const num = Number(candidate)
|
||||
if (Number.isNaN(num)) return 0
|
||||
if (row.type === 'DECREASE') return -Math.abs(num)
|
||||
if (row.type === 'INCREASE') return Math.abs(num)
|
||||
return num
|
||||
},
|
||||
getLogDeltaSign (row) {
|
||||
const num = this.getLogDeltaRaw(row)
|
||||
return num >= 0 ? '+' : '-'
|
||||
},
|
||||
getLogDeltaAbsValue (row) {
|
||||
const num = this.getLogDeltaRaw(row)
|
||||
return Math.abs(num)
|
||||
},
|
||||
getLogDeltaColor (row) {
|
||||
return this.getLogDeltaRaw(row) >= 0 ? 'green' : 'red'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
h3 {
|
||||
font-size: 16px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.summary {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.rulesDesc {
|
||||
margin: 10px 0 0 0;
|
||||
padding: 10px 12px;
|
||||
border: 1px solid $border_color;
|
||||
border-radius: 4px;
|
||||
background: #fff;
|
||||
color: $light_sub_color;
|
||||
font-size: 12px;
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
.gradeCard {
|
||||
padding: 16px;
|
||||
border: 1px solid $border_color;
|
||||
border-radius: 6px;
|
||||
background: #fff;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.gradeLeft {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.gradeIcon {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
object-fit: contain;
|
||||
border-radius: 4px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.gradeNameRow {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 8px 10px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.gradeNameText {
|
||||
font-size: 16px;
|
||||
color: $light_title_color;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.benefitTagsInline {
|
||||
display: inline-flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 6px 8px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.benefitTag {
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
.gradeExp,
|
||||
.gradeNext {
|
||||
margin-top: 6px;
|
||||
font-size: 12px;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.num {
|
||||
color: $theme_color;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.ruleItem {
|
||||
padding: 10px 8px;
|
||||
}
|
||||
|
||||
.ruleTop {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.ruleName {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
color: $light_title_color;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.ruleDesc {
|
||||
margin-top: 6px;
|
||||
color: $light_sub_color;
|
||||
font-size: 12px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.ruleMeta {
|
||||
margin-top: 8px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 16px;
|
||||
color: $light_sub_color;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.metaItem b {
|
||||
color: $theme_color;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -54,14 +54,40 @@ export default {
|
||||
},
|
||||
mounted () {
|
||||
this.formItem = JSON.parse(storage.getItem('userInfo'))
|
||||
this.formItem.birthday = this.normalizeBirthday(this.formItem.birthday)
|
||||
this.accessToken.accessToken = storage.getItem('accessToken');
|
||||
},
|
||||
methods: {
|
||||
normalizeBirthday (value) {
|
||||
if (!value) return ''
|
||||
if (value instanceof Date) return value
|
||||
if (typeof value === 'number') return new Date(value)
|
||||
if (typeof value === 'string') {
|
||||
const m = value.match(/^(\d{4})-(\d{2})-(\d{2})/)
|
||||
if (m) return new Date(Number(m[1]), Number(m[2]) - 1, Number(m[3]))
|
||||
const d = new Date(value)
|
||||
return isNaN(d.getTime()) ? '' : d
|
||||
}
|
||||
return ''
|
||||
},
|
||||
formatBirthday (value) {
|
||||
if (!value) return null
|
||||
if (typeof value === 'string') {
|
||||
const m = value.match(/^(\d{4})-(\d{2})-(\d{2})/)
|
||||
return m ? `${m[1]}-${m[2]}-${m[3]}` : null
|
||||
}
|
||||
const d = value instanceof Date ? value : new Date(value)
|
||||
if (isNaN(d.getTime())) return null
|
||||
const yyyy = d.getFullYear()
|
||||
const mm = String(d.getMonth() + 1).padStart(2, '0')
|
||||
const dd = String(d.getDate()).padStart(2, '0')
|
||||
return `${yyyy}-${mm}-${dd}`
|
||||
},
|
||||
save () { // 保存
|
||||
this.$refs.form.validate(valid => {
|
||||
if (valid) {
|
||||
let params = {
|
||||
birthday: this.$options.filters.unixToDate(this.formItem.birthday / 1000, 'yyyy-MM-dd'),
|
||||
birthday: this.formatBirthday(this.formItem.birthday),
|
||||
face: this.formItem.face,
|
||||
nickName: this.formItem.nickName,
|
||||
sex: this.formItem.sex
|
||||
|
||||
@@ -95,12 +95,43 @@
|
||||
</div>
|
||||
<div class="order-card" v-if="order.order.payStatus === 'PAID'">
|
||||
<h3>发票信息</h3>
|
||||
<template v-if="order.order.needReceipt && order.receipt">
|
||||
<p>发票抬头:{{ order.receipt.receiptTitle }}</p>
|
||||
<p>发票内容:{{ order.receipt.receiptContent }}</p>
|
||||
<!-- 以 li_receipt 为准:needReceipt 可能为 null/false 导致有 receipt 仍显示「未开发票」 -->
|
||||
<template v-if="hasValidReceipt()">
|
||||
<p>发票类型:{{ formatReceiptType(order.receipt) }}</p>
|
||||
<p>发票抬头:{{ formatReceiptHeaderType(order.receipt) }}</p>
|
||||
<p v-if="isPersonalReceipt(order.receipt) && order.receipt.personalName">
|
||||
个人名称:{{ order.receipt.personalName }}
|
||||
</p>
|
||||
<p v-if="order.receipt.companyName">
|
||||
单位名称:{{ order.receipt.companyName }}
|
||||
</p>
|
||||
<p v-if="order.receipt.taxpayerId">
|
||||
纳税人识别号:{{ order.receipt.taxpayerId }}
|
||||
</p>
|
||||
<p v-if="order.receipt.companyAddress">
|
||||
单位地址:{{ order.receipt.companyAddress }}
|
||||
</p>
|
||||
<p v-if="order.receipt.companyPhone">
|
||||
单位电话:{{ order.receipt.companyPhone }}
|
||||
</p>
|
||||
<p v-if="order.receipt.bankName">
|
||||
开户银行:{{ order.receipt.bankName }}
|
||||
</p>
|
||||
<p v-if="order.receipt.bankAccount">
|
||||
银行账号:{{ order.receipt.bankAccount }}
|
||||
</p>
|
||||
<p>发票内容:{{ order.receipt.receiptContent }}</p>
|
||||
<p v-if="order.receipt.receiptPhone">
|
||||
收票人手机:{{ order.receipt.receiptPhone }}
|
||||
</p>
|
||||
<p v-if="order.receipt.receiptEmail">
|
||||
收票人邮箱:{{ order.receipt.receiptEmail }}
|
||||
</p>
|
||||
<div v-if="Number(order.receipt.receiptStatus) === 1" class="receipt-action">
|
||||
<Button size="small" type="primary" ghost @click="viewReceiptInvoice(order.receipt)">
|
||||
查看发票
|
||||
</Button>
|
||||
</div>
|
||||
</template>
|
||||
<div v-else style="color: #999; margin-left: 5px">未开发票</div>
|
||||
</div>
|
||||
@@ -307,7 +338,7 @@ import {
|
||||
cancelOrder,
|
||||
getPackage
|
||||
} from "@/api/order.js";
|
||||
import { afterSaleReason } from "@/api/member";
|
||||
import { afterSaleReason, receiptDetail } from "@/api/member";
|
||||
export default {
|
||||
name: "order-detail",
|
||||
data() {
|
||||
@@ -328,6 +359,51 @@ export default {
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
isVatSpecialReceipt (receipt) {
|
||||
if (!receipt) return false;
|
||||
const rt = receipt.receiptType != null ? String(receipt.receiptType).trim() : "";
|
||||
if (rt === "2" || rt === "增值税专用发票" || receipt.invoiceKind === "VAT_SPECIAL") {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
isPersonalReceipt (receipt) {
|
||||
return !this.isVatSpecialReceipt(receipt);
|
||||
},
|
||||
formatReceiptType (receipt) {
|
||||
if (!receipt) return "";
|
||||
const rt = receipt.receiptType != null ? String(receipt.receiptType).trim() : "";
|
||||
if (rt === "电子普通发票" || rt === "增值税专用发票") return rt;
|
||||
return this.isVatSpecialReceipt(receipt) ? "增值税专用发票" : "电子普通发票";
|
||||
},
|
||||
formatReceiptHeaderType (receipt) {
|
||||
if (!receipt) return "";
|
||||
if (this.isVatSpecialReceipt(receipt)) return "单位";
|
||||
if (receipt.taxpayerId) return "单位";
|
||||
return "个人";
|
||||
},
|
||||
hasValidReceipt () {
|
||||
const receipt = this.order && this.order.receipt;
|
||||
if (!receipt) return false;
|
||||
const content = receipt.receiptContent ? String(receipt.receiptContent).trim() : '';
|
||||
const title = receipt.receiptTitle ? String(receipt.receiptTitle).trim() : '';
|
||||
const taxpayerId = receipt.taxpayerId ? String(receipt.taxpayerId).trim() : '';
|
||||
// 后端有时会返回占位 receipt(如 receiptContent=不开发票),这里过滤掉
|
||||
if (content === '不开发票') return false;
|
||||
return Boolean(content || title || taxpayerId);
|
||||
},
|
||||
getInvoiceAddress (receipt) {
|
||||
if (!receipt) return "";
|
||||
return receipt.invoiceAddress || receipt.invoiceFileUrl || "";
|
||||
},
|
||||
viewReceiptInvoice (receipt) {
|
||||
const invoiceAddress = this.getInvoiceAddress(receipt);
|
||||
if (!invoiceAddress) {
|
||||
this.$Message.warning("暂无发票附件");
|
||||
return;
|
||||
}
|
||||
window.open(invoiceAddress, "_blank");
|
||||
},
|
||||
// 退款状态枚举
|
||||
refundPriceList(status) {
|
||||
switch (status) {
|
||||
@@ -359,11 +435,21 @@ export default {
|
||||
});
|
||||
window.open(routeUrl.href, "_blank");
|
||||
},
|
||||
getDetail() {
|
||||
async getDetail() {
|
||||
// 获取订单详情
|
||||
orderDetail(this.$route.query.sn).then((res) => {
|
||||
orderDetail(this.$route.query.sn).then(async (res) => {
|
||||
if (res.success) {
|
||||
this.order = res.result;
|
||||
const receiptId =
|
||||
(res.result.order && res.result.order.receiptId) ||
|
||||
res.result.receiptId ||
|
||||
(res.result.receipt && res.result.receipt.id);
|
||||
if (receiptId) {
|
||||
const receiptRes = await receiptDetail(receiptId);
|
||||
if (receiptRes && receiptRes.success && receiptRes.result) {
|
||||
this.$set(this.order, "receipt", receiptRes.result);
|
||||
}
|
||||
}
|
||||
this.progressList = res.result.orderLogs;
|
||||
if (this.order.order.deliveryMethod === 'LOGISTICS') {
|
||||
this.getOrderPackage(this.order.order.sn);
|
||||
@@ -604,15 +690,15 @@ table {
|
||||
.layui-layer-wrap > .div-express-log {
|
||||
max-height: 300px;
|
||||
}
|
||||
/deep/ .layui-layer-wrap > .div-express-log::-webkit-scrollbar{
|
||||
::v-deep .layui-layer-wrap > .div-express-log::-webkit-scrollbar{
|
||||
width: 1px;
|
||||
height: 5px;
|
||||
}
|
||||
/deep/ .layui-layer-wrap > .div-express-log::-webkit-scrollbar-thumb{
|
||||
::v-deep .layui-layer-wrap > .div-express-log::-webkit-scrollbar-thumb{
|
||||
border-radius: 1em;
|
||||
background-color: rgba(50,50,50,.3);
|
||||
}
|
||||
/deep/ .layui-layer-wrap > .div-express-log::-webkit-scrollbar-track{
|
||||
::v-deep .layui-layer-wrap > .div-express-log::-webkit-scrollbar-track{
|
||||
border-radius: 1em;
|
||||
background-color: rgba(50,50,50,.1);
|
||||
}
|
||||
@@ -625,6 +711,10 @@ table {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.receipt-action {
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.express-log {
|
||||
/*margin: 5px -10px 5px 5px;*/
|
||||
padding: 10px;
|
||||
|
||||
@@ -157,8 +157,11 @@
|
||||
</span></span>
|
||||
</div>
|
||||
<div class="inovice-content">
|
||||
<span>{{ invoiceData.receiptTitle }}</span>
|
||||
<span>{{ invoiceData.receiptContent }}</span>
|
||||
<template v-if="hasInvoiceInfo">
|
||||
<span>{{ invoiceDisplayTitle }}</span>
|
||||
<span>{{ invoiceData.receiptContent }}</span>
|
||||
</template>
|
||||
<span v-else>不开发票</span>
|
||||
<span @click="editInvoice">编辑</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -258,6 +261,28 @@ import { canUseCouponList } from "@/api/member.js";
|
||||
export default {
|
||||
name: "Pay",
|
||||
components: { invoiceModal, addressManage },
|
||||
computed: {
|
||||
hasInvoiceInfo() {
|
||||
const title =
|
||||
this.invoiceData.personalName ||
|
||||
this.invoiceData.companyName ||
|
||||
this.invoiceData.receiptTitle;
|
||||
const content = this.invoiceData.receiptContent;
|
||||
if (content && String(content).trim() === "不开发票") return false;
|
||||
return Boolean(
|
||||
(title && String(title).trim()) ||
|
||||
(content && String(content).trim())
|
||||
);
|
||||
},
|
||||
invoiceDisplayTitle() {
|
||||
return (
|
||||
this.invoiceData.personalName ||
|
||||
this.invoiceData.companyName ||
|
||||
this.invoiceData.receiptTitle ||
|
||||
""
|
||||
);
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
selectedStoreAddress: 'm',
|
||||
@@ -270,8 +295,7 @@ export default {
|
||||
storeMoreAddr: false,
|
||||
invoiceData: {
|
||||
// 发票数据
|
||||
receiptTitle: "个人",
|
||||
receiptContent: "不开发票",
|
||||
//receiptContent: "不开发票",
|
||||
},
|
||||
searchForm: {
|
||||
pageNumber: 1,
|
||||
|
||||
@@ -76,6 +76,11 @@ const member = [{
|
||||
icon: '',
|
||||
title: '我的积分',
|
||||
path: 'Point'
|
||||
},
|
||||
{
|
||||
icon: '',
|
||||
title: '我的等级',
|
||||
path: 'MemberGrade'
|
||||
}
|
||||
],
|
||||
display: true
|
||||
|
||||
@@ -68,6 +68,8 @@ const ComplainDetail = (resolve) =>
|
||||
require(["@/pages/home/memberCenter/ComplainDetail"], resolve);
|
||||
const Point = (resolve) =>
|
||||
require(["@/pages/home/memberCenter/Point"], resolve);
|
||||
const MemberGrade = (resolve) =>
|
||||
require(["@/pages/home/memberCenter/MemberGrade"], resolve);
|
||||
const MsgList = (resolve) =>
|
||||
require(["@/pages/home/memberCenter/memberMsg/MsgList"], resolve);
|
||||
const MsgDetail = (resolve) =>
|
||||
@@ -326,6 +328,12 @@ export default new Router({
|
||||
component: Point,
|
||||
meta: { title: "我的积分" },
|
||||
},
|
||||
{
|
||||
path: "MemberGrade",
|
||||
name: "MemberGrade",
|
||||
component: MemberGrade,
|
||||
meta: { title: "我的等级" },
|
||||
},
|
||||
{
|
||||
path: "Profile",
|
||||
name: "Profile",
|
||||
|
||||
@@ -70,7 +70,7 @@ module.exports = {
|
||||
|
||||
loaderOptions: {
|
||||
sass: {
|
||||
data: `@import "@/assets/styles/global.scss";` //全局加载scss
|
||||
additionalData: `@import "@/assets/styles/global.scss";` //全局加载scss
|
||||
},
|
||||
// 向 CSS 相关的 loader 传递选项
|
||||
less: {
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
"vue-cropper": "^0.5.5",
|
||||
"vue-prism-editor": "^0.5.1",
|
||||
"vue-router": "^3.4.9",
|
||||
"vue-virtual-scroller": "^1.1.2",
|
||||
"vuex": "^3.5.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -121,13 +121,23 @@ export default {
|
||||
// })
|
||||
// },
|
||||
getGoodsDetail () {
|
||||
if(this.toUser.storeFlag){
|
||||
ServeGetGoodsDetail(this.goodsParams).then(res => {
|
||||
if (res.success) {
|
||||
this.goodsDetail = res.result.data
|
||||
}
|
||||
})
|
||||
// 检查必要参数是否存在
|
||||
if (!this.toUser.storeFlag) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!this.goodsParams || !this.goodsParams.goodsId) {
|
||||
console.warn('getGoodsDetail: goodsParams 或 goodsId 参数缺失')
|
||||
return
|
||||
}
|
||||
|
||||
ServeGetGoodsDetail(this.goodsParams).then(res => {
|
||||
if (res.success) {
|
||||
this.goodsDetail = res.result.data
|
||||
}
|
||||
}).catch(error => {
|
||||
console.error('获取商品详情失败:', error)
|
||||
})
|
||||
},
|
||||
getFootPrint() {
|
||||
if (this.toUser.storeFlag) {
|
||||
@@ -284,4 +294,4 @@ export default {
|
||||
/deep/ .el-tabs__header{
|
||||
margin-bottom: 0;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -33,6 +33,11 @@ Object.keys(filters).forEach((key) => {
|
||||
Vue.filter(key, filters[key]);
|
||||
});
|
||||
|
||||
|
||||
import VueVirtualScroller from 'vue-virtual-scroller'
|
||||
import 'vue-virtual-scroller/dist/vue-virtual-scroller.css'
|
||||
Vue.component('RecycleScroller', VueVirtualScroller.RecycleScroller)
|
||||
|
||||
// 引入自定义全局css
|
||||
import '@/assets/css/global.less'
|
||||
|
||||
|
||||
@@ -65,9 +65,14 @@
|
||||
> -->
|
||||
</p>
|
||||
<!-- 对话列表 -->
|
||||
<template v-if="loadStatus === 1">
|
||||
<div v-for="(item, index) in userTalkItem" :key="item.id" class="talk-item pointer"
|
||||
:class="{ active: activeIndex == index }" @click="clickTab(item.userId, item, index)">
|
||||
<RecycleScroller
|
||||
:item-size="64"
|
||||
:items="userTalkItem"
|
||||
:prerender="10"
|
||||
v-slot="{ item, index }"
|
||||
>
|
||||
|
||||
<div v-bind:key="item.id" class="talk-item pointer" :class="{ active: activeIndex == index }" @click="clickTab(item.userId, item, index)">
|
||||
<div class="avatar-box">
|
||||
<face :text="item.face" v-if="item.face"></face>
|
||||
<face-null :text="item.name" v-else></face-null>
|
||||
@@ -79,9 +84,7 @@
|
||||
<div class="title">
|
||||
<div class="card-name">
|
||||
<p class="nickname">
|
||||
{{
|
||||
item.remark_name ? item.remark_name : item.name
|
||||
}}
|
||||
{{ item.remark_name ? item.remark_name : item.name }}
|
||||
</p>
|
||||
<div v-show="item.unread" class="larkc-tag">
|
||||
{{ item.unread }}条未读
|
||||
@@ -89,11 +92,9 @@
|
||||
<div v-show="item.is_top" class="larkc-tag top">
|
||||
TOP
|
||||
</div>
|
||||
|
||||
<div v-show="item.is_robot" class="larkc-tag top">
|
||||
BOT
|
||||
</div>
|
||||
|
||||
<div v-show="item.talk_type == 2" class="larkc-tag group">
|
||||
群组
|
||||
</div>
|
||||
@@ -111,9 +112,7 @@
|
||||
<span v-if="item.lastMessageType === 'ORDER'">[订单链接]</span>
|
||||
</div>
|
||||
<div class="content">
|
||||
<template v-if="
|
||||
index_name != item.index_name && item.draft_text
|
||||
">
|
||||
<template v-if="index_name != item.index_name && item.draft_text">
|
||||
<span class="draft-color">[草稿]</span>
|
||||
<span>{{ item.draft_text }}</span>
|
||||
</template>
|
||||
@@ -124,13 +123,12 @@
|
||||
</span>
|
||||
<span v-else>[群消息]</span>
|
||||
</template>
|
||||
|
||||
<span>{{ item.msg_text }}</span>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</RecycleScroller>
|
||||
</el-main>
|
||||
</el-scrollbar>
|
||||
</el-container>
|
||||
@@ -151,6 +149,8 @@
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { RecycleScroller } from 'vue-virtual-scroller'
|
||||
import 'vue-virtual-scroller/dist/vue-virtual-scroller.css'
|
||||
import { mapGetters, mapState } from "vuex";
|
||||
import MainLayout from "@/views/layout/MainLayout";
|
||||
import WelcomeModule from "@/components/layout/WelcomeModule";
|
||||
@@ -179,6 +179,7 @@ export default {
|
||||
UserSearch,
|
||||
OtherLink,
|
||||
WelcomeModule,
|
||||
RecycleScroller
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
@@ -288,6 +289,8 @@ export default {
|
||||
beforeRouteUpdate (to, from, next) {
|
||||
let index_name = getCacheIndexName();
|
||||
if (index_name) this.clickTab(index_name);
|
||||
// 更新商品参数
|
||||
this.initGoodsParams(to.query);
|
||||
next();
|
||||
},
|
||||
beforeCreate () {
|
||||
@@ -295,8 +298,10 @@ export default {
|
||||
},
|
||||
async created () {
|
||||
await this.initialize();
|
||||
await this.loadUserSetting();
|
||||
/**
|
||||
await this.loadUserSetting();
|
||||
// 初始化商品参数
|
||||
this.initGoodsParams(this.$route.query);
|
||||
/**
|
||||
* 如果说有id 说明是用户点击 “联系客服” 进入的该页面
|
||||
* 所以创建会话 并请求用户列表
|
||||
* 如果没有id说明当前商家登录 直接请求用户列表
|
||||
@@ -316,6 +321,16 @@ export default {
|
||||
// 美化时间格式
|
||||
beautifyTime,
|
||||
|
||||
// 初始化商品参数
|
||||
initGoodsParams (query) {
|
||||
this.goodsParams = {
|
||||
goodsId: query.goodsId || '',
|
||||
skuId: query.skuId || '',
|
||||
};
|
||||
|
||||
console.log('初始化商品参数:', this.goodsParams);
|
||||
},
|
||||
|
||||
//创建会话
|
||||
async createTalk (id) {
|
||||
await ServeCreateTalkList(id);
|
||||
|
||||
1
manager/.npmrc
Normal file
1
manager/.npmrc
Normal file
@@ -0,0 +1 @@
|
||||
engine-strict=false
|
||||
1
manager/.yarnrc
Normal file
1
manager/.yarnrc
Normal file
@@ -0,0 +1 @@
|
||||
--ignore-engines true
|
||||
@@ -1,29 +1,5 @@
|
||||
# LILISHOP-UI
|
||||
|
||||
## Project setup
|
||||
```
|
||||
npm install
|
||||
```
|
||||
|
||||
### Compiles and hot-reloads for development
|
||||
```
|
||||
npm run serve
|
||||
```
|
||||
|
||||
### Compiles and minifies for production
|
||||
```
|
||||
npm run build
|
||||
```
|
||||
|
||||
### Run your tests
|
||||
```
|
||||
npm run test
|
||||
```
|
||||
|
||||
### Lints and fixes files
|
||||
```
|
||||
npm run lint
|
||||
```
|
||||
|
||||
### Customize configuration
|
||||
详情点击 [https://cli.vuejs.org/zn/config/](https://cli.vuejs.org/zn/config/).
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
"build": "vue-cli-service build",
|
||||
"dev": "vue-cli-service serve"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"dependencies": {
|
||||
"@amap/amap-jsapi-loader": "0.0.7",
|
||||
"@antv/g2": "^4.1.12",
|
||||
@@ -16,8 +19,9 @@
|
||||
"core-js": "^3.6.5",
|
||||
"dplayer": "^1.26.0",
|
||||
"js-cookie": "^2.2.1",
|
||||
"node-sass": "^4.14.1",
|
||||
"sass-loader": "^8.0.2",
|
||||
"price-color": "1.0.2",
|
||||
"sass": "^1.63.6",
|
||||
"sass-loader": "^10.4.1",
|
||||
"sockjs-client": "^1.4.0",
|
||||
"swiper": "^6.3.5",
|
||||
"uuid": "^8.3.2",
|
||||
@@ -31,8 +35,7 @@
|
||||
"vue-router": "^3.1.3",
|
||||
"vuedraggable": "^2.23.2",
|
||||
"vuex": "^3.4.0",
|
||||
"xss": "^1.0.7",
|
||||
"price-color":"1.0.2"
|
||||
"xss": "^1.0.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/cli-plugin-babel": "^4.4.4",
|
||||
@@ -48,5 +51,10 @@
|
||||
"uglifyjs-webpack-plugin": "^2.2.0",
|
||||
"vue-cli-plugin-style-resources-loader": "^0.1.4",
|
||||
"vue-template-compiler": "^2.6.10"
|
||||
},
|
||||
"resolutions": {
|
||||
"minimatch": "^3.1.2",
|
||||
"node-sass": "npm:sass@^1.63.6",
|
||||
"@achrinza/node-ipc": "9.2.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,26 @@ export const getCategoryBrandListData = (category_id, params) => {
|
||||
export const saveCategoryBrand = (category_id, params) => {
|
||||
return postRequest(`/goods/categoryBrand/${category_id}`, params)
|
||||
}
|
||||
// 根据品牌id获取关联分类
|
||||
export const getBrandCategoryListData = (brand_id, params) => {
|
||||
return getRequest(`/goods/categoryBrand/${brand_id}`, params)
|
||||
}
|
||||
// 保存品牌分类关联
|
||||
export const saveBrandCategory = (brand_id, categoryIds) => {
|
||||
return postRequest(`/goods/categoryBrand/${brand_id}`, categoryIds, {
|
||||
"Content-Type": "application/json"
|
||||
})
|
||||
}
|
||||
|
||||
export const getParameterCategoryListData = (parameter_id, params) => {
|
||||
return getRequest(`/goods/parameters/category/${parameter_id}`, params)
|
||||
}
|
||||
|
||||
export const saveParameterCategory = (parameter_id, categoryIds) => {
|
||||
return postRequest(`/goods/parameters/category/${parameter_id}`, categoryIds, {
|
||||
"Content-Type": "application/json"
|
||||
})
|
||||
}
|
||||
//保存获取关联规格
|
||||
export const saveCategorySpec = (category_id, params) => {
|
||||
return postRequest(`/goods/categorySpec/${category_id}`, params)
|
||||
@@ -101,31 +121,76 @@ export const getGoodsCategory = (parent_id) => {
|
||||
}
|
||||
|
||||
// 上架商品
|
||||
export const upGoods = (id, params) => {
|
||||
return putRequest(`/goods/goods/${id}/up`, params)
|
||||
}
|
||||
// 下架商品
|
||||
export const lowGoods = (id, params) => {
|
||||
return putRequest(`/goods/goods/${id}/under`, params)
|
||||
}
|
||||
export const upGoods = (params) => {
|
||||
return putRequest(`/goods/goods/up`, params)
|
||||
}
|
||||
|
||||
// 下架商品
|
||||
export const lowGoods = (params) => {
|
||||
return putRequest(`/goods/goods/under`, params)
|
||||
}
|
||||
|
||||
// 获取商品sku分页列表
|
||||
export const getGoodsSkuData = (params) => {
|
||||
return getRequest('/goods/goods/sku/list', params)
|
||||
}
|
||||
|
||||
// 设置单个商品规格虚拟销量
|
||||
export const updateGoodsSkuVirtualSales = (skuId, params) => {
|
||||
return putRequest(`/goods/goods/virtualSales/${skuId}`, params)
|
||||
}
|
||||
|
||||
// 批量设置商品规格虚拟销量
|
||||
export const batchUpdateGoodsSkuVirtualSales = (params) => {
|
||||
return putRequest('/goods/goods/virtualSales', params, {
|
||||
"Content-Type": "application/json"
|
||||
})
|
||||
}
|
||||
// 获取商品数量
|
||||
export const getGoodsNumerData = (params) => {
|
||||
return getRequest('/goods/goods/goodsNumber', params)
|
||||
}
|
||||
// 获取商品分页列表
|
||||
export const getGoodsListData = (params) => {
|
||||
return getRequest('/goods/goods/list', params)
|
||||
}
|
||||
// 商品分组分页
|
||||
export const getGoodsGroupByPage = (params) => {
|
||||
return getRequest('/goods/goodsGroup/getByPage', params)
|
||||
}
|
||||
// 商品分组详情
|
||||
export const getGoodsGroup = (id) => {
|
||||
return getRequest(`/goods/goodsGroup/get/${id}`)
|
||||
}
|
||||
// 新增商品分组
|
||||
export const addGoodsGroup = (params) => {
|
||||
return postRequest('/goods/goodsGroup', params)
|
||||
}
|
||||
// 修改商品分组
|
||||
export const updateGoodsGroup = (id, params) => {
|
||||
return putRequest(`/goods/goodsGroup/update/${id}`, params)
|
||||
}
|
||||
// 删除商品分组
|
||||
export const deleteGoodsGroup = (id) => {
|
||||
return deleteRequest(`/goods/goodsGroup/delete/${id}`)
|
||||
}
|
||||
// 设定商品分组(批量)
|
||||
export const addGoodsGroupItems = (groupId, goodsIds) => {
|
||||
return postRequest(`/goods/goodsGroup/${groupId}/goods`, {
|
||||
goodsIds: Array.isArray(goodsIds) ? goodsIds.join(",") : goodsIds,
|
||||
})
|
||||
}
|
||||
// 获取待审核商品分页列表
|
||||
export const getAuthGoodsListData = (params) => {
|
||||
return getRequest('/goods/goods/auth/list', params)
|
||||
}
|
||||
// 审核商品
|
||||
export const authGoods = (id, params) => {
|
||||
return putRequest(`/goods/goods/${id}/auth`, params)
|
||||
export const authGoods = (params) => {
|
||||
return putRequest(`/goods/goods/auth`, params,{
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
//查询分类绑定参数信息
|
||||
@@ -133,17 +198,28 @@ export const getCategoryParamsListData = (id, params) => {
|
||||
return getRequest(`/goods/categoryParameters/${id}`, params)
|
||||
}
|
||||
|
||||
// 参数组分页列表
|
||||
export const getCategoryParametersGroupPage = (params) => {
|
||||
return getRequest(`/goods/categoryParameters`, params)
|
||||
}
|
||||
|
||||
//查询商品绑定参数信息
|
||||
export const getCategoryParamsByGoodsId = (goodsId, categoryId) => {
|
||||
return getRequest(`/goods/parameters/${goodsId}/${categoryId}`)
|
||||
}
|
||||
export const getGoodsParamsPage = (params) => {
|
||||
return getRequest(`/goods/parameters`, params)
|
||||
}
|
||||
export const getGoodsParamsDetail = (id, params) => {
|
||||
return getRequest(`/goods/parameters/${id}`, params)
|
||||
}
|
||||
//保存参数
|
||||
export const insertGoodsParams = (params) => {
|
||||
return postRequest('/goods/parameters', params)
|
||||
export const insertGoodsParams = (params, headers) => {
|
||||
return postRequest('/goods/parameters', params, headers)
|
||||
}
|
||||
//更新参数
|
||||
export const updateGoodsParams = (params) => {
|
||||
return putRequest('/goods/parameters', params)
|
||||
export const updateGoodsParams = (params, headers) => {
|
||||
return putRequest('/goods/parameters', params, headers)
|
||||
}
|
||||
//删除参数
|
||||
export const deleteParams = (id, params) => {
|
||||
|
||||
@@ -111,7 +111,7 @@ export const changeMobile = (params) => {
|
||||
};
|
||||
// 获取用户数据 多条件
|
||||
export const getUserListData = (params) => {
|
||||
return getRequest("/passport/user", params);
|
||||
return getRequest("/passport/user/getByCondition", params);
|
||||
};
|
||||
// 通过用户名搜索
|
||||
export const searchUserByName = (username, params) => {
|
||||
@@ -368,6 +368,31 @@ export const setSetting = (key, params) => {
|
||||
return putRequestWithNoForm(`/setting/setting/put/${key}`, params);
|
||||
};
|
||||
|
||||
// 微信视频号小店类目(三级)
|
||||
export const getWxChannelsThirdCategory = (params) => {
|
||||
return getRequest(`/wxchannels/category/third`, params);
|
||||
};
|
||||
|
||||
// 微信视频号商品分页
|
||||
export const getWxChannelsGoodsPage = (params) => {
|
||||
return getRequest(`/wxchannels/goods`, params);
|
||||
};
|
||||
|
||||
// 微信视频号订单分页
|
||||
export const getWxChannelsOrderPage = (params) => {
|
||||
return getRequest(`/wxchannels/order`, params);
|
||||
};
|
||||
|
||||
// 微信视频号概况
|
||||
export const getWxChannelsOverviewSummary = (params) => {
|
||||
return getRequest(`/wxchannels/overview/summary`, params);
|
||||
};
|
||||
|
||||
// 微信视频号退单分页
|
||||
export const getWxChannelsRefundPage = (params) => {
|
||||
return getRequest(`/wxchannels/refund`, params);
|
||||
};
|
||||
|
||||
// 分页查询敏感词
|
||||
|
||||
export const getSensitiveWordsPage = (params) => {
|
||||
@@ -445,6 +470,21 @@ export const getProgress = () => {
|
||||
return getRequest(`/other/elasticsearch/progress`);
|
||||
};
|
||||
|
||||
// 删除ES中下架的商品
|
||||
export const deleteGoodsDown = () => {
|
||||
return getRequest(`/other/elasticsearch/deleteGoodsDown`);
|
||||
};
|
||||
|
||||
// 删除不存在的索引
|
||||
export const delSkuIndex = () => {
|
||||
return getRequest(`/other/elasticsearch/delSkuIndex`);
|
||||
};
|
||||
|
||||
// 生成所有商品的缓存
|
||||
export const generateGoodsCache = () => {
|
||||
return getRequest(`/other/elasticsearch/cache`);
|
||||
};
|
||||
|
||||
// 分页查询自定义分词
|
||||
export const getCustomWordsPage = (params) => {
|
||||
return getRequest(`/other/customWords/page`, params);
|
||||
|
||||
@@ -30,6 +30,11 @@ export const updateMemberReview = (id, params) => {
|
||||
return getRequest(`/member/evaluation/updateStatus/${id}`, params);
|
||||
};
|
||||
|
||||
// 修改评价置顶状态
|
||||
export const updateMemberReviewTop = (id, params) => {
|
||||
return putRequest(`/member/evaluation/updateTop/${id}`, params);
|
||||
};
|
||||
|
||||
// 添加或修改
|
||||
export const insertOrUpdateSpec = (params) => {
|
||||
return postRequest("/memberNoticeSenter/insertOrUpdate", params);
|
||||
@@ -117,6 +122,9 @@ export const getMemberNum = (params) => {
|
||||
export const getHistoryPointData = (params) => {
|
||||
return getRequest(`/member/memberPointsHistory/getByPage`, params);
|
||||
};
|
||||
export const queryMemberPointsStatistics = () => {
|
||||
return getRequest(`/member/memberPointsHistory/queryMemberPointsStatistics`);
|
||||
};
|
||||
//查询会员的收货地址
|
||||
export const getMemberAddressData = (id, params) => {
|
||||
return getRequest(`/member/address/${id}`, params);
|
||||
@@ -137,3 +145,86 @@ export const editMemberAddress = (params) => {
|
||||
export const getMemberWallet = (params) => {
|
||||
return getRequest(`/wallet/wallet`, params);
|
||||
};
|
||||
|
||||
export const increaseMemberWallet = (params) => {
|
||||
return putRequest(`/wallet/wallet/increase`, params);
|
||||
};
|
||||
|
||||
export const updateMemberPoint = (params) => {
|
||||
return putRequest(`/passport/member/updateMemberPoint`, params);
|
||||
};
|
||||
|
||||
export const getMemberGroupByPage = (params) => {
|
||||
return getRequest("/member/memberGroup/getByPage", params);
|
||||
};
|
||||
export const getMemberGroup = (id) => {
|
||||
return getRequest(`/member/memberGroup/get/${id}`);
|
||||
};
|
||||
export const addMemberGroup = (params) => {
|
||||
return postRequest(`/member/memberGroup`, params);
|
||||
};
|
||||
export const updateMemberGroup = (id, params) => {
|
||||
return putRequest(`/member/memberGroup/update/${id}`, params);
|
||||
};
|
||||
export const deleteMemberGroup = (id) => {
|
||||
return deleteRequest(`/member/memberGroup/delete/${id}`);
|
||||
};
|
||||
|
||||
export const addMemberGroupUsers = (groupId, memberIds) => {
|
||||
return postRequest(`/member/memberGroup/${groupId}/users`, {
|
||||
memberIds: Array.isArray(memberIds) ? memberIds.join(",") : memberIds,
|
||||
});
|
||||
};
|
||||
|
||||
// 客户等级
|
||||
export const getMemberGradeByPage = (params) => {
|
||||
return getRequest("/member/memberGrade/getByPage");
|
||||
};
|
||||
export const getMemberGrade = (id) => {
|
||||
return getRequest(`/member/memberGrade/get/${id}`);
|
||||
};
|
||||
export const addMemberGrade = (params) => {
|
||||
return postRequest(`/member/memberGrade`, params);
|
||||
};
|
||||
export const updateMemberGrade = (id, params) => {
|
||||
return putRequest(`/member/memberGrade/update/${id}`, params);
|
||||
};
|
||||
export const updateMemberGradeState = (id, state) => {
|
||||
return putRequest(`/member/memberGrade/state/${id}?state=${state}`);
|
||||
};
|
||||
export const deleteMemberGrade = (id) => {
|
||||
return deleteRequest(`/member/memberGrade/delete/${id}`);
|
||||
};
|
||||
export const getMemberExperienceByPage = (params) => {
|
||||
return getRequest(`/member/memberGrade/experience/getByPage`, params);
|
||||
};
|
||||
|
||||
// 客户权益
|
||||
export const getMemberBenefitByPage = (params) => {
|
||||
return getRequest("/member/benefit/getByPage", params);
|
||||
};
|
||||
|
||||
export const getMemberBenefit = (id) => {
|
||||
return getRequest(`/member/benefit/get/${id}`);
|
||||
};
|
||||
|
||||
export const addMemberBenefit = (params) => {
|
||||
return postRequest("/member/benefit", params);
|
||||
};
|
||||
|
||||
export const updateMemberBenefit = (id, params) => {
|
||||
return putRequest(`/member/benefit/update/${id}`, params);
|
||||
};
|
||||
|
||||
export const updateMemberBenefitState = (id, state) => {
|
||||
return putRequest(`/member/benefit/state/${id}?state=${state}`);
|
||||
};
|
||||
|
||||
export const deleteMemberBenefit = (id) => {
|
||||
return deleteRequest(`/member/benefit/delete/${id}`);
|
||||
};
|
||||
|
||||
/** 客户权益类型枚举(管理端) */
|
||||
export const getMemberBenefitTypes = () => {
|
||||
return getRequest("/member/benefit/types");
|
||||
};
|
||||
|
||||
@@ -160,3 +160,13 @@ export const refundLog = (params) => {
|
||||
export const storeAddress = (sn) => {
|
||||
return getRequest(`/order/afterSale/getStoreAfterSaleAddress/${sn}`)
|
||||
}
|
||||
|
||||
// 获取订单数量统计
|
||||
export const getOrderNum = (params) => {
|
||||
return getRequest(`/order/order/orderNum`, params)
|
||||
}
|
||||
|
||||
// 获取售后数量统计
|
||||
export const getAfterSaleNumVO = (params) => {
|
||||
return getRequest(`/order/afterSale/afterSaleNumVO`, params)
|
||||
}
|
||||
|
||||
@@ -114,5 +114,5 @@ export const getPrivacy = (type) => {
|
||||
}
|
||||
//修改隐私协议数据
|
||||
export const updatePrivacy = (id,type,params) => {
|
||||
return putRequest(`/other/article/updateArticle/${type}?id=${id}`, params, {"Content-Type": "application/json"})
|
||||
return putRequest(`/other/article/updateArticle/${type}/${id}`, params, {"Content-Type": "application/json"})
|
||||
}
|
||||
@@ -40,7 +40,7 @@ export default {
|
||||
params: {
|
||||
// 请求参数
|
||||
pageNumber: 1,
|
||||
pageSize: 10,
|
||||
pageSize: 20,
|
||||
storeName: "",
|
||||
},
|
||||
dateList: [
|
||||
|
||||
@@ -57,11 +57,11 @@ export default {
|
||||
};
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
/deep/ .ivu-modal {
|
||||
::v-deep .ivu-modal {
|
||||
overflow: hidden;
|
||||
height: 650px !important;
|
||||
}
|
||||
/deep/ .ivu-modal-body {
|
||||
::v-deep .ivu-modal-body {
|
||||
width: 100%;
|
||||
height: 500px;
|
||||
overflow: hidden;
|
||||
|
||||
@@ -86,11 +86,11 @@ export default {
|
||||
};
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
/deep/ .ivu-modal {
|
||||
::v-deep .ivu-modal {
|
||||
overflow: hidden;
|
||||
height: 650px !important;
|
||||
}
|
||||
/deep/ .ivu-modal-body {
|
||||
::v-deep .ivu-modal-body {
|
||||
width: 100%;
|
||||
height: 500px;
|
||||
overflow: hidden;
|
||||
|
||||
@@ -122,11 +122,11 @@ export default {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/deep/ .ivu-modal {
|
||||
::v-deep .ivu-modal {
|
||||
overflow: hidden;
|
||||
height: 650px !important;
|
||||
}
|
||||
/deep/ .ivu-modal-body {
|
||||
::v-deep .ivu-modal-body {
|
||||
width: 100%;
|
||||
height: 500px;
|
||||
overflow: hidden;
|
||||
|
||||
@@ -42,12 +42,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
/deep/ .ivu-scroll-container {
|
||||
::v-deep .ivu-scroll-container {
|
||||
width: 100% !important;
|
||||
height: 400px !important;
|
||||
}
|
||||
|
||||
/deep/ .ivu-scroll-content {
|
||||
::v-deep .ivu-scroll-content {
|
||||
/* */
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
@@ -81,7 +81,7 @@
|
||||
align-items: center;
|
||||
margin: 10px;
|
||||
|
||||
/deep/ img {
|
||||
::v-deep img {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
text-align: center;
|
||||
|
||||
@@ -70,7 +70,7 @@ export default {
|
||||
params: {
|
||||
// 请求参数
|
||||
pageNumber: 1,
|
||||
pageSize: 10,
|
||||
pageSize: 20,
|
||||
},
|
||||
pintuanColumns: [
|
||||
{
|
||||
@@ -101,12 +101,12 @@ export default {
|
||||
render: (h, params) => {
|
||||
return h("div", [
|
||||
h(
|
||||
"Button",
|
||||
"a",
|
||||
{
|
||||
props: {
|
||||
// type: this.index == params.index ? "primary" : "",
|
||||
type: 'default',
|
||||
size: "small",
|
||||
style: {
|
||||
color: "#2d8cf0",
|
||||
cursor: "pointer",
|
||||
textDecoration: "none",
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
@@ -194,12 +194,12 @@ export default {
|
||||
render: (h, params) => {
|
||||
return h("div", [
|
||||
h(
|
||||
"Button",
|
||||
"a",
|
||||
{
|
||||
props: {
|
||||
// type: this.index == params.index ? "primary" : "",
|
||||
type: 'default',
|
||||
size: "small",
|
||||
style: {
|
||||
color: "#2d8cf0",
|
||||
cursor: "pointer",
|
||||
textDecoration: "none",
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
@@ -246,12 +246,12 @@ export default {
|
||||
render: (h, params) => {
|
||||
return h("div", [
|
||||
h(
|
||||
"Button",
|
||||
"a",
|
||||
{
|
||||
props: {
|
||||
// type: this.index == params.index ? "primary" : "",
|
||||
type: 'default',
|
||||
size: "small",
|
||||
style: {
|
||||
color: "#2d8cf0",
|
||||
cursor: "pointer",
|
||||
textDecoration: "none",
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
@@ -420,7 +420,7 @@ img {
|
||||
overflow: auto;
|
||||
width: 100%;
|
||||
}
|
||||
/deep/ .ivu-table-wrapper {
|
||||
::v-deep .ivu-table-wrapper {
|
||||
width: 100%;
|
||||
}
|
||||
.list {
|
||||
|
||||
@@ -157,7 +157,7 @@ export default {
|
||||
text-align: center;
|
||||
transition: 0.35s;
|
||||
cursor: pointer;
|
||||
/deep/ p {
|
||||
::v-deep p {
|
||||
margin: 10px 0;
|
||||
}
|
||||
border: 1px solid #ededed;
|
||||
|
||||
@@ -33,7 +33,7 @@ export default {
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
/deep/ .ivu-card-body {
|
||||
::v-deep .ivu-card-body {
|
||||
height: 414px;
|
||||
overflow: auto;
|
||||
}
|
||||
@@ -69,11 +69,11 @@ export default {
|
||||
height: 416px;
|
||||
overflow: hidden;
|
||||
}
|
||||
/deep/ .ivu-table {
|
||||
::v-deep .ivu-table {
|
||||
height: 300px !important;
|
||||
overflow: auto;
|
||||
}
|
||||
/deep/ .ivu-card-body {
|
||||
::v-deep .ivu-card-body {
|
||||
padding: 0;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ export default {
|
||||
order: "desc",
|
||||
pageClientType: "H5",
|
||||
pageNumber: 1,
|
||||
pageSize: 10,
|
||||
pageSize: 20,
|
||||
pageType: "SPECIAL",
|
||||
},
|
||||
total: 0, // 表单数据总数
|
||||
@@ -137,7 +137,7 @@ img {
|
||||
overflow: auto;
|
||||
width: 100%;
|
||||
}
|
||||
/deep/ .ivu-table-wrapper {
|
||||
::v-deep .ivu-table-wrapper {
|
||||
width: 100%;
|
||||
}
|
||||
.list {
|
||||
|
||||
@@ -39,14 +39,20 @@
|
||||
<!--</Upload>-->
|
||||
</div>
|
||||
|
||||
<Modal title="图片预览" v-model="viewImage" :styles="{top: '30px'}" draggable>
|
||||
<Modal
|
||||
title="图片预览"
|
||||
v-model="viewImage"
|
||||
:styles="{ top: '30px' }"
|
||||
:z-index="3500"
|
||||
draggable
|
||||
>
|
||||
<img :src="currentValue" alt="该资源不存在" style="max-width: 300px;margin: 0 auto;display: block;" />
|
||||
<div slot="footer">
|
||||
<Button @click="viewImage=false">关闭</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
<Modal width="1200px" v-model="picModalFlag">
|
||||
<Modal width="1200px" v-model="picModalFlag" :z-index="3500">
|
||||
<ossManage @callback="callbackSelected" ref="ossManage" :isComponent="true" :initialize="picModalFlag" />
|
||||
</Modal>
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ export const otherRouter = {
|
||||
},
|
||||
{
|
||||
path: "category",
|
||||
title: "类型列表",
|
||||
title: "分类列表",
|
||||
name: "category",
|
||||
component: () => import("@/views/goods/goods-manage/category.vue")
|
||||
},
|
||||
@@ -91,6 +91,12 @@ export const otherRouter = {
|
||||
name: "goods-category",
|
||||
component: () => import("@/views/goods/goods-manage/category.vue")
|
||||
},
|
||||
{
|
||||
path: "goods-group",
|
||||
title: "商品分组",
|
||||
name: "goods-group",
|
||||
component: () => import("@/views/goods/group/index.vue")
|
||||
},
|
||||
{
|
||||
path: "goods-parameter",
|
||||
title: "商品参数",
|
||||
@@ -98,10 +104,10 @@ export const otherRouter = {
|
||||
component: () => import("@/views/goods/goods-manage/parameter.vue")
|
||||
},
|
||||
{
|
||||
path: "goods-spec",
|
||||
title: "商品参数",
|
||||
name: "goods-spec",
|
||||
component: () => import("@/views/goods/goods-manage/spec.vue")
|
||||
path: "goods-parameter-edit",
|
||||
title: "编辑商品参数",
|
||||
name: "goods-parameter-edit",
|
||||
component: () => import("@/views/goods/goods-manage/parameter-edit.vue")
|
||||
},
|
||||
{
|
||||
path: "order-complaint-detail",
|
||||
@@ -141,6 +147,37 @@ export const otherRouter = {
|
||||
name: "member-detail",
|
||||
component: () => import("@/views/member/list/memberDetail.vue")
|
||||
},
|
||||
{
|
||||
path: "member-group",
|
||||
title: "会员分组",
|
||||
name: "member-group",
|
||||
component: () => import("@/views/member/group/index.vue")
|
||||
},
|
||||
{
|
||||
path: "member-grade",
|
||||
title: "客户等级",
|
||||
name: "member-grade",
|
||||
component: () => import("@/views/member/grade/index.vue")
|
||||
},
|
||||
{
|
||||
path: "member-benefit",
|
||||
title: "客户权益管理",
|
||||
name: "member-benefit",
|
||||
component: () => import("@/views/member/benefit/index.vue")
|
||||
},
|
||||
{
|
||||
path: "member-grade-experience",
|
||||
title: "等级权益设置",
|
||||
name: "member-grade-experience",
|
||||
component: () => import("@/views/member/grade/experience-setting.vue")
|
||||
},
|
||||
{
|
||||
path: "member-grade-experience-log",
|
||||
title: "客户经验值记录",
|
||||
name: "member-grade-experience-log",
|
||||
component: () => import("@/views/member/grade/experience-log.vue")
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
path: "goods/goods-info/goodsDetail",
|
||||
|
||||
@@ -19,10 +19,9 @@
|
||||
width: 100% !important;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: #f0f0f0;
|
||||
// background-color: #f0f0f0;
|
||||
border-radius: 0.4em;
|
||||
padding: 10px;
|
||||
margin: 0;
|
||||
|
||||
flex-wrap: wrap;
|
||||
> .ivu-form-item {
|
||||
margin: 8px 10px !important;
|
||||
@@ -42,3 +41,8 @@
|
||||
-webkit-line-clamp: 4;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
// 为Card组件之间增加间距
|
||||
.ivu-card + .ivu-card {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
@@ -85,3 +85,36 @@ export function memberPromotionsStatusRender(h, status) {
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 平台优惠券「活动时间 / 有效期」文案(活动获取券:effectiveDays 为领取后有效天数)
|
||||
*/
|
||||
export function formatPromotionCouponValidityHtml(row) {
|
||||
if (!row) return "-";
|
||||
if (row.getType === "ACTIVITY") {
|
||||
const days = row.effectiveDays;
|
||||
if (days !== undefined && days !== null && days !== "") {
|
||||
const n = Number(days);
|
||||
if (!Number.isNaN(n) && n > 0) {
|
||||
return `领取后${n}天有效`;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (row.startTime && row.endTime) {
|
||||
return `${row.startTime}<br/>${row.endTime}`;
|
||||
}
|
||||
if (row.getType === "ACTIVITY" && row.rangeDayType === "DYNAMICTIME") {
|
||||
return "长期有效";
|
||||
}
|
||||
return "-";
|
||||
}
|
||||
|
||||
/** Table 列 render:活动时间(与 formatPromotionCouponValidityHtml 一致) */
|
||||
export function promotionsCouponActivityTimeRender(h, params) {
|
||||
const html = formatPromotionCouponValidityHtml(params.row);
|
||||
if (html === "-") return h("div", "-");
|
||||
if (html.indexOf("<br/>") !== -1) {
|
||||
return h("div", { domProps: { innerHTML: html } });
|
||||
}
|
||||
return h("div", html);
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
:page-size="searchForm.pageSize"
|
||||
@on-change="changePage"
|
||||
@on-page-size-change="changePageSize"
|
||||
:page-size-opts="[10, 20, 50]"
|
||||
:page-size-opts="[20, 50, 100]"
|
||||
size="small"
|
||||
show-total
|
||||
show-elevator
|
||||
@@ -69,7 +69,7 @@ export default {
|
||||
searchForm: {
|
||||
// 搜索框初始化对象
|
||||
pageNumber: 1, // 当前页数
|
||||
pageSize: 10, // 页面大小
|
||||
pageSize: 20, // 页面大小
|
||||
sort: "createTime", // 默认排序字段
|
||||
order: "desc", // 默认排序方式
|
||||
words: "",
|
||||
@@ -124,14 +124,12 @@ export default {
|
||||
render: (h, params) => {
|
||||
return h("div", [
|
||||
h(
|
||||
"Button",
|
||||
"a",
|
||||
{
|
||||
props: {
|
||||
type: "info",
|
||||
size: "small",
|
||||
},
|
||||
style: {
|
||||
marginRight: "5px",
|
||||
color: "#2d8cf0",
|
||||
cursor: "pointer",
|
||||
textDecoration: "none",
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
@@ -142,14 +140,17 @@ export default {
|
||||
"修改"
|
||||
),
|
||||
h(
|
||||
"Button",
|
||||
"span",
|
||||
{ style: { margin: "0 8px", color: "#dcdee2" } },
|
||||
"|"
|
||||
),
|
||||
h(
|
||||
"a",
|
||||
{
|
||||
props: {
|
||||
type: "error",
|
||||
size: "small",
|
||||
},
|
||||
style: {
|
||||
marginRight: "5px",
|
||||
color: "#2d8cf0",
|
||||
cursor: "pointer",
|
||||
textDecoration: "none",
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
|
||||
@@ -15,13 +15,13 @@
|
||||
v-model="searchForm.memberName"
|
||||
placeholder="请输入会员名称"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
style="width: 240px"
|
||||
/>
|
||||
</Form-item>
|
||||
<Form-item label="状态">
|
||||
<Select
|
||||
v-model="searchForm.distributionStatus"
|
||||
style="width: 200px"
|
||||
style="width: 240px"
|
||||
>
|
||||
<Option
|
||||
v-for="item in distributionStatusList"
|
||||
@@ -42,6 +42,8 @@
|
||||
>
|
||||
</Form>
|
||||
</Row>
|
||||
</Card>
|
||||
<Card>
|
||||
<Table
|
||||
:loading="loading"
|
||||
border
|
||||
@@ -57,7 +59,7 @@
|
||||
:page-size="searchForm.pageSize"
|
||||
@on-change="changePage"
|
||||
@on-page-size-change="changePageSize"
|
||||
:page-size-opts="[10, 20, 50]"
|
||||
:page-size-opts="[20, 50, 100]"
|
||||
size="small"
|
||||
show-total
|
||||
show-elevator
|
||||
@@ -138,7 +140,7 @@ export default {
|
||||
searchForm: {
|
||||
// 搜索框初始化对象
|
||||
pageNumber: 1, // 当前页数
|
||||
pageSize: 10, // 页面大小
|
||||
pageSize: 20, // 页面大小
|
||||
},
|
||||
columns: [
|
||||
{
|
||||
@@ -344,7 +346,7 @@ export default {
|
||||
// 搜索
|
||||
handleSearch() {
|
||||
this.searchForm.pageNumber = 1;
|
||||
this.searchForm.pageSize = 10;
|
||||
this.searchForm.pageSize = 20;
|
||||
this.getDataList();
|
||||
},
|
||||
// 获取列表数据
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
v-model="searchForm.memberName"
|
||||
placeholder="请输入会员名称"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
style="width: 240px"
|
||||
/>
|
||||
</Form-item>
|
||||
<Button
|
||||
@@ -26,6 +26,8 @@
|
||||
>
|
||||
</Form>
|
||||
</Row>
|
||||
</Card>
|
||||
<Card>
|
||||
<Table
|
||||
class="mt_10"
|
||||
:loading="loading"
|
||||
@@ -41,7 +43,7 @@
|
||||
:page-size="searchForm.pageSize"
|
||||
@on-change="changePage"
|
||||
@on-page-size-change="changePageSize"
|
||||
:page-size-opts="[10, 20, 50]"
|
||||
:page-size-opts="[20, 50, 100]"
|
||||
size="small"
|
||||
show-total
|
||||
show-elevator
|
||||
@@ -63,7 +65,7 @@ export default {
|
||||
searchForm: {
|
||||
// 搜索框初始化对象
|
||||
pageNumber: 1, // 当前页数
|
||||
pageSize: 10, // 页面大小
|
||||
pageSize: 20, // 页面大小
|
||||
sort: "createTime", // 默认排序字段
|
||||
order: "desc", // 默认排序方式
|
||||
startDate: "", // 起始时间
|
||||
@@ -113,17 +115,10 @@ export default {
|
||||
fixed: "right",
|
||||
width: 200,
|
||||
render: (h, params) => {
|
||||
return h("div", [
|
||||
return h("div", { class: "ops" }, [
|
||||
h(
|
||||
"Button",
|
||||
"a",
|
||||
{
|
||||
props: {
|
||||
type: "success",
|
||||
size: "small",
|
||||
},
|
||||
style: {
|
||||
marginRight: "5px",
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
this.audit(params.row, "PASS");
|
||||
@@ -132,13 +127,10 @@ export default {
|
||||
},
|
||||
"通过"
|
||||
),
|
||||
h("span", {}, "|"),
|
||||
h(
|
||||
"Button",
|
||||
"a",
|
||||
{
|
||||
props: {
|
||||
type: "error",
|
||||
size: "small",
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
this.audit(params.row, "REFUSE");
|
||||
@@ -174,7 +166,7 @@ export default {
|
||||
// 搜索
|
||||
handleSearch() {
|
||||
this.searchForm.pageNumber = 1;
|
||||
this.searchForm.pageSize = 10;
|
||||
this.searchForm.pageSize = 20;
|
||||
this.getDataList();
|
||||
},
|
||||
// 获取列表数据
|
||||
@@ -222,3 +214,15 @@ export default {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.ops a {
|
||||
color: #2d8cf0;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
}
|
||||
.ops span {
|
||||
display: inline-block;
|
||||
margin: 0 8px;
|
||||
color: #dcdee2;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -5,15 +5,15 @@
|
||||
<Form-item label="会员名称" class="flex" prop="memberName">
|
||||
<Input
|
||||
type="text" placeholder="请输入会员名称" v-model="searchForm.memberName" clearable
|
||||
style="width: 200px"></Input>
|
||||
style="width: 240px"></Input>
|
||||
</Form-item>
|
||||
<Form-item label="编号" class="flex">
|
||||
<Input
|
||||
type="text" placeholder="请输入编号" v-model="searchForm.sn" clearable
|
||||
style="width: 200px"></Input>
|
||||
style="width: 240px"></Input>
|
||||
</Form-item>
|
||||
<Form-item label="状态"
|
||||
style="width: 200px">
|
||||
style="width: 240px">
|
||||
<Select v-model="searchForm.distributionCashStatus" clearable style="width: 150px">
|
||||
<Option v-for="item in cashStatusList" :value="item.value" :key="item.value">{{ item.label }}</Option>
|
||||
</Select>
|
||||
@@ -22,9 +22,11 @@
|
||||
<Button @click="handleSearch" type="primary">搜索</Button>
|
||||
</Form-item>
|
||||
</Form>
|
||||
</Card>
|
||||
<Card>
|
||||
<Table :loading="loading" border :columns="columns" :data="data" ref="table" class="mt_10"></Table>
|
||||
<Row type="flex" justify="end" class="page padding-row">
|
||||
<Page :current="searchForm.pageNumber" :total="total" :page-size="searchForm.pageSize" @on-change="changePage" @on-page-size-change="changePageSize" :page-size-opts="[10,20,50]" size="small" show-total show-elevator show-sizer></Page>
|
||||
<Page :current="searchForm.pageNumber" :total="total" :page-size="searchForm.pageSize" @on-change="changePage" @on-page-size-change="changePageSize" :page-size-opts="[20,50,100]" size="small" show-total show-elevator show-sizer></Page>
|
||||
</Row>
|
||||
</Card>
|
||||
<Modal :title="modalTitle" v-model="modalVisible" :mask-closable='false' :width="500">
|
||||
@@ -70,7 +72,7 @@ export default {
|
||||
result: 'FAIL_AUDITING', // 是否通过
|
||||
searchForm: { // 搜索框初始化对象
|
||||
pageNumber: 1, // 当前页数
|
||||
pageSize: 10, // 页面大小
|
||||
pageSize: 20, // 页面大小
|
||||
sort: "createTime", // 默认排序字段
|
||||
order: "desc", // 默认排序方式
|
||||
},
|
||||
@@ -158,50 +160,34 @@ export default {
|
||||
fixed: "right",
|
||||
width: 130,
|
||||
render: (h, params) => {
|
||||
if(params.row.distributionCashStatus != 'APPLY'){
|
||||
return h("div", [
|
||||
h(
|
||||
"Button",
|
||||
{
|
||||
props: {
|
||||
type: "primary",
|
||||
size: "small",
|
||||
},
|
||||
style: {
|
||||
marginRight: "5px"
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
this.view(params.row);
|
||||
}
|
||||
if (params.row.distributionCashStatus != 'APPLY') {
|
||||
return h("div", { class: "ops" }, [
|
||||
h(
|
||||
"a",
|
||||
{
|
||||
on: {
|
||||
click: () => {
|
||||
this.view(params.row);
|
||||
}
|
||||
},
|
||||
"查看"
|
||||
),
|
||||
|
||||
]);
|
||||
}else {
|
||||
return h("div", [
|
||||
h(
|
||||
"Button",
|
||||
{
|
||||
props: {
|
||||
type: "primary",
|
||||
size: "small",
|
||||
},
|
||||
style: {
|
||||
marginRight: "5px"
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
this.edit(params.row);
|
||||
}
|
||||
}
|
||||
},
|
||||
"查看"
|
||||
),
|
||||
]);
|
||||
} else {
|
||||
return h("div", { class: "ops" }, [
|
||||
h(
|
||||
"a",
|
||||
{
|
||||
on: {
|
||||
click: () => {
|
||||
this.edit(params.row);
|
||||
}
|
||||
},
|
||||
"审核"
|
||||
),
|
||||
|
||||
]);
|
||||
}
|
||||
},
|
||||
"审核"
|
||||
),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -228,7 +214,7 @@ export default {
|
||||
// 搜索
|
||||
handleSearch() {
|
||||
this.searchForm.pageNumber = 1;
|
||||
this.searchForm.pageSize = 10;
|
||||
this.searchForm.pageSize = 20;
|
||||
this.getDataList();
|
||||
},
|
||||
// 获取列表数据
|
||||
@@ -310,3 +296,15 @@ export default {
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.ops a {
|
||||
color: #2d8cf0;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
}
|
||||
.ops span {
|
||||
display: inline-block;
|
||||
margin: 0 8px;
|
||||
color: #dcdee2;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -4,10 +4,12 @@
|
||||
<Form @keydown.enter.native.prevent="handleSearch" ref="searchForm" :model="searchForm" inline :label-width="70"
|
||||
class="search-form">
|
||||
<Form-item label="商品名称" prop="goodsName">
|
||||
<Input type="text" v-model="searchForm.goodsName" placeholder="请输入商品名称" clearable style="width: 200px" />
|
||||
<Input type="text" v-model="searchForm.goodsName" placeholder="请输入商品名称" clearable style="width: 240px" />
|
||||
</Form-item>
|
||||
<Button @click="handleSearch" type="primary" icon="ios-search" class="search-btn">搜索</Button>
|
||||
</Form>
|
||||
</Card>
|
||||
<Card>
|
||||
<Row class="operation" style="margin:10px 0;">
|
||||
<Button @click="delAll" type="primary">批量下架</Button>
|
||||
</Row>
|
||||
@@ -30,7 +32,7 @@
|
||||
</Table>
|
||||
<Row type="flex" justify="end" class="mt_10">
|
||||
<Page :current="searchForm.pageNumber" :total="total" :page-size="searchForm.pageSize" @on-change="changePage"
|
||||
@on-page-size-change="changePageSize" :page-size-opts="[10,20,50]" size="small" show-total show-elevator
|
||||
@on-page-size-change="changePageSize" :page-size-opts="[20,50,100]" size="small" show-total show-elevator
|
||||
show-sizer></Page>
|
||||
</Row>
|
||||
</Card>
|
||||
@@ -51,7 +53,7 @@ export default {
|
||||
searchForm: {
|
||||
// 搜索框初始化对象
|
||||
pageNumber: 1, // 当前页数
|
||||
pageSize: 10, // 页面大小
|
||||
pageSize: 20, // 页面大小
|
||||
sort: "createTime", // 默认排序字段
|
||||
order: "desc", // 默认排序方式
|
||||
},
|
||||
@@ -135,14 +137,10 @@ export default {
|
||||
fixed: "right",
|
||||
minWidth: 100,
|
||||
render: (h, params) => {
|
||||
return h("div", [
|
||||
return h("div", { class: "ops" }, [
|
||||
h(
|
||||
"Button",
|
||||
"a",
|
||||
{
|
||||
props: {
|
||||
type: "error",
|
||||
size: "small",
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
this.remove(params.row);
|
||||
@@ -178,7 +176,7 @@ export default {
|
||||
// 搜索
|
||||
handleSearch() {
|
||||
this.searchForm.pageNumber = 1;
|
||||
this.searchForm.pageSize = 10;
|
||||
this.searchForm.pageSize = 20;
|
||||
this.getDataList();
|
||||
},
|
||||
// 清除选中状态
|
||||
@@ -254,5 +252,17 @@ export default {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.ops a {
|
||||
color: #2d8cf0;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
}
|
||||
.ops span {
|
||||
display: inline-block;
|
||||
margin: 0 8px;
|
||||
color: #dcdee2;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
v-model="searchForm.orderSn"
|
||||
placeholder="请输入订单编号"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
style="width: 240px"
|
||||
/>
|
||||
</Form-item>
|
||||
<Form-item label="分销商" prop="distributionName">
|
||||
@@ -17,21 +17,23 @@
|
||||
v-model="searchForm.distributionName"
|
||||
placeholder="请输入分销商名称"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
style="width: 240px"
|
||||
/>
|
||||
</Form-item>
|
||||
<Form-item label="店铺名称">
|
||||
<Select v-model="searchForm.storeId" placeholder="请选择" @on-query-change="searchChange" filterable
|
||||
clearable style="width: 150px">
|
||||
clearable style="width: 240px">
|
||||
<Option v-for="item in shopList" :value="item.id" :key="item.id">{{ item.storeName }}</Option>
|
||||
</Select>
|
||||
</Form-item>
|
||||
<Form-item label="订单时间">
|
||||
<DatePicker type="daterange" v-model="timeRange" format="yyyy-MM-dd" placeholder="选择时间"
|
||||
style="width: 210px"></DatePicker>
|
||||
style="width: 240px"></DatePicker>
|
||||
</Form-item>
|
||||
<Button @click="handleSearch" type="primary" icon="ios-search" class="search-btn">搜索</Button>
|
||||
</Form>
|
||||
</Card>
|
||||
<Card>
|
||||
<Table :loading="loading" border :columns="columns" :data="data" ref="table" class="mt_10">
|
||||
<template slot-scope="{row}" slot="goodsMsg">
|
||||
<div class="goods-msg">
|
||||
@@ -56,7 +58,7 @@
|
||||
</Table>
|
||||
<Row type="flex" justify="end" class="mt_10">
|
||||
<Page :current="searchForm.pageNumber" :total="total" :page-size="searchForm.pageSize"
|
||||
@on-change="changePage" @on-page-size-change="changePageSize" :page-size-opts="[10,20,50]"
|
||||
@on-change="changePage" @on-page-size-change="changePageSize" :page-size-opts="[20,50,100]"
|
||||
size="small" show-total show-elevator show-sizer></Page>
|
||||
</Row>
|
||||
</Card>
|
||||
@@ -85,7 +87,7 @@
|
||||
loading: true, // 表单加载状态
|
||||
searchForm: { // 搜索框初始化对象
|
||||
pageNumber: 1, // 当前页数
|
||||
pageSize: 10, // 页面大小
|
||||
pageSize: 20, // 页面大小
|
||||
sort:"create_time",
|
||||
order:"desc"
|
||||
},
|
||||
@@ -162,7 +164,7 @@
|
||||
// 搜索
|
||||
handleSearch() {
|
||||
this.searchForm.pageNumber = 1;
|
||||
this.searchForm.pageSize = 10;
|
||||
this.searchForm.pageSize = 20;
|
||||
this.getDataList();
|
||||
},
|
||||
// 获取列表数据
|
||||
@@ -190,7 +192,7 @@
|
||||
getShopList(val) { // 获取店铺列表 搜索用
|
||||
const params = {
|
||||
pageNumber: 1,
|
||||
pageSize: 10,
|
||||
pageSize: 20,
|
||||
storeName: ''
|
||||
}
|
||||
if (val) {
|
||||
@@ -208,7 +210,7 @@
|
||||
},
|
||||
filterStatus (status) { // 过滤订单状态
|
||||
const arr = [
|
||||
{status: 'WAIT_BILL', title: '待结算'},
|
||||
{status: 'NO_COMPLETED', title: '未完成'},
|
||||
{status: 'COMPLETE', title: '完成'},
|
||||
{status: 'REFUND', title: '退款'},
|
||||
]
|
||||
@@ -217,21 +219,20 @@
|
||||
return arr[i].title;
|
||||
}
|
||||
}
|
||||
return '未完成'; // 默认返回未完成
|
||||
},
|
||||
filterStatusColor (status) { // 状态tag标签颜色
|
||||
const arr = [
|
||||
{status: 'WAIT_BILL', color: 'blue'},
|
||||
{status: 'WAIT_CASH', color: 'orange'},
|
||||
{status: 'COMPLETE_CASH', color: 'green'},
|
||||
{status: 'CANCEL', color: 'red'},
|
||||
{status: 'NO_COMPLETED', color: 'red'},
|
||||
{status: 'REFUND', color: 'magenta'},
|
||||
{status: 'NO_COMPLETED', color: 'orange'},
|
||||
{status: 'COMPLETE', color: 'green'},
|
||||
{status: 'REFUND', color: 'red'},
|
||||
]
|
||||
for (let i=0;i<arr.length;i++) {
|
||||
if (arr[i].status === status) {
|
||||
return arr[i].color;
|
||||
}
|
||||
}
|
||||
return 'orange'; // 默认返回橙色
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
<Card>
|
||||
<Row class="operation">
|
||||
<Button @click="add" type="primary">添加</Button>
|
||||
<Button @click="refresh">刷新</Button>
|
||||
<Button @click="delAll">批量删除</Button>
|
||||
</Row>
|
||||
<Table
|
||||
@@ -22,7 +21,7 @@
|
||||
:page-size="searchForm.pageSize"
|
||||
@on-change="changePage"
|
||||
@on-page-size-change="changePageSize"
|
||||
:page-size-opts="[10, 20, 50]"
|
||||
:page-size-opts="[20, 50, 100]"
|
||||
size="small"
|
||||
show-total
|
||||
show-elevator
|
||||
@@ -71,7 +70,7 @@ export default {
|
||||
searchForm: {
|
||||
// 搜索框初始化对象
|
||||
pageNumber: 1, // 当前页数
|
||||
pageSize: 10, // 页面大小
|
||||
pageSize: 20, // 页面大小
|
||||
sort: "createTime", // 默认排序字段
|
||||
order: "desc", // 默认排序方式
|
||||
name: "",
|
||||
@@ -122,18 +121,17 @@ export default {
|
||||
title: "操作",
|
||||
key: "action",
|
||||
align: "center",
|
||||
fixed: "right",
|
||||
width: 200,
|
||||
render: (h, params) => {
|
||||
return h("div", [
|
||||
h(
|
||||
"Button",
|
||||
"a",
|
||||
{
|
||||
props: {
|
||||
type: "info",
|
||||
size: "small",
|
||||
},
|
||||
style: {
|
||||
marginRight: "5px",
|
||||
color: "#2d8cf0",
|
||||
cursor: "pointer",
|
||||
textDecoration: "none",
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
@@ -144,14 +142,17 @@ export default {
|
||||
"修改"
|
||||
),
|
||||
h(
|
||||
"Button",
|
||||
"span",
|
||||
{ style: { margin: "0 8px", color: "#dcdee2" } },
|
||||
"|"
|
||||
),
|
||||
h(
|
||||
"a",
|
||||
{
|
||||
props: {
|
||||
type: "error",
|
||||
size: "small",
|
||||
},
|
||||
style: {
|
||||
marginRight: "5px",
|
||||
color: "#2d8cf0",
|
||||
cursor: "pointer",
|
||||
textDecoration: "none",
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
@@ -188,7 +189,7 @@ export default {
|
||||
// 搜索
|
||||
handleSearch() {
|
||||
this.searchForm.pageNumber = 1;
|
||||
this.searchForm.pageSize = 10;
|
||||
this.searchForm.pageSize = 20;
|
||||
this.getDataList();
|
||||
},
|
||||
// 清除选中
|
||||
@@ -285,15 +286,7 @@ export default {
|
||||
},
|
||||
});
|
||||
},
|
||||
// 刷新
|
||||
refresh() {
|
||||
this.loading = true;
|
||||
setTimeout(() => {
|
||||
this.getDataList();
|
||||
this.loading = false;
|
||||
this.$Message.success("刷新成功");
|
||||
}, 500);
|
||||
},
|
||||
|
||||
// 全部删除
|
||||
delAll() {
|
||||
if (this.selectCount <= 0) {
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
v-model="searchForm.goodsName"
|
||||
placeholder="请输入商品名称"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
style="width: 240px"
|
||||
/>
|
||||
</Form-item>
|
||||
<Form-item label="商品编号" prop="id">
|
||||
@@ -24,7 +24,7 @@
|
||||
v-model="searchForm.id"
|
||||
placeholder="请输入商品编号"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
style="width: 240px"
|
||||
/>
|
||||
</Form-item>
|
||||
<Form-item label="店铺名称" prop="id">
|
||||
@@ -33,26 +33,15 @@
|
||||
v-model="searchForm.storeName"
|
||||
placeholder="请输入店铺名称"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
style="width: 240px"
|
||||
/>
|
||||
</Form-item>
|
||||
<Form-item label="状态" prop="status">
|
||||
<Select
|
||||
v-model="searchForm.marketEnable"
|
||||
placeholder="请选择"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
>
|
||||
<Option value="UPPER">上架</Option>
|
||||
<Option value="DOWN">下架</Option>
|
||||
</Select>
|
||||
</Form-item>
|
||||
<Form-item label="销售模式" prop="status">
|
||||
<Select
|
||||
v-model="searchForm.salesModel"
|
||||
placeholder="请选择"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
style="width: 240px"
|
||||
>
|
||||
<Option value="RETAIL">零售</Option>
|
||||
<Option value="WHOLESALE">批发</Option>
|
||||
@@ -63,12 +52,23 @@
|
||||
v-model="searchForm.goodsType"
|
||||
placeholder="请选择"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
style="width: 240px"
|
||||
>
|
||||
<Option value="PHYSICAL_GOODS">实物商品</Option>
|
||||
<Option value="VIRTUAL_GOODS">虚拟商品</Option>
|
||||
</Select>
|
||||
</Form-item>
|
||||
<Form-item label="商品分组" prop="groupId">
|
||||
<Select
|
||||
v-model="searchForm.groupId"
|
||||
placeholder="请选择商品分组"
|
||||
clearable
|
||||
filterable
|
||||
style="width: 240px"
|
||||
>
|
||||
<Option v-for="item in goodsGroupList" :value="item.id" :key="item.id">{{ item.groupName }}</Option>
|
||||
</Select>
|
||||
</Form-item>
|
||||
<Button
|
||||
@click="handleSearch"
|
||||
class="search-btn"
|
||||
@@ -77,46 +77,77 @@
|
||||
>搜索</Button
|
||||
>
|
||||
</Form>
|
||||
</Card>
|
||||
<Card>
|
||||
|
||||
<div class="goods-tab">
|
||||
<Tabs v-model="currentStatus" @on-click="goodsStatusClick">
|
||||
<TabPane v-for="(item,index) in goodsStatusWithCount" :key="index" :label="item.title" :name="item.value">
|
||||
</TabPane>
|
||||
</Tabs>
|
||||
</div>
|
||||
|
||||
<!-- 批量操作按钮 -->
|
||||
<div class="batch-operations" style="margin: 10px 0;">
|
||||
<Button
|
||||
type="primary"
|
||||
:disabled="selectedRows.length === 0"
|
||||
@click="openSetGoodsGroup"
|
||||
style="margin-right: 10px;"
|
||||
>
|
||||
批量设置分组
|
||||
</Button>
|
||||
<Button
|
||||
type="success"
|
||||
:disabled="selectedRows.length === 0"
|
||||
@click="batchUpper"
|
||||
style="margin-right: 10px;"
|
||||
>
|
||||
批量上架
|
||||
</Button>
|
||||
<Button
|
||||
type="warning"
|
||||
:disabled="selectedRows.length === 0"
|
||||
@click="batchLower"
|
||||
style="margin-right: 10px;"
|
||||
>
|
||||
批量下架
|
||||
</Button>
|
||||
<Button
|
||||
v-if="currentStatus === 'TOBEAUDITED'"
|
||||
type="primary"
|
||||
:disabled="selectedRows.length === 0"
|
||||
@click="batchAudit"
|
||||
>
|
||||
批量审核
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<Table
|
||||
:loading="loading"
|
||||
border
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
ref="table"
|
||||
class="mt_10"
|
||||
@on-select="onSelect"
|
||||
@on-select-all="onSelectAll"
|
||||
@on-selection-change="onSelectionChange"
|
||||
>
|
||||
<!-- 商品图片格式化 -->
|
||||
<template slot="imageSlot" slot-scope="{ row }">
|
||||
<div style="margin-top: 5px;">
|
||||
<img
|
||||
:src="row.original"
|
||||
style="height: 50px; width: 50px; object-fit: cover;"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 商品栏目格式化 -->
|
||||
<template slot="goodsSlot" slot-scope="{ row }">
|
||||
<div style="margin: 5px 0px; height: 80px; display: flex">
|
||||
<div style="">
|
||||
<img
|
||||
:src="row.original"
|
||||
style="height: 60px; margin-top: 1px; width: 60px"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div style="margin-left: 13px">
|
||||
<div class="div-zoom">
|
||||
<a @click="linkTo(row.id, row.skuId)">{{ row.goodsName }}</a>
|
||||
</div>
|
||||
<Poptip trigger="hover" title="扫码在手机中查看" transfer>
|
||||
<div slot="content">
|
||||
<vue-qr
|
||||
:text="wapLinkTo(row.id, row.skuId)"
|
||||
:margin="0"
|
||||
colorDark="#000"
|
||||
colorLight="#fff"
|
||||
:size="150"
|
||||
></vue-qr>
|
||||
</div>
|
||||
<img
|
||||
src="../../../assets/qrcode.svg"
|
||||
class="hover-pointer"
|
||||
width="20"
|
||||
height="20"
|
||||
alt=""
|
||||
/>
|
||||
</Poptip>
|
||||
<div style="margin: 5px 0px; padding: 10px 0px;">
|
||||
<div class="div-zoom">
|
||||
<a @click="linkTo(row.id, row.skuId)">{{ row.goodsName }}</a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -128,7 +159,7 @@
|
||||
:page-size="searchForm.pageSize"
|
||||
@on-change="changePage"
|
||||
@on-page-size-change="changePageSize"
|
||||
:page-size-opts="[10, 20, 50]"
|
||||
:page-size-opts="[20, 50, 100]"
|
||||
size="small"
|
||||
show-total
|
||||
show-elevator
|
||||
@@ -154,11 +185,82 @@
|
||||
>
|
||||
</div>
|
||||
</Modal>
|
||||
<Modal
|
||||
title="商品审核"
|
||||
v-model="auditModalVisible"
|
||||
:mask-closable="false"
|
||||
:width="500"
|
||||
>
|
||||
<Form ref="auditForm" :model="goodsAuditForm" :label-width="100">
|
||||
<FormItem label="审核结果" prop="auth_flag">
|
||||
<RadioGroup v-model="goodsAuditForm.auth_flag">
|
||||
<Radio :label="1">审核通过</Radio>
|
||||
<Radio :label="2">审核拒绝</Radio>
|
||||
</RadioGroup>
|
||||
</FormItem>
|
||||
<!-- <FormItem label="审核备注" prop="reason" v-if="goodsAuditForm.auth_flag === 2">
|
||||
<Input v-model="goodsAuditForm.reason" type="textarea" :rows="3" placeholder="请输入拒绝原因" />
|
||||
</FormItem> -->
|
||||
</Form>
|
||||
<div slot="footer">
|
||||
<Button type="text" @click="auditModalVisible = false">取消</Button>
|
||||
<Button type="primary" @click="confirmAudit">提交审核</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
<!-- 批量审核弹框 -->
|
||||
<Modal
|
||||
title="批量商品审核"
|
||||
v-model="batchAuditModalVisible"
|
||||
:mask-closable="false"
|
||||
:width="500"
|
||||
>
|
||||
<Form ref="batchAuditForm" :model="batchAuditForm" :label-width="100">
|
||||
<FormItem label="审核结果" prop="auth_flag">
|
||||
<RadioGroup v-model="batchAuditForm.auth_flag">
|
||||
<Radio :label="1">审核通过</Radio>
|
||||
<Radio :label="2">审核拒绝</Radio>
|
||||
</RadioGroup>
|
||||
</FormItem>
|
||||
<FormItem label="审核备注" prop="reason" v-if="batchAuditForm.auth_flag === 2">
|
||||
<Input v-model="batchAuditForm.reason" type="textarea" :rows="3" placeholder="请输入拒绝原因" />
|
||||
</FormItem>
|
||||
<FormItem label="选中商品">
|
||||
<div style="max-height: 200px; overflow-y: auto;">
|
||||
<Tag v-for="item in selectedRows" :key="item.id" style="margin: 2px;">{{item.goodsName}}</Tag>
|
||||
</div>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer">
|
||||
<Button type="text" @click="batchAuditModalVisible = false">取消</Button>
|
||||
<Button type="primary" @click="submitBatchAudit">提交审核</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
<Modal v-model="goodsGroupFlag" title="批量设置商品分组" width="420">
|
||||
<Form ref="goodsGroupForm" :model="goodsGroupForm" :rules="goodsGroupRule" :label-width="90">
|
||||
<FormItem label="商品分组" prop="groupId">
|
||||
<Select v-model="goodsGroupForm.groupId" clearable filterable style="width: 240px">
|
||||
<Option v-for="item in goodsGroupList" :value="item.id" :key="item.id">{{ item.groupName }}</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer">
|
||||
<Button @click="goodsGroupFlag = false">取消</Button>
|
||||
<Button type="primary" :loading="goodsGroupLoading" @click="submitSetGoodsGroup">确定</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getGoodsListData, upGoods, lowGoods } from "@/api/goods";
|
||||
import {
|
||||
getGoodsListData,
|
||||
getGoodsNumerData,
|
||||
upGoods,
|
||||
lowGoods,
|
||||
authGoods,
|
||||
getGoodsGroupByPage,
|
||||
addGoodsGroupItems
|
||||
} from "@/api/goods";
|
||||
import vueQr from "vue-qr";
|
||||
export default {
|
||||
components: {
|
||||
@@ -173,36 +275,70 @@ export default {
|
||||
searchForm: {
|
||||
// 搜索框初始化对象
|
||||
pageNumber: 1, // 当前页数
|
||||
pageSize: 10, // 页面大小
|
||||
pageSize: 20, // 页面大小
|
||||
sort: "create_time", // 默认排序字段
|
||||
order: "desc", // 默认排序方式
|
||||
groupId: "",
|
||||
},
|
||||
underForm: {
|
||||
// 下架原因
|
||||
reason: "",
|
||||
},
|
||||
goodsAuditForm: {
|
||||
// 商品审核表单
|
||||
auth_flag: 1,
|
||||
},
|
||||
auditModalVisible: false, // 审核弹框显示状态
|
||||
currentAuditGoods: null, // 当前审核的商品
|
||||
submitLoading: false, // 添加或编辑提交状态
|
||||
columns: [
|
||||
{
|
||||
type: 'selection',
|
||||
width: 60,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: "商品ID",
|
||||
key: "id",
|
||||
width: 180,
|
||||
tooltip: true,
|
||||
},
|
||||
{
|
||||
title: "商品图片",
|
||||
key: "original",
|
||||
width: 180,
|
||||
slot: "imageSlot",
|
||||
},
|
||||
{
|
||||
title: "商品名称",
|
||||
key: "goodsName",
|
||||
minWidth: 180,
|
||||
slot: "goodsSlot",
|
||||
},
|
||||
{
|
||||
title: "商品编号",
|
||||
key: "id",
|
||||
minWidth: 150,
|
||||
tooltip: true,
|
||||
},
|
||||
{
|
||||
title: "价格",
|
||||
key: "price",
|
||||
width: 130,
|
||||
width: 100,
|
||||
render: (h, params) => {
|
||||
return h("priceColorScheme", {props:{value:params.row.price,color:this.$mainColor}} );
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "销量",
|
||||
key: "buyCount",
|
||||
width: 100,
|
||||
render: (h, params) => {
|
||||
return h("span", params.row.buyCount || 0);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "库存",
|
||||
key: "quantity",
|
||||
width: 100,
|
||||
render: (h, params) => {
|
||||
return h("span", params.row.quantity || 0);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "销售模式",
|
||||
key: "salesModel",
|
||||
@@ -220,7 +356,7 @@ export default {
|
||||
{
|
||||
title: "商品类型",
|
||||
key: "goodsType",
|
||||
width: 130,
|
||||
width: 120,
|
||||
render: (h, params) => {
|
||||
if (params.row.goodsType === "PHYSICAL_GOODS") {
|
||||
return h("Tag", { props: { color: "green" } }, "实物商品");
|
||||
@@ -234,7 +370,7 @@ export default {
|
||||
{
|
||||
title: "状态",
|
||||
key: "marketEnable",
|
||||
width: 100,
|
||||
width: 120,
|
||||
render: (h, params) => {
|
||||
if (params.row.marketEnable == "DOWN") {
|
||||
return h("Tag", { props: { color: "volcano" } }, "下架");
|
||||
@@ -246,7 +382,7 @@ export default {
|
||||
{
|
||||
title: "审核状态",
|
||||
key: "authFlag",
|
||||
width: 130,
|
||||
width: 180,
|
||||
render: (h, params) => {
|
||||
if (params.row.authFlag == "TOBEAUDITED") {
|
||||
return h("Tag", { props: { color: "volcano" } }, "待审核");
|
||||
@@ -260,7 +396,7 @@ export default {
|
||||
{
|
||||
title: "店铺名称",
|
||||
key: "storeName",
|
||||
minWidth: 100,
|
||||
width: 180, // 使用minWidth替代width
|
||||
tooltip: true,
|
||||
},
|
||||
{
|
||||
@@ -268,19 +404,61 @@ export default {
|
||||
key: "action",
|
||||
align: "center",
|
||||
fixed: "right",
|
||||
width: 150,
|
||||
width: 200,
|
||||
render: (h, params) => {
|
||||
if (params.row.marketEnable == "DOWN") {
|
||||
// 如果是待审核状态,显示审核按钮
|
||||
if (params.row.authFlag === "TOBEAUDITED") {
|
||||
return h("div", [
|
||||
h(
|
||||
"Button",
|
||||
"a",
|
||||
{
|
||||
props: {
|
||||
type: "info",
|
||||
size: "small",
|
||||
},
|
||||
style: {
|
||||
marginRight: "5px",
|
||||
color: "#2d8cf0",
|
||||
cursor: "pointer",
|
||||
textDecoration: "none"
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
this.openAuditModal(params.row);
|
||||
},
|
||||
},
|
||||
},
|
||||
"审核"
|
||||
),
|
||||
h("span", {
|
||||
style: {
|
||||
margin: "0 8px",
|
||||
color: "#dcdee2"
|
||||
}
|
||||
}, "|"),
|
||||
h(
|
||||
"a",
|
||||
{
|
||||
style: {
|
||||
color: "#2d8cf0",
|
||||
cursor: "pointer",
|
||||
textDecoration: "none"
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
this.showDetail(params.row);
|
||||
},
|
||||
},
|
||||
},
|
||||
"查看"
|
||||
),
|
||||
]);
|
||||
}
|
||||
// 原有的上架/下架逻辑
|
||||
else if (params.row.marketEnable == "DOWN") {
|
||||
return h("div", [
|
||||
h(
|
||||
"a",
|
||||
{
|
||||
style: {
|
||||
color: "#2d8cf0",
|
||||
cursor: "pointer",
|
||||
textDecoration: "none"
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
@@ -290,11 +468,19 @@ export default {
|
||||
},
|
||||
"上架"
|
||||
),
|
||||
h("span", {
|
||||
style: {
|
||||
margin: "0 8px",
|
||||
color: "#dcdee2"
|
||||
}
|
||||
}, "|"),
|
||||
h(
|
||||
"Button",
|
||||
"a",
|
||||
{
|
||||
props: {
|
||||
size: "small",
|
||||
style: {
|
||||
color: "#2d8cf0",
|
||||
cursor: "pointer",
|
||||
textDecoration: "none"
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
@@ -308,14 +494,12 @@ export default {
|
||||
} else {
|
||||
return h("div", [
|
||||
h(
|
||||
"Button",
|
||||
"a",
|
||||
{
|
||||
props: {
|
||||
type: "error",
|
||||
size: "small",
|
||||
},
|
||||
style: {
|
||||
marginRight: "5px",
|
||||
color: "#2d8cf0",
|
||||
cursor: "pointer",
|
||||
textDecoration: "none"
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
@@ -325,11 +509,19 @@ export default {
|
||||
},
|
||||
"下架"
|
||||
),
|
||||
h("span", {
|
||||
style: {
|
||||
margin: "0 8px",
|
||||
color: "#dcdee2"
|
||||
}
|
||||
}, "|"),
|
||||
h(
|
||||
"Button",
|
||||
"a",
|
||||
{
|
||||
props: {
|
||||
size: "small",
|
||||
style: {
|
||||
color: "#2d8cf0",
|
||||
cursor: "pointer",
|
||||
textDecoration: "none"
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
@@ -346,12 +538,47 @@ export default {
|
||||
],
|
||||
data: [], // 表单数据
|
||||
total: 0, // 表单数据总数
|
||||
currentStatus: '',
|
||||
goodsNumerData: {},
|
||||
goodsAuditForm: {
|
||||
// 商品编辑表单
|
||||
auth_flag: 1,
|
||||
},
|
||||
selectedRows: [], // 选中的行数据
|
||||
selectAll: false, // 全选状态
|
||||
batchAuditModalVisible: false, // 批量审核弹框显示状态
|
||||
batchAuditForm: {
|
||||
auth_flag: 1,
|
||||
reason: ''
|
||||
},
|
||||
goodsGroupFlag: false,
|
||||
goodsGroupLoading: false,
|
||||
goodsGroupList: [],
|
||||
goodsGroupForm: {
|
||||
groupId: ""
|
||||
},
|
||||
goodsGroupRule: {
|
||||
groupId: [{ required: true, message: "请选择商品分组", trigger: "change" }]
|
||||
}
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
goodsStatusWithCount() {
|
||||
return [
|
||||
{title: '全部', value: ''},
|
||||
{title: `出售中${this.goodsNumerData.upperGoodsNum ? '(' + this.goodsNumerData.upperGoodsNum + ')' : ''}`, value: 'UPPER'},
|
||||
{title: `仓库中${this.goodsNumerData.downGoodsNum ? '(' + this.goodsNumerData.downGoodsNum + ')' : ''}`, value: 'DOWN'},
|
||||
{title: `待审核${this.goodsNumerData.auditGoodsNum ? '(' + this.goodsNumerData.auditGoodsNum + ')' : ''}`, value: 'TOBEAUDITED'},
|
||||
{title: `审核未通过${this.goodsNumerData.refuseGoodsNum ? '(' + this.goodsNumerData.refuseGoodsNum + ')' : ''}`, value: 'REFUSE'}
|
||||
];
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 初始化数据
|
||||
init() {
|
||||
this.getDataList();
|
||||
this.getNumberData();
|
||||
this.loadGoodsGroupList();
|
||||
},
|
||||
// 分页 改变页码
|
||||
changePage(v) {
|
||||
@@ -366,8 +593,9 @@ export default {
|
||||
// 搜索
|
||||
handleSearch() {
|
||||
this.searchForm.pageNumber = 1;
|
||||
this.searchForm.pageSize = 10;
|
||||
this.searchForm.pageSize = 20;
|
||||
this.getDataList();
|
||||
this.getNumberData();
|
||||
},
|
||||
// 获取数据
|
||||
getDataList() {
|
||||
@@ -380,6 +608,15 @@ export default {
|
||||
}
|
||||
});
|
||||
},
|
||||
getNumberData() {
|
||||
// 创建一个不包含goodsStatus字段的搜索参数
|
||||
const { goodsStatus, ...searchParams } = this.searchForm;
|
||||
getGoodsNumerData(searchParams).then((res) => {
|
||||
if (res.success) {
|
||||
this.goodsNumerData = res.result;
|
||||
}
|
||||
})
|
||||
},
|
||||
// 编辑
|
||||
edit(v) {
|
||||
this.id = v.id;
|
||||
@@ -392,27 +629,36 @@ export default {
|
||||
},
|
||||
// 下架
|
||||
lower() {
|
||||
lowGoods(this.id, this.underForm).then((res) => {
|
||||
let params = {
|
||||
goodsId: this.id,
|
||||
reason:this.underForm.reason
|
||||
};
|
||||
lowGoods(params).then((res) => {
|
||||
this.$Modal.remove();
|
||||
if (res.success) {
|
||||
this.$Message.success("操作成功");
|
||||
this.modalVisible = false;
|
||||
this.getDataList();
|
||||
this.getNumberData(); // 添加这行
|
||||
}
|
||||
});
|
||||
},
|
||||
// 商家
|
||||
// 上架
|
||||
upper(v) {
|
||||
this.$Modal.confirm({
|
||||
title: "确认上架",
|
||||
content: "您确认要上架 " + v.goodsName + " ?",
|
||||
loading: true,
|
||||
onOk: () => {
|
||||
upGoods(v.id).then((res) => {
|
||||
let params = {
|
||||
goodsId: v.id
|
||||
};
|
||||
upGoods(params).then((res) => {
|
||||
this.$Modal.remove();
|
||||
if (res.success) {
|
||||
this.$Message.success("上架成功");
|
||||
this.getDataList();
|
||||
this.getNumberData(); // 添加这行
|
||||
}
|
||||
});
|
||||
},
|
||||
@@ -427,9 +673,296 @@ export default {
|
||||
query: { id: id },
|
||||
})
|
||||
},
|
||||
|
||||
// 商品状态筛选
|
||||
goodsStatusClick(item) {
|
||||
// 根据选择的状态设置搜索条件
|
||||
if (item === 0) {
|
||||
// 全部:清除状态筛选
|
||||
delete this.searchForm.goodsStatus;
|
||||
} else {
|
||||
// 其他状态正常赋值
|
||||
this.searchForm.goodsStatus = item;
|
||||
}
|
||||
this.currentStatus = item;
|
||||
|
||||
// tab切换时清除选中内容
|
||||
this.selectedRows = [];
|
||||
if (this.$refs.table) {
|
||||
this.$refs.table.selectAll(false);
|
||||
}
|
||||
|
||||
this.getDataList();
|
||||
},
|
||||
examine(v, authFlag) {
|
||||
// 审核商品
|
||||
let examine = "通过";
|
||||
this.goodsAuditForm.authFlag = "PASS";
|
||||
if (authFlag != 1) {
|
||||
examine = "拒绝";
|
||||
this.goodsAuditForm.authFlag = "REFUSE";
|
||||
}
|
||||
|
||||
this.$Modal.confirm({
|
||||
title: "确认审核",
|
||||
content: "您确认要审核" + examine + " " + v.goodsName + " ?",
|
||||
loading: true,
|
||||
onOk: () => {
|
||||
this.goodsAuditForm.goodsIds=v.id;
|
||||
let formData = new FormData();
|
||||
formData.append('goodsIds', v.id);
|
||||
formData.append('authFlag', this.goodsAuditForm.authFlag);
|
||||
|
||||
authGoods(formData).then((res) => {
|
||||
this.$Modal.remove();
|
||||
if (res.success) {
|
||||
this.$Message.success("审核成功");
|
||||
this.getDataList();
|
||||
this.getNumberData();
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
// 打开审核弹框
|
||||
openAuditModal(goods) {
|
||||
this.currentAuditGoods = goods;
|
||||
this.goodsAuditForm.auth_flag = 1;
|
||||
this.goodsAuditForm.reason = '';
|
||||
this.auditModalVisible = true;
|
||||
},
|
||||
|
||||
// 确认审核(二次确认)
|
||||
confirmAudit() {
|
||||
const auditText = this.goodsAuditForm.auth_flag === 1 ? '通过' : '拒绝';
|
||||
this.$Modal.confirm({
|
||||
title: '确认审核',
|
||||
content: `您确认要审核${auditText} "${this.currentAuditGoods.goodsName}" 吗?`,
|
||||
loading: true,
|
||||
onOk: () => {
|
||||
this.submitAudit();
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
// 提交审核
|
||||
submitAudit() {
|
||||
let formData = new FormData();
|
||||
formData.append('goodsIds', this.currentAuditGoods.id);
|
||||
formData.append('authFlag', this.goodsAuditForm.auth_flag === 1 ? 'PASS' : 'REFUSE');
|
||||
authGoods(formData).then((res) => {
|
||||
this.$Modal.remove();
|
||||
if (res.success) {
|
||||
this.$Message.success('审核成功');
|
||||
this.auditModalVisible = false;
|
||||
this.getDataList();
|
||||
this.getNumberData();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 选择框事件处理
|
||||
onSelect(selection, row) {
|
||||
// 单行选择时触发
|
||||
},
|
||||
|
||||
onSelectAll(selection) {
|
||||
// 全选时触发
|
||||
},
|
||||
|
||||
onSelectionChange(selection) {
|
||||
this.selectedRows = selection;
|
||||
},
|
||||
|
||||
// 批量上架
|
||||
batchUpper() {
|
||||
if (this.selectedRows.length === 0) {
|
||||
this.$Message.warning('请先选择要上架的商品');
|
||||
return;
|
||||
}
|
||||
|
||||
const goodsNames = this.selectedRows.map(item => item.goodsName).join('、');
|
||||
this.$Modal.confirm({
|
||||
title: '确认批量上架',
|
||||
content: `您确认要上架以下商品吗?\n${goodsNames}`,
|
||||
loading: true,
|
||||
onOk: () => {
|
||||
// 提取所有选中商品的ID
|
||||
const goodsIds = this.selectedRows.map(item => item.id);
|
||||
const params = {
|
||||
goodsId: goodsIds // 传递ID数组
|
||||
};
|
||||
|
||||
upGoods(params).then((res) => {
|
||||
this.$Modal.remove();
|
||||
if (res.success) {
|
||||
this.$Message.success('批量上架成功');
|
||||
this.selectedRows = [];
|
||||
this.selectAll = false;
|
||||
this.getDataList();
|
||||
this.getNumberData();
|
||||
}
|
||||
}).catch(() => {
|
||||
this.$Modal.remove();
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 批量下架
|
||||
batchLower() {
|
||||
if (this.selectedRows.length === 0) {
|
||||
this.$Message.warning('请先选择要下架的商品');
|
||||
return;
|
||||
}
|
||||
|
||||
const goodsNames = this.selectedRows.map(item => item.goodsName).join('、');
|
||||
this.$Modal.confirm({
|
||||
title: '确认批量下架',
|
||||
content: `您确认要下架以下商品吗?\n${goodsNames}`,
|
||||
loading: true,
|
||||
onOk: () => {
|
||||
// 提取所有选中商品的ID
|
||||
const goodsIds = this.selectedRows.map(item => item.id);
|
||||
const params = {
|
||||
goodsId: goodsIds, // 传递ID数组
|
||||
reason: '批量下架操作' // 可以设置默认下架原因
|
||||
};
|
||||
|
||||
lowGoods(params).then((res) => {
|
||||
this.$Modal.remove();
|
||||
if (res.success) {
|
||||
this.$Message.success('批量下架成功');
|
||||
this.selectedRows = [];
|
||||
this.selectAll = false;
|
||||
this.getDataList();
|
||||
this.getNumberData();
|
||||
}
|
||||
}).catch(() => {
|
||||
this.$Modal.remove();
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 批量审核
|
||||
batchAudit() {
|
||||
if (this.selectedRows.length === 0) {
|
||||
this.$Message.warning('请先选择要审核的商品');
|
||||
return;
|
||||
}
|
||||
|
||||
// 重置批量审核表单
|
||||
this.batchAuditForm = {
|
||||
auth_flag: 1,
|
||||
reason: ''
|
||||
};
|
||||
this.batchAuditModalVisible = true;
|
||||
},
|
||||
|
||||
// 提交批量审核
|
||||
submitBatchAudit() {
|
||||
if (this.selectedRows.length === 0) {
|
||||
this.$Message.warning('请先选择要审核的商品');
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果是拒绝审核,必须填写原因
|
||||
if (this.batchAuditForm.auth_flag === 2 && !this.batchAuditForm.reason.trim()) {
|
||||
this.$Message.warning('审核拒绝时必须填写拒绝原因');
|
||||
return;
|
||||
}
|
||||
|
||||
const actionText = this.batchAuditForm.auth_flag === 1 ? '通过' : '拒绝';
|
||||
const goodsNames = this.selectedRows.map(item => item.goodsName).join('、');
|
||||
|
||||
this.$Modal.confirm({
|
||||
title: `确认批量审核${actionText}`,
|
||||
content: `您确认要${actionText}以下商品的审核吗?\n${goodsNames}`,
|
||||
loading: true,
|
||||
onOk: () => {
|
||||
// 提取所有选中商品的ID
|
||||
const goodsIds = this.selectedRows.map(item => item.id);
|
||||
|
||||
let formData = new FormData();
|
||||
formData.append('goodsId', goodsIds);
|
||||
formData.append('authFlag', this.batchAuditForm.auth_flag === 1 ? 'PASS' : 'REFUSE');
|
||||
formData.append('reason', this.batchAuditForm.reason || '');
|
||||
|
||||
// 修正:直接调用authGoods,不传递'batch'参数
|
||||
authGoods(formData).then((res) => {
|
||||
this.$Modal.remove();
|
||||
if (res.success) {
|
||||
this.$Message.success(`批量审核${actionText}成功`);
|
||||
this.selectedRows = [];
|
||||
this.selectAll = false;
|
||||
this.batchAuditModalVisible = false;
|
||||
this.getDataList();
|
||||
this.getNumberData();
|
||||
}
|
||||
}).catch(() => {
|
||||
this.$Modal.remove();
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
loadGoodsGroupList() {
|
||||
getGoodsGroupByPage({ pageNumber: 1, pageSize: 1000 }).then((res) => {
|
||||
if (res && res.success && res.result) {
|
||||
this.goodsGroupList = res.result.records || [];
|
||||
}
|
||||
});
|
||||
},
|
||||
openSetGoodsGroup() {
|
||||
if (this.selectedRows.length === 0) {
|
||||
this.$Message.warning("请先选择商品");
|
||||
return;
|
||||
}
|
||||
this.goodsGroupFlag = true;
|
||||
this.goodsGroupLoading = false;
|
||||
this.goodsGroupForm = { groupId: "" };
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.goodsGroupForm) this.$refs.goodsGroupForm.resetFields();
|
||||
});
|
||||
this.loadGoodsGroupList();
|
||||
},
|
||||
submitSetGoodsGroup() {
|
||||
this.$refs.goodsGroupForm.validate((valid) => {
|
||||
if (!valid) return;
|
||||
const goodsIds = this.selectedRows.map((item) => item.id);
|
||||
this.goodsGroupLoading = true;
|
||||
addGoodsGroupItems(this.goodsGroupForm.groupId, goodsIds).then((res) => {
|
||||
this.goodsGroupLoading = false;
|
||||
if (res && res.success) {
|
||||
this.$Message.success("设置成功");
|
||||
this.goodsGroupFlag = false;
|
||||
this.selectedRows = [];
|
||||
this.selectAll = false;
|
||||
if (this.$refs.table && this.$refs.table.selectAll) {
|
||||
this.$refs.table.selectAll(false);
|
||||
}
|
||||
this.getDataList();
|
||||
} else if (res && res.message) {
|
||||
this.$Message.error(res.message);
|
||||
}
|
||||
}).catch(() => {
|
||||
this.goodsGroupLoading = false;
|
||||
this.$Message.error("设置失败,请检查权限或后端接口");
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.init();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
// Tab组件样式
|
||||
.goods-tab {
|
||||
::v-deep .ivu-tabs-tab {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
v-model="searchForm.goodsName"
|
||||
placeholder="请输入商品名称"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
style="width: 240px"
|
||||
/>
|
||||
</Form-item>
|
||||
<Form-item label="商品编号" prop="id">
|
||||
@@ -24,13 +24,15 @@
|
||||
v-model="searchForm.id"
|
||||
placeholder="请输入商品编号"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
style="width: 240px"
|
||||
/>
|
||||
</Form-item>
|
||||
<Button @click="handleSearch" class="search-btn" type="primary" icon="ios-search"
|
||||
>搜索</Button
|
||||
>
|
||||
</Form>
|
||||
</Card>
|
||||
<Card>
|
||||
<Table
|
||||
:loading="loading"
|
||||
border
|
||||
@@ -64,7 +66,7 @@
|
||||
:page-size="searchForm.pageSize"
|
||||
@on-change="changePage"
|
||||
@on-page-size-change="changePageSize"
|
||||
:page-size-opts="[10, 20, 50]"
|
||||
:page-size-opts="[20, 50, 100]"
|
||||
size="small"
|
||||
show-total
|
||||
show-elevator
|
||||
@@ -88,7 +90,7 @@ export default {
|
||||
searchForm: {
|
||||
// 搜索框初始化对象
|
||||
pageNumber: 1, // 当前页数
|
||||
pageSize: 10, // 页面大小
|
||||
pageSize: 20, // 页面大小
|
||||
sort: "create_time", // 默认排序字段
|
||||
order: "desc", // 默认排序方式
|
||||
},
|
||||
@@ -169,13 +171,12 @@ export default {
|
||||
render: (h, params) => {
|
||||
return h("div", [
|
||||
h(
|
||||
"Button",
|
||||
"a",
|
||||
{
|
||||
props: {
|
||||
type: "success",
|
||||
size: "small",
|
||||
},
|
||||
style: {
|
||||
color: "#2d8cf0",
|
||||
cursor: "pointer",
|
||||
textDecoration: "none",
|
||||
marginRight: "5px",
|
||||
},
|
||||
on: {
|
||||
@@ -187,13 +188,17 @@ export default {
|
||||
"通过"
|
||||
),
|
||||
h(
|
||||
"Button",
|
||||
"span",
|
||||
{ style: { margin: "0 8px", color: "#dcdee2" } },
|
||||
"|"
|
||||
),
|
||||
h(
|
||||
"a",
|
||||
{
|
||||
props: {
|
||||
type: "error",
|
||||
size: "small",
|
||||
},
|
||||
style: {
|
||||
color: "#2d8cf0",
|
||||
cursor: "pointer",
|
||||
textDecoration: "none",
|
||||
marginRight: "5px",
|
||||
},
|
||||
on: {
|
||||
@@ -205,11 +210,17 @@ export default {
|
||||
"拒绝"
|
||||
),
|
||||
h(
|
||||
"Button",
|
||||
"span",
|
||||
{ style: { margin: "0 8px", color: "#dcdee2" } },
|
||||
"|"
|
||||
),
|
||||
h(
|
||||
"a",
|
||||
{
|
||||
props: {
|
||||
type: 'default',
|
||||
size: "small",
|
||||
style: {
|
||||
color: "#2d8cf0",
|
||||
cursor: "pointer",
|
||||
textDecoration: "none"
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
@@ -245,7 +256,7 @@ export default {
|
||||
handleSearch() {
|
||||
// 搜索
|
||||
this.searchForm.pageNumber = 1;
|
||||
this.searchForm.pageSize = 10;
|
||||
this.searchForm.pageSize = 20;
|
||||
this.getDataList();
|
||||
},
|
||||
getDataList() {
|
||||
@@ -274,7 +285,11 @@ export default {
|
||||
content: "您确认要审核" + examine + " " + v.goodsName + " ?",
|
||||
loading: true,
|
||||
onOk: () => {
|
||||
authGoods(v.id, this.goodsAuditForm).then((res) => {
|
||||
let formData = new FormData();
|
||||
formData.append('goodsIds', v.id);
|
||||
formData.append('authFlag', this.goodsAuditForm.authFlag);
|
||||
|
||||
authGoods(formData).then((res) => {
|
||||
this.$Modal.remove();
|
||||
if (res.success) {
|
||||
this.$Message.success("审核成功");
|
||||
|
||||
@@ -4,18 +4,19 @@
|
||||
<Form ref="searchForm" @submit.native.prevent @keydown.enter.native="handleSearch" :model="searchForm" inline :label-width="70"
|
||||
class="search-form">
|
||||
<Form-item label="品牌名称">
|
||||
<Input type="text" v-model="searchForm.name" placeholder="请输入品牌名称" clearable style="width: 200px"/>
|
||||
<Input type="text" v-model="searchForm.name" placeholder="请输入品牌名称" clearable style="width: 240px"/>
|
||||
</Form-item>
|
||||
<Button @click="handleSearch" type="primary">搜索</Button>
|
||||
</Form>
|
||||
</Card>
|
||||
<Card>
|
||||
<Row class="operation padding-row">
|
||||
<Button @click="add" type="primary">添加</Button>
|
||||
<Button @click="refresh">刷新</Button>
|
||||
</Row>
|
||||
<Table :loading="loading" border :columns="columns" :data="data" ref="table"></Table>
|
||||
<Row type="flex" justify="end" class="mt_10">
|
||||
<Page :current="searchForm.pageNumber" :total="total" :page-size="searchForm.pageSize" @on-change="changePage"
|
||||
@on-page-size-change="changePageSize" :page-size-opts="[10, 20, 50]" size="small"
|
||||
@on-page-size-change="changePageSize" :page-size-opts="[20, 50, 100]" size="small"
|
||||
show-total show-elevator show-sizer></Page>
|
||||
</Row>
|
||||
</Card>
|
||||
@@ -25,7 +26,14 @@
|
||||
<Input v-model="form.name" clearable style="width: 100%"/>
|
||||
</FormItem>
|
||||
<FormItem label="品牌图标" prop="logo">
|
||||
<upload-pic-input v-model="form.logo" style="width: 100%"></upload-pic-input>
|
||||
<div style="display: flex; align-items: center; gap: 12px;">
|
||||
<img
|
||||
:src="form.logo || defaultPic"
|
||||
alt="品牌图标"
|
||||
style="width: 80px; height: 60px; object-fit: contain; border: 1px solid #dcdee2; border-radius: 4px; background: #fff;"
|
||||
/>
|
||||
<Button type="text" @click="openLogoPicker">修改</Button>
|
||||
</div>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer">
|
||||
@@ -33,6 +41,34 @@
|
||||
<Button type="primary" :loading="submitLoading" @click="handleSubmit">提交</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
<Modal width="1200px" v-model="picModelFlag" footer-hide>
|
||||
<ossManage @callback="callbackSelected" :isComponent="true" :initialize="picModelFlag" ref="ossManage" />
|
||||
</Modal>
|
||||
|
||||
<Modal
|
||||
:title="categoryModalTitle"
|
||||
v-model="categoryModalVisible"
|
||||
:mask-closable="false"
|
||||
:width="700"
|
||||
>
|
||||
<div style="position: relative; max-height: 520px; overflow: auto;">
|
||||
<Spin size="large" fix v-if="categoryTreeLoading"></Spin>
|
||||
<Tree
|
||||
ref="categoryTree"
|
||||
:key="categoryTreeKey"
|
||||
:data="categoryTreeData"
|
||||
show-checkbox
|
||||
@on-check-change="onCategoryTreeCheckChange"
|
||||
></Tree>
|
||||
</div>
|
||||
<div slot="footer">
|
||||
<Button type="text" @click="categoryModalVisible = false">取消</Button>
|
||||
<Button type="primary" :loading="categorySubmitLoading" @click="submitBrandCategory"
|
||||
>提交</Button
|
||||
>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -43,26 +79,39 @@ import {
|
||||
updateBrand,
|
||||
disableBrand,
|
||||
delBrand,
|
||||
getCategoryTree,
|
||||
getBrandCategoryListData,
|
||||
saveBrandCategory,
|
||||
} from "@/api/goods";
|
||||
import uploadPicInput from "@/components/lili/upload-pic-input";
|
||||
import ossManage from "@/views/sys/oss-manage/ossManage";
|
||||
|
||||
import {regular} from "@/utils";
|
||||
|
||||
export default {
|
||||
name: "brand",
|
||||
components: {
|
||||
uploadPicInput
|
||||
ossManage
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
defaultPic: require("@/assets/default.png"),
|
||||
loading: true, // 表单加载状态
|
||||
modalType: 0, // 添加或编辑标识
|
||||
modalVisible: false, // 添加或编辑显示
|
||||
modalTitle: "", // 添加或编辑标题
|
||||
picModelFlag: false, // 图片选择器
|
||||
categoryModalVisible: false,
|
||||
categoryModalTitle: "关联分类",
|
||||
categoryTreeLoading: false,
|
||||
categoryTreeData: [],
|
||||
categoryTreeKey: 0,
|
||||
categorySubmitLoading: false,
|
||||
currentBrandId: "",
|
||||
selectedCategoryIds: [],
|
||||
searchForm: {
|
||||
// 搜索框初始化对象
|
||||
pageNumber: 1, // 当前页数
|
||||
pageSize: 10, // 页面大小
|
||||
pageSize: 20, // 页面大小
|
||||
sort: "create_time", // 默认排序字段
|
||||
order: "desc", // 默认排序方式
|
||||
},
|
||||
@@ -117,11 +166,24 @@ export default {
|
||||
key: "deleteFlag",
|
||||
align: "left",
|
||||
render: (h, params) => {
|
||||
if (params.row.deleteFlag == 0) {
|
||||
return h("Tag", {props: {color: "green",},}, "启用");
|
||||
} else if (params.row.deleteFlag == 1) {
|
||||
return h("Tag", {props: {color: "volcano",},}, "禁用");
|
||||
}
|
||||
return h(
|
||||
"i-switch",
|
||||
{
|
||||
props: {
|
||||
value: params.row.deleteFlag == 0,
|
||||
size: "large",
|
||||
},
|
||||
on: {
|
||||
"on-change": (checked) => {
|
||||
this.handleStatusSwitchChange(params.row, checked);
|
||||
},
|
||||
},
|
||||
},
|
||||
[
|
||||
h("span", { slot: "open" }, "启用"),
|
||||
h("span", { slot: "close" }, "禁用"),
|
||||
]
|
||||
);
|
||||
},
|
||||
filters: [
|
||||
{
|
||||
@@ -145,60 +207,18 @@ export default {
|
||||
{
|
||||
title: "操作",
|
||||
key: "action",
|
||||
width: 180,
|
||||
width: 210,
|
||||
align: "center",
|
||||
fixed: "right",
|
||||
render: (h, params) => {
|
||||
let enableOrDisable = "";
|
||||
if (params.row.deleteFlag == 0) {
|
||||
enableOrDisable = h(
|
||||
"Button",
|
||||
{
|
||||
props: {
|
||||
size: "small",
|
||||
type: "error",
|
||||
},
|
||||
style: {
|
||||
marginRight: "5px",
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
this.disable(params.row);
|
||||
},
|
||||
},
|
||||
},
|
||||
"禁用"
|
||||
);
|
||||
} else {
|
||||
enableOrDisable = h(
|
||||
"Button",
|
||||
{
|
||||
props: {
|
||||
type: "success",
|
||||
size: "small",
|
||||
},
|
||||
style: {
|
||||
marginRight: "5px",
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
this.enable(params.row);
|
||||
},
|
||||
},
|
||||
},
|
||||
"启用"
|
||||
);
|
||||
}
|
||||
return h("div", [
|
||||
h(
|
||||
"Button",
|
||||
"a",
|
||||
{
|
||||
props: {
|
||||
type: "info",
|
||||
size: "small",
|
||||
},
|
||||
style: {
|
||||
marginRight: "5px",
|
||||
color: "#2d8cf0",
|
||||
cursor: "pointer",
|
||||
textDecoration: "none",
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
@@ -208,17 +228,39 @@ export default {
|
||||
},
|
||||
"编辑"
|
||||
),
|
||||
enableOrDisable,
|
||||
|
||||
h(
|
||||
"Button",
|
||||
"span",
|
||||
{ style: { margin: "0 8px", color: "#dcdee2" } },
|
||||
"|"
|
||||
),
|
||||
h(
|
||||
"a",
|
||||
{
|
||||
props: {
|
||||
type: 'default',
|
||||
size: "small",
|
||||
},
|
||||
style: {
|
||||
marginRight: "5px",
|
||||
color: "#2d8cf0",
|
||||
cursor: "pointer",
|
||||
textDecoration: "none",
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
this.openCategoryModal(params.row);
|
||||
},
|
||||
},
|
||||
},
|
||||
"关联分类"
|
||||
),
|
||||
h(
|
||||
"span",
|
||||
{ style: { margin: "0 8px", color: "#dcdee2" } },
|
||||
"|"
|
||||
),
|
||||
h(
|
||||
"a",
|
||||
{
|
||||
style: {
|
||||
color: "#2d8cf0",
|
||||
cursor: "pointer",
|
||||
textDecoration: "none",
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
@@ -237,6 +279,100 @@ export default {
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
openLogoPicker() {
|
||||
this.$refs.ossManage.selectImage = true;
|
||||
this.picModelFlag = true;
|
||||
},
|
||||
callbackSelected(val) {
|
||||
this.picModelFlag = false;
|
||||
this.form.logo = val.url;
|
||||
},
|
||||
buildCategoryTreeNodes(list, selectedSet) {
|
||||
if (!Array.isArray(list) || list.length === 0) return [];
|
||||
return list.map((item) => {
|
||||
const children = this.buildCategoryTreeNodes(item.children || [], selectedSet);
|
||||
return {
|
||||
id: item.id,
|
||||
title: item.name,
|
||||
expand: true,
|
||||
checked: selectedSet.has(item.id),
|
||||
children,
|
||||
};
|
||||
});
|
||||
},
|
||||
async openCategoryModal(row) {
|
||||
this.currentBrandId = row.id;
|
||||
this.categoryModalTitle = "关联分类 - " + (row.name || "");
|
||||
this.categoryModalVisible = true;
|
||||
this.categoryTreeLoading = true;
|
||||
this.categoryTreeKey += 1;
|
||||
this.categoryTreeData = [];
|
||||
this.selectedCategoryIds = [];
|
||||
try {
|
||||
const [treeRes, bindRes] = await Promise.all([
|
||||
getCategoryTree(),
|
||||
getBrandCategoryListData(row.id),
|
||||
]);
|
||||
const selectedIds = Array.isArray(bindRes?.result)
|
||||
? bindRes.result
|
||||
.map((x) => (typeof x === "string" ? x : x && x.id))
|
||||
.filter(Boolean)
|
||||
: [];
|
||||
this.selectedCategoryIds = selectedIds;
|
||||
const selectedSet = new Set(selectedIds);
|
||||
this.categoryTreeData = treeRes && treeRes.success
|
||||
? this.buildCategoryTreeNodes(treeRes.result || [], selectedSet)
|
||||
: [];
|
||||
} finally {
|
||||
this.categoryTreeLoading = false;
|
||||
}
|
||||
},
|
||||
onCategoryTreeCheckChange(checkedNodes) {
|
||||
if (!Array.isArray(checkedNodes)) {
|
||||
this.selectedCategoryIds = [];
|
||||
return;
|
||||
}
|
||||
this.selectedCategoryIds = checkedNodes
|
||||
.map((node) => node && node.id)
|
||||
.filter(Boolean);
|
||||
},
|
||||
submitBrandCategory() {
|
||||
if (!this.currentBrandId) return;
|
||||
this.categorySubmitLoading = true;
|
||||
saveBrandCategory(
|
||||
this.currentBrandId,
|
||||
(this.selectedCategoryIds || []).map((id) => String(id))
|
||||
).then((res) => {
|
||||
this.categorySubmitLoading = false;
|
||||
if (res && res.success) {
|
||||
this.$Message.success("操作成功");
|
||||
this.categoryModalVisible = false;
|
||||
return;
|
||||
}
|
||||
}).catch(() => {
|
||||
this.categorySubmitLoading = false;
|
||||
});
|
||||
},
|
||||
handleStatusSwitchChange(row, checked) {
|
||||
const disable = !checked;
|
||||
this.$Modal.confirm({
|
||||
title: disable ? "确认禁用" : "确认启用",
|
||||
content: "您确认要" + (disable ? "禁用" : "启用") + "品牌 " + row.name + " ?",
|
||||
loading: true,
|
||||
onOk: () => {
|
||||
disableBrand(row.id, { disable }).then((res) => {
|
||||
this.$Modal.remove();
|
||||
if (res.success) {
|
||||
this.$Message.success("操作成功");
|
||||
}
|
||||
this.getDataList();
|
||||
});
|
||||
},
|
||||
onCancel: () => {
|
||||
this.$nextTick(() => this.$forceUpdate());
|
||||
},
|
||||
});
|
||||
},
|
||||
// 删除品牌
|
||||
async delBrand(id) {
|
||||
let res = await delBrand(id);
|
||||
@@ -263,7 +399,7 @@ export default {
|
||||
// 搜索
|
||||
handleSearch() {
|
||||
this.searchForm.pageNumber = 1;
|
||||
this.searchForm.pageSize = 10;
|
||||
this.searchForm.pageSize = 20;
|
||||
this.getDataList();
|
||||
},
|
||||
// 获取数据
|
||||
@@ -315,15 +451,7 @@ export default {
|
||||
delete this.form.id;
|
||||
this.modalVisible = true;
|
||||
},
|
||||
// 刷新
|
||||
refresh() {
|
||||
this.loading = true;
|
||||
setTimeout(() => {
|
||||
this.getDataList();
|
||||
this.loading = false;
|
||||
this.$Message.success("刷新成功");
|
||||
}, 500);
|
||||
},
|
||||
|
||||
// 编辑
|
||||
edit(v) {
|
||||
this.modalType = 1;
|
||||
@@ -340,40 +468,6 @@ export default {
|
||||
this.form = data;
|
||||
this.modalVisible = true;
|
||||
},
|
||||
// 启用品牌
|
||||
enable(v) {
|
||||
this.$Modal.confirm({
|
||||
title: "确认启用",
|
||||
content: "您确认要启用品牌 " + v.name + " ?",
|
||||
loading: true,
|
||||
onOk: () => {
|
||||
disableBrand(v.id, {disable: false}).then((res) => {
|
||||
this.$Modal.remove();
|
||||
if (res.success) {
|
||||
this.$Message.success("操作成功");
|
||||
this.getDataList();
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
// 禁用
|
||||
disable(v) {
|
||||
this.$Modal.confirm({
|
||||
title: "确认禁用",
|
||||
content: "您确认要禁用品牌 " + v.name + " ?",
|
||||
loading: true,
|
||||
onOk: () => {
|
||||
disableBrand(v.id, {disable: true}).then((res) => {
|
||||
this.$Modal.remove();
|
||||
if (res.success) {
|
||||
this.$Message.success("操作成功");
|
||||
this.getDataList();
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.init();
|
||||
|
||||
@@ -14,55 +14,11 @@
|
||||
:columns="columns"
|
||||
>
|
||||
<template slot="action" slot-scope="scope">
|
||||
<Dropdown v-show="scope.row.level == 2" trigger="click">
|
||||
<Button size="small">
|
||||
绑定
|
||||
<Icon type="ios-arrow-down"></Icon>
|
||||
</Button>
|
||||
<DropdownMenu slot="list">
|
||||
<DropdownItem @click.native="brandOperation(scope.row)"
|
||||
>编辑绑定品牌</DropdownItem
|
||||
>
|
||||
<DropdownItem @click.native="specOperation(scope.row)"
|
||||
>编辑绑定规格</DropdownItem
|
||||
>
|
||||
<DropdownItem @click.native="parameterOperation(scope.row)"
|
||||
>编辑绑定参数</DropdownItem
|
||||
>
|
||||
</DropdownMenu>
|
||||
</Dropdown>
|
||||
|
||||
|
||||
<Dropdown trigger="click">
|
||||
<Button size="small">
|
||||
操作
|
||||
<Icon type="ios-arrow-down"></Icon>
|
||||
</Button>
|
||||
<DropdownMenu slot="list">
|
||||
<DropdownItem @click.native="edit(scope.row)">编辑</DropdownItem>
|
||||
<DropdownItem
|
||||
v-if="scope.row.deleteFlag == 1"
|
||||
@click.native="enable(scope.row)"
|
||||
>启用</DropdownItem
|
||||
>
|
||||
<DropdownItem
|
||||
v-if="scope.row.deleteFlag == 0"
|
||||
@click.native="disable(scope.row)"
|
||||
>禁用</DropdownItem
|
||||
>
|
||||
<DropdownItem @click.native="remove(scope.row)">删除</DropdownItem>
|
||||
</DropdownMenu>
|
||||
</Dropdown>
|
||||
|
||||
<Button
|
||||
v-show="scope.row.level != 2"
|
||||
type="primary"
|
||||
@click="addChildren(scope.row)"
|
||||
size="small"
|
||||
icon="md-add"
|
||||
style="margin-right: 5px"
|
||||
>添加子分类
|
||||
</Button>
|
||||
<div class="ops">
|
||||
<a class="ops-link" @click="edit(scope.row)">编辑</a>
|
||||
<a class="ops-link" @click="remove(scope.row)">删除</a>
|
||||
<a v-show="scope.row.level != 2" class="ops-link" @click="addChildren(scope.row)">添加子分类</a>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template slot="commissionRate" slot-scope="scope">
|
||||
@@ -72,12 +28,17 @@
|
||||
</template>
|
||||
|
||||
<template slot="deleteFlag" slot-scope="{ row }">
|
||||
<Tag
|
||||
:class="{ ml_10: row.deleteFlag }"
|
||||
:color="row.deleteFlag == false ? 'success' : 'error'"
|
||||
>
|
||||
{{ row.deleteFlag == false ? "正常启用" : "禁用" }}</Tag
|
||||
<i-switch
|
||||
size="large"
|
||||
v-model="row.deleteFlag"
|
||||
:true-value="false"
|
||||
:false-value="true"
|
||||
:loading="row._statusLoading"
|
||||
@on-change="onStatusSwitchChange(row, $event)"
|
||||
>
|
||||
<span slot="open">开启</span>
|
||||
<span slot="close">关闭</span>
|
||||
</i-switch>
|
||||
</template>
|
||||
</Table>
|
||||
|
||||
@@ -272,6 +233,52 @@ export default {
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
normalizeCategoryTree(list) {
|
||||
if (!Array.isArray(list) || list.length === 0) return;
|
||||
list.forEach((item) => {
|
||||
if (!item || typeof item !== "object") return;
|
||||
if (item.deleteFlag === 0) item.deleteFlag = false;
|
||||
else if (item.deleteFlag === 1) item.deleteFlag = true;
|
||||
else item.deleteFlag = !!item.deleteFlag;
|
||||
if (Array.isArray(item.children) && item.children.length) {
|
||||
this.normalizeCategoryTree(item.children);
|
||||
}
|
||||
});
|
||||
},
|
||||
onStatusSwitchChange(row, nextDeleteFlag) {
|
||||
const previousDeleteFlag = !nextDeleteFlag;
|
||||
const isClosing = nextDeleteFlag === true;
|
||||
this.$Modal.confirm({
|
||||
title: isClosing ? "确认关闭" : "确认开启",
|
||||
content:
|
||||
"您是否要" +
|
||||
(isClosing ? "关闭" : "开启") +
|
||||
"当前分类 " +
|
||||
row.name +
|
||||
" 及其子分类?",
|
||||
loading: true,
|
||||
okText: "是",
|
||||
cancelText: "否",
|
||||
onOk: () => {
|
||||
this.$set(row, "_statusLoading", true);
|
||||
disableCategory(row.id, { enableOperations: isClosing ? true : 0 }).then(
|
||||
(res) => {
|
||||
this.$Modal.remove();
|
||||
this.$set(row, "_statusLoading", false);
|
||||
if (res && res.success) {
|
||||
this.$Message.success("操作成功");
|
||||
this.getAllList(0);
|
||||
return;
|
||||
}
|
||||
row.deleteFlag = previousDeleteFlag;
|
||||
}
|
||||
);
|
||||
},
|
||||
onCancel: () => {
|
||||
row.deleteFlag = previousDeleteFlag;
|
||||
},
|
||||
});
|
||||
},
|
||||
// 初始化数据
|
||||
init() {
|
||||
this.getAllList(0);
|
||||
@@ -330,10 +337,6 @@ export default {
|
||||
}
|
||||
});
|
||||
},
|
||||
// 编辑绑定参数
|
||||
parameterOperation(v) {
|
||||
this.$router.push({ name: "parameter", query: { id: v.id } });
|
||||
},
|
||||
// 添加子分类
|
||||
addChildren(v) {
|
||||
this.modalType = 0;
|
||||
@@ -434,6 +437,7 @@ export default {
|
||||
child._loading = false;
|
||||
child.children = [];
|
||||
});
|
||||
this.normalizeCategoryTree(val.children);
|
||||
// 模拟加载
|
||||
setTimeout(() => {
|
||||
callback(val.children);
|
||||
@@ -442,6 +446,7 @@ export default {
|
||||
});
|
||||
} else {
|
||||
this.deepCategoryChildren(item.id, this.categoryList);
|
||||
this.normalizeCategoryTree(this.checkedCategoryChildren);
|
||||
setTimeout(() => {
|
||||
callback(this.checkedCategoryChildren);
|
||||
}, 100);
|
||||
@@ -469,6 +474,7 @@ export default {
|
||||
this.loading = false;
|
||||
if (res.success) {
|
||||
localStorage.setItem("category", JSON.stringify(res.result));
|
||||
this.normalizeCategoryTree(res.result);
|
||||
this.categoryList = JSON.parse(JSON.stringify(res.result));
|
||||
this.tableData = res.result.map((item) => {
|
||||
if(this.recordLevel[0] && item.id === this.recordLevel[0]) {
|
||||
@@ -543,11 +549,30 @@ export default {
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
/deep/ .ivu-table-wrapper {
|
||||
::v-deep .ivu-table-wrapper {
|
||||
overflow: auto;
|
||||
}
|
||||
.table {
|
||||
min-height: 100vh;
|
||||
height: auto;
|
||||
}
|
||||
.ops-link {
|
||||
color: #2d8cf0;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
}
|
||||
.ops {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.ops-link + .ops-link {
|
||||
margin-left: 16px;
|
||||
position: relative;
|
||||
}
|
||||
.ops-link + .ops-link::before {
|
||||
content: "|";
|
||||
position: absolute;
|
||||
left: -10px;
|
||||
color: #dcdee2;
|
||||
}
|
||||
</style>
|
||||
|
||||
442
manager/src/views/goods/goods-manage/parameter-edit.vue
Normal file
442
manager/src/views/goods/goods-manage/parameter-edit.vue
Normal file
@@ -0,0 +1,442 @@
|
||||
<template>
|
||||
<div class="search">
|
||||
<Card>
|
||||
<Form ref="form" :model="form" :label-width="100" :rules="formValidate">
|
||||
<FormItem label="参数名称" prop="paramName">
|
||||
<Input v-model="form.paramName" clearable style="width: 520px" />
|
||||
</FormItem>
|
||||
<FormItem label="是否必填" prop="required">
|
||||
<RadioGroup v-model="form.required">
|
||||
<Radio :label="0">否</Radio>
|
||||
<Radio :label="1">是</Radio>
|
||||
</RadioGroup>
|
||||
<span style="margin-left: 10px; color: #999; font-size: 12px"
|
||||
>商品发布时参数是否必填</span
|
||||
>
|
||||
</FormItem>
|
||||
<FormItem label="是否索引" prop="isIndex">
|
||||
<RadioGroup v-model="form.isIndex">
|
||||
<Radio :label="0">否</Radio>
|
||||
<Radio :label="1">是</Radio>
|
||||
</RadioGroup>
|
||||
<span style="margin-left: 10px; color: #999; font-size: 12px"
|
||||
>开启索引后,用户将可以通过该参数筛选商品,索引开关不影响商详页的参数展示</span
|
||||
>
|
||||
</FormItem>
|
||||
<FormItem label="排序" prop="sort">
|
||||
<InputNumber :min="0" type="number" v-model="form.sort" style="width: 520px" />
|
||||
</FormItem>
|
||||
<FormItem label="参数值" prop="options">
|
||||
<Table :columns="optionColumns" :data="form.options" border size="small" style="width: 520px" />
|
||||
<div style="margin-top: 10px">
|
||||
<Button type="primary" @click="addOptionRow">新增</Button>
|
||||
</div>
|
||||
</FormItem>
|
||||
<FormItem label="关联分类">
|
||||
<Button type="default" @click="openCategoryModal">选择分类</Button>
|
||||
<span v-if="selectedCategoryNamesText" style="margin-left: 10px; color: #999; font-size: 12px"
|
||||
>{{ selectedCategoryNamesText }}</span
|
||||
>
|
||||
<span v-else style="margin-left: 10px; color: #999; font-size: 12px"
|
||||
>已选择{{ selectedCategoryIds.length }}个分类</span
|
||||
>
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<Button type="default" @click="back">返回</Button>
|
||||
<Button type="primary" :loading="submitLoading" @click="handleSubmit">保存</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Card>
|
||||
|
||||
<Modal
|
||||
:title="categoryModalTitle"
|
||||
v-model="categoryModalVisible"
|
||||
:mask-closable="false"
|
||||
:width="700"
|
||||
>
|
||||
<div style="position: relative; max-height: 520px; overflow: auto;">
|
||||
<Spin size="large" fix v-if="categoryTreeLoading"></Spin>
|
||||
<Tree
|
||||
:key="categoryTreeKey"
|
||||
:data="categoryTreeData"
|
||||
show-checkbox
|
||||
@on-check-change="onCategoryTreeCheckChange"
|
||||
></Tree>
|
||||
</div>
|
||||
<div slot="footer">
|
||||
<Button type="text" @click="categoryModalVisible = false">取消</Button>
|
||||
<Button type="primary" style="margin-left: 8px" @click="categoryModalVisible = false">确定</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
getCategoryTree,
|
||||
getGoodsParamsDetail,
|
||||
insertGoodsParams,
|
||||
updateGoodsParams,
|
||||
} from "@/api/goods";
|
||||
import { regular } from "@/utils";
|
||||
|
||||
const getOptionText = (value) => {
|
||||
if (value && typeof value === "object") return value.value;
|
||||
return value;
|
||||
};
|
||||
|
||||
const normalizeOptions = (value) => {
|
||||
const arr = Array.isArray(value)
|
||||
? value
|
||||
: typeof value === "string"
|
||||
? value.split(",")
|
||||
: [];
|
||||
const cleaned = arr
|
||||
.map((x) => String(getOptionText(x) ?? "").trim())
|
||||
.filter((x) => x.length > 0);
|
||||
return Array.from(new Set(cleaned));
|
||||
};
|
||||
|
||||
const validateOptions = (rule, value, callback) => {
|
||||
const arr = Array.isArray(value)
|
||||
? value
|
||||
: typeof value === "string"
|
||||
? value.split(",")
|
||||
: [];
|
||||
const options = normalizeOptions(arr);
|
||||
if (options.length === 0) {
|
||||
callback(new Error("请填写参数值"));
|
||||
return;
|
||||
}
|
||||
const joined = options.join(",");
|
||||
if (!/^.{1,255}$/.test(joined)) {
|
||||
callback(new Error("超出最大长度限制"));
|
||||
return;
|
||||
}
|
||||
callback();
|
||||
};
|
||||
|
||||
const normalize01 = (value, fallback = 0) => {
|
||||
const n = Number(value);
|
||||
if (n === 0 || n === 1) return n;
|
||||
return fallback;
|
||||
};
|
||||
|
||||
const buildSpringFormPayload = (payload) => {
|
||||
const out = {};
|
||||
if (payload && payload.id !== undefined && payload.id !== null && String(payload.id)) {
|
||||
out.id = String(payload.id);
|
||||
}
|
||||
out.paramName = payload && payload.paramName !== undefined && payload.paramName !== null ? String(payload.paramName) : "";
|
||||
out.options = payload && payload.options !== undefined && payload.options !== null ? String(payload.options) : "";
|
||||
out.required = payload ? Number(payload.required) : 0;
|
||||
out.isIndex = payload ? Number(payload.isIndex) : 0;
|
||||
out.sort = payload ? Number(payload.sort) : 0;
|
||||
|
||||
const categoryList = payload && Array.isArray(payload.categoryParameterList) ? payload.categoryParameterList : [];
|
||||
const categoryIds = categoryList
|
||||
.map((x) => (x && x.categoryId !== undefined && x.categoryId !== null ? String(x.categoryId) : ""))
|
||||
.filter((x) => x.length > 0);
|
||||
categoryIds.forEach((categoryId, index) => {
|
||||
out[`categoryParameterList[${index}].categoryId`] = categoryId;
|
||||
});
|
||||
return out;
|
||||
};
|
||||
|
||||
const validateRadioRequired = (message) => (rule, value, callback) => {
|
||||
const n = normalize01(value, NaN);
|
||||
if (!(n === 0 || n === 1)) {
|
||||
callback(new Error(message));
|
||||
return;
|
||||
}
|
||||
callback();
|
||||
};
|
||||
|
||||
const toStringArray = (arr) => {
|
||||
if (!Array.isArray(arr)) return [];
|
||||
return arr.map((x) => String(x)).filter((x) => x.length > 0);
|
||||
};
|
||||
|
||||
const cacheKey = (id) => `goods-parameter-edit:${id}`;
|
||||
|
||||
const buildCategoryIdNameMap = (list, map) => {
|
||||
if (!Array.isArray(list) || list.length === 0) return;
|
||||
list.forEach((item) => {
|
||||
if (!item) return;
|
||||
const id = item.id !== undefined && item.id !== null ? String(item.id) : "";
|
||||
if (id) map[id] = item.name;
|
||||
buildCategoryIdNameMap(item.children || [], map);
|
||||
});
|
||||
};
|
||||
|
||||
export default {
|
||||
name: "parameterEdit",
|
||||
data() {
|
||||
return {
|
||||
submitLoading: false,
|
||||
modalType: 0,
|
||||
categoryModalVisible: false,
|
||||
categoryModalTitle: "关联分类",
|
||||
categoryTreeLoading: false,
|
||||
categoryTreeData: [],
|
||||
categoryTreeSource: [],
|
||||
categoryIdNameMap: {},
|
||||
categoryTreeKey: 0,
|
||||
selectedCategoryIds: [],
|
||||
form: {
|
||||
paramName: "",
|
||||
options: [{ value: "" }],
|
||||
required: 0,
|
||||
isIndex: 0,
|
||||
sort: 0,
|
||||
},
|
||||
optionColumns: [
|
||||
{
|
||||
title: "参数值",
|
||||
key: "value",
|
||||
minWidth: 420,
|
||||
render: (h, params) => {
|
||||
return h("Input", {
|
||||
props: {
|
||||
value: params.row.value,
|
||||
clearable: true,
|
||||
},
|
||||
on: {
|
||||
input: (val) => {
|
||||
if (!Array.isArray(this.form.options)) this.form.options = [];
|
||||
if (!this.form.options[params.index]) return;
|
||||
this.form.options[params.index].value = val;
|
||||
},
|
||||
"on-blur": () => {
|
||||
this.touchOptionsValidate();
|
||||
},
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "操作",
|
||||
width: 90,
|
||||
align: "center",
|
||||
render: (h, params) => {
|
||||
return h(
|
||||
"Button",
|
||||
{
|
||||
props: {
|
||||
type: "error",
|
||||
size: "small",
|
||||
},
|
||||
on: {
|
||||
click: () => this.removeOptionRow(params.index),
|
||||
},
|
||||
},
|
||||
"删除",
|
||||
);
|
||||
},
|
||||
},
|
||||
],
|
||||
formValidate: {
|
||||
paramName: [regular.REQUIRED, regular.VARCHAR5],
|
||||
options: [{ required: true, validator: validateOptions, trigger: "change" }],
|
||||
required: [{ required: true, validator: validateRadioRequired("请选择是否必填"), trigger: "change" }],
|
||||
isIndex: [{ required: true, validator: validateRadioRequired("请选择是否索引"), trigger: "change" }],
|
||||
sort: [regular.REQUIRED, regular.INTEGER],
|
||||
},
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
id() {
|
||||
return this.$route.query && this.$route.query.id ? String(this.$route.query.id) : "";
|
||||
},
|
||||
selectedCategoryNamesText() {
|
||||
if (!Array.isArray(this.categoryTreeSource) || this.categoryTreeSource.length === 0) return "";
|
||||
const selectedSet = new Set(toStringArray(this.selectedCategoryIds));
|
||||
const isSelected = (node) => {
|
||||
if (!node) return false;
|
||||
const id = node.id !== undefined && node.id !== null ? String(node.id) : "";
|
||||
if (id && selectedSet.has(id)) return true;
|
||||
const children = Array.isArray(node.children) ? node.children : [];
|
||||
if (children.length === 0) return false;
|
||||
return children.every(isSelected);
|
||||
};
|
||||
const collect = (node, out) => {
|
||||
if (!node) return;
|
||||
if (isSelected(node)) {
|
||||
if (node.name) out.push(node.name);
|
||||
return;
|
||||
}
|
||||
const children = Array.isArray(node.children) ? node.children : [];
|
||||
children.forEach((c) => collect(c, out));
|
||||
};
|
||||
const names = [];
|
||||
this.categoryTreeSource.forEach((n) => collect(n, names));
|
||||
return names.join(",");
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
"form.required"(val) {
|
||||
const n = normalize01(val, 0);
|
||||
if (val !== n) this.$set(this.form, "required", n);
|
||||
},
|
||||
"form.isIndex"(val) {
|
||||
const n = normalize01(val, 0);
|
||||
if (val !== n) this.$set(this.form, "isIndex", n);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
back() {
|
||||
this.$router.push({ name: "goods-parameter" });
|
||||
},
|
||||
touchOptionsValidate() {
|
||||
if (this.$refs.form && this.$refs.form.validateField) {
|
||||
this.$refs.form.validateField("options");
|
||||
}
|
||||
},
|
||||
addOptionRow() {
|
||||
if (!Array.isArray(this.form.options)) this.form.options = [];
|
||||
this.form.options.push({ value: "" });
|
||||
this.touchOptionsValidate();
|
||||
},
|
||||
removeOptionRow(index) {
|
||||
if (!Array.isArray(this.form.options)) this.form.options = [];
|
||||
this.form.options.splice(index, 1);
|
||||
this.touchOptionsValidate();
|
||||
},
|
||||
buildCategoryTreeNodes(list, selectedSet) {
|
||||
if (!Array.isArray(list) || list.length === 0) return [];
|
||||
return list.map((item) => {
|
||||
const children = this.buildCategoryTreeNodes(item.children || [], selectedSet);
|
||||
return {
|
||||
id: item.id,
|
||||
title: item.name,
|
||||
expand: true,
|
||||
checked: selectedSet.has(String(item.id)),
|
||||
children,
|
||||
};
|
||||
});
|
||||
},
|
||||
async loadDetail(parameterId) {
|
||||
if (!parameterId) return;
|
||||
const res = await getGoodsParamsDetail(parameterId).catch(() => null);
|
||||
if (!(res && res.success && res.result)) return;
|
||||
const dto = res.result;
|
||||
const opts = normalizeOptions(dto.options);
|
||||
this.form = {
|
||||
id: dto.id || parameterId,
|
||||
paramName: dto.paramName || "",
|
||||
options: opts.map((x) => ({ value: x })),
|
||||
required: normalize01(dto.required, 0),
|
||||
isIndex: normalize01(dto.isIndex, 0),
|
||||
sort: Number(dto.sort ?? 0) || 0,
|
||||
};
|
||||
const list = Array.isArray(dto.categoryParameterList) ? dto.categoryParameterList : [];
|
||||
this.selectedCategoryIds = toStringArray(list.map((x) => x && x.categoryId).filter(Boolean));
|
||||
},
|
||||
async openCategoryModal() {
|
||||
this.categoryModalVisible = true;
|
||||
this.categoryTreeLoading = true;
|
||||
this.categoryTreeKey += 1;
|
||||
try {
|
||||
const selectedSet = new Set(toStringArray(this.selectedCategoryIds));
|
||||
if (!Array.isArray(this.categoryTreeSource) || this.categoryTreeSource.length === 0) {
|
||||
const treeRes = await getCategoryTree();
|
||||
this.categoryTreeSource = treeRes && treeRes.success ? treeRes.result || [] : [];
|
||||
const map = {};
|
||||
buildCategoryIdNameMap(this.categoryTreeSource, map);
|
||||
this.categoryIdNameMap = map;
|
||||
}
|
||||
this.categoryTreeData = this.buildCategoryTreeNodes(this.categoryTreeSource || [], selectedSet);
|
||||
} finally {
|
||||
this.categoryTreeLoading = false;
|
||||
}
|
||||
},
|
||||
onCategoryTreeCheckChange(checkedNodes) {
|
||||
if (!Array.isArray(checkedNodes)) {
|
||||
this.selectedCategoryIds = [];
|
||||
return;
|
||||
}
|
||||
this.selectedCategoryIds = toStringArray(checkedNodes.map((node) => node && node.id).filter(Boolean));
|
||||
},
|
||||
initForm() {
|
||||
if (this.id) {
|
||||
this.modalType = 1;
|
||||
const cached = window.sessionStorage.getItem(cacheKey(this.id));
|
||||
if (cached) {
|
||||
try {
|
||||
const row = JSON.parse(cached);
|
||||
const opts = normalizeOptions(row.options);
|
||||
this.form = {
|
||||
id: row.id,
|
||||
paramName: row.paramName || "",
|
||||
options: opts.map((x) => ({ value: x })),
|
||||
required: normalize01(row.required, 0),
|
||||
isIndex: normalize01(row.isIndex, 0),
|
||||
sort: Number(row.sort ?? 0) || 0,
|
||||
};
|
||||
} catch (e) {
|
||||
this.modalType = 0;
|
||||
}
|
||||
}
|
||||
this.loadDetail(String(this.id));
|
||||
} else {
|
||||
this.modalType = 0;
|
||||
if (!Array.isArray(this.form.options) || this.form.options.length === 0) {
|
||||
this.form.options = [{ value: "" }];
|
||||
}
|
||||
this.selectedCategoryIds = [];
|
||||
}
|
||||
},
|
||||
handleSubmit() {
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (!valid) return;
|
||||
this.submitLoading = true;
|
||||
const options = normalizeOptions(this.form.options);
|
||||
const categoryIds = toStringArray(this.selectedCategoryIds);
|
||||
const payload = {
|
||||
...this.form,
|
||||
options: options.join(","),
|
||||
required: Number(this.form.required),
|
||||
isIndex: Number(this.form.isIndex),
|
||||
sort: Number(this.form.sort || 0),
|
||||
categoryParameterList: categoryIds.map((categoryId) => ({ categoryId })),
|
||||
};
|
||||
if (this.modalType === 0) {
|
||||
delete payload.id;
|
||||
insertGoodsParams(buildSpringFormPayload(payload))
|
||||
.then((res) => {
|
||||
if (!(res && res.success)) return;
|
||||
this.$Message.success("操作成功");
|
||||
this.back();
|
||||
})
|
||||
.finally(() => {
|
||||
this.submitLoading = false;
|
||||
});
|
||||
} else {
|
||||
updateGoodsParams(buildSpringFormPayload(payload))
|
||||
.then((res) => {
|
||||
if (!(res && res.success)) return;
|
||||
this.$Message.success("操作成功");
|
||||
this.back();
|
||||
})
|
||||
.finally(() => {
|
||||
this.submitLoading = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
getCategoryTree().then((res) => {
|
||||
if (res && res.success) {
|
||||
this.categoryTreeSource = res.result || [];
|
||||
const map = {};
|
||||
buildCategoryIdNameMap(this.categoryTreeSource, map);
|
||||
this.categoryIdNameMap = map;
|
||||
}
|
||||
});
|
||||
this.initForm();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss"></style>
|
||||
@@ -1,385 +1,202 @@
|
||||
<template>
|
||||
<div style="width: 100%">
|
||||
<div class="search">
|
||||
<Card>
|
||||
<Button @click="handleAddParamsGroup" type="primary">添加</Button>
|
||||
<Form
|
||||
ref="searchForm"
|
||||
@submit.native.prevent
|
||||
@keydown.enter.native="handleSearch"
|
||||
:model="searchForm"
|
||||
inline
|
||||
:label-width="70"
|
||||
class="search-form"
|
||||
>
|
||||
<Form-item label="参数名称">
|
||||
<Input
|
||||
type="text"
|
||||
v-model="searchForm.paramName"
|
||||
placeholder="请输入参数名称"
|
||||
clearable
|
||||
style="width: 240px"
|
||||
/>
|
||||
</Form-item>
|
||||
<Button @click="handleSearch" type="primary">搜索</Button>
|
||||
</Form>
|
||||
</Card>
|
||||
|
||||
<div class="row">
|
||||
<Card v-if="paramsGroup.length == 0"> 暂无参数绑定信息 </Card>
|
||||
<div class="paramsGroup" v-else>
|
||||
<Card
|
||||
style="width: 350px; margin: 7px"
|
||||
v-for="(group, index) in paramsGroup"
|
||||
:key="index"
|
||||
:bordered="false"
|
||||
>
|
||||
<p slot="title">
|
||||
<Icon type="ios-film-outline"></Icon> {{ group.groupName }}
|
||||
</p>
|
||||
<p slot="extra">
|
||||
<Dropdown slot="extra">
|
||||
<a href="javascript:void(0)">
|
||||
操作
|
||||
<Icon type="ios-arrow-down"></Icon>
|
||||
</a>
|
||||
<Dropdown-menu slot="list">
|
||||
<Dropdown-item @click.native="handleEditParamsGroup(group)"
|
||||
>编辑</Dropdown-item
|
||||
>
|
||||
<Dropdown-item @click.native="handleDeleteParamGroup(group)"
|
||||
>删除</Dropdown-item
|
||||
>
|
||||
</Dropdown-menu>
|
||||
</Dropdown>
|
||||
<Icon type="arrow-down-b"></Icon>
|
||||
</p>
|
||||
<template v-if="group.params && group.params.length > 0">
|
||||
<div
|
||||
v-for="(param, paramId) in group.params"
|
||||
:key="paramId"
|
||||
class="params"
|
||||
>
|
||||
<span>{{ param.paramName }}</span>
|
||||
|
||||
<span>
|
||||
<i-button type="text" @click="handleEditParams(group, param)"
|
||||
>编辑</i-button
|
||||
>
|
||||
<i-button
|
||||
type="text"
|
||||
size="small"
|
||||
style="color: #f56c6c"
|
||||
@click="handleDeleteParam(group, param)"
|
||||
>删除</i-button
|
||||
>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<div v-else style="align-content: center">暂无数据...</div>
|
||||
<div style="text-align: center">
|
||||
<i-button type="text" @click="handleAddParams(group)"
|
||||
>添加</i-button
|
||||
>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<Modal
|
||||
:title="modalTitle"
|
||||
v-model="dialogParamsVisible"
|
||||
:mask-closable="false"
|
||||
:width="500"
|
||||
>
|
||||
<Form
|
||||
ref="paramForm"
|
||||
:model="paramForm"
|
||||
:label-width="100"
|
||||
:rules="formValidate"
|
||||
>
|
||||
<FormItem label="参数名称" prop="paramName">
|
||||
<Input v-model="paramForm.paramName" style="width: 100%" />
|
||||
</FormItem>
|
||||
<FormItem label="可选值" prop="options">
|
||||
<Select
|
||||
v-model="paramForm.options"
|
||||
placeholder="输入后回车添加"
|
||||
multiple
|
||||
filterable
|
||||
allow-create
|
||||
:popper-append-to-body="false"
|
||||
popper-class="spec-values-popper"
|
||||
style="width: 100%; text-align: left; margin-right: 10px"
|
||||
>
|
||||
<Option
|
||||
v-for="(item, itemIndex) in ops.options"
|
||||
:value="item"
|
||||
:key="itemIndex"
|
||||
:label="item"
|
||||
>
|
||||
{{ item }}
|
||||
</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem label="选项" prop="specName3">
|
||||
<Checkbox label="1" v-model="paramForm.required">必填</Checkbox>
|
||||
<Checkbox label="1" v-model="paramForm.isIndex">可索引</Checkbox>
|
||||
</FormItem>
|
||||
<FormItem label="排序" prop="sort">
|
||||
<InputNumber
|
||||
:min="0"
|
||||
type="number"
|
||||
v-model="paramForm.sort"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</FormItem>
|
||||
</Form>
|
||||
|
||||
<div slot="footer">
|
||||
<Button type="text" @click="dialogParamsVisible = false">取消</Button>
|
||||
<Button
|
||||
type="primary"
|
||||
:loading="submitLoading"
|
||||
@click="submitParamForm"
|
||||
>提交</Button
|
||||
>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Modal
|
||||
:title="modalTitle"
|
||||
v-model="dialogParamsGroupVisible"
|
||||
:mask-closable="false"
|
||||
:width="500"
|
||||
>
|
||||
<Form
|
||||
@submit.native.prevent
|
||||
@keydown.enter.native="submitParamGroupForm"
|
||||
ref="paramGroupForm"
|
||||
:model="paramGroupForm"
|
||||
:label-width="100"
|
||||
:rules="paramGroupValidate"
|
||||
>
|
||||
<FormItem label="参数名称" prop="groupName">
|
||||
<Input v-model="paramGroupForm.groupName" style="width: 100%" />
|
||||
</FormItem>
|
||||
</Form>
|
||||
|
||||
<div slot="footer">
|
||||
<Button type="text" @click="dialogParamsGroupVisible = false"
|
||||
>取消</Button
|
||||
>
|
||||
<Button
|
||||
type="primary"
|
||||
:loading="submitLoading"
|
||||
@click="submitParamGroupForm"
|
||||
>提交</Button
|
||||
>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
<Card>
|
||||
<Row class="operation padding-row">
|
||||
<Button @click="goAdd" type="primary">添加</Button>
|
||||
</Row>
|
||||
<Table :loading="loading" border :columns="columns" :data="data" ref="table"></Table>
|
||||
<Row type="flex" justify="end" class="mt_10">
|
||||
<Page
|
||||
:current="searchForm.pageNumber"
|
||||
:total="total"
|
||||
:page-size="searchForm.pageSize"
|
||||
@on-change="changePage"
|
||||
@on-page-size-change="changePageSize"
|
||||
:page-size-opts="[20, 50, 100]"
|
||||
size="small"
|
||||
show-total
|
||||
show-elevator
|
||||
show-sizer
|
||||
></Page>
|
||||
</Row>
|
||||
</Card>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import {
|
||||
getCategoryParamsListData,
|
||||
insertGoodsParams,
|
||||
updateGoodsParams,
|
||||
deleteParams,
|
||||
insertParamsGroup,
|
||||
updateParamsGroup,
|
||||
deleteParamsGroup,
|
||||
getGoodsParamsPage,
|
||||
} from "@/api/goods";
|
||||
|
||||
import { regular } from "@/utils";
|
||||
|
||||
export default {
|
||||
name: "categoryParams",
|
||||
data() {
|
||||
return {
|
||||
submitLoading: false,
|
||||
/** 分类ID */
|
||||
categoryId: this.$route.query.id,
|
||||
/** 参数组 */
|
||||
paramsGroup: [],
|
||||
/** 添加或编辑标识 */
|
||||
modalType: 0,
|
||||
/** 添加或编辑标题 */
|
||||
modalTitle: "",
|
||||
/** 参数添加或编辑弹出框 */
|
||||
dialogParamsVisible: false,
|
||||
/** 参数组添加或编辑弹出框 */
|
||||
dialogParamsGroupVisible: false,
|
||||
//参数表单
|
||||
paramForm: {
|
||||
sort: 1,
|
||||
},
|
||||
/** 参数值 **/
|
||||
ops: {
|
||||
options: [],
|
||||
},
|
||||
// 参数表单
|
||||
paramGroupForm: {},
|
||||
/** 添加、编辑参数 规格 */
|
||||
formValidate: {
|
||||
paramName: [regular.REQUIRED, regular.VARCHAR5],
|
||||
options: [regular.REQUIRED, regular.VARCHAR255],
|
||||
sort: [regular.REQUIRED, regular.INTEGER],
|
||||
},
|
||||
/** 参数组*/
|
||||
paramGroupValidate: {
|
||||
groupName: [regular.REQUIRED, regular.VARCHAR5],
|
||||
loading: true,
|
||||
total: 0,
|
||||
searchForm: {
|
||||
pageNumber: 1,
|
||||
pageSize: 20,
|
||||
sort: "createTime",
|
||||
order: "desc",
|
||||
paramName: "",
|
||||
},
|
||||
data: [],
|
||||
columns: [
|
||||
{
|
||||
title: "参数名称",
|
||||
key: "paramName",
|
||||
width: 300,
|
||||
resizable: true,
|
||||
sortable: false,
|
||||
},
|
||||
{
|
||||
title: "参数值",
|
||||
key: "options",
|
||||
minWidth: 260,
|
||||
tooltip: true,
|
||||
},
|
||||
{
|
||||
title: "必填",
|
||||
key: "required",
|
||||
width: 300,
|
||||
align: "center",
|
||||
render: (h, params) => {
|
||||
const val = params.row.required;
|
||||
const on = val === 1 || val === "1" || val === true;
|
||||
return h("span", on ? "是" : "否");
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "可索引",
|
||||
key: "isIndex",
|
||||
width: 300,
|
||||
align: "center",
|
||||
render: (h, params) => {
|
||||
const val = params.row.isIndex;
|
||||
const on = val === 1 || val === "1" || val === true;
|
||||
return h("span", on ? "是" : "否");
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "操作",
|
||||
key: "action",
|
||||
width: 300,
|
||||
align: "center",
|
||||
fixed: "right",
|
||||
render: (h, params) => {
|
||||
return h("div", [
|
||||
h(
|
||||
"a",
|
||||
{
|
||||
style: {
|
||||
color: "#2d8cf0",
|
||||
cursor: "pointer",
|
||||
textDecoration: "none",
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
this.goEdit(params.row);
|
||||
},
|
||||
},
|
||||
},
|
||||
"编辑"
|
||||
),
|
||||
h("span", { style: { margin: "0 8px", color: "#dcdee2" } }, "|"),
|
||||
h(
|
||||
"a",
|
||||
{
|
||||
style: {
|
||||
color: "#2d8cf0",
|
||||
cursor: "pointer",
|
||||
textDecoration: "none",
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
this.remove(params.row);
|
||||
},
|
||||
},
|
||||
},
|
||||
"删除"
|
||||
),
|
||||
]);
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
filters: {
|
||||
paramTypeFilter(val) {
|
||||
return val === 1 ? "输入项" : "选择项";
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
// 初始化数据
|
||||
init() {
|
||||
this.getDataList();
|
||||
},
|
||||
//弹出添加参数框
|
||||
handleAddParams(group) {
|
||||
this.paramForm = {
|
||||
paramName: "",
|
||||
paramType: 1,
|
||||
options: "",
|
||||
required: false,
|
||||
isIndex: false,
|
||||
sort: 0,
|
||||
groupId: group.groupId,
|
||||
categoryId: this.categoryId,
|
||||
};
|
||||
this.modalTitle = "添加参数";
|
||||
this.modalType = 0;
|
||||
this.dialogParamsVisible = true;
|
||||
changePage(v) {
|
||||
this.searchForm.pageNumber = v;
|
||||
this.getDataList();
|
||||
},
|
||||
//弹出修改参数框
|
||||
handleEditParams(group, param) {
|
||||
console.log(group, param);
|
||||
this.paramForm = {
|
||||
paramName: param.paramName,
|
||||
options: param.options.split(","),
|
||||
required: param.required == 1 ? true : false,
|
||||
isIndex: param.isIndex == 1 ? true : false,
|
||||
groupId: param.groupId || "",
|
||||
categoryId: param.categoryId || "",
|
||||
sort: param.sort || 1,
|
||||
id: param.id,
|
||||
};
|
||||
this.ops.options = this.paramForm.options;
|
||||
this.modalType = 1;
|
||||
this.modalTitle = "修改参数";
|
||||
this.dialogParamsVisible = true;
|
||||
changePageSize(v) {
|
||||
this.searchForm.pageNumber = 1;
|
||||
this.searchForm.pageSize = v;
|
||||
this.getDataList();
|
||||
},
|
||||
//弹出修改参数组框
|
||||
handleEditParamsGroup(group) {
|
||||
this.paramGroupForm = {
|
||||
groupName: group.groupName,
|
||||
categoryId: this.categoryId,
|
||||
id: group.groupId,
|
||||
};
|
||||
this.modalType = 1;
|
||||
this.modalTitle = "修改参数组";
|
||||
this.dialogParamsGroupVisible = true;
|
||||
handleSearch() {
|
||||
this.searchForm.pageNumber = 1;
|
||||
this.searchForm.pageSize = 20;
|
||||
this.getDataList();
|
||||
},
|
||||
// 添加参数
|
||||
handleAddParamsGroup() {
|
||||
this.paramGroupForm = {};
|
||||
this.ops = {};
|
||||
(this.paramGroupForm.categoryId = this.categoryId), (this.modalType = 0);
|
||||
|
||||
this.modalTitle = "添加参数组";
|
||||
this.dialogParamsGroupVisible = true;
|
||||
},
|
||||
//保存参数组
|
||||
submitParamGroupForm() {
|
||||
this.$refs.paramGroupForm.validate((valid) => {
|
||||
if (valid) {
|
||||
if (this.modalType === 0) {
|
||||
insertParamsGroup(this.paramGroupForm).then((res) => {
|
||||
this.submitLoading = false;
|
||||
if (res.success) {
|
||||
this.$Message.success("参数组修改成功");
|
||||
this.getDataList();
|
||||
this.dialogParamsVisible = false;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
console.warn(this.paramGroupForm);
|
||||
updateParamsGroup(this.paramGroupForm).then((res) => {
|
||||
this.submitLoading = false;
|
||||
if (res.success) {
|
||||
this.$Message.success("参数组修改成功");
|
||||
this.getDataList();
|
||||
this.dialogParamsVisible = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
this.dialogParamsGroupVisible = false;
|
||||
}
|
||||
});
|
||||
},
|
||||
//保存参数
|
||||
submitParamForm() {
|
||||
this.$refs.paramForm.validate((valid) => {
|
||||
if (valid) {
|
||||
this.submitLoading = true;
|
||||
let data = JSON.parse(JSON.stringify(this.paramForm));
|
||||
data.isIndex = Number(data.isIndex);
|
||||
data.required = Number(data.required);
|
||||
if (this.modalType === 0) {
|
||||
insertGoodsParams(data).then((res) => {
|
||||
this.submitLoading = false;
|
||||
if (res.success) {
|
||||
this.$Message.success("参数添加成功");
|
||||
this.getDataList();
|
||||
this.dialogParamsVisible = false;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
console.warn(data.isIndex);
|
||||
data.isIndex = Number(data.isIndex);
|
||||
data.required = Number(data.required);
|
||||
updateGoodsParams(data).then((res) => {
|
||||
this.submitLoading = false;
|
||||
if (res.success) {
|
||||
this.$Message.success("参数修改成功");
|
||||
this.getDataList();
|
||||
this.dialogParamsVisible = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
// 获取分类列表
|
||||
getDataList() {
|
||||
getCategoryParamsListData(this.categoryId).then((res) => {
|
||||
if (res.success) {
|
||||
this.paramsGroup = res.result;
|
||||
this.loading = true;
|
||||
getGoodsParamsPage(this.searchForm).then((res) => {
|
||||
this.loading = false;
|
||||
if (res && res.success) {
|
||||
this.data = (res.result && res.result.records) || [];
|
||||
this.total = (res.result && res.result.total) || 0;
|
||||
}
|
||||
});
|
||||
},
|
||||
//删除参数方法
|
||||
handleDeleteParam(group, param) {
|
||||
this.$Modal.confirm({
|
||||
title: "确认删除",
|
||||
// 记得确认修改此处
|
||||
content: "您确认要删除 " + param.paramName + " ?",
|
||||
loading: true,
|
||||
onOk: () => {
|
||||
// 删除
|
||||
deleteParams(param.id).then((res) => {
|
||||
this.$Modal.remove();
|
||||
if (res.success) {
|
||||
this.$Message.success("删除参数成功");
|
||||
this.getDataList();
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
goAdd() {
|
||||
this.$router.push({ name: "goods-parameter-edit" });
|
||||
},
|
||||
//删除参数组方法
|
||||
handleDeleteParamGroup(group) {
|
||||
goEdit(row) {
|
||||
if (!row || !row.id) return;
|
||||
try {
|
||||
window.sessionStorage.setItem(`goods-parameter-edit:${row.id}`, JSON.stringify(row));
|
||||
} catch (e) {}
|
||||
this.$router.push({ name: "goods-parameter-edit", query: { id: row.id } });
|
||||
},
|
||||
remove(row) {
|
||||
this.$Modal.confirm({
|
||||
title: "确认删除",
|
||||
// 记得确认修改此处
|
||||
content: "您确认要删除 " + group.groupName + " ?",
|
||||
content: "您确认要删除 " + (row.paramName || "") + " ?",
|
||||
loading: true,
|
||||
onOk: () => {
|
||||
// 删除
|
||||
deleteParamsGroup(group.groupId).then((res) => {
|
||||
deleteParams(row.id).then((res) => {
|
||||
this.$Modal.remove();
|
||||
if (res.success) {
|
||||
this.$Message.success("删除参数成功");
|
||||
if (res && res.success) {
|
||||
this.$Message.success("删除成功");
|
||||
this.getDataList();
|
||||
}
|
||||
});
|
||||
@@ -392,33 +209,4 @@ export default {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.row {
|
||||
overflow: hidden;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.params {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
padding: 3px;
|
||||
background-color: #f5f7fa;
|
||||
font-size: 14px;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.ivu-card-head {
|
||||
background-color: #f5f7fa;
|
||||
}
|
||||
|
||||
.ivu-btn {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.paramsGroup {
|
||||
flex-wrap: wrap;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
<style lang="scss"></style>
|
||||
|
||||
@@ -1,334 +0,0 @@
|
||||
<template>
|
||||
<div class="search">
|
||||
<Card>
|
||||
<Form @submit.native.prevent @keydown.enter.native="handleSearch" ref="searchForm" :model="searchForm" inline :label-width="70"
|
||||
class="search-form">
|
||||
<Form-item label="规格名称" prop="specName">
|
||||
<Input type="text" v-model="searchForm.specName" placeholder="请输入规格名称" clearable style="width: 200px" />
|
||||
</Form-item>
|
||||
<Button @click="handleSearch" type="primary" class="search-btn">搜索</Button>
|
||||
</Form>
|
||||
<Row class="operation padding-row">
|
||||
<Button @click="add" type="primary">添加</Button>
|
||||
<Button @click="delAll">批量删除</Button>
|
||||
</Row>
|
||||
<Table :loading="loading" border :columns="columns" :data="data" ref="table" sortable="custom"
|
||||
@on-sort-change="changeSort" @on-selection-change="changeSelect">
|
||||
</Table>
|
||||
<Row type="flex" justify="end" class="mt_10">
|
||||
<Page :current="searchForm.pageNumber" :total="total" :page-size="searchForm.pageSize" @on-change="changePage"
|
||||
@on-page-size-change="changePageSize" :page-size-opts="[10, 20, 50]" size="small" show-total show-elevator
|
||||
show-sizer></Page>
|
||||
</Row>
|
||||
</Card>
|
||||
<Modal :title="modalTitle" v-model="modalVisible" :mask-closable="false" :width="500">
|
||||
<Form ref="form" :model="form" :label-width="100" :rules="formValidate">
|
||||
<FormItem label="规格名称" prop="specName">
|
||||
<Input v-model="form.specName" maxlength="30" clearable style="width: 100%" />
|
||||
</FormItem>
|
||||
<FormItem label="规格值" prop="specValue">
|
||||
<Select v-model="form.specValue" placeholder="输入后回车添加" multiple filterable allow-create
|
||||
:popper-append-to-body="false" popper-class="spec-values-popper"
|
||||
style="width: 100%; text-align: left; margin-right: 10px" @on-create="handleCreate2">
|
||||
<Option v-for="item in specValue" :value="item" :label="item" :key="item">
|
||||
</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer">
|
||||
<Button type="text" @click="modalVisible = false">取消</Button>
|
||||
<Button type="primary" :loading="submitLoading" @click="saveSpec">提交</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getSpecListData, insertSpec, updateSpec, delSpec } from "@/api/goods";
|
||||
|
||||
import { regular } from "@/utils";
|
||||
export default {
|
||||
name: "spec",
|
||||
components: {},
|
||||
data () {
|
||||
return {
|
||||
loading: true, // 表单加载状态
|
||||
modalType: 0, // 添加或编辑标识
|
||||
modalVisible: false, // 添加或编辑显示
|
||||
modalTitle: "", // 添加或编辑标题
|
||||
searchForm: {
|
||||
// 搜索框初始化对象
|
||||
pageNumber: 1, // 当前页数
|
||||
pageSize: 10, // 页面大小
|
||||
sort: "createTime", // 默认排序字段
|
||||
order: "asc", // 默认排序方式
|
||||
},
|
||||
// 表单验证规则
|
||||
formValidate: {
|
||||
specName: [
|
||||
regular.REQUIRED,
|
||||
// regular.VARCHAR20
|
||||
],
|
||||
specValue: [regular.REQUIRED, regular.VARCHAR255],
|
||||
},
|
||||
form: {
|
||||
// 添加或编辑表单对象初始化数据
|
||||
specName: "",
|
||||
specValue: "",
|
||||
},
|
||||
/** 编辑规格值 */
|
||||
specValue: [],
|
||||
submitLoading: false, // 添加或编辑提交状态
|
||||
selectList: [], // 多选数据
|
||||
selectCount: 0, // 多选计数
|
||||
columns: [
|
||||
// 表头
|
||||
{
|
||||
type: "selection",
|
||||
width: 60,
|
||||
align: "center",
|
||||
},
|
||||
{
|
||||
title: "规格名称",
|
||||
key: "specName",
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
title: "规格值",
|
||||
key: "specValue",
|
||||
minWidth: 250,
|
||||
tooltip: true,
|
||||
},
|
||||
{
|
||||
title: "操作",
|
||||
key: "action",
|
||||
align: "center",
|
||||
fixed: "right",
|
||||
width: 250,
|
||||
render: (h, params) => {
|
||||
return h("div", [
|
||||
h(
|
||||
"Button",
|
||||
{
|
||||
props: {
|
||||
type: "info",
|
||||
size: "small",
|
||||
},
|
||||
style: {
|
||||
marginRight: "5px",
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
this.edit(params.row);
|
||||
},
|
||||
},
|
||||
},
|
||||
"编辑"
|
||||
),
|
||||
h(
|
||||
"Button",
|
||||
{
|
||||
props: {
|
||||
type: "error",
|
||||
size: "small",
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
this.remove(params.row);
|
||||
},
|
||||
},
|
||||
},
|
||||
"删除"
|
||||
),
|
||||
]);
|
||||
},
|
||||
},
|
||||
],
|
||||
data: [], // 表单数据
|
||||
total: 0, // 表单数据总数
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
handleCreate2 (v) {
|
||||
console.log(v);
|
||||
},
|
||||
//初始化,获取数据
|
||||
init () {
|
||||
this.getDataList();
|
||||
},
|
||||
//修改分页
|
||||
changePage (v) {
|
||||
this.searchForm.pageNumber = v;
|
||||
this.getDataList();
|
||||
this.clearSelectAll();
|
||||
},
|
||||
//修改页面大小
|
||||
changePageSize (v) {
|
||||
this.searchForm.pageSize = v;
|
||||
this.getDataList();
|
||||
},
|
||||
//搜索参数
|
||||
handleSearch () {
|
||||
this.searchForm.pageNumber = 1;
|
||||
this.searchForm.pageSize = 10;
|
||||
this.getDataList();
|
||||
},
|
||||
//重置搜索参数
|
||||
handleReset () {
|
||||
this.$refs.searchForm.resetFields();
|
||||
this.searchForm.pageNumber = 1;
|
||||
this.searchForm.pageSize = 10;
|
||||
// 重新加载数据
|
||||
this.getDataList();
|
||||
},
|
||||
//更改排序
|
||||
changeSort (e) {
|
||||
this.searchForm.sort = e.key;
|
||||
this.searchForm.order = e.order;
|
||||
if (e.order === "normal") {
|
||||
this.searchForm.order = "";
|
||||
}
|
||||
this.getDataList();
|
||||
},
|
||||
//清除已选择
|
||||
clearSelectAll () {
|
||||
this.$refs.table.selectAll(false);
|
||||
},
|
||||
//修改已选择
|
||||
changeSelect (e) {
|
||||
this.selectList = e;
|
||||
this.selectCount = e.length;
|
||||
},
|
||||
//获取数据
|
||||
getDataList () {
|
||||
this.loading = true;
|
||||
// 带多条件搜索参数获取表单数据 请自行修改接口
|
||||
getSpecListData(this.searchForm).then((res) => {
|
||||
this.loading = false;
|
||||
if (res.success) {
|
||||
this.data = res.result.records;
|
||||
this.total = res.result.total;
|
||||
}
|
||||
});
|
||||
this.loading = false;
|
||||
},
|
||||
//新增规格
|
||||
saveSpec () {
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (valid) {
|
||||
this.submitLoading = true;
|
||||
if (this.modalType === 0) {
|
||||
if (this.data.find((item) => item.specName == this.form.specName)) {
|
||||
this.$Message.error("请勿添加重复规格名称!");
|
||||
this.submitLoading = false;
|
||||
return;
|
||||
}
|
||||
// 添加 避免编辑后传入id等数据
|
||||
delete this.form.id;
|
||||
insertSpec(this.form).then((res) => {
|
||||
this.submitLoading = false;
|
||||
if (res.success) {
|
||||
this.$Message.success("操作成功");
|
||||
this.getDataList();
|
||||
this.modalVisible = false;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// 编辑
|
||||
updateSpec(this.form.id, this.form).then((res) => {
|
||||
this.submitLoading = false;
|
||||
if (res.success) {
|
||||
this.$Message.success("操作成功");
|
||||
this.getDataList();
|
||||
this.modalVisible = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
//弹出添加框
|
||||
add () {
|
||||
this.modalType = 0;
|
||||
this.modalTitle = "添加";
|
||||
this.$refs.form.resetFields();
|
||||
this.specValue = "";
|
||||
delete this.form.id;
|
||||
this.modalVisible = true;
|
||||
},
|
||||
//弹出编辑框
|
||||
edit (v) {
|
||||
this.modalType = 1;
|
||||
this.modalTitle = "编辑";
|
||||
// 转换null为""
|
||||
for (let attr in v) {
|
||||
if (v[attr] === null) {
|
||||
v[attr] = "";
|
||||
}
|
||||
}
|
||||
let localVal = v.specValue;
|
||||
this.form.specName = v.specName;
|
||||
this.form.id = v.id;
|
||||
this.$nextTick(() => {
|
||||
this.$set(this.form, 'specValue', v.specValue);
|
||||
})
|
||||
|
||||
if (localVal && localVal.indexOf("," > 0)) {
|
||||
this.$set(this.form, 'specValue', localVal.split(","));
|
||||
this.specValue = this.form.specValue;
|
||||
} else {
|
||||
this.specValue = [];
|
||||
}
|
||||
this.modalVisible = true;
|
||||
},
|
||||
// 删除规格
|
||||
remove (v) {
|
||||
this.$Modal.confirm({
|
||||
title: "确认删除",
|
||||
content: "您确认要删除 " + v.specName + " ?",
|
||||
loading: true,
|
||||
onOk: () => {
|
||||
delSpec(v.id).then((res) => {
|
||||
this.$Modal.remove();
|
||||
if (res.success) {
|
||||
this.$Message.success("操作成功");
|
||||
this.getDataList();
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
// 批量删除
|
||||
delAll () {
|
||||
if (this.selectCount <= 0) {
|
||||
this.$Message.warning("您还未选择要删除的数据");
|
||||
return;
|
||||
}
|
||||
this.$Modal.confirm({
|
||||
title: "确认删除",
|
||||
content: "您确认要删除所选的 " + this.selectCount + " 条数据?",
|
||||
loading: true,
|
||||
onOk: () => {
|
||||
let ids = "";
|
||||
this.selectList.forEach(function (e) {
|
||||
ids += e.id + ",";
|
||||
});
|
||||
ids = ids.substring(0, ids.length - 1);
|
||||
delSpec(ids).then((res) => {
|
||||
this.$Modal.remove();
|
||||
if (res.success) {
|
||||
this.$Message.success("删除成功");
|
||||
this.clearSelectAll();
|
||||
this.searchForm.pageNumber = 1;
|
||||
this.getDataList();
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
mounted () {
|
||||
this.init();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -4,11 +4,16 @@
|
||||
<Row>
|
||||
<Form ref="searchForm" :model="searchForm" @keydown.enter.native="handleSearch" @submit.native.prevent inline :label-width="70" class="search-form">
|
||||
<Form-item label="会员名称" prop="memberName">
|
||||
<Input type="text" v-model="searchForm.memberName" placeholder="请输入会员名称" clearable style="width: 200px"/>
|
||||
<Input type="text" v-model="searchForm.memberName" placeholder="请输入会员名称" clearable style="width: 240px"/>
|
||||
</Form-item>
|
||||
<Form-item label="商品名称" prop="goodsName">
|
||||
<Input type="text" v-model="searchForm.goodsName" placeholder="请输入商品名称" clearable style="width: 240px"/>
|
||||
</Form-item>
|
||||
<Button @click="handleSearch" type="primary" class="search-btn" icon="ios-search">搜索</Button>
|
||||
</Form>
|
||||
</Row>
|
||||
</Card>
|
||||
<Card>
|
||||
<Table :loading="loading" border :columns="columns" :data="data" ref="table" class="mt_10">
|
||||
<!-- 页面展示 -->
|
||||
<template slot="shopDisableSlot" slot-scope="scope">
|
||||
@@ -21,7 +26,7 @@
|
||||
</Table>
|
||||
<Row type="flex" justify="end" class="mt_10">
|
||||
<Page :current="searchForm.pageNumber" :total="total" :page-size="searchForm.pageSize" @on-change="changePage"
|
||||
@on-page-size-change="changePageSize" :page-size-opts="[10, 20, 50]"
|
||||
@on-page-size-change="changePageSize" :page-size-opts="[20, 50, 100]"
|
||||
size="small" show-total show-elevator show-sizer></Page>
|
||||
</Row>
|
||||
</Card>
|
||||
@@ -110,7 +115,8 @@ export default {
|
||||
searchForm: {
|
||||
// 搜索框初始化对象
|
||||
pageNumber: 1, // 当前页数
|
||||
pageSize: 10, // 页面大小
|
||||
pageSize: 20, // 页面大小
|
||||
goodsName: "",
|
||||
sort: "createTime", // 默认排序字段
|
||||
order: "desc", // 默认排序方式
|
||||
startDate: "", // 起始时间
|
||||
@@ -132,6 +138,30 @@ export default {
|
||||
align: "left",
|
||||
tooltip: true,
|
||||
},
|
||||
{
|
||||
title: "评论内容",
|
||||
key: "content",
|
||||
minWidth: 220,
|
||||
align: "left",
|
||||
tooltip: true,
|
||||
},
|
||||
{
|
||||
title: "是否置顶",
|
||||
key: "top",
|
||||
align: "center",
|
||||
width: 100,
|
||||
render: (h, params) => {
|
||||
return h(
|
||||
"Tag",
|
||||
{
|
||||
props: {
|
||||
color: params.row.top ? "red" : "default",
|
||||
},
|
||||
},
|
||||
params.row.top ? "已置顶" : "未置顶"
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "评价",
|
||||
key: "grade",
|
||||
@@ -147,27 +177,6 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "物流评分",
|
||||
key: "deliveryScore",
|
||||
render: (h, params) => {
|
||||
return h('div',params.row.deliveryScore || 5 + '星')
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "服务评分",
|
||||
key: "deliveryScore",
|
||||
render: (h, params) => {
|
||||
return h('div',params.row.serviceScore || 5 + '星')
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "描述评分",
|
||||
key: "deliveryScore",
|
||||
render: (h, params) => {
|
||||
return h('div',params.row.descriptionScore || 5 + '星')
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "评价时间",
|
||||
key: "createTime",
|
||||
@@ -184,21 +193,18 @@ export default {
|
||||
{
|
||||
title: "操作",
|
||||
key: "action",
|
||||
width: 150,
|
||||
width: 220,
|
||||
align: "center",
|
||||
fixed: "right",
|
||||
|
||||
render: (h, params) => {
|
||||
return h("div", [
|
||||
return h("div", { class: "ops" }, [
|
||||
h(
|
||||
"Button",
|
||||
"a",
|
||||
{
|
||||
props: {
|
||||
size: "small",
|
||||
type: "info",
|
||||
},
|
||||
style: {
|
||||
marginRight: "5px",
|
||||
color: "#2d8cf0",
|
||||
cursor: "pointer",
|
||||
textDecoration: "none",
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
@@ -209,22 +215,64 @@ export default {
|
||||
"查看"
|
||||
),
|
||||
h(
|
||||
"Button",
|
||||
"span",
|
||||
{
|
||||
props: {
|
||||
type: "error",
|
||||
size: "small",
|
||||
},
|
||||
style: {
|
||||
marginRight: "5px",
|
||||
margin: "0 8px",
|
||||
color: "#dcdee2",
|
||||
},
|
||||
},
|
||||
"|"
|
||||
),
|
||||
h(
|
||||
"a",
|
||||
{
|
||||
style: {
|
||||
color: "#2d8cf0",
|
||||
cursor: "pointer",
|
||||
textDecoration: "none",
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
this.updateTop(params.row);
|
||||
},
|
||||
},
|
||||
},
|
||||
params.row.top ? "取消置顶" : "置顶评论"
|
||||
),
|
||||
h(
|
||||
"span",
|
||||
{
|
||||
style: {
|
||||
margin: "0 8px",
|
||||
color: "#dcdee2",
|
||||
},
|
||||
},
|
||||
"|"
|
||||
),
|
||||
h(
|
||||
"Poptip",
|
||||
{
|
||||
props: { confirm: true, title: "确认删除" },
|
||||
on: {
|
||||
"on-ok": () => {
|
||||
this.remove(params.row);
|
||||
},
|
||||
},
|
||||
},
|
||||
"删除"
|
||||
[
|
||||
h(
|
||||
"a",
|
||||
{
|
||||
style: {
|
||||
color: "#2d8cf0",
|
||||
cursor: "pointer",
|
||||
textDecoration: "none",
|
||||
},
|
||||
},
|
||||
"删除"
|
||||
),
|
||||
]
|
||||
),
|
||||
]);
|
||||
},
|
||||
@@ -263,7 +311,7 @@ export default {
|
||||
// 搜索
|
||||
handleSearch() {
|
||||
this.searchForm.pageNumber = 1;
|
||||
this.searchForm.pageSize = 10;
|
||||
this.searchForm.pageSize = 20;
|
||||
this.getDataList();
|
||||
},
|
||||
//列表直接选择页面是否展示
|
||||
@@ -273,6 +321,25 @@ export default {
|
||||
this.init();
|
||||
});
|
||||
},
|
||||
// 置顶评论
|
||||
updateTop(v) {
|
||||
const top = !v.top;
|
||||
API_Member.updateMemberReviewTop(v.id, { top }).then((res) => {
|
||||
if (res.success) {
|
||||
this.data = this.data.map((item) => {
|
||||
if (item.goodsId !== v.goodsId) {
|
||||
return item;
|
||||
}
|
||||
return {
|
||||
...item,
|
||||
top: item.id === v.id ? top : false,
|
||||
};
|
||||
});
|
||||
this.$Message.success(top ? "置顶成功!" : "取消置顶成功!");
|
||||
this.init();
|
||||
}
|
||||
});
|
||||
},
|
||||
// 获取列表
|
||||
getDataList() {
|
||||
this.loading = true;
|
||||
@@ -370,4 +437,14 @@ label {
|
||||
margin: 5px 0;
|
||||
span{margin-right: 20px;}
|
||||
}
|
||||
.ops a {
|
||||
color: #2d8cf0;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
}
|
||||
.ops span {
|
||||
display: inline-block;
|
||||
margin: 0 8px;
|
||||
color: #dcdee2;
|
||||
}
|
||||
</style>
|
||||
|
||||
273
manager/src/views/goods/group/index.vue
Normal file
273
manager/src/views/goods/group/index.vue
Normal file
@@ -0,0 +1,273 @@
|
||||
<template>
|
||||
<div class="search">
|
||||
<Card>
|
||||
<Row class="operation padding-row">
|
||||
<Button type="primary" @click="openAdd">添加分组</Button>
|
||||
</Row>
|
||||
<Table
|
||||
:loading="loading"
|
||||
border
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
ref="table"
|
||||
class="mt_10"
|
||||
></Table>
|
||||
<Row type="flex" justify="end" class="mt_10">
|
||||
<Page
|
||||
:current="searchForm.pageNumber"
|
||||
:total="total"
|
||||
:page-size="searchForm.pageSize"
|
||||
@on-change="changePage"
|
||||
@on-page-size-change="changePageSize"
|
||||
:page-size-opts="[20, 50, 100]"
|
||||
size="small"
|
||||
show-total
|
||||
show-elevator
|
||||
show-sizer
|
||||
></Page>
|
||||
</Row>
|
||||
</Card>
|
||||
<Modal v-model="addFlag" title="添加商品分组">
|
||||
<Form ref="addForm" :model="formAdd" :rules="rulesAdd" :label-width="90">
|
||||
<FormItem label="分组名称" prop="groupName" style="width: 90%;">
|
||||
<Input v-model="formAdd.groupName" maxlength="30" placeholder="请输入分组名称" />
|
||||
</FormItem>
|
||||
<FormItem label="分组描述" prop="description" style="width: 90%;">
|
||||
<Input v-model="formAdd.description" maxlength="200" placeholder="请输入分组描述" />
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer">
|
||||
<Button @click="addFlag = false">取消</Button>
|
||||
<Button type="primary" :loading="submitAddLoading" @click="submitAdd">确定</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
<Modal v-model="editFlag" title="编辑商品分组">
|
||||
<Form ref="editForm" :model="formEdit" :rules="rulesEdit" :label-width="90">
|
||||
<Input v-model="formEdit.id" v-show="false" />
|
||||
<FormItem label="分组名称" prop="groupName" style="width: 90%;">
|
||||
<Input v-model="formEdit.groupName" maxlength="30" placeholder="请输入分组名称" />
|
||||
</FormItem>
|
||||
<FormItem label="分组描述" prop="description" style="width: 90%;">
|
||||
<Input v-model="formEdit.description" maxlength="200" placeholder="请输入分组描述" />
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer">
|
||||
<Button @click="editFlag = false">取消</Button>
|
||||
<Button type="primary" :loading="submitEditLoading" @click="submitEdit">确定</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as API_Goods from "@/api/goods.js";
|
||||
|
||||
export default {
|
||||
name: "goodsGroup",
|
||||
data() {
|
||||
return {
|
||||
loading: true,
|
||||
searchForm: {
|
||||
pageNumber: 1,
|
||||
pageSize: 20,
|
||||
},
|
||||
columns: [
|
||||
{
|
||||
title: "分组名称",
|
||||
key: "groupName",
|
||||
minWidth: 160,
|
||||
tooltip: true,
|
||||
},
|
||||
{
|
||||
title: "分组描述",
|
||||
key: "description",
|
||||
minWidth: 240,
|
||||
tooltip: true,
|
||||
},
|
||||
{
|
||||
title: "创建时间",
|
||||
key: "createTime",
|
||||
width: 180,
|
||||
},
|
||||
{
|
||||
title: "更新时间",
|
||||
key: "updateTime",
|
||||
width: 180,
|
||||
},
|
||||
{
|
||||
title: "操作",
|
||||
key: "action",
|
||||
align: "center",
|
||||
width: 200,
|
||||
fixed: "right",
|
||||
render: (h, params) => {
|
||||
const linkStyle = {
|
||||
color: "#2d8cf0",
|
||||
cursor: "pointer",
|
||||
textDecoration: "none",
|
||||
};
|
||||
const sep = h(
|
||||
"span",
|
||||
{ style: { margin: "0 8px", color: "#dcdee2" } },
|
||||
"|"
|
||||
);
|
||||
return h("div", { class: "ops", style: { display: "flex", justifyContent: "center" } }, [
|
||||
h("a", { style: linkStyle, on: { click: () => this.openEdit(params.row) } }, "编辑"),
|
||||
sep,
|
||||
h("a", { style: linkStyle, on: { click: () => this.remove(params.row) } }, "删除"),
|
||||
]);
|
||||
},
|
||||
},
|
||||
],
|
||||
data: [],
|
||||
total: 0,
|
||||
addFlag: false,
|
||||
editFlag: false,
|
||||
submitAddLoading: false,
|
||||
submitEditLoading: false,
|
||||
formAdd: {
|
||||
groupName: "",
|
||||
description: "",
|
||||
},
|
||||
formEdit: {
|
||||
id: "",
|
||||
groupName: "",
|
||||
description: "",
|
||||
},
|
||||
rulesAdd: {
|
||||
groupName: [{ required: true, message: "请输入分组名称" }],
|
||||
},
|
||||
rulesEdit: {
|
||||
groupName: [{ required: true, message: "请输入分组名称" }],
|
||||
},
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
this.getData();
|
||||
},
|
||||
changePage(v) {
|
||||
this.searchForm.pageNumber = v;
|
||||
this.getData();
|
||||
},
|
||||
changePageSize(v) {
|
||||
this.searchForm.pageNumber = 1;
|
||||
this.searchForm.pageSize = v;
|
||||
this.getData();
|
||||
},
|
||||
getData() {
|
||||
this.loading = true;
|
||||
API_Goods.getGoodsGroupByPage(this.searchForm)
|
||||
.then((res) => {
|
||||
this.loading = false;
|
||||
if (res && res.success && res.result) {
|
||||
this.data = res.result.records || [];
|
||||
this.total = res.result.total || 0;
|
||||
} else if (res && res.message) {
|
||||
this.$Message.error(res.message);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.loading = false;
|
||||
this.$Message.error("加载商品分组失败");
|
||||
});
|
||||
},
|
||||
openAdd() {
|
||||
this.addFlag = true;
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.addForm) this.$refs.addForm.resetFields();
|
||||
this.formAdd = { groupName: "", description: "" };
|
||||
});
|
||||
},
|
||||
submitAdd() {
|
||||
this.$refs.addForm.validate((valid) => {
|
||||
if (!valid) return;
|
||||
this.submitAddLoading = true;
|
||||
API_Goods.addGoodsGroup(this.formAdd)
|
||||
.then((res) => {
|
||||
this.submitAddLoading = false;
|
||||
if (res && res.success) {
|
||||
this.$Message.success("添加成功");
|
||||
this.addFlag = false;
|
||||
this.getData();
|
||||
} else if (res && res.message) {
|
||||
this.$Message.error(res.message);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.submitAddLoading = false;
|
||||
this.$Message.error("添加失败,请检查权限或后端接口");
|
||||
});
|
||||
});
|
||||
},
|
||||
openEdit(row) {
|
||||
this.editFlag = true;
|
||||
this.submitEditLoading = false;
|
||||
API_Goods.getGoodsGroup(row.id)
|
||||
.then((res) => {
|
||||
if (res && res.success && res.result) {
|
||||
this.formEdit = {
|
||||
id: res.result.id,
|
||||
groupName: res.result.groupName || "",
|
||||
description: res.result.description || "",
|
||||
};
|
||||
} else {
|
||||
this.formEdit = {
|
||||
id: row.id,
|
||||
groupName: row.groupName || "",
|
||||
description: row.description || "",
|
||||
};
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.$Message.error("获取分组详情失败");
|
||||
});
|
||||
},
|
||||
submitEdit() {
|
||||
this.$refs.editForm.validate((valid) => {
|
||||
if (!valid) return;
|
||||
this.submitEditLoading = true;
|
||||
const { id, groupName, description } = this.formEdit;
|
||||
API_Goods.updateGoodsGroup(id, { id, groupName, description })
|
||||
.then((res) => {
|
||||
this.submitEditLoading = false;
|
||||
if (res && res.success) {
|
||||
this.$Message.success("修改成功");
|
||||
this.editFlag = false;
|
||||
this.getData();
|
||||
} else if (res && res.message) {
|
||||
this.$Message.error(res.message);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.submitEditLoading = false;
|
||||
this.$Message.error("修改失败,请检查权限或后端接口");
|
||||
});
|
||||
});
|
||||
},
|
||||
remove(row) {
|
||||
this.$Modal.confirm({
|
||||
title: "提示",
|
||||
content: "<p>确定删除该分组?</p>",
|
||||
onOk: () => {
|
||||
API_Goods.deleteGoodsGroup(row.id)
|
||||
.then((res) => {
|
||||
if (res && res.success) {
|
||||
this.$Message.success("删除成功");
|
||||
this.getData();
|
||||
} else if (res && res.message) {
|
||||
this.$Message.error(res.message);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.$Message.error("删除失败,请检查权限或后端接口");
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.init();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
540
manager/src/views/goods/virtual-sales/index.vue
Normal file
540
manager/src/views/goods/virtual-sales/index.vue
Normal file
@@ -0,0 +1,540 @@
|
||||
<template>
|
||||
<div class="search">
|
||||
<Card>
|
||||
<Form
|
||||
ref="searchForm"
|
||||
:model="searchForm"
|
||||
inline
|
||||
:label-width="70"
|
||||
class="search-form"
|
||||
@keydown.enter.native="handleSearch"
|
||||
>
|
||||
<Form-item label="商品名称" prop="goodsName">
|
||||
<Input
|
||||
v-model="searchForm.goodsName"
|
||||
placeholder="请输入商品名称"
|
||||
clearable
|
||||
style="width: 240px"
|
||||
/>
|
||||
</Form-item>
|
||||
<Form-item label="商品ID" prop="goodsId">
|
||||
<Input
|
||||
v-model="searchForm.goodsId"
|
||||
placeholder="请输入商品ID"
|
||||
clearable
|
||||
style="width: 240px"
|
||||
/>
|
||||
</Form-item>
|
||||
<Form-item label="SKU货号" prop="sn">
|
||||
<Input
|
||||
v-model="searchForm.sn"
|
||||
placeholder="请输入SKU货号"
|
||||
clearable
|
||||
style="width: 240px"
|
||||
/>
|
||||
</Form-item>
|
||||
<Form-item label="店铺名称" prop="storeName">
|
||||
<Input
|
||||
v-model="searchForm.storeName"
|
||||
placeholder="请输入店铺名称"
|
||||
clearable
|
||||
style="width: 240px"
|
||||
/>
|
||||
</Form-item>
|
||||
<Button
|
||||
@click="handleSearch"
|
||||
class="search-btn"
|
||||
type="primary"
|
||||
icon="ios-search"
|
||||
>
|
||||
搜索
|
||||
</Button>
|
||||
<Button @click="handleReset" style="margin-left: 8px">重置</Button>
|
||||
</Form>
|
||||
</Card>
|
||||
|
||||
<Card class="mt_10">
|
||||
<Alert show-icon>
|
||||
支持按规格逐条设置虚拟销量,列表总销量 = 真实销量 + 虚拟销量。
|
||||
</Alert>
|
||||
|
||||
<div class="batch-operations">
|
||||
<Button
|
||||
type="primary"
|
||||
:disabled="selectedRows.length === 0"
|
||||
@click="openBatchVirtualSalesModal"
|
||||
>
|
||||
批量设置虚拟销量
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<Table
|
||||
:loading="loading"
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
ref="table"
|
||||
class="mt_10"
|
||||
sortable="custom"
|
||||
@on-sort-change="changeSort"
|
||||
@on-selection-change="handleSelectionChange"
|
||||
>
|
||||
<template slot="goodsSlot" slot-scope="{ row }">
|
||||
<div class="goods-info">
|
||||
<img
|
||||
:src="row.thumbnail"
|
||||
class="goods-thumbnail"
|
||||
/>
|
||||
<div class="goods-text">
|
||||
<div class="div-zoom">{{ row.goodsName }}</div>
|
||||
<div class="sub-title" v-if="row.simpleSpecs">
|
||||
规格:{{ row.simpleSpecs.trim() || "-" }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</Table>
|
||||
|
||||
<Row type="flex" justify="end" class="mt_10">
|
||||
<Page
|
||||
:current="searchForm.pageNumber"
|
||||
:total="total"
|
||||
:page-size="searchForm.pageSize"
|
||||
:page-size-opts="[20, 50, 100]"
|
||||
size="small"
|
||||
show-total
|
||||
show-elevator
|
||||
show-sizer
|
||||
@on-change="changePage"
|
||||
@on-page-size-change="changePageSize"
|
||||
></Page>
|
||||
</Row>
|
||||
</Card>
|
||||
|
||||
<Modal
|
||||
v-model="editModalVisible"
|
||||
:title="modalMode === 'batch' ? '批量设置虚拟销量' : '设置虚拟销量'"
|
||||
:mask-closable="false"
|
||||
:closable="!modalSubmitting"
|
||||
>
|
||||
<div v-if="modalMode === 'single' && currentSku" class="virtual-sales-modal">
|
||||
<div class="sku-info-item">
|
||||
<span class="sku-info-label">商品名称:</span>
|
||||
<span>{{ currentSku.goodsName || "-" }}</span>
|
||||
</div>
|
||||
<div class="sku-info-item">
|
||||
<span class="sku-info-label">规格信息:</span>
|
||||
<span>{{ currentSku.simpleSpecs || "-" }}</span>
|
||||
</div>
|
||||
<div class="sku-info-item">
|
||||
<span class="sku-info-label">SKU ID:</span>
|
||||
<span>{{ currentSku.id || "-" }}</span>
|
||||
</div>
|
||||
|
||||
<Form :label-width="90" class="mt_10">
|
||||
<Form-item label="虚拟销量">
|
||||
<InputNumber
|
||||
v-model="editForm.virtualSales"
|
||||
:min="0"
|
||||
:max="99999999"
|
||||
:precision="0"
|
||||
style="width: 200px"
|
||||
/>
|
||||
</Form-item>
|
||||
</Form>
|
||||
</div>
|
||||
<div v-else-if="modalMode === 'batch'" class="virtual-sales-modal">
|
||||
<div class="sku-info-item">
|
||||
<span class="sku-info-label">已选规格:</span>
|
||||
<span>{{ selectedRows.length }} 个</span>
|
||||
</div>
|
||||
|
||||
<Form :label-width="90" class="mt_10">
|
||||
<Form-item label="虚拟销量">
|
||||
<InputNumber
|
||||
v-model="editForm.virtualSales"
|
||||
:min="0"
|
||||
:max="99999999"
|
||||
:precision="0"
|
||||
style="width: 200px"
|
||||
/>
|
||||
</Form-item>
|
||||
</Form>
|
||||
</div>
|
||||
<div slot="footer">
|
||||
<Button @click="handleCancelVirtualSales" :disabled="modalSubmitting">
|
||||
取消
|
||||
</Button>
|
||||
<Button
|
||||
type="primary"
|
||||
:loading="modalSubmitting"
|
||||
@click="handleSubmitVirtualSales"
|
||||
>
|
||||
提交
|
||||
</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
batchUpdateGoodsSkuVirtualSales,
|
||||
getGoodsSkuData,
|
||||
updateGoodsSkuVirtualSales,
|
||||
} from "@/api/goods";
|
||||
|
||||
const VIRTUAL_SALES_FIELDS = [
|
||||
"virtualSales",
|
||||
"fictitiousSales",
|
||||
"fakeBuyCount",
|
||||
"fictitiousBuyCount",
|
||||
"mockBuyCount",
|
||||
"salesVolume",
|
||||
];
|
||||
|
||||
export default {
|
||||
name: "goodsVirtualSales",
|
||||
data() {
|
||||
return {
|
||||
loading: true,
|
||||
editModalVisible: false,
|
||||
modalSubmitting: false,
|
||||
modalMode: "single",
|
||||
currentSku: null,
|
||||
currentIndex: -1,
|
||||
selectedRows: [],
|
||||
editForm: {
|
||||
virtualSales: 0,
|
||||
},
|
||||
searchForm: {
|
||||
pageNumber: 1,
|
||||
pageSize: 20,
|
||||
sort: "create_time",
|
||||
order: "desc",
|
||||
goodsName: "",
|
||||
goodsId: "",
|
||||
sn: "",
|
||||
storeName: "",
|
||||
},
|
||||
columns: [
|
||||
{
|
||||
type: "selection",
|
||||
width: 60,
|
||||
align: "center",
|
||||
},
|
||||
{
|
||||
title: "SKU ID",
|
||||
key: "id",
|
||||
width: 180,
|
||||
tooltip: true,
|
||||
},
|
||||
{
|
||||
title: "商品ID",
|
||||
key: "goodsId",
|
||||
width: 180,
|
||||
tooltip: true,
|
||||
},
|
||||
{
|
||||
title: "商品信息",
|
||||
key: "goodsName",
|
||||
minWidth: 360,
|
||||
slot: "goodsSlot",
|
||||
},
|
||||
{
|
||||
title: "真实销量",
|
||||
key: "buyCount",
|
||||
width: 110,
|
||||
render: (h, params) => h("span", params.row.buyCount || 0),
|
||||
},
|
||||
{
|
||||
title: "虚拟销量",
|
||||
key: "virtualSalesInput",
|
||||
width: 110,
|
||||
render: (h, params) => h("span", params.row.virtualSalesInput || 0),
|
||||
},
|
||||
{
|
||||
title: "总销量",
|
||||
key: "totalSalesDisplay",
|
||||
width: 110,
|
||||
render: (h, params) => h("span", this.getTotalSales(params.row)),
|
||||
},
|
||||
{
|
||||
title: "状态",
|
||||
key: "marketEnable",
|
||||
width: 100,
|
||||
render: (h, params) => {
|
||||
const isUpper = params.row.marketEnable === "UPPER";
|
||||
return h(
|
||||
"Tag",
|
||||
{ props: { color: isUpper ? "green" : "volcano" } },
|
||||
isUpper ? "上架" : "下架"
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "操作",
|
||||
key: "action",
|
||||
width: 100,
|
||||
align: "center",
|
||||
render: (h, params) => {
|
||||
return h(
|
||||
"Button",
|
||||
{
|
||||
props: {
|
||||
type: "primary",
|
||||
size: "small",
|
||||
loading: !!params.row.saving,
|
||||
},
|
||||
on: {
|
||||
click: () => this.openVirtualSalesModal(params.row, params.index),
|
||||
},
|
||||
},
|
||||
"设置"
|
||||
);
|
||||
},
|
||||
},
|
||||
],
|
||||
data: [],
|
||||
total: 0,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
this.getDataList();
|
||||
},
|
||||
changePage(v) {
|
||||
this.searchForm.pageNumber = v;
|
||||
this.getDataList();
|
||||
},
|
||||
changePageSize(v) {
|
||||
this.searchForm.pageNumber = 1;
|
||||
this.searchForm.pageSize = v;
|
||||
this.getDataList();
|
||||
},
|
||||
handleSearch() {
|
||||
this.searchForm.pageNumber = 1;
|
||||
this.getDataList();
|
||||
},
|
||||
handleReset() {
|
||||
this.searchForm = {
|
||||
pageNumber: 1,
|
||||
pageSize: 20,
|
||||
sort: "create_time",
|
||||
order: "desc",
|
||||
goodsName: "",
|
||||
goodsId: "",
|
||||
sn: "",
|
||||
storeName: "",
|
||||
};
|
||||
this.getDataList();
|
||||
},
|
||||
changeSort(e) {
|
||||
this.searchForm.sort = e.key;
|
||||
this.searchForm.order = e.order;
|
||||
if (e.order === "normal") {
|
||||
this.searchForm.sort = "create_time";
|
||||
this.searchForm.order = "desc";
|
||||
}
|
||||
this.getDataList();
|
||||
},
|
||||
handleSelectionChange(selection) {
|
||||
this.selectedRows = selection;
|
||||
},
|
||||
getDataList() {
|
||||
this.loading = true;
|
||||
getGoodsSkuData(this.searchForm)
|
||||
.then((res) => {
|
||||
if (res && res.success && res.result) {
|
||||
this.data = (res.result.records || []).map((item) => ({
|
||||
...item,
|
||||
virtualSalesInput: this.getVirtualSalesValue(item),
|
||||
saving: false,
|
||||
}));
|
||||
this.total = res.result.total || 0;
|
||||
this.selectedRows = [];
|
||||
} else {
|
||||
this.data = [];
|
||||
this.total = 0;
|
||||
this.selectedRows = [];
|
||||
this.$Message.error((res && res.message) || "加载规格列表失败");
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.data = [];
|
||||
this.total = 0;
|
||||
this.selectedRows = [];
|
||||
this.$Message.error("加载规格列表失败");
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
getVirtualSalesValue(row) {
|
||||
const field = VIRTUAL_SALES_FIELDS.find(
|
||||
(item) => row[item] !== undefined && row[item] !== null && row[item] !== ""
|
||||
);
|
||||
return field ? Number(row[field]) || 0 : 0;
|
||||
},
|
||||
openVirtualSalesModal(row, index) {
|
||||
this.modalMode = "single";
|
||||
this.currentSku = { ...row };
|
||||
this.currentIndex = index;
|
||||
this.editForm.virtualSales = this.getVirtualSalesValue(row);
|
||||
this.editModalVisible = true;
|
||||
},
|
||||
openBatchVirtualSalesModal() {
|
||||
if (!this.selectedRows.length) {
|
||||
this.$Message.warning("请先选择要设置的商品规格");
|
||||
return;
|
||||
}
|
||||
this.modalMode = "batch";
|
||||
this.currentSku = null;
|
||||
this.currentIndex = -1;
|
||||
this.editForm.virtualSales = 0;
|
||||
this.editModalVisible = true;
|
||||
},
|
||||
handleCancelVirtualSales() {
|
||||
if (this.modalSubmitting) {
|
||||
return;
|
||||
}
|
||||
this.resetVirtualSalesModal();
|
||||
},
|
||||
resetVirtualSalesModal() {
|
||||
this.editModalVisible = false;
|
||||
this.modalMode = "single";
|
||||
this.currentSku = null;
|
||||
this.currentIndex = -1;
|
||||
this.editForm.virtualSales = 0;
|
||||
},
|
||||
handleSubmitVirtualSales() {
|
||||
const virtualSales = Number(this.editForm.virtualSales);
|
||||
if (!Number.isInteger(virtualSales) || virtualSales < 0) {
|
||||
this.$Message.warning("请输入大于等于 0 的整数虚拟销量");
|
||||
return;
|
||||
}
|
||||
if (this.modalMode === "batch") {
|
||||
this.handleBatchSubmitVirtualSales(virtualSales);
|
||||
return;
|
||||
}
|
||||
if (!this.currentSku || this.currentIndex < 0) {
|
||||
return;
|
||||
}
|
||||
const currentIndex = this.currentIndex;
|
||||
const currentSkuId = this.currentSku.id;
|
||||
this.modalSubmitting = true;
|
||||
this.$set(this.data[currentIndex], "saving", true);
|
||||
updateGoodsSkuVirtualSales(currentSkuId, { virtualSales })
|
||||
.then((res) => {
|
||||
if (res && res.success) {
|
||||
this.$set(this.data[currentIndex], "virtualSales", virtualSales);
|
||||
this.$set(this.data[currentIndex], "virtualSalesInput", virtualSales);
|
||||
this.$Message.success("虚拟销量设置成功");
|
||||
this.resetVirtualSalesModal();
|
||||
} else {
|
||||
this.$Message.error((res && res.message) || "规格虚拟销量设置失败");
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.$Message.error("规格虚拟销量设置失败");
|
||||
})
|
||||
.finally(() => {
|
||||
if (this.data[currentIndex]) {
|
||||
this.$set(this.data[currentIndex], "saving", false);
|
||||
}
|
||||
this.modalSubmitting = false;
|
||||
});
|
||||
},
|
||||
handleBatchSubmitVirtualSales(virtualSales) {
|
||||
const skuIds = this.selectedRows.map((item) => item.id).filter(Boolean);
|
||||
if (!skuIds.length) {
|
||||
this.$Message.warning("请先选择要设置的商品规格");
|
||||
return;
|
||||
}
|
||||
this.modalSubmitting = true;
|
||||
batchUpdateGoodsSkuVirtualSales({ skuIds, virtualSales })
|
||||
.then((res) => {
|
||||
if (res && res.success) {
|
||||
this.data = this.data.map((item) => {
|
||||
if (!skuIds.includes(item.id)) {
|
||||
return item;
|
||||
}
|
||||
return {
|
||||
...item,
|
||||
virtualSales,
|
||||
virtualSalesInput: virtualSales,
|
||||
};
|
||||
});
|
||||
this.selectedRows = [];
|
||||
if (this.$refs.table) {
|
||||
this.$refs.table.selectAll(false);
|
||||
}
|
||||
this.$Message.success("虚拟销量设置成功");
|
||||
this.resetVirtualSalesModal();
|
||||
} else {
|
||||
this.$Message.error((res && res.message) || "虚拟销量设置失败");
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.$Message.error("虚拟销量设置失败");
|
||||
})
|
||||
.finally(() => {
|
||||
this.modalSubmitting = false;
|
||||
});
|
||||
},
|
||||
getTotalSales(row) {
|
||||
return (Number(row.buyCount) || 0) + (Number(row.virtualSalesInput) || 0);
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.init();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.sub-title {
|
||||
margin-top: 6px;
|
||||
color: #808695;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.goods-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 5px 0;
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
.goods-thumbnail {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
margin-right: 12px;
|
||||
object-fit: cover;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.goods-text {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.batch-operations {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.virtual-sales-modal {
|
||||
padding-top: 8px;
|
||||
}
|
||||
|
||||
.sku-info-item {
|
||||
display: flex;
|
||||
line-height: 24px;
|
||||
margin-bottom: 8px;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.sku-info-label {
|
||||
width: 90px;
|
||||
color: #808695;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
</style>
|
||||
@@ -10,7 +10,7 @@ h4 {
|
||||
margin: 20px 0;
|
||||
font-size: 18px;
|
||||
}
|
||||
/deep/ .ivu-icon {
|
||||
::v-deep .ivu-icon {
|
||||
margin-left: 40px;
|
||||
margin-right: 40px;
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
:page-size="searchForm.pageSize"
|
||||
@on-change="changePage"
|
||||
@on-page-size-change="changePageSize"
|
||||
:page-size-opts="[10, 20, 50]"
|
||||
:page-size-opts="[20, 50, 100]"
|
||||
size="small"
|
||||
show-total
|
||||
show-elevator
|
||||
|
||||
@@ -66,16 +66,16 @@ export default {
|
||||
};
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
/deep/ .ivu-select-dropdown {
|
||||
::v-deep .ivu-select-dropdown {
|
||||
text-align: left;
|
||||
}
|
||||
.message-con {
|
||||
margin-right: 10px;
|
||||
}
|
||||
/deep/ .ivu-dropdown-item{
|
||||
::v-deep .ivu-dropdown-item{
|
||||
padding: 7px 20px !important;
|
||||
}
|
||||
/deep/ .ivu-badge-count{
|
||||
::v-deep .ivu-badge-count{
|
||||
right: -10px !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<Menu
|
||||
ref="childrenMenu"
|
||||
:active-name="$route.name"
|
||||
width="100px"
|
||||
width="120px"
|
||||
@on-select="changeMenu"
|
||||
>
|
||||
<template v-for="item in menuList">
|
||||
@@ -49,7 +49,7 @@ export default {
|
||||
this.selectNav(val.meta.firstRouterName)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
changeMenu(name) { //二级路由点击
|
||||
@@ -71,7 +71,7 @@ export default {
|
||||
<style lang="scss" scoped>
|
||||
.ivu-shrinkable-menu{
|
||||
height: calc(100% - 60px);
|
||||
width: 180px;
|
||||
width: 200px;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ export default {
|
||||
.ivu-menu-dark.ivu-menu-vertical .ivu-menu-item-active:not(.ivu-menu-submenu), .ivu-menu-dark.ivu-menu-vertical .ivu-menu-submenu-title-active:not(.ivu-menu-submenu){
|
||||
color: $theme_color;
|
||||
}
|
||||
/deep/.ivu-menu-vertical .ivu-menu-item-group-title {
|
||||
::v-deep.ivu-menu-vertical .ivu-menu-item-group-title {
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
padding-left: 20px;
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
box-sizing: border-box;
|
||||
position: fixed;
|
||||
display: block;
|
||||
padding-left: 180px;
|
||||
padding-left: 200px;
|
||||
width: 100%;
|
||||
height: 100px;
|
||||
z-index: 20;
|
||||
@@ -218,12 +218,12 @@
|
||||
.single-page-con {
|
||||
min-width: 740px;
|
||||
position: relative;
|
||||
left: 180px;
|
||||
left: 220px;
|
||||
top: 100px;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
height: calc(100% - 110px);
|
||||
width: calc(100% - 180px);
|
||||
width: calc(100% - 220px);
|
||||
overflow: auto;
|
||||
background-color: #f0f0f0;
|
||||
z-index: 1;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
v-model="searchForm.memberName"
|
||||
placeholder="请输入会员名称"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
style="width: 240px"
|
||||
/>
|
||||
</Form-item>
|
||||
<Form-item label="充值单号" prop="rechargeSn">
|
||||
@@ -23,7 +23,7 @@
|
||||
v-model="searchForm.rechargeSn"
|
||||
placeholder="请输入充值单号"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
style="width: 240px"
|
||||
/>
|
||||
</Form-item>
|
||||
<Form-item label="支付时间">
|
||||
@@ -34,11 +34,13 @@
|
||||
clearable
|
||||
@on-change="selectDateRange"
|
||||
placeholder="选择起始时间"
|
||||
style="width: 200px"
|
||||
style="width: 240px"
|
||||
></DatePicker>
|
||||
</Form-item>
|
||||
<Button @click="handleSearch" type="primary" icon="ios-search" class="search-btn">搜索</Button>
|
||||
</Form>
|
||||
</Card>
|
||||
<Card>
|
||||
<Table
|
||||
:loading="loading"
|
||||
border
|
||||
@@ -54,7 +56,7 @@
|
||||
:page-size="searchForm.pageSize"
|
||||
@on-change="changePage"
|
||||
@on-page-size-change="changePageSize"
|
||||
:page-size-opts="[10, 20, 50]"
|
||||
:page-size-opts="[20, 50, 100]"
|
||||
size="small"
|
||||
show-total
|
||||
show-elevator
|
||||
@@ -77,7 +79,7 @@
|
||||
searchForm: {
|
||||
// 搜索框初始化对象
|
||||
pageNumber: 1, // 当前页数
|
||||
pageSize: 10, // 页面大小
|
||||
pageSize: 20, // 页面大小
|
||||
sort: "createTime", // 默认排序字段
|
||||
order: "desc", // 默认排序方式
|
||||
startDate: "", // 起始时间
|
||||
@@ -173,11 +175,11 @@
|
||||
this.getDataList();
|
||||
},
|
||||
// 搜索
|
||||
handleSearch() {
|
||||
this.searchForm.pageNumber = 1;
|
||||
this.searchForm.pageSize = 10;
|
||||
this.getDataList();
|
||||
},
|
||||
handleSearch() {
|
||||
this.searchForm.pageNumber = 1;
|
||||
this.searchForm.pageSize = 20;
|
||||
this.getDataList();
|
||||
},
|
||||
// 时间段赋值
|
||||
selectDateRange(v) {
|
||||
if (v) {
|
||||
|
||||
@@ -5,17 +5,19 @@
|
||||
<Row @keydown.enter.native="handleSearch">
|
||||
<Form ref="searchForm" :model="searchForm" inline :label-width="70" class="search-form">
|
||||
<Form-item label="会员名称" prop="memberName">
|
||||
<Input type="text" v-model="searchForm.memberName" placeholder="请输入会员名称" clearable style="width: 200px" />
|
||||
<Input type="text" v-model="searchForm.memberName" placeholder="请输入会员名称" clearable style="width: 240px" />
|
||||
</Form-item>
|
||||
<Form-item label="支付时间">
|
||||
<DatePicker v-model="selectDate" type="datetimerange" format="yyyy-MM-dd HH:mm:ss" clearable @on-change="selectDateRange" placeholder="选择起始时间" style="width: 200px"></DatePicker>
|
||||
<DatePicker v-model="selectDate" type="datetimerange" format="yyyy-MM-dd HH:mm:ss" clearable @on-change="selectDateRange" placeholder="选择起始时间" style="width: 240px"></DatePicker>
|
||||
</Form-item>
|
||||
<Button @click="handleSearch" type="primary" icon="ios-search" class="search-btn">搜索</Button>
|
||||
</Form>
|
||||
</Row>
|
||||
<Table class="mt_10" :loading="loading" border :columns="columns" :data="data" ref="table"></Table>
|
||||
</Card>
|
||||
<Card>
|
||||
<Table class="mt_10" :loading="loading" border :columns="columns" :data="data" ref="table"></Table>
|
||||
<Row type="flex" justify="end" class="mt_10">
|
||||
<Page :current="searchForm.pageNumber" :total="total" :page-size="searchForm.pageSize" @on-change="changePage" @on-page-size-change="changePageSize" :page-size-opts="[10, 20, 50]"
|
||||
<Page :current="searchForm.pageNumber" :total="total" :page-size="searchForm.pageSize" @on-change="changePage" @on-page-size-change="changePageSize" :page-size-opts="[20, 50, 100]"
|
||||
size="small" show-total show-elevator show-sizer></Page>
|
||||
</Row>
|
||||
</Card>
|
||||
@@ -29,16 +31,16 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
loading: true, // 表单加载状态
|
||||
searchForm: {
|
||||
// 搜索框初始化对象
|
||||
pageNumber: 1, // 当前页数
|
||||
pageSize: 10, // 页面大小
|
||||
sort: "createTime", // 默认排序字段
|
||||
order: "desc", // 默认排序方式
|
||||
startDate: "", // 起始时间
|
||||
endDate: "", // 终止时间
|
||||
memberName: "",
|
||||
},
|
||||
searchForm: {
|
||||
// 搜索框初始化对象
|
||||
pageNumber: 1, // 当前页数
|
||||
pageSize: 20, // 页面大小
|
||||
sort: "createTime", // 默认排序字段
|
||||
order: "desc", // 默认排序方式
|
||||
startDate: "", // 起始时间
|
||||
endDate: "", // 终止时间
|
||||
memberName: "",
|
||||
},
|
||||
selectDate: null, // 选择时间段
|
||||
columns: [
|
||||
// 表头
|
||||
@@ -113,7 +115,7 @@ export default {
|
||||
// 搜索
|
||||
handleSearch() {
|
||||
this.searchForm.pageNumber = 1;
|
||||
this.searchForm.pageSize = 10;
|
||||
this.searchForm.pageSize = 20;
|
||||
this.getDataList();
|
||||
},
|
||||
// 时间段赋值
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
<Row @keydown.enter.native="handleSearch">
|
||||
<Form ref="searchForm" :model="searchForm" inline :label-width="70" class="search-form">
|
||||
<Form-item label="会员名称" prop="memberName">
|
||||
<Input type="text" v-model="searchForm.memberName" placeholder="请输入会员名称" clearable style="width: 200px" />
|
||||
<Input type="text" v-model="searchForm.memberName" placeholder="请输入会员名称" clearable style="width: 240px" />
|
||||
</Form-item>
|
||||
<Form-item label="审核状态" prop="applyStatus">
|
||||
<Select v-model="searchForm.applyStatus" clearable style="width: 200px">
|
||||
<Select v-model="searchForm.applyStatus" clearable style="width: 240px">
|
||||
<Option value="APPLY">申请中</Option>
|
||||
<Option value="VIA_AUDITING">审核通过</Option>
|
||||
<Option value="FAIL_AUDITING">审核拒绝</Option>
|
||||
@@ -16,7 +16,7 @@
|
||||
</Select>
|
||||
</Form-item>
|
||||
<Form-item label="申请时间">
|
||||
<DatePicker v-model="selectDate" type="datetimerange" format="yyyy-MM-dd HH:mm:ss" clearable @on-change="selectDateRange" placeholder="选择起始时间" style="width: 200px"></DatePicker>
|
||||
<DatePicker v-model="selectDate" type="datetimerange" format="yyyy-MM-dd HH:mm:ss" clearable @on-change="selectDateRange" placeholder="选择起始时间" style="width: 240px"></DatePicker>
|
||||
</Form-item>
|
||||
<Form-item style="margin-left: -35px" class="br">
|
||||
<Button @click="handleSearch" type="primary" icon="ios-search">搜索
|
||||
@@ -24,9 +24,11 @@
|
||||
</Form-item>
|
||||
</Form>
|
||||
</Row>
|
||||
</Card>
|
||||
<Card>
|
||||
<Table class="mt_10" :loading="loading" border :columns="columns" :data="data" ref="table" sortable="custom" @on-sort-change="changeSort" @on-selection-change="changeSelect"></Table>
|
||||
<Row type="flex" justify="end" class="mt_10">
|
||||
<Page :current="searchForm.pageNumber" :total="total" :page-size="searchForm.pageSize" @on-change="changePage" @on-page-size-change="changePageSize" :page-size-opts="[10, 20, 50]" size="small"
|
||||
<Page :current="searchForm.pageNumber" :total="total" :page-size="searchForm.pageSize" @on-change="changePage" @on-page-size-change="changePageSize" :page-size-opts="[20, 50, 100]" size="small"
|
||||
show-total show-elevator show-sizer></Page>
|
||||
</Row>
|
||||
</Card>
|
||||
@@ -115,7 +117,7 @@ export default {
|
||||
searchForm: {
|
||||
// 搜索框初始化对象
|
||||
pageNumber: 1, // 当前页数
|
||||
pageSize: 10, // 页面大小
|
||||
pageSize: 20, // 页面大小
|
||||
sort: "createTime", // 默认排序字段
|
||||
order: "desc", // 默认排序方式
|
||||
startDate: "", // 起始时间
|
||||
@@ -192,49 +194,49 @@ export default {
|
||||
fixed: "right",
|
||||
render: (h, params) => {
|
||||
if (params.row.applyStatus == "APPLY") {
|
||||
return h(
|
||||
"Button",
|
||||
{
|
||||
props: {
|
||||
type: "primary",
|
||||
size: "small",
|
||||
},
|
||||
style: {
|
||||
marginRight: "5px",
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
this.showList = {};
|
||||
this.roleModalVisible = true;
|
||||
this.showList = params.row;
|
||||
this.audit =""
|
||||
return h("div", { class: "ops" }, [
|
||||
h(
|
||||
"a",
|
||||
{
|
||||
style: {
|
||||
color: "#2d8cf0",
|
||||
cursor: "pointer",
|
||||
textDecoration: "none",
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
this.showList = {};
|
||||
this.roleModalVisible = true;
|
||||
this.showList = params.row;
|
||||
this.audit = "";
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"审核"
|
||||
);
|
||||
"审核"
|
||||
),
|
||||
]);
|
||||
} else {
|
||||
return h(
|
||||
"Button",
|
||||
{
|
||||
props: {
|
||||
type: "default",
|
||||
size: "small",
|
||||
},
|
||||
style: {
|
||||
marginRight: "5px",
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
this.showList = {};
|
||||
this.queryModalVisible = true;
|
||||
this.showList = params.row;
|
||||
this.modalTitle = "查看";
|
||||
return h("div", { class: "ops" }, [
|
||||
h(
|
||||
"a",
|
||||
{
|
||||
style: {
|
||||
color: "#2d8cf0",
|
||||
cursor: "pointer",
|
||||
textDecoration: "none",
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
this.showList = {};
|
||||
this.queryModalVisible = true;
|
||||
this.showList = params.row;
|
||||
this.modalTitle = "查看";
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"查看"
|
||||
);
|
||||
"查看"
|
||||
),
|
||||
]);
|
||||
}
|
||||
},
|
||||
},
|
||||
@@ -291,13 +293,13 @@ export default {
|
||||
},
|
||||
handleSearch() {
|
||||
this.searchForm.pageNumber = 1;
|
||||
this.searchForm.pageSize = 10;
|
||||
this.searchForm.pageSize = 20;
|
||||
this.getDataList();
|
||||
},
|
||||
handleReset() {
|
||||
this.$refs.searchForm.resetFields();
|
||||
this.searchForm.pageNumber = 1;
|
||||
this.searchForm.pageSize = 10;
|
||||
this.searchForm.pageSize = 20;
|
||||
this.selectDate = null;
|
||||
this.searchForm.startDate = "";
|
||||
this.searchForm.endDate = "";
|
||||
@@ -345,4 +347,16 @@ export default {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.ops a {
|
||||
color: #2d8cf0;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
}
|
||||
.ops span {
|
||||
display: inline-block;
|
||||
margin: 0 8px;
|
||||
color: #dcdee2;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
992
manager/src/views/member/benefit/index.vue
Normal file
992
manager/src/views/member/benefit/index.vue
Normal file
@@ -0,0 +1,992 @@
|
||||
<template>
|
||||
<div class="search member-benefit">
|
||||
<Card>
|
||||
<Row class="operation padding-row">
|
||||
<Button type="primary" @click="openAdd">添加权益设置</Button>
|
||||
</Row>
|
||||
<Table
|
||||
:loading="loading"
|
||||
stripe
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
no-data-text="暂无数据"
|
||||
class="mt_10 benefit-list-table benefit-list-table--no-vertical-borders"
|
||||
></Table>
|
||||
<Row type="flex" justify="end" class="mt_10">
|
||||
<Page
|
||||
:current="searchForm.pageNumber"
|
||||
:total="total"
|
||||
:page-size="searchForm.pageSize"
|
||||
@on-change="changePage"
|
||||
@on-page-size-change="changePageSize"
|
||||
:page-size-opts="[20, 30, 50]"
|
||||
size="small"
|
||||
show-total
|
||||
show-elevator
|
||||
show-sizer
|
||||
></Page>
|
||||
</Row>
|
||||
</Card>
|
||||
|
||||
<!-- 平台优惠券选择(与「添加优惠券活动」coupon-publish 相同组件) -->
|
||||
<Modal
|
||||
v-model="couponPickerVisible"
|
||||
title="选择优惠券"
|
||||
width="80%"
|
||||
:z-index="3000"
|
||||
:mask-closable="false"
|
||||
@on-ok="handleCouponPickerClose"
|
||||
@on-cancel="handleCouponPickerClose"
|
||||
>
|
||||
<couponTemplate
|
||||
v-if="couponPickerVisible"
|
||||
:selectedList="couponPickerSelectedList"
|
||||
getType="ACTIVITY"
|
||||
promotionStatus="START"
|
||||
@selected="onCouponTemplateSelected"
|
||||
/>
|
||||
</Modal>
|
||||
|
||||
<Drawer
|
||||
v-model="addFlag"
|
||||
title="添加权益设置"
|
||||
width="1120"
|
||||
placement="right"
|
||||
:z-index="950"
|
||||
:mask-closable="false"
|
||||
:closable="true"
|
||||
scrollable
|
||||
class-name="benefit-form-drawer"
|
||||
>
|
||||
<Form ref="addForm" :model="formAdd" :rules="rulesAdd" :label-width="110">
|
||||
<FormItem label="权益类型" prop="benefitType">
|
||||
<Select
|
||||
v-model="formAdd.benefitType"
|
||||
clearable
|
||||
placeholder="请选择权益类型"
|
||||
style="width: 100%"
|
||||
@on-change="onAddBenefitTypeChange"
|
||||
>
|
||||
<Option v-for="item in benefitTypeOptions" :key="item.value" :value="item.value">{{ item.description }}</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem
|
||||
v-show="formAdd.benefitType === 'GIFT_POINT'"
|
||||
label="赠送积分"
|
||||
prop="giftPoint"
|
||||
:required="formAdd.benefitType === 'GIFT_POINT'"
|
||||
>
|
||||
<InputNumber
|
||||
v-model="formAdd.giftPoint"
|
||||
:min="0"
|
||||
:max="99999"
|
||||
:precision="0"
|
||||
style="width: 220px"
|
||||
placeholder="必填,范围 0-99999"
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem
|
||||
v-show="formAdd.benefitType === 'COUPON_PACKAGE'"
|
||||
label="赠送优惠券"
|
||||
prop="couponPackageRows"
|
||||
:required="formAdd.benefitType === 'COUPON_PACKAGE'"
|
||||
>
|
||||
<div>
|
||||
<Button type="dashed" icon="ios-add" class="mb_10" @click="openCouponPicker('add')">添加优惠券</Button>
|
||||
<Table
|
||||
border
|
||||
size="small"
|
||||
:columns="couponPackageTableColumns"
|
||||
:data="formAdd.couponPackageRows"
|
||||
no-data-text="请添加优惠券"
|
||||
></Table>
|
||||
</div>
|
||||
</FormItem>
|
||||
<FormItem label="权益名称" prop="benefitName">
|
||||
<Input v-model="formAdd.benefitName" maxlength="50" placeholder="请输入权益名称" />
|
||||
</FormItem>
|
||||
<FormItem label="权益LOGO" prop="benefitLogo">
|
||||
<div class="benefit-logo-field">
|
||||
<div v-if="formAdd.benefitLogo" class="benefit-logo-thumb">
|
||||
<img :src="formAdd.benefitLogo" alt="" />
|
||||
</div>
|
||||
<div class="benefit-logo-upload">
|
||||
<upload-pic-input v-model="formAdd.benefitLogo" placeholder="请上传权益 LOGO 图片地址" style="width: 100%" />
|
||||
</div>
|
||||
</div>
|
||||
</FormItem>
|
||||
<FormItem label="权益介绍" prop="benefitDesc">
|
||||
<Input v-model="formAdd.benefitDesc" type="textarea" :rows="4" maxlength="500" placeholder="请输入权益介绍" />
|
||||
</FormItem>
|
||||
<FormItem label="启用状态" prop="benefitState">
|
||||
<RadioGroup v-model="formAdd.benefitState">
|
||||
<Radio label="OPEN">开启</Radio>
|
||||
<Radio label="CLOSE">关闭</Radio>
|
||||
</RadioGroup>
|
||||
</FormItem>
|
||||
<FormItem label="排序" prop="benefitSort">
|
||||
<InputNumber v-model="formAdd.benefitSort" :min="1" :max="9999" :precision="0" style="width: 220px" />
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div class="benefit-drawer-footer-btns">
|
||||
<Button @click="addFlag = false">取消</Button>
|
||||
<Button type="primary" :loading="submitAddLoading" @click="submitAdd">提交</Button>
|
||||
</div>
|
||||
</Drawer>
|
||||
|
||||
<Drawer
|
||||
v-model="editFlag"
|
||||
title="编辑权益设置"
|
||||
width="1120"
|
||||
placement="right"
|
||||
:z-index="950"
|
||||
:mask-closable="false"
|
||||
:closable="true"
|
||||
scrollable
|
||||
class-name="benefit-form-drawer"
|
||||
>
|
||||
<Form ref="editForm" :model="formEdit" :rules="rulesEdit" :label-width="110">
|
||||
<Input v-model="formEdit.id" v-show="false" />
|
||||
<FormItem label="权益类型" prop="benefitType">
|
||||
<Select
|
||||
v-model="formEdit.benefitType"
|
||||
clearable
|
||||
placeholder="请选择权益类型"
|
||||
style="width: 100%"
|
||||
@on-change="onEditBenefitTypeChange"
|
||||
>
|
||||
<Option v-for="item in benefitTypeOptions" :key="item.value" :value="item.value">{{ item.description }}</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem
|
||||
v-show="formEdit.benefitType === 'GIFT_POINT'"
|
||||
label="赠送积分"
|
||||
prop="giftPoint"
|
||||
:required="formEdit.benefitType === 'GIFT_POINT'"
|
||||
>
|
||||
<InputNumber
|
||||
v-model="formEdit.giftPoint"
|
||||
:min="0"
|
||||
:max="99999"
|
||||
:precision="0"
|
||||
style="width: 220px"
|
||||
placeholder="必填,范围 0-99999"
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem
|
||||
v-show="formEdit.benefitType === 'COUPON_PACKAGE'"
|
||||
label="赠送优惠券"
|
||||
prop="couponPackageRows"
|
||||
:required="formEdit.benefitType === 'COUPON_PACKAGE'"
|
||||
>
|
||||
<div>
|
||||
<Button type="dashed" icon="ios-add" class="mb_10" @click="openCouponPicker('edit')">添加优惠券</Button>
|
||||
<Table
|
||||
border
|
||||
size="small"
|
||||
:columns="couponPackageTableColumnsEdit"
|
||||
:data="formEdit.couponPackageRows"
|
||||
no-data-text="请添加优惠券"
|
||||
></Table>
|
||||
</div>
|
||||
</FormItem>
|
||||
<FormItem label="权益名称" prop="benefitName">
|
||||
<Input v-model="formEdit.benefitName" maxlength="50" placeholder="请输入权益名称" />
|
||||
</FormItem>
|
||||
<FormItem label="权益LOGO" prop="benefitLogo">
|
||||
<div class="benefit-logo-field">
|
||||
<div v-if="formEdit.benefitLogo" class="benefit-logo-thumb">
|
||||
<img :src="formEdit.benefitLogo" alt="" />
|
||||
</div>
|
||||
<div class="benefit-logo-upload">
|
||||
<upload-pic-input v-model="formEdit.benefitLogo" placeholder="请上传权益 LOGO 图片地址" style="width: 100%" />
|
||||
</div>
|
||||
</div>
|
||||
</FormItem>
|
||||
<FormItem label="权益介绍" prop="benefitDesc">
|
||||
<Input v-model="formEdit.benefitDesc" type="textarea" :rows="4" maxlength="500" placeholder="请输入权益介绍" />
|
||||
</FormItem>
|
||||
<FormItem label="启用状态" prop="benefitState">
|
||||
<RadioGroup v-model="formEdit.benefitState">
|
||||
<Radio label="OPEN">开启</Radio>
|
||||
<Radio label="CLOSE">关闭</Radio>
|
||||
</RadioGroup>
|
||||
</FormItem>
|
||||
<FormItem label="排序" prop="benefitSort">
|
||||
<InputNumber v-model="formEdit.benefitSort" :min="1" :max="9999" :precision="0" style="width: 220px" />
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div class="benefit-drawer-footer-btns">
|
||||
<Button @click="editFlag = false">取消</Button>
|
||||
<Button type="primary" :loading="submitEditLoading" @click="submitEdit">提交</Button>
|
||||
</div>
|
||||
</Drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as API_Member from "@/api/member.js";
|
||||
import { getPlatformCoupon } from "@/api/promotion";
|
||||
import { formatPromotionCouponValidityHtml } from "@/utils/promotions";
|
||||
import couponTemplate from "@/views/promotions/coupon/coupon.vue";
|
||||
import uploadPicInput from "@/components/lili/upload-pic-input.vue";
|
||||
|
||||
const GIFT_POINT = "GIFT_POINT";
|
||||
const COUPON_PACKAGE = "COUPON_PACKAGE";
|
||||
|
||||
const buildDefaultForm = () => ({
|
||||
id: "",
|
||||
benefitName: "",
|
||||
benefitCode: "",
|
||||
benefitType: "",
|
||||
benefitLogo: "",
|
||||
benefitDesc: "",
|
||||
benefitSort: 1,
|
||||
benefitState: "OPEN",
|
||||
benefitConfig: "",
|
||||
/** 仅 UI:赠送积分数量;提交时写入 benefitConfig */
|
||||
giftPoint: null,
|
||||
/** 仅 UI:券礼包已选优惠券(含展示字段);提交时写入 benefitConfig.coupons */
|
||||
couponPackageRows: [],
|
||||
});
|
||||
|
||||
export default {
|
||||
name: "memberBenefit",
|
||||
components: {
|
||||
uploadPicInput,
|
||||
couponTemplate,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
benefitTypeOptions: [],
|
||||
loading: false,
|
||||
total: 0,
|
||||
searchForm: {
|
||||
pageNumber: 1,
|
||||
pageSize: 20,
|
||||
},
|
||||
columns: [
|
||||
{
|
||||
title: "权益类型",
|
||||
key: "benefitType",
|
||||
width: 132,
|
||||
render: (h, params) => {
|
||||
const v = params.row.benefitType;
|
||||
let text = "-";
|
||||
if (v) {
|
||||
const opt = this.benefitTypeOptions.find((o) => o.value === v);
|
||||
text = opt ? opt.description : v;
|
||||
}
|
||||
return h(
|
||||
"span",
|
||||
{
|
||||
attrs: { title: text },
|
||||
class: "benefit-list-cell-ellipsis benefit-list-cell-ellipsis--type",
|
||||
},
|
||||
text
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "权益名称",
|
||||
key: "benefitName",
|
||||
width: 188,
|
||||
render: (h, params) => {
|
||||
const text = params.row.benefitName || "-";
|
||||
return h(
|
||||
"span",
|
||||
{
|
||||
attrs: { title: text },
|
||||
class: "benefit-list-cell-ellipsis benefit-list-cell-ellipsis--name",
|
||||
},
|
||||
text
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "权益LOGO",
|
||||
key: "benefitLogo",
|
||||
width: 116,
|
||||
align: "center",
|
||||
render: (h, params) => {
|
||||
const src = params.row.benefitLogo;
|
||||
if (!src) return h("span", "-");
|
||||
return h(
|
||||
"div",
|
||||
{
|
||||
class: "benefit-logo-thumb benefit-logo-thumb--table",
|
||||
},
|
||||
[
|
||||
h("img", {
|
||||
attrs: { src, alt: "" },
|
||||
}),
|
||||
]
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "状态",
|
||||
key: "benefitState",
|
||||
width: 118,
|
||||
align: "center",
|
||||
render: (h, params) => {
|
||||
const row = params.row;
|
||||
return h("i-switch", {
|
||||
props: {
|
||||
value: row.benefitState === "OPEN",
|
||||
size: "large",
|
||||
loading: !!row._benefitStateLoading,
|
||||
},
|
||||
on: {
|
||||
"on-change": (checked) => {
|
||||
this.onBenefitStateSwitch(row, checked);
|
||||
},
|
||||
},
|
||||
}, [
|
||||
h("span", { slot: "open" }, "开启"),
|
||||
h("span", { slot: "close" }, "关闭"),
|
||||
]);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "操作",
|
||||
key: "action",
|
||||
align: "center",
|
||||
width: 140,
|
||||
render: (h, params) => {
|
||||
const linkStyle = {
|
||||
color: "#2d8cf0",
|
||||
cursor: "pointer",
|
||||
textDecoration: "none",
|
||||
};
|
||||
const sep = h("span", { style: { margin: "0 8px", color: "#dcdee2" } }, "|");
|
||||
return h("div", { style: { display: "flex", justifyContent: "center" } }, [
|
||||
h("a", { style: linkStyle, on: { click: () => this.openEdit(params.row) } }, "编辑"),
|
||||
sep,
|
||||
h("a", { style: linkStyle, on: { click: () => this.remove(params.row) } }, "删除"),
|
||||
]);
|
||||
},
|
||||
},
|
||||
],
|
||||
data: [],
|
||||
addFlag: false,
|
||||
editFlag: false,
|
||||
submitAddLoading: false,
|
||||
submitEditLoading: false,
|
||||
formAdd: buildDefaultForm(),
|
||||
formEdit: buildDefaultForm(),
|
||||
couponPickerVisible: false,
|
||||
couponPickerWhich: "add",
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
rulesAdd() {
|
||||
return this.buildFormRules("add");
|
||||
},
|
||||
rulesEdit() {
|
||||
return this.buildFormRules("edit");
|
||||
},
|
||||
couponPackageTableColumns() {
|
||||
return this.buildCouponPackageTableColumns("add");
|
||||
},
|
||||
couponPackageTableColumnsEdit() {
|
||||
return this.buildCouponPackageTableColumns("edit");
|
||||
},
|
||||
/** 传给优惠券列表组件,用于勾选回显(与 coupon-publish 一致用 id) */
|
||||
couponPickerSelectedList() {
|
||||
const form = this.couponPickerWhich === "add" ? this.formAdd : this.formEdit;
|
||||
return (form.couponPackageRows || []).map((r) => ({
|
||||
id: r.couponId,
|
||||
couponName: r.couponName || "",
|
||||
}));
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
buildFormRules(which) {
|
||||
const formKey = which === "add" ? "formAdd" : "formEdit";
|
||||
return {
|
||||
benefitType: [{ required: true, message: "请选择权益类型", trigger: "change" }],
|
||||
benefitName: [{ required: true, message: "请输入权益名称", trigger: "blur" }],
|
||||
benefitLogo: [{ required: true, message: "请配置权益LOGO", trigger: "change" }],
|
||||
benefitSort: [{ required: true, type: "number", message: "请输入排序", trigger: "change" }],
|
||||
benefitState: [{ required: true, message: "请选择启用状态", trigger: "change" }],
|
||||
giftPoint: [
|
||||
{
|
||||
validator: (rule, value, callback) => {
|
||||
const form = this[formKey];
|
||||
this.validateGiftPoint(form, value, callback);
|
||||
},
|
||||
trigger: ["change", "blur"],
|
||||
},
|
||||
],
|
||||
couponPackageRows: [
|
||||
{
|
||||
validator: (rule, value, callback) => {
|
||||
const form = this[formKey];
|
||||
this.validateCouponPackage(form, callback);
|
||||
},
|
||||
trigger: "change",
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
validateGiftPoint(form, value, callback) {
|
||||
if (form.benefitType !== GIFT_POINT) return callback();
|
||||
if (value === null || value === undefined || value === "") {
|
||||
return callback(new Error("请输入赠送积分"));
|
||||
}
|
||||
const n = Number(value);
|
||||
if (Number.isNaN(n) || n < 0 || n > 99999) {
|
||||
return callback(new Error("赠送积分范围为 0-99999"));
|
||||
}
|
||||
callback();
|
||||
},
|
||||
validateCouponPackage(form, callback) {
|
||||
if (form.benefitType !== COUPON_PACKAGE) return callback();
|
||||
const rows = form.couponPackageRows || [];
|
||||
if (!rows.length) {
|
||||
return callback(new Error("请添加至少一张优惠券"));
|
||||
}
|
||||
for (let i = 0; i < rows.length; i++) {
|
||||
const q = Number(rows[i].quantity);
|
||||
if (Number.isNaN(q) || q < 1 || q > 10) {
|
||||
return callback(new Error("每张券赠送张数需在 1~10 之间"));
|
||||
}
|
||||
}
|
||||
callback();
|
||||
},
|
||||
formatCouponFace(row) {
|
||||
if (!row) return "-";
|
||||
if (row.price !== undefined && row.price !== null && row.price !== "") {
|
||||
return `¥${row.price}`;
|
||||
}
|
||||
if (row.couponDiscount !== undefined && row.couponDiscount !== null && row.couponDiscount !== "") {
|
||||
return `${row.couponDiscount}折`;
|
||||
}
|
||||
return "-";
|
||||
},
|
||||
formatCouponValidity(row) {
|
||||
return formatPromotionCouponValidityHtml(row);
|
||||
},
|
||||
buildCouponDisplayRow(detail, quantity) {
|
||||
const qty = Math.min(10, Math.max(1, Number(quantity) || 1));
|
||||
return {
|
||||
couponId: detail.id,
|
||||
quantity: qty,
|
||||
couponName: detail.couponName || "",
|
||||
faceValueLabel: this.formatCouponFace(detail),
|
||||
validRange: this.formatCouponValidity(detail),
|
||||
};
|
||||
},
|
||||
buildCouponPackageTableColumns(which) {
|
||||
const formKey = which === "add" ? "formAdd" : "formEdit";
|
||||
const linkStyle = { color: "#2d8cf0", cursor: "pointer" };
|
||||
return [
|
||||
{ title: "优惠券名称", key: "couponName", minWidth: 100, tooltip: true },
|
||||
{
|
||||
title: "有效期",
|
||||
minWidth: 100,
|
||||
render: (h, p) =>
|
||||
h("span", {
|
||||
domProps: { innerHTML: p.row.validRange || "-" },
|
||||
}),
|
||||
},
|
||||
{ title: "面额", key: "faceValueLabel", minWidth: 100 },
|
||||
{
|
||||
title: "赠送张数",
|
||||
key: "quantity",
|
||||
width: 150,
|
||||
render: (h, params) =>
|
||||
h("InputNumber", {
|
||||
props: {
|
||||
min: 1,
|
||||
max: 10,
|
||||
precision: 0,
|
||||
value: params.row.quantity,
|
||||
},
|
||||
style: { width: "100px" },
|
||||
on: {
|
||||
"on-change": (val) => {
|
||||
this.$set(this[formKey].couponPackageRows[params.index], "quantity", val);
|
||||
this.$nextTick(() => {
|
||||
const ref = which === "add" ? this.$refs.addForm : this.$refs.editForm;
|
||||
if (ref) ref.validateField("couponPackageRows");
|
||||
});
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
{
|
||||
title: "操作",
|
||||
key: "action",
|
||||
width: 90,
|
||||
align: "center",
|
||||
render: (h, params) =>
|
||||
h(
|
||||
"a",
|
||||
{
|
||||
style: linkStyle,
|
||||
on: {
|
||||
click: () => {
|
||||
this.removeCouponRow(which, params.index);
|
||||
},
|
||||
},
|
||||
},
|
||||
"删除"
|
||||
),
|
||||
},
|
||||
];
|
||||
},
|
||||
/** 构造 benefitConfig JSON 字符串 */
|
||||
buildBenefitConfigString(slice) {
|
||||
const { benefitType, giftPoint, couponPackageRows } = slice;
|
||||
if (benefitType === GIFT_POINT) {
|
||||
return JSON.stringify({ giftPoint: Number(giftPoint) });
|
||||
}
|
||||
if (benefitType === COUPON_PACKAGE) {
|
||||
const coupons = (couponPackageRows || []).map((r) => ({
|
||||
couponId: String(r.couponId),
|
||||
quantity: Math.min(10, Math.max(1, Number(r.quantity) || 1)),
|
||||
}));
|
||||
return JSON.stringify({ coupons });
|
||||
}
|
||||
return "";
|
||||
},
|
||||
/** 从详情 benefitConfig 解析赠送积分,解析失败时返回 null */
|
||||
parseGiftPointFromConfig(benefitType, benefitConfigStr) {
|
||||
if (benefitType !== GIFT_POINT || !benefitConfigStr) return null;
|
||||
try {
|
||||
const o = JSON.parse(benefitConfigStr);
|
||||
if (o && typeof o.giftPoint !== "undefined") {
|
||||
const n = Number(o.giftPoint);
|
||||
return Number.isNaN(n) ? null : n;
|
||||
}
|
||||
} catch (e) {
|
||||
/* ignore */
|
||||
}
|
||||
return null;
|
||||
},
|
||||
onAddBenefitTypeChange(val) {
|
||||
if (val !== GIFT_POINT) {
|
||||
this.formAdd.giftPoint = null;
|
||||
}
|
||||
if (val !== COUPON_PACKAGE) {
|
||||
this.formAdd.couponPackageRows = [];
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.addForm && val !== GIFT_POINT) {
|
||||
this.$refs.addForm.validateField("giftPoint");
|
||||
}
|
||||
if (this.$refs.addForm && val !== COUPON_PACKAGE) {
|
||||
this.$refs.addForm.validateField("couponPackageRows");
|
||||
}
|
||||
});
|
||||
},
|
||||
onEditBenefitTypeChange(val) {
|
||||
if (val !== GIFT_POINT) {
|
||||
this.formEdit.giftPoint = null;
|
||||
}
|
||||
if (val !== COUPON_PACKAGE) {
|
||||
this.formEdit.couponPackageRows = [];
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.editForm && val !== GIFT_POINT) {
|
||||
this.$refs.editForm.validateField("giftPoint");
|
||||
}
|
||||
if (this.$refs.editForm && val !== COUPON_PACKAGE) {
|
||||
this.$refs.editForm.validateField("couponPackageRows");
|
||||
}
|
||||
});
|
||||
},
|
||||
parseCouponsFromConfig(str) {
|
||||
if (!str) return [];
|
||||
try {
|
||||
const o = JSON.parse(str);
|
||||
if (o && Array.isArray(o.coupons)) {
|
||||
return o.coupons.map((c) => ({
|
||||
couponId: c.couponId,
|
||||
quantity: c.quantity,
|
||||
}));
|
||||
}
|
||||
} catch (e) {
|
||||
/* ignore */
|
||||
}
|
||||
return [];
|
||||
},
|
||||
/** 与添加时 formatCouponFace 一致;仅有 faceValueText 时去掉「减免」前缀 */
|
||||
normalizeCouponFaceFromDetail(item) {
|
||||
let face = this.formatCouponFace(item);
|
||||
if (face !== "-") return face;
|
||||
const raw = item.faceValueText;
|
||||
if (raw == null || raw === "") return "-";
|
||||
return String(raw)
|
||||
.replace(/^减免现金\s*/, "")
|
||||
.replace(/^减免\s*/, "")
|
||||
.trim() || "-";
|
||||
},
|
||||
/** 管理端详情 couponItems → 表格行(面额展示与添加一致) */
|
||||
mapCouponItemsToPackageRows(items) {
|
||||
if (!Array.isArray(items)) return [];
|
||||
return items.map((item) => {
|
||||
const face = this.normalizeCouponFaceFromDetail(item);
|
||||
const validHtml = item.validityText
|
||||
? String(item.validityText).replace(/\n/g, "<br/>")
|
||||
: "-";
|
||||
return {
|
||||
couponId: item.couponId,
|
||||
quantity: Math.min(10, Math.max(1, Number(item.quantity) || 1)),
|
||||
couponName: item.couponName || "",
|
||||
faceValueLabel: face,
|
||||
validRange: validHtml,
|
||||
};
|
||||
});
|
||||
},
|
||||
async hydrateCouponRowsForEdit(snippets) {
|
||||
const rows = [];
|
||||
for (const s of snippets) {
|
||||
const cid = s.couponId;
|
||||
const qty = s.quantity;
|
||||
try {
|
||||
const res = await getPlatformCoupon(cid);
|
||||
if (res && res.success && res.result) {
|
||||
rows.push(this.buildCouponDisplayRow(res.result, qty));
|
||||
} else {
|
||||
rows.push({
|
||||
couponId: cid,
|
||||
quantity: Math.min(10, Math.max(1, Number(qty) || 1)),
|
||||
couponName: String(cid),
|
||||
faceValueLabel: "-",
|
||||
validRange: "-",
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
rows.push({
|
||||
couponId: cid,
|
||||
quantity: Math.min(10, Math.max(1, Number(qty) || 1)),
|
||||
couponName: String(cid),
|
||||
faceValueLabel: "-",
|
||||
validRange: "-",
|
||||
});
|
||||
}
|
||||
}
|
||||
this.$set(this.formEdit, "couponPackageRows", rows);
|
||||
},
|
||||
handleCouponPickerClose() {
|
||||
this.couponPickerVisible = false;
|
||||
},
|
||||
openCouponPicker(which) {
|
||||
this.couponPickerWhich = which;
|
||||
this.couponPickerVisible = true;
|
||||
},
|
||||
/** 与 coupon-publish `selectedCoupon`:表格多选变更时同步到券礼包配置 */
|
||||
onCouponTemplateSelected(selectedRows) {
|
||||
const which = this.couponPickerWhich;
|
||||
const form = which === "add" ? this.formAdd : this.formEdit;
|
||||
const refName = which === "add" ? "addForm" : "editForm";
|
||||
const list = selectedRows || [];
|
||||
const rows = list.map((row) => {
|
||||
const existing = (form.couponPackageRows || []).find((r) => String(r.couponId) === String(row.id));
|
||||
const qty = existing ? existing.quantity : 1;
|
||||
return this.buildCouponDisplayRow(row, qty);
|
||||
});
|
||||
this.$set(form, "couponPackageRows", rows);
|
||||
this.$nextTick(() => {
|
||||
const ref = this.$refs[refName];
|
||||
if (ref) ref.validateField("couponPackageRows");
|
||||
});
|
||||
},
|
||||
removeCouponRow(which, index) {
|
||||
const form = which === "add" ? this.formAdd : this.formEdit;
|
||||
const refName = which === "add" ? "addForm" : "editForm";
|
||||
form.couponPackageRows.splice(index, 1);
|
||||
this.$nextTick(() => {
|
||||
const ref = this.$refs[refName];
|
||||
if (ref) ref.validateField("couponPackageRows");
|
||||
});
|
||||
},
|
||||
init() {
|
||||
this.loadBenefitTypes();
|
||||
this.getData();
|
||||
},
|
||||
loadBenefitTypes() {
|
||||
API_Member.getMemberBenefitTypes().then((res) => {
|
||||
if (res && res.success && Array.isArray(res.result)) {
|
||||
this.benefitTypeOptions = res.result;
|
||||
} else {
|
||||
this.benefitTypeOptions = [];
|
||||
}
|
||||
});
|
||||
},
|
||||
changePage(page) {
|
||||
this.searchForm.pageNumber = page;
|
||||
this.getData();
|
||||
},
|
||||
changePageSize(size) {
|
||||
this.searchForm.pageSize = size;
|
||||
this.searchForm.pageNumber = 1;
|
||||
this.getData();
|
||||
},
|
||||
getData() {
|
||||
this.loading = true;
|
||||
const params = { ...this.searchForm };
|
||||
API_Member.getMemberBenefitByPage(params).then((res) => {
|
||||
this.loading = false;
|
||||
if (res && res.success && res.result) {
|
||||
this.data = Array.isArray(res.result.records) ? res.result.records : [];
|
||||
this.total = Number(res.result.total) || 0;
|
||||
} else {
|
||||
this.data = [];
|
||||
this.total = 0;
|
||||
}
|
||||
});
|
||||
},
|
||||
openAdd() {
|
||||
this.addFlag = true;
|
||||
this.submitAddLoading = false;
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.addForm) this.$refs.addForm.resetFields();
|
||||
this.formAdd = buildDefaultForm();
|
||||
});
|
||||
},
|
||||
submitAdd() {
|
||||
if (!this.$refs.addForm) {
|
||||
this.$Message.warning("表单未就绪,请稍后重试");
|
||||
return;
|
||||
}
|
||||
this.$refs.addForm.validate((valid) => {
|
||||
if (!valid) return;
|
||||
this.submitAddLoading = true;
|
||||
const { giftPoint, couponPackageRows, ...rest } = this.formAdd;
|
||||
const payload = {
|
||||
...rest,
|
||||
benefitConfig: this.buildBenefitConfigString({
|
||||
benefitType: this.formAdd.benefitType,
|
||||
giftPoint,
|
||||
couponPackageRows,
|
||||
}),
|
||||
};
|
||||
API_Member.addMemberBenefit(payload).then((res) => {
|
||||
this.submitAddLoading = false;
|
||||
if (res && res.success) {
|
||||
this.$Message.success("添加成功");
|
||||
this.addFlag = false;
|
||||
this.getData();
|
||||
} else if (res && res.message) {
|
||||
this.$Message.error(res.message);
|
||||
} else {
|
||||
this.$Message.error("添加失败");
|
||||
}
|
||||
}).catch(() => {
|
||||
this.submitAddLoading = false;
|
||||
this.$Message.error("网络异常,请稍后重试");
|
||||
});
|
||||
});
|
||||
},
|
||||
openEdit(row) {
|
||||
this.editFlag = true;
|
||||
this.submitEditLoading = false;
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.editForm) this.$refs.editForm.resetFields();
|
||||
});
|
||||
API_Member.getMemberBenefit(row.id).then((res) => {
|
||||
if (res && res.success && res.result) {
|
||||
const raw = res.result;
|
||||
/** 新接口:{ benefit, couponItems };旧接口:扁平 MemberBenefit */
|
||||
const detail = raw.benefit != null ? raw.benefit : raw;
|
||||
const couponItems = raw.couponItems;
|
||||
const bt = detail.benefitType || "";
|
||||
const parsed = this.parseGiftPointFromConfig(bt, detail.benefitConfig || "");
|
||||
const couponSnippets = this.parseCouponsFromConfig(detail.benefitConfig || "");
|
||||
|
||||
let couponRows = [];
|
||||
if (bt === COUPON_PACKAGE && Array.isArray(couponItems) && couponItems.length) {
|
||||
couponRows = this.mapCouponItemsToPackageRows(couponItems);
|
||||
}
|
||||
|
||||
this.formEdit = {
|
||||
id: detail.id || row.id || "",
|
||||
benefitName: detail.benefitName || "",
|
||||
benefitCode: detail.benefitCode || "",
|
||||
benefitType: bt,
|
||||
benefitLogo: detail.benefitLogo || "",
|
||||
benefitDesc: detail.benefitDesc || "",
|
||||
benefitSort: Number(detail.benefitSort) > 0 ? Number(detail.benefitSort) : 1,
|
||||
benefitState: detail.benefitState || "OPEN",
|
||||
benefitConfig: detail.benefitConfig || "",
|
||||
giftPoint: bt === GIFT_POINT ? (parsed !== null ? parsed : null) : null,
|
||||
couponPackageRows: couponRows,
|
||||
};
|
||||
|
||||
if (bt === COUPON_PACKAGE && couponRows.length === 0 && couponSnippets.length) {
|
||||
this.hydrateCouponRowsForEdit(couponSnippets);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
submitEdit() {
|
||||
if (!this.$refs.editForm) {
|
||||
this.$Message.warning("表单未就绪,请稍后重试");
|
||||
return;
|
||||
}
|
||||
this.$refs.editForm.validate((valid) => {
|
||||
if (!valid) return;
|
||||
this.submitEditLoading = true;
|
||||
const { id, giftPoint, couponPackageRows, ...rest } = this.formEdit;
|
||||
const payload = {
|
||||
...rest,
|
||||
benefitConfig: this.buildBenefitConfigString({
|
||||
benefitType: this.formEdit.benefitType,
|
||||
giftPoint,
|
||||
couponPackageRows,
|
||||
}),
|
||||
};
|
||||
API_Member.updateMemberBenefit(id, payload).then((res) => {
|
||||
this.submitEditLoading = false;
|
||||
if (res && res.success) {
|
||||
this.$Message.success("修改成功");
|
||||
this.editFlag = false;
|
||||
this.getData();
|
||||
} else if (res && res.message) {
|
||||
this.$Message.error(res.message);
|
||||
} else {
|
||||
this.$Message.error("修改失败");
|
||||
}
|
||||
}).catch(() => {
|
||||
this.submitEditLoading = false;
|
||||
this.$Message.error("网络异常,请稍后重试");
|
||||
});
|
||||
});
|
||||
},
|
||||
onBenefitStateSwitch(row, checked) {
|
||||
const nextState = checked ? "OPEN" : "CLOSE";
|
||||
const prevState = row.benefitState;
|
||||
if (nextState === prevState) return;
|
||||
const text = checked ? "开启" : "关闭";
|
||||
this.$Modal.confirm({
|
||||
title: "提示",
|
||||
content: `<p>确定${text}该客户权益?</p>`,
|
||||
onOk: () => {
|
||||
this.$set(row, "_benefitStateLoading", true);
|
||||
return API_Member.updateMemberBenefitState(row.id, nextState)
|
||||
.then((res) => {
|
||||
this.$set(row, "_benefitStateLoading", false);
|
||||
if (res && res.success) {
|
||||
this.$Message.success(`${text}成功`);
|
||||
this.$set(row, "benefitState", nextState);
|
||||
} else {
|
||||
this.getData();
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.$set(row, "_benefitStateLoading", false);
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
remove(row) {
|
||||
this.$Modal.confirm({
|
||||
title: "提示",
|
||||
content: "<p>确定删除该客户权益?</p>",
|
||||
onOk: () => {
|
||||
API_Member.deleteMemberBenefit(row.id).then((res) => {
|
||||
if (res && res.success) {
|
||||
this.$Message.success("删除成功");
|
||||
this.getData();
|
||||
} else if (res && res.message) {
|
||||
this.$Message.error(res.message);
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.init();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.benefit-drawer-footer-btns {
|
||||
margin-top: 24px;
|
||||
padding-top: 16px;
|
||||
border-top: 1px solid #e8eaec;
|
||||
text-align: right;
|
||||
}
|
||||
.benefit-drawer-footer-btns .ivu-btn + .ivu-btn {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<!--
|
||||
权益 LOGO 缩略图:固定 100×100。
|
||||
不使用 .member-benefit 前缀:Modal 默认 transfer 到 body,弹窗内节点不在 .member-benefit 下。
|
||||
Table 列 render 生成的节点在子组件内,同样用非 scoped。
|
||||
-->
|
||||
<style lang="scss">
|
||||
.benefit-logo-thumb {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
min-width: 100px;
|
||||
min-height: 100px;
|
||||
max-width: 100px;
|
||||
max-height: 100px;
|
||||
flex-shrink: 0;
|
||||
border: 1px solid #dcdee2;
|
||||
border-radius: 4px;
|
||||
background: #f8f8f9;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.benefit-logo-thumb img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
display: block;
|
||||
}
|
||||
.benefit-logo-thumb--table {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
/* 权益列表:固定类型/名称列宽并省略过长文案(悬浮 title 可看全文) */
|
||||
.member-benefit .benefit-list-table table {
|
||||
table-layout: fixed;
|
||||
}
|
||||
.member-benefit .benefit-list-cell-ellipsis {
|
||||
display: inline-block;
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.member-benefit .benefit-list-cell-ellipsis--type {
|
||||
max-width: 118px;
|
||||
}
|
||||
.member-benefit .benefit-list-cell-ellipsis--name {
|
||||
max-width: 172px;
|
||||
}
|
||||
|
||||
/* 列表不出现列与列之间的竖线(保留行间分隔) */
|
||||
.member-benefit .benefit-list-table--no-vertical-borders .ivu-table th,
|
||||
.member-benefit .benefit-list-table--no-vertical-borders .ivu-table td {
|
||||
border-right: none !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.benefit-logo-field {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.benefit-logo-upload {
|
||||
flex: 1;
|
||||
min-width: 200px;
|
||||
}
|
||||
</style>
|
||||
197
manager/src/views/member/grade/experience-log.vue
Normal file
197
manager/src/views/member/grade/experience-log.vue
Normal file
@@ -0,0 +1,197 @@
|
||||
<template>
|
||||
<div class="search">
|
||||
<Card>
|
||||
<Form
|
||||
ref="searchForm"
|
||||
:model="searchForm"
|
||||
inline
|
||||
:label-width="90"
|
||||
@keydown.enter.native="handleSearch"
|
||||
@submit.native.prevent
|
||||
class="search-form"
|
||||
>
|
||||
<FormItem label="客户手机号" prop="mobile">
|
||||
<Input
|
||||
v-model="searchForm.memberMobile"
|
||||
clearable
|
||||
placeholder="请输入客户手机号"
|
||||
style="width: 220px"
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem label="规则" prop="ruleKey">
|
||||
<Select v-model="searchForm.ruleKey" clearable filterable style="width: 220px">
|
||||
<Option v-for="item in ruleOptions" :key="item.value" :value="item.value">
|
||||
{{ item.label }}
|
||||
</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<Button type="primary" icon="ios-search" @click="handleSearch">搜索</Button>
|
||||
</Form>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<Table
|
||||
:loading="loading"
|
||||
border
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
class="mt_10"
|
||||
></Table>
|
||||
<Row type="flex" justify="end" class="mt_10">
|
||||
<Page
|
||||
:current="searchForm.pageNumber"
|
||||
:total="total"
|
||||
:page-size="searchForm.pageSize"
|
||||
@on-change="changePage"
|
||||
@on-page-size-change="changePageSize"
|
||||
:page-size-opts="[20, 50, 100]"
|
||||
size="small"
|
||||
show-total
|
||||
show-elevator
|
||||
show-sizer
|
||||
></Page>
|
||||
</Row>
|
||||
</Card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as API_Member from "@/api/member";
|
||||
|
||||
const RULE_OPTIONS = [
|
||||
{ value: "CONSUME", label: "消费" },
|
||||
{ value: "REGISTER", label: "注册" },
|
||||
{ value: "SIGN_IN", label: "签到" },
|
||||
{ value: "COMMENT", label: "评价" },
|
||||
{ value: "SHARE", label: "分享商城" },
|
||||
{ value: "PROFILE", label: "完善信息" },
|
||||
{ value: "FOLLOW_STORE", label: "关注店铺" },
|
||||
{ value: "BIND_WECHAT", label: "绑定微信" },
|
||||
{ value: "ADD_ADDRESS", label: "添加收货地址" },
|
||||
{ value: "SHARE_REGISTER", label: "分享注册" },
|
||||
{ value: "SHARE_BUY", label: "分享购买" },
|
||||
];
|
||||
|
||||
export default {
|
||||
name: "memberGradeExperienceLog",
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
total: 0,
|
||||
data: [],
|
||||
ruleOptions: RULE_OPTIONS,
|
||||
searchForm: {
|
||||
pageNumber: 1,
|
||||
pageSize: 20,
|
||||
memberMobile: "",
|
||||
ruleKey: "",
|
||||
},
|
||||
columns: [
|
||||
{
|
||||
title: "客户手机号",
|
||||
key: "memberMobile",
|
||||
width: 140,
|
||||
tooltip: true,
|
||||
render: (h, params) => {
|
||||
const v = params.row.memberMobile || params.row.mobile || "-";
|
||||
return h("span", v);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "规则名称",
|
||||
key: "ruleName",
|
||||
width: 150,
|
||||
tooltip: true,
|
||||
render: (h, params) => {
|
||||
const text = params.row.ruleName || this.findRuleName(params.row.ruleKey) || "-";
|
||||
return h("span", text);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "变化经验值",
|
||||
key: "value",
|
||||
width: 120,
|
||||
render: (h, params) => {
|
||||
const v =
|
||||
params.row.value ??
|
||||
params.row.variableExperience ??
|
||||
params.row.experience ??
|
||||
params.row.variableValue;
|
||||
return h("span", v == null ? "-" : v);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "经验值限额",
|
||||
key: "maxValue",
|
||||
width: 120,
|
||||
render: (h, params) => {
|
||||
const v = params.row.maxValue ?? params.row.maxExperience ?? params.row.limitValue;
|
||||
return h("span", v == null ? "-" : v);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "操作说明",
|
||||
key: "content",
|
||||
minWidth: 200,
|
||||
tooltip: true,
|
||||
render: (h, params) => {
|
||||
const text = params.row.content || params.row.remark || params.row.description || "-";
|
||||
return h("span", text);
|
||||
},
|
||||
},
|
||||
{ title: "创建时间", key: "createTime", width: 170 },
|
||||
],
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
findRuleName(ruleKey) {
|
||||
const hit = this.ruleOptions.find((item) => item.value === ruleKey);
|
||||
return hit ? hit.label : "";
|
||||
},
|
||||
init() {
|
||||
this.getData();
|
||||
},
|
||||
buildParams() {
|
||||
const params = {
|
||||
pageNumber: this.searchForm.pageNumber,
|
||||
pageSize: this.searchForm.pageSize,
|
||||
};
|
||||
if (this.searchForm.memberMobile) params.mobile = this.searchForm.memberMobile;
|
||||
if (this.searchForm.ruleKey) params.ruleKey = this.searchForm.ruleKey;
|
||||
return params;
|
||||
},
|
||||
getData() {
|
||||
this.loading = true;
|
||||
API_Member.getMemberExperienceByPage(this.buildParams())
|
||||
.then((res) => {
|
||||
if (res && res.success && res.result) {
|
||||
this.data = res.result.records || [];
|
||||
this.total = res.result.total || 0;
|
||||
} else {
|
||||
this.data = [];
|
||||
this.total = 0;
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
handleSearch() {
|
||||
this.searchForm.pageNumber = 1;
|
||||
this.getData();
|
||||
},
|
||||
changePage(v) {
|
||||
this.searchForm.pageNumber = v;
|
||||
this.getData();
|
||||
},
|
||||
changePageSize(v) {
|
||||
this.searchForm.pageNumber = 1;
|
||||
this.searchForm.pageSize = v;
|
||||
this.getData();
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
556
manager/src/views/member/grade/experience-setting.vue
Normal file
556
manager/src/views/member/grade/experience-setting.vue
Normal file
@@ -0,0 +1,556 @@
|
||||
<template>
|
||||
<div class="experience-setting">
|
||||
<Card>
|
||||
<Form :label-width="120" label-position="right">
|
||||
<Table :loading="loading" :columns="columns" :data="form.items" class="mt_10 experience-table"></Table>
|
||||
<FormItem label="经验值说明" style="margin-top: 16px" class="desc-item">
|
||||
<Input
|
||||
v-model="form.description"
|
||||
type="textarea"
|
||||
:rows="4"
|
||||
maxlength="500"
|
||||
show-word-limit
|
||||
placeholder="请输入经验值说明"
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<Button type="primary" :loading="submitLoading" @click="submit">保存</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getSetting, setSetting } from "@/api/index";
|
||||
|
||||
const RULE_OPTIONS = [
|
||||
{ ruleKey: "CONSUME", ruleName: "消费" },
|
||||
{ ruleKey: "REGISTER", ruleName: "注册" },
|
||||
{ ruleKey: "SIGN_IN", ruleName: "签到" },
|
||||
{ ruleKey: "COMMENT", ruleName: "评价" },
|
||||
{ ruleKey: "SHARE", ruleName: "分享商城" },
|
||||
{ ruleKey: "PROFILE", ruleName: "完善信息" },
|
||||
{ ruleKey: "FOLLOW_STORE", ruleName: "关注店铺" },
|
||||
{ ruleKey: "BIND_WECHAT", ruleName: "绑定微信" },
|
||||
{ ruleKey: "ADD_ADDRESS", ruleName: "添加收货地址" },
|
||||
{ ruleKey: "SHARE_REGISTER", ruleName: "分享注册" },
|
||||
{ ruleKey: "SHARE_BUY", ruleName: "分享购买" },
|
||||
];
|
||||
|
||||
const defaultRuleItem = (rule) => ({
|
||||
ruleKey: rule.ruleKey,
|
||||
ruleName: rule.ruleName,
|
||||
enabled: false,
|
||||
value: 1,
|
||||
maxValue: null,
|
||||
});
|
||||
|
||||
const defaultForm = () => ({
|
||||
items: RULE_OPTIONS.map((item) => defaultRuleItem(item)),
|
||||
description: "",
|
||||
});
|
||||
|
||||
export default {
|
||||
name: "memberGradeExperienceSetting",
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
submitLoading: false,
|
||||
form: defaultForm(),
|
||||
columns: [
|
||||
{
|
||||
title: "是否开启",
|
||||
key: "enabled",
|
||||
width: 90,
|
||||
align: "center",
|
||||
render: (h, params) => {
|
||||
return h("Checkbox", {
|
||||
props: { value: !!this.form.items[params.index].enabled },
|
||||
on: {
|
||||
"on-change": (checked) => {
|
||||
this.updateRuleEnabled(params.index, checked);
|
||||
},
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "类型",
|
||||
key: "ruleName",
|
||||
width: 160,
|
||||
},
|
||||
{
|
||||
title: "经验值(1-100)",
|
||||
key: "value",
|
||||
minWidth: 700,
|
||||
render: (h, params) => {
|
||||
const row = this.form.items[params.index] || {};
|
||||
const inputNode = h("Input", {
|
||||
style: { width: "120px" },
|
||||
props: {
|
||||
value: row.value == null ? "" : String(row.value),
|
||||
number: true,
|
||||
},
|
||||
on: {
|
||||
input: (val) => {
|
||||
this.updateRuleValue(params.index, val);
|
||||
},
|
||||
"on-change": (v) => {
|
||||
this.updateRuleValue(params.index, v);
|
||||
},
|
||||
"on-blur": () => {
|
||||
this.commitRuleValue(params.index);
|
||||
},
|
||||
},
|
||||
});
|
||||
const maxInputNode = h("Input", {
|
||||
style: { width: "120px" },
|
||||
props: {
|
||||
value: row.maxValue == null ? "" : String(row.maxValue),
|
||||
number: true,
|
||||
},
|
||||
on: {
|
||||
input: (val) => {
|
||||
this.updateRuleMaxValue(params.index, val);
|
||||
},
|
||||
"on-change": (v) => {
|
||||
this.updateRuleMaxValue(params.index, v);
|
||||
},
|
||||
"on-blur": () => {
|
||||
this.commitRuleMaxValue(params.index);
|
||||
},
|
||||
},
|
||||
});
|
||||
if (params.row.ruleKey === "REGISTER") {
|
||||
return h(
|
||||
"div",
|
||||
{ style: { display: "flex", flexDirection: "column", alignItems: "flex-start" } },
|
||||
[
|
||||
h(
|
||||
"div",
|
||||
{ style: { display: "flex", alignItems: "center" } },
|
||||
[h("span", { style: { marginRight: "8px" } }, "获得经验值:"), inputNode]
|
||||
),
|
||||
h(
|
||||
"div",
|
||||
{ style: { marginTop: "6px", color: "#808695", fontSize: "12px" } },
|
||||
"会员注册成功后可获得经验值"
|
||||
),
|
||||
]
|
||||
);
|
||||
}
|
||||
if (params.row.ruleKey === "SHARE") {
|
||||
return h(
|
||||
"div",
|
||||
{ style: { display: "flex", flexDirection: "column", alignItems: "flex-start" } },
|
||||
[
|
||||
h(
|
||||
"div",
|
||||
{ style: { display: "flex", alignItems: "center", flexWrap: "wrap" } },
|
||||
[
|
||||
h(
|
||||
"div",
|
||||
{ style: { display: "flex", alignItems: "center", marginRight: "16px" } },
|
||||
[h("span", { style: { marginRight: "8px" } }, "分享商品详情页获得经验值:"), inputNode]
|
||||
),
|
||||
h(
|
||||
"div",
|
||||
{ style: { display: "flex", alignItems: "center" } },
|
||||
[h("span", { style: { marginRight: "8px" } }, "可获得经验值限额:"), maxInputNode]
|
||||
),
|
||||
]
|
||||
),
|
||||
h(
|
||||
"div",
|
||||
{ style: { marginTop: "6px", color: "#808695", fontSize: "12px" } },
|
||||
"会员分享商城页面可获得的经验值"
|
||||
),
|
||||
]
|
||||
);
|
||||
}
|
||||
if (params.row.ruleKey === "COMMENT") {
|
||||
return h(
|
||||
"div",
|
||||
{ style: { display: "flex", flexDirection: "column", alignItems: "flex-start" } },
|
||||
[
|
||||
h(
|
||||
"div",
|
||||
{ style: { display: "flex", alignItems: "center", flexWrap: "wrap" } },
|
||||
[h("span", { style: { marginRight: "8px" } }, "对已购买商品完成提交评论获得经验值:"), inputNode]
|
||||
),
|
||||
h(
|
||||
"div",
|
||||
{ style: { marginTop: "6px", color: "#808695", fontSize: "12px" } },
|
||||
"仅针对评论字数大于30字的评论进行发放"
|
||||
),
|
||||
]
|
||||
);
|
||||
}
|
||||
if (params.row.ruleKey === "FOLLOW_STORE") {
|
||||
return h(
|
||||
"div",
|
||||
{ style: { display: "flex", flexDirection: "column", alignItems: "flex-start" } },
|
||||
[
|
||||
h(
|
||||
"div",
|
||||
{ style: { display: "flex", alignItems: "center", flexWrap: "wrap" } },
|
||||
[
|
||||
h(
|
||||
"div",
|
||||
{ style: { display: "flex", alignItems: "center", marginRight: "16px" } },
|
||||
[h("span", { style: { marginRight: "8px" } }, "获得经验值:"), inputNode]
|
||||
),
|
||||
h(
|
||||
"div",
|
||||
{ style: { display: "flex", alignItems: "center" } },
|
||||
[h("span", { style: { marginRight: "8px" } }, "可获得经验值限额:"), maxInputNode]
|
||||
),
|
||||
]
|
||||
),
|
||||
h(
|
||||
"div",
|
||||
{ style: { marginTop: "6px", color: "#808695", fontSize: "12px" } },
|
||||
"关注店铺可获得经验值,每个客户D相同店铺仅第一次关注可进行获得"
|
||||
),
|
||||
]
|
||||
);
|
||||
}
|
||||
if (params.row.ruleKey === "PROFILE") {
|
||||
return h(
|
||||
"div",
|
||||
{ style: { display: "flex", flexDirection: "column", alignItems: "flex-start" } },
|
||||
[
|
||||
h(
|
||||
"div",
|
||||
{ style: { display: "flex", alignItems: "center", flexWrap: "wrap" } },
|
||||
[h("span", { style: { marginRight: "8px" } }, "获得经验值:"), inputNode]
|
||||
),
|
||||
h(
|
||||
"div",
|
||||
{ style: { marginTop: "6px", color: "#808695", fontSize: "12px" } },
|
||||
"完善个人基本信息可获得经验值,每个会员仅可获得一次"
|
||||
),
|
||||
]
|
||||
);
|
||||
}
|
||||
if (params.row.ruleKey === "BIND_WECHAT") {
|
||||
return h(
|
||||
"div",
|
||||
{ style: { display: "flex", flexDirection: "column", alignItems: "flex-start" } },
|
||||
[
|
||||
h(
|
||||
"div",
|
||||
{ style: { display: "flex", alignItems: "center", flexWrap: "wrap" } },
|
||||
[h("span", { style: { marginRight: "8px" } }, "获取经验值:"), inputNode]
|
||||
),
|
||||
h(
|
||||
"div",
|
||||
{ style: { marginTop: "6px", color: "#808695", fontSize: "12px" } },
|
||||
"绑定微信成功获得经验值,每个会员仅可获得一次"
|
||||
),
|
||||
]
|
||||
);
|
||||
}
|
||||
if (params.row.ruleKey === "ADD_ADDRESS") {
|
||||
return h(
|
||||
"div",
|
||||
{ style: { display: "flex", flexDirection: "column", alignItems: "flex-start" } },
|
||||
[
|
||||
h(
|
||||
"div",
|
||||
{ style: { display: "flex", alignItems: "center", flexWrap: "wrap" } },
|
||||
[h("span", { style: { marginRight: "8px" } }, "获取经验值:"), inputNode]
|
||||
),
|
||||
h(
|
||||
"div",
|
||||
{ style: { marginTop: "6px", color: "#808695", fontSize: "12px" } },
|
||||
"添加收货地址后获得经验值,每个会员仅可获得一次"
|
||||
),
|
||||
]
|
||||
);
|
||||
}
|
||||
if (params.row.ruleKey === "SHARE_REGISTER") {
|
||||
return h(
|
||||
"div",
|
||||
{ style: { display: "flex", flexDirection: "column", alignItems: "flex-start" } },
|
||||
[
|
||||
h(
|
||||
"div",
|
||||
{ style: { display: "flex", alignItems: "center", flexWrap: "wrap" } },
|
||||
[
|
||||
h(
|
||||
"div",
|
||||
{ style: { display: "flex", alignItems: "center", marginRight: "16px" } },
|
||||
[h("span", { style: { marginRight: "8px" } }, "获取的经验值:"), inputNode]
|
||||
),
|
||||
h(
|
||||
"div",
|
||||
{ style: { display: "flex", alignItems: "center" } },
|
||||
[h("span", { style: { marginRight: "8px" } }, "可获得经验值限额:"), maxInputNode]
|
||||
),
|
||||
]
|
||||
),
|
||||
h(
|
||||
"div",
|
||||
{ style: { marginTop: "6px", color: "#808695", fontSize: "12px" } },
|
||||
"仅被注册成功后才可获得相应奖励经验值"
|
||||
),
|
||||
]
|
||||
);
|
||||
}
|
||||
if (params.row.ruleKey === "SHARE_BUY") {
|
||||
return h(
|
||||
"div",
|
||||
{ style: { display: "flex", flexDirection: "column", alignItems: "flex-start" } },
|
||||
[
|
||||
h(
|
||||
"div",
|
||||
{ style: { display: "flex", alignItems: "center", flexWrap: "wrap" } },
|
||||
[
|
||||
h(
|
||||
"div",
|
||||
{ style: { display: "flex", alignItems: "center", marginRight: "16px" } },
|
||||
[h("span", { style: { marginRight: "8px" } }, "获取的经验值:"), inputNode]
|
||||
),
|
||||
h(
|
||||
"div",
|
||||
{ style: { display: "flex", alignItems: "center" } },
|
||||
[h("span", { style: { marginRight: "8px" } }, "可获得经验值限额:"), maxInputNode]
|
||||
),
|
||||
]
|
||||
),
|
||||
h(
|
||||
"div",
|
||||
{ style: { marginTop: "6px", color: "#808695", fontSize: "12px" } },
|
||||
"仅被购买成功后才可获得相应奖励经验值"
|
||||
),
|
||||
]
|
||||
);
|
||||
}
|
||||
if (params.row.ruleKey === "SIGN_IN") {
|
||||
return h(
|
||||
"div",
|
||||
{ style: { display: "flex", flexDirection: "column", alignItems: "flex-start" } },
|
||||
[
|
||||
h(
|
||||
"div",
|
||||
{ style: { display: "flex", alignItems: "center", flexWrap: "wrap" } },
|
||||
[h("span", { style: { marginRight: "8px" } }, "获取的经验值:"), inputNode]
|
||||
),
|
||||
h(
|
||||
"div",
|
||||
{ style: { marginTop: "6px", color: "#808695", fontSize: "12px" } },
|
||||
"客户每日签到后可获的经验值"
|
||||
),
|
||||
]
|
||||
);
|
||||
}
|
||||
if (params.row.ruleKey === "CONSUME") {
|
||||
return h(
|
||||
"div",
|
||||
{ style: { display: "flex", flexDirection: "column", alignItems: "flex-start" } },
|
||||
[
|
||||
h(
|
||||
"div",
|
||||
{ style: { display: "flex", alignItems: "center", flexWrap: "wrap" } },
|
||||
[h("span", { style: { marginRight: "8px" } }, "1元获取经验值:"), inputNode]
|
||||
),
|
||||
h(
|
||||
"div",
|
||||
{ style: { marginTop: "6px", color: "#808695", fontSize: "12px" } },
|
||||
"客户消费1元可获取经验值,向下取整"
|
||||
),
|
||||
]
|
||||
);
|
||||
}
|
||||
return inputNode;
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.loadData();
|
||||
},
|
||||
methods: {
|
||||
getRawInputValue(v) {
|
||||
return v && v.target ? v.target.value : v;
|
||||
},
|
||||
updateRuleEnabled(index, enabled) {
|
||||
const item = this.form.items[index] || {};
|
||||
this.$set(this.form.items, index, {
|
||||
...item,
|
||||
enabled: !!enabled,
|
||||
});
|
||||
},
|
||||
updateRuleValue(index, v) {
|
||||
const raw = this.getRawInputValue(v);
|
||||
const next = Number(raw);
|
||||
const item = this.form.items[index] || {};
|
||||
this.$set(this.form.items, index, {
|
||||
...item,
|
||||
value: Number.isFinite(next) ? next : null,
|
||||
});
|
||||
},
|
||||
commitRuleValue(index) {
|
||||
const item = this.form.items[index] || {};
|
||||
const next = Number(item.value);
|
||||
let value = 1;
|
||||
if (Number.isFinite(next)) {
|
||||
if (next < 1) value = 1;
|
||||
else if (next > 100) value = 100;
|
||||
else value = Math.floor(next);
|
||||
}
|
||||
this.$set(this.form.items, index, {
|
||||
...item,
|
||||
value,
|
||||
});
|
||||
},
|
||||
updateRuleMaxValue(index, v) {
|
||||
const raw = this.getRawInputValue(v);
|
||||
const item = this.form.items[index] || {};
|
||||
if (raw == null || raw === "") {
|
||||
this.$set(this.form.items, index, {
|
||||
...item,
|
||||
maxValue: null,
|
||||
});
|
||||
return;
|
||||
}
|
||||
const next = Number(raw);
|
||||
this.$set(this.form.items, index, {
|
||||
...item,
|
||||
maxValue: Number.isFinite(next) ? next : null,
|
||||
});
|
||||
},
|
||||
commitRuleMaxValue(index) {
|
||||
const item = this.form.items[index] || {};
|
||||
if (item.maxValue == null || item.maxValue === "") {
|
||||
this.$set(this.form.items, index, {
|
||||
...item,
|
||||
maxValue: null,
|
||||
});
|
||||
return;
|
||||
}
|
||||
const next = Number(item.maxValue);
|
||||
this.$set(this.form.items, index, {
|
||||
...item,
|
||||
maxValue: Number.isFinite(next) && next >= 1 ? Math.floor(next) : null,
|
||||
});
|
||||
},
|
||||
normalizeConfig(val) {
|
||||
if (!val) return {};
|
||||
if (typeof val === "string") {
|
||||
try {
|
||||
return JSON.parse(val);
|
||||
} catch (e) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
if (typeof val === "object") return val;
|
||||
return {};
|
||||
},
|
||||
normalizeItems(items) {
|
||||
const map = {};
|
||||
if (Array.isArray(items)) {
|
||||
items.forEach((item) => {
|
||||
if (!item || !item.ruleKey) return;
|
||||
map[item.ruleKey] = item;
|
||||
});
|
||||
}
|
||||
return RULE_OPTIONS.map((rule) => {
|
||||
const hit = map[rule.ruleKey] || {};
|
||||
return {
|
||||
ruleKey: rule.ruleKey,
|
||||
ruleName: hit.ruleName || rule.ruleName,
|
||||
enabled: !!hit.enabled,
|
||||
value: Number(hit.value) > 0 ? Number(hit.value) : 1,
|
||||
maxValue: hit.maxValue == null || hit.maxValue === "" ? null : Number(hit.maxValue),
|
||||
};
|
||||
});
|
||||
},
|
||||
loadData() {
|
||||
this.loading = true;
|
||||
getSetting("EXPERIENCE_SETTING")
|
||||
.then((res) => {
|
||||
if (res && res.success) {
|
||||
const cfg = this.normalizeConfig(res.result);
|
||||
this.form = {
|
||||
items: this.normalizeItems(cfg.items),
|
||||
description: cfg.description || "",
|
||||
};
|
||||
} else {
|
||||
this.form = defaultForm();
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
validateForm() {
|
||||
const invalid = this.form.items.find((item) => {
|
||||
const v = Number(item.value);
|
||||
if (!Number.isInteger(v) || v < 1 || v > 100) return true;
|
||||
if (item.maxValue != null && item.maxValue !== "") {
|
||||
const m = Number(item.maxValue);
|
||||
if (!Number.isInteger(m) || m < 1) return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
if (invalid) {
|
||||
this.$Message.error("请检查经验值配置,经验值范围为1-100,限额需为正整数");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
submit() {
|
||||
if (!this.validateForm()) return;
|
||||
const payload = {
|
||||
items: this.form.items.map((item) => ({
|
||||
ruleKey: item.ruleKey,
|
||||
ruleName: item.ruleName,
|
||||
enabled: !!item.enabled,
|
||||
value: Number(item.value),
|
||||
maxValue: item.maxValue == null || item.maxValue === "" ? null : Number(item.maxValue),
|
||||
})),
|
||||
description: this.form.description || "",
|
||||
};
|
||||
this.submitLoading = true;
|
||||
setSetting("EXPERIENCE_SETTING", payload)
|
||||
.then((res) => {
|
||||
if (res && res.success) {
|
||||
this.$Message.success("保存成功");
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.submitLoading = false;
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.experience-setting {
|
||||
padding: 2px 0;
|
||||
}
|
||||
|
||||
::v-deep .experience-table .ivu-table th {
|
||||
background: #fafbfc;
|
||||
}
|
||||
|
||||
::v-deep .experience-table .ivu-table td {
|
||||
padding-top: 12px;
|
||||
padding-bottom: 12px;
|
||||
}
|
||||
|
||||
::v-deep .experience-table .ivu-table-cell {
|
||||
font-size: 13px;
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
::v-deep .desc-item .ivu-form-item-label {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
</style>
|
||||
547
manager/src/views/member/grade/index.vue
Normal file
547
manager/src/views/member/grade/index.vue
Normal file
@@ -0,0 +1,547 @@
|
||||
<template>
|
||||
<div class="search">
|
||||
<Card>
|
||||
<Row class="operation padding-row">
|
||||
<Button type="primary" @click="openAdd">添加客户等级</Button>
|
||||
</Row>
|
||||
<Table
|
||||
:loading="loading"
|
||||
border
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
class="mt_10"
|
||||
></Table>
|
||||
</Card>
|
||||
|
||||
<Modal v-model="addFlag" title="添加客户等级" width="720" :z-index="950" :mask-closable="false">
|
||||
<Form ref="addForm" :model="formAdd" :rules="rules" :label-width="110">
|
||||
<FormItem label="等级名称" prop="gradeName">
|
||||
<Input v-model="formAdd.gradeName" maxlength="50" placeholder="请输入等级名称" />
|
||||
</FormItem>
|
||||
<FormItem label="是否默认" prop="isDefault">
|
||||
<RadioGroup v-model="formAdd.isDefault">
|
||||
<Radio :label="true">是</Radio>
|
||||
<Radio :label="false">否</Radio>
|
||||
</RadioGroup>
|
||||
</FormItem>
|
||||
<FormItem label="等级图标" prop="gradeImage">
|
||||
<upload-pic-input v-model="formAdd.gradeImage"></upload-pic-input>
|
||||
</FormItem>
|
||||
<FormItem label="等级背景图" prop="gradeBackground">
|
||||
<upload-pic-input v-model="formAdd.gradeBackground"></upload-pic-input>
|
||||
</FormItem>
|
||||
<FormItem label="字体颜色" prop="gradeFontColor">
|
||||
<Input v-model="formAdd.gradeFontColor" maxlength="20" placeholder="如:#333333" />
|
||||
</FormItem>
|
||||
<FormItem label="所需经验值" prop="requiredExperience">
|
||||
<InputNumber v-model="formAdd.requiredExperience" :min="1" :precision="0" style="width: 220px"></InputNumber>
|
||||
</FormItem>
|
||||
<FormItem label="等级排序" prop="gradeSort">
|
||||
<InputNumber v-model="formAdd.gradeSort" :min="1" :max="9999" :precision="0" style="width: 220px"></InputNumber>
|
||||
</FormItem>
|
||||
<FormItem label="等级开关" prop="gradeState">
|
||||
<RadioGroup v-model="formAdd.gradeState">
|
||||
<Radio label="OPEN">开启</Radio>
|
||||
<Radio label="CLOSE">关闭</Radio>
|
||||
</RadioGroup>
|
||||
</FormItem>
|
||||
<FormItem label="关联权益" prop="benefitIds">
|
||||
<Select
|
||||
:value="addBenefitOrder"
|
||||
multiple
|
||||
filterable
|
||||
placeholder="请选择客户权益"
|
||||
style="width: 100%"
|
||||
@on-change="onAddBenefitIdsChange"
|
||||
>
|
||||
<Option v-for="b in benefitOptions" :key="b.id" :value="String(b.id)">{{ benefitOptionLabel(b) }}</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer">
|
||||
<Button @click="addFlag = false">取消</Button>
|
||||
<Button type="primary" :loading="submitAddLoading" @click="submitAdd">确定</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
<Modal v-model="editFlag" title="编辑客户等级" width="720" :z-index="950" :mask-closable="false">
|
||||
<Form ref="editForm" :model="formEdit" :rules="rules" :label-width="110">
|
||||
<Input v-model="formEdit.id" v-show="false" />
|
||||
<FormItem label="等级名称" prop="gradeName">
|
||||
<Input v-model="formEdit.gradeName" maxlength="50" placeholder="请输入等级名称" />
|
||||
</FormItem>
|
||||
<FormItem label="是否默认" prop="isDefault">
|
||||
<RadioGroup v-model="formEdit.isDefault">
|
||||
<Radio :label="true">是</Radio>
|
||||
<Radio :label="false">否</Radio>
|
||||
</RadioGroup>
|
||||
</FormItem>
|
||||
<FormItem label="等级图标" prop="gradeImage">
|
||||
<upload-pic-input v-model="formEdit.gradeImage"></upload-pic-input>
|
||||
</FormItem>
|
||||
<FormItem label="等级背景图" prop="gradeBackground">
|
||||
<upload-pic-input v-model="formEdit.gradeBackground"></upload-pic-input>
|
||||
</FormItem>
|
||||
<FormItem label="字体颜色" prop="gradeFontColor">
|
||||
<Input v-model="formEdit.gradeFontColor" maxlength="20" placeholder="如:#333333" />
|
||||
</FormItem>
|
||||
<FormItem label="所需经验值" prop="requiredExperience">
|
||||
<InputNumber v-model="formEdit.requiredExperience" :min="1" :precision="0" style="width: 220px"></InputNumber>
|
||||
</FormItem>
|
||||
<FormItem label="等级排序" prop="gradeSort">
|
||||
<InputNumber v-model="formEdit.gradeSort" :min="1" :max="9999" :precision="0" style="width: 220px"></InputNumber>
|
||||
</FormItem>
|
||||
<FormItem label="等级开关" prop="gradeState">
|
||||
<RadioGroup v-model="formEdit.gradeState">
|
||||
<Radio label="OPEN">开启</Radio>
|
||||
<Radio label="CLOSE">关闭</Radio>
|
||||
</RadioGroup>
|
||||
</FormItem>
|
||||
<FormItem label="关联权益" prop="benefitIds">
|
||||
<Select
|
||||
:value="editBenefitOrder"
|
||||
multiple
|
||||
filterable
|
||||
placeholder="请选择客户权益"
|
||||
style="width: 100%"
|
||||
@on-change="onEditBenefitIdsChange"
|
||||
>
|
||||
<Option v-for="b in benefitOptions" :key="b.id" :value="String(b.id)">{{ benefitOptionLabel(b) }}</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer">
|
||||
<Button @click="editFlag = false">取消</Button>
|
||||
<Button type="primary" :loading="submitEditLoading" @click="submitEdit">确定</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as API_Member from "@/api/member.js";
|
||||
import uploadPicInput from "@/components/lili/upload-pic-input";
|
||||
|
||||
const buildDefaultForm = () => ({
|
||||
id: "",
|
||||
gradeName: "",
|
||||
isDefault: false,
|
||||
gradeImage: "",
|
||||
gradeBackground: "",
|
||||
gradeFontColor: "",
|
||||
requiredExperience: 1,
|
||||
gradeSort: 1,
|
||||
gradeState: "OPEN",
|
||||
benefitIds: "",
|
||||
});
|
||||
|
||||
/** 权益多选:新勾选追加到末尾,取消勾选移除,保持已有顺序 */
|
||||
function syncOrderedBenefitIds(prevOrder, selected) {
|
||||
const sel = Array.isArray(selected) ? selected.map((id) => String(id)) : [];
|
||||
const out = [];
|
||||
(prevOrder || []).forEach((id) => {
|
||||
const s = String(id);
|
||||
if (sel.includes(s)) out.push(s);
|
||||
});
|
||||
sel.forEach((s) => {
|
||||
if (!out.includes(s)) out.push(s);
|
||||
});
|
||||
return out;
|
||||
}
|
||||
|
||||
export default {
|
||||
name: "memberGrade",
|
||||
components: {
|
||||
uploadPicInput,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: true,
|
||||
columns: [
|
||||
{
|
||||
title: "等级名称",
|
||||
key: "gradeName",
|
||||
width: 130,
|
||||
tooltip: true,
|
||||
},
|
||||
{
|
||||
title: "默认等级",
|
||||
key: "isDefault",
|
||||
width: 95,
|
||||
render: (h, params) => {
|
||||
const yes = params.row.isDefault === true;
|
||||
return h(
|
||||
"Tag",
|
||||
{
|
||||
props: {
|
||||
color: yes ? "success" : "default",
|
||||
},
|
||||
},
|
||||
yes ? "是" : "否"
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "等级图标",
|
||||
key: "gradeImage",
|
||||
width: 100,
|
||||
render: (h, params) => {
|
||||
if (!params.row.gradeImage) return h("span", "-");
|
||||
return h("img", {
|
||||
attrs: {
|
||||
src: params.row.gradeImage,
|
||||
alt: "等级图标",
|
||||
},
|
||||
style: {
|
||||
width: "48px",
|
||||
height: "48px",
|
||||
objectFit: "contain",
|
||||
border: "1px solid #dcdee2",
|
||||
borderRadius: "4px",
|
||||
background: "#fff",
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "等级背景图",
|
||||
key: "gradeBackground",
|
||||
width: 120,
|
||||
render: (h, params) => {
|
||||
if (!params.row.gradeBackground) return h("span", "-");
|
||||
return h("img", {
|
||||
attrs: {
|
||||
src: params.row.gradeBackground,
|
||||
alt: "等级背景图",
|
||||
},
|
||||
style: {
|
||||
width: "64px",
|
||||
height: "40px",
|
||||
objectFit: "cover",
|
||||
border: "1px solid #dcdee2",
|
||||
borderRadius: "4px",
|
||||
background: "#fff",
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "所需经验值",
|
||||
key: "requiredExperience",
|
||||
width: 110,
|
||||
},
|
||||
{
|
||||
title: "等级排序",
|
||||
key: "gradeSort",
|
||||
width: 95,
|
||||
},
|
||||
{
|
||||
title: "状态",
|
||||
key: "gradeState",
|
||||
width: 118,
|
||||
align: "center",
|
||||
render: (h, params) => {
|
||||
const row = params.row;
|
||||
return h("i-switch", {
|
||||
props: {
|
||||
value: row.gradeState === "OPEN",
|
||||
size: "large",
|
||||
loading: !!row._gradeStateLoading,
|
||||
},
|
||||
on: {
|
||||
"on-change": (checked) => {
|
||||
this.onGradeStateSwitch(row, checked);
|
||||
},
|
||||
},
|
||||
}, [
|
||||
h("span", { slot: "open" }, "开启"),
|
||||
h("span", { slot: "close" }, "关闭"),
|
||||
]);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "操作",
|
||||
key: "action",
|
||||
align: "center",
|
||||
width: 130,
|
||||
render: (h, params) => {
|
||||
const linkStyle = {
|
||||
color: "#2d8cf0",
|
||||
cursor: "pointer",
|
||||
textDecoration: "none",
|
||||
};
|
||||
const sep = h(
|
||||
"span",
|
||||
{ style: { margin: "0 8px", color: "#dcdee2" } },
|
||||
"|"
|
||||
);
|
||||
return h(
|
||||
"div",
|
||||
{ class: "ops", style: { display: "flex", justifyContent: "center" } },
|
||||
[
|
||||
h(
|
||||
"a",
|
||||
{ style: linkStyle, on: { click: () => this.openEdit(params.row) } },
|
||||
"编辑"
|
||||
),
|
||||
sep,
|
||||
h(
|
||||
"a",
|
||||
{ style: linkStyle, on: { click: () => this.remove(params.row) } },
|
||||
"删除"
|
||||
),
|
||||
]
|
||||
);
|
||||
},
|
||||
},
|
||||
],
|
||||
data: [],
|
||||
addFlag: false,
|
||||
editFlag: false,
|
||||
submitAddLoading: false,
|
||||
submitEditLoading: false,
|
||||
formAdd: buildDefaultForm(),
|
||||
formEdit: buildDefaultForm(),
|
||||
/** 关联权益 id 顺序(与 benefitIds 一致) */
|
||||
addBenefitOrder: [],
|
||||
editBenefitOrder: [],
|
||||
benefitOptions: [],
|
||||
benefitTypeOptions: [],
|
||||
benefitOptionsLoading: false,
|
||||
editDetailLoading: false,
|
||||
rules: {
|
||||
gradeName: [{ required: true, message: "请输入等级名称", trigger: "blur" }],
|
||||
gradeImage: [{ required: true, message: "请上传等级图标", trigger: "change" }],
|
||||
requiredExperience: [{ required: true, type: "number", message: "请输入所需经验值", trigger: "change" }],
|
||||
gradeSort: [{ required: true, type: "number", message: "请输入等级排序", trigger: "change" }],
|
||||
gradeState: [{ required: true, message: "请选择等级开关", trigger: "change" }],
|
||||
},
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
benefitOptionLabel(b) {
|
||||
if (!b) return "";
|
||||
const name = b.benefitName || String(b.id);
|
||||
const opt = this.benefitTypeOptions.find((o) => o.value === b.benefitType);
|
||||
const typeText = opt ? opt.description : b.benefitType || "";
|
||||
return typeText ? `${name}(${typeText})` : name;
|
||||
},
|
||||
onAddBenefitIdsChange(val) {
|
||||
this.addBenefitOrder = syncOrderedBenefitIds(this.addBenefitOrder, val);
|
||||
},
|
||||
onEditBenefitIdsChange(val) {
|
||||
this.editBenefitOrder = syncOrderedBenefitIds(this.editBenefitOrder, val);
|
||||
},
|
||||
loadBenefitTypes() {
|
||||
API_Member.getMemberBenefitTypes().then((res) => {
|
||||
if (res && res.success && Array.isArray(res.result)) {
|
||||
this.benefitTypeOptions = res.result;
|
||||
} else {
|
||||
this.benefitTypeOptions = [];
|
||||
}
|
||||
});
|
||||
},
|
||||
loadBenefitOptions() {
|
||||
this.benefitOptionsLoading = true;
|
||||
const pageSize = 500;
|
||||
const fetchPage = (pageNumber) =>
|
||||
API_Member.getMemberBenefitByPage({ pageNumber, pageSize, sort: "benefitSort", order: "asc" });
|
||||
return fetchPage(1)
|
||||
.then((res) => {
|
||||
if (!(res && res.success && res.result)) {
|
||||
this.benefitOptions = [];
|
||||
return;
|
||||
}
|
||||
const records = Array.isArray(res.result.records) ? res.result.records : [];
|
||||
const total = Number(res.result.total) || records.length;
|
||||
let all = records.slice();
|
||||
if (total > pageSize) {
|
||||
const pages = Math.ceil(total / pageSize);
|
||||
const rest = [];
|
||||
for (let p = 2; p <= pages; p++) {
|
||||
rest.push(fetchPage(p));
|
||||
}
|
||||
return Promise.all(rest).then((results) => {
|
||||
results.forEach((r) => {
|
||||
if (r && r.success && r.result && Array.isArray(r.result.records)) {
|
||||
all = all.concat(r.result.records);
|
||||
}
|
||||
});
|
||||
this.benefitOptions = all;
|
||||
});
|
||||
}
|
||||
this.benefitOptions = all;
|
||||
})
|
||||
.catch(() => {
|
||||
this.benefitOptions = [];
|
||||
})
|
||||
.finally(() => {
|
||||
this.benefitOptionsLoading = false;
|
||||
});
|
||||
},
|
||||
parseBenefitIdsFromString(str) {
|
||||
return String(str || "")
|
||||
.split(",")
|
||||
.map((s) => s.trim())
|
||||
.filter(Boolean);
|
||||
},
|
||||
fillEditFormFromGrade(grade, benefitsOrderedIds) {
|
||||
this.formEdit = {
|
||||
id: grade.id || "",
|
||||
gradeName: grade.gradeName || "",
|
||||
isDefault: grade.isDefault === true,
|
||||
gradeImage: grade.gradeImage || "",
|
||||
gradeBackground: grade.gradeBackground || "",
|
||||
gradeFontColor: grade.gradeFontColor || "",
|
||||
requiredExperience: Number(grade.requiredExperience) > 0 ? Number(grade.requiredExperience) : 1,
|
||||
gradeSort: Number(grade.gradeSort) > 0 ? Number(grade.gradeSort) : 1,
|
||||
gradeState: grade.gradeState || "OPEN",
|
||||
benefitIds: grade.benefitIds || "",
|
||||
};
|
||||
this.editBenefitOrder = (benefitsOrderedIds || []).map((id) => String(id));
|
||||
},
|
||||
init() {
|
||||
this.getData();
|
||||
this.loadBenefitTypes();
|
||||
this.loadBenefitOptions();
|
||||
},
|
||||
getData() {
|
||||
this.loading = true;
|
||||
API_Member.getMemberGradeByPage().then((res) => {
|
||||
this.loading = false;
|
||||
if (res && res.success) {
|
||||
this.data = Array.isArray(res.result) ? res.result : [];
|
||||
}
|
||||
});
|
||||
},
|
||||
openAdd() {
|
||||
this.addFlag = true;
|
||||
this.submitAddLoading = false;
|
||||
if (!this.benefitOptions.length && !this.benefitOptionsLoading) {
|
||||
this.loadBenefitOptions();
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.addForm) this.$refs.addForm.resetFields();
|
||||
this.formAdd = buildDefaultForm();
|
||||
this.addBenefitOrder = [];
|
||||
});
|
||||
},
|
||||
submitAdd() {
|
||||
this.$refs.addForm.validate((valid) => {
|
||||
if (!valid) return;
|
||||
this.submitAddLoading = true;
|
||||
const { benefitIds: _omit, ...rest } = this.formAdd;
|
||||
const payload = {
|
||||
...rest,
|
||||
benefitIds: (this.addBenefitOrder || []).join(","),
|
||||
};
|
||||
API_Member.addMemberGrade(payload).then((res) => {
|
||||
this.submitAddLoading = false;
|
||||
if (res && res.success) {
|
||||
this.$Message.success("添加成功");
|
||||
this.addFlag = false;
|
||||
this.getData();
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
openEdit(row) {
|
||||
this.editFlag = true;
|
||||
this.submitEditLoading = false;
|
||||
this.editDetailLoading = true;
|
||||
if (!this.benefitOptions.length && !this.benefitOptionsLoading) {
|
||||
this.loadBenefitOptions();
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.editForm) this.$refs.editForm.resetFields();
|
||||
});
|
||||
API_Member.getMemberGrade(row.id)
|
||||
.then((res) => {
|
||||
this.editDetailLoading = false;
|
||||
if (res && res.success && res.result) {
|
||||
const raw = res.result;
|
||||
const grade = raw.grade != null ? raw.grade : raw;
|
||||
const benefits = Array.isArray(raw.benefits) ? raw.benefits : [];
|
||||
const orderedIds = benefits.length
|
||||
? benefits.map((b) => b.id).filter((id) => id != null && id !== "")
|
||||
: String(grade.benefitIds || "")
|
||||
.split(",")
|
||||
.map((s) => s.trim())
|
||||
.filter(Boolean);
|
||||
this.fillEditFormFromGrade(grade, orderedIds);
|
||||
} else {
|
||||
this.fillEditFormFromGrade(row, this.parseBenefitIdsFromString(row.benefitIds));
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.editDetailLoading = false;
|
||||
this.fillEditFormFromGrade(row, this.parseBenefitIdsFromString(row.benefitIds));
|
||||
});
|
||||
},
|
||||
submitEdit() {
|
||||
this.$refs.editForm.validate((valid) => {
|
||||
if (!valid) return;
|
||||
this.submitEditLoading = true;
|
||||
const { id, benefitIds: _omit, ...rest } = this.formEdit;
|
||||
const payload = {
|
||||
...rest,
|
||||
benefitIds: (this.editBenefitOrder || []).join(","),
|
||||
};
|
||||
API_Member.updateMemberGrade(id, payload).then((res) => {
|
||||
this.submitEditLoading = false;
|
||||
if (res && res.success) {
|
||||
this.$Message.success("修改成功");
|
||||
this.editFlag = false;
|
||||
this.getData();
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
onGradeStateSwitch(row, checked) {
|
||||
const nextState = checked ? "OPEN" : "CLOSE";
|
||||
const prevState = row.gradeState;
|
||||
if (nextState === prevState) return;
|
||||
const text = checked ? "开启" : "关闭";
|
||||
this.$Modal.confirm({
|
||||
title: "提示",
|
||||
content: `<p>确定${text}该客户等级?</p>`,
|
||||
onOk: () => {
|
||||
this.$set(row, "_gradeStateLoading", true);
|
||||
return API_Member.updateMemberGradeState(row.id, nextState)
|
||||
.then((res) => {
|
||||
this.$set(row, "_gradeStateLoading", false);
|
||||
if (res && res.success) {
|
||||
this.$Message.success(`${text}成功`);
|
||||
this.$set(row, "gradeState", nextState);
|
||||
} else {
|
||||
this.getData();
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.$set(row, "_gradeStateLoading", false);
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
remove(row) {
|
||||
this.$Modal.confirm({
|
||||
title: "提示",
|
||||
content: "<p>确定删除该客户等级?</p>",
|
||||
onOk: () => {
|
||||
API_Member.deleteMemberGrade(row.id).then((res) => {
|
||||
if (res && res.success) {
|
||||
this.$Message.success("删除成功");
|
||||
this.getData();
|
||||
} else if (res && res.message) {
|
||||
this.$Message.error(res.message);
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.init();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
257
manager/src/views/member/group/index.vue
Normal file
257
manager/src/views/member/group/index.vue
Normal file
@@ -0,0 +1,257 @@
|
||||
<template>
|
||||
<div class="search">
|
||||
<Card>
|
||||
<Row class="operation padding-row">
|
||||
<Button type="primary" @click="openAdd">添加分组</Button>
|
||||
</Row>
|
||||
<Table
|
||||
:loading="loading"
|
||||
border
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
ref="table"
|
||||
class="mt_10"
|
||||
></Table>
|
||||
<Row type="flex" justify="end" class="mt_10">
|
||||
<Page
|
||||
:current="searchForm.pageNumber"
|
||||
:total="total"
|
||||
:page-size="searchForm.pageSize"
|
||||
@on-change="changePage"
|
||||
@on-page-size-change="changePageSize"
|
||||
:page-size-opts="[20, 50, 100]"
|
||||
size="small"
|
||||
show-total
|
||||
show-elevator
|
||||
show-sizer
|
||||
></Page>
|
||||
</Row>
|
||||
</Card>
|
||||
<Modal v-model="addFlag" title="添加分组">
|
||||
<Form ref="addForm" :model="formAdd" :rules="rulesAdd" :label-width="90">
|
||||
<FormItem label="分组名称" prop="groupName" style="width: 90%;">
|
||||
<Input v-model="formAdd.groupName" maxlength="30" placeholder="请输入分组名称" />
|
||||
</FormItem>
|
||||
<FormItem label="分组描述" prop="description" style="width: 90%;">
|
||||
<Input v-model="formAdd.description" maxlength="200" placeholder="请输入分组描述" />
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer">
|
||||
<Button @click="addFlag = false">取消</Button>
|
||||
<Button type="primary" :loading="submitAddLoading" @click="submitAdd">确定</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
<Modal v-model="editFlag" title="编辑分组">
|
||||
<Form ref="editForm" :model="formEdit" :rules="rulesEdit" :label-width="90">
|
||||
<Input v-model="formEdit.id" v-show="false" />
|
||||
<FormItem label="分组名称" prop="groupName" style="width: 90%;">
|
||||
<Input v-model="formEdit.groupName" maxlength="30" placeholder="请输入分组名称" />
|
||||
</FormItem>
|
||||
<FormItem label="分组描述" prop="description" style="width: 90%;">
|
||||
<Input v-model="formEdit.description" maxlength="200" placeholder="请输入分组描述" />
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer">
|
||||
<Button @click="editFlag = false">取消</Button>
|
||||
<Button type="primary" :loading="submitEditLoading" @click="submitEdit">确定</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as API_Member from "@/api/member.js";
|
||||
|
||||
export default {
|
||||
name: "memberGroup",
|
||||
data() {
|
||||
return {
|
||||
loading: true,
|
||||
searchForm: {
|
||||
pageNumber: 1,
|
||||
pageSize: 20,
|
||||
},
|
||||
columns: [
|
||||
{
|
||||
title: "分组名称",
|
||||
key: "groupName",
|
||||
minWidth: 160,
|
||||
tooltip: true,
|
||||
},
|
||||
{
|
||||
title: "分组描述",
|
||||
key: "description",
|
||||
minWidth: 240,
|
||||
tooltip: true,
|
||||
},
|
||||
{
|
||||
title: "创建时间",
|
||||
key: "createTime",
|
||||
width: 180,
|
||||
},
|
||||
{
|
||||
title: "更新时间",
|
||||
key: "updateTime",
|
||||
width: 180,
|
||||
},
|
||||
{
|
||||
title: "操作",
|
||||
key: "action",
|
||||
align: "center",
|
||||
width: 200,
|
||||
fixed: "right",
|
||||
render: (h, params) => {
|
||||
const linkStyle = {
|
||||
color: "#2d8cf0",
|
||||
cursor: "pointer",
|
||||
textDecoration: "none",
|
||||
};
|
||||
const sep = h(
|
||||
"span",
|
||||
{ style: { margin: "0 8px", color: "#dcdee2" } },
|
||||
"|"
|
||||
);
|
||||
const children = [
|
||||
h(
|
||||
"a",
|
||||
{ style: linkStyle, on: { click: () => this.openEdit(params.row) } },
|
||||
"编辑"
|
||||
),
|
||||
sep,
|
||||
h(
|
||||
"a",
|
||||
{ style: linkStyle, on: { click: () => this.remove(params.row) } },
|
||||
"删除"
|
||||
),
|
||||
];
|
||||
return h(
|
||||
"div",
|
||||
{ class: "ops", style: { display: "flex", justifyContent: "center" } },
|
||||
children
|
||||
);
|
||||
},
|
||||
},
|
||||
],
|
||||
data: [],
|
||||
total: 0,
|
||||
addFlag: false,
|
||||
editFlag: false,
|
||||
submitAddLoading: false,
|
||||
submitEditLoading: false,
|
||||
formAdd: {
|
||||
groupName: "",
|
||||
description: "",
|
||||
},
|
||||
formEdit: {
|
||||
id: "",
|
||||
groupName: "",
|
||||
description: "",
|
||||
},
|
||||
rulesAdd: {
|
||||
groupName: [{ required: true, message: "请输入分组名称" }],
|
||||
},
|
||||
rulesEdit: {
|
||||
groupName: [{ required: true, message: "请输入分组名称" }],
|
||||
},
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
this.getData();
|
||||
},
|
||||
changePage(v) {
|
||||
this.searchForm.pageNumber = v;
|
||||
this.getData();
|
||||
},
|
||||
changePageSize(v) {
|
||||
this.searchForm.pageNumber = 1;
|
||||
this.searchForm.pageSize = v;
|
||||
this.getData();
|
||||
},
|
||||
getData() {
|
||||
this.loading = true;
|
||||
API_Member.getMemberGroupByPage(this.searchForm).then((res) => {
|
||||
this.loading = false;
|
||||
if (res && res.success && res.result) {
|
||||
this.data = res.result.records || [];
|
||||
this.total = res.result.total || 0;
|
||||
}
|
||||
});
|
||||
},
|
||||
openAdd() {
|
||||
this.addFlag = true;
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.addForm) this.$refs.addForm.resetFields();
|
||||
this.formAdd = { groupName: "", description: "" };
|
||||
});
|
||||
},
|
||||
submitAdd() {
|
||||
this.$refs.addForm.validate((valid) => {
|
||||
if (!valid) return;
|
||||
this.submitAddLoading = true;
|
||||
API_Member.addMemberGroup(this.formAdd).then((res) => {
|
||||
this.submitAddLoading = false;
|
||||
if (res && res.success) {
|
||||
this.$Message.success("添加成功");
|
||||
this.addFlag = false;
|
||||
this.getData();
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
openEdit(row) {
|
||||
this.editFlag = true;
|
||||
this.submitEditLoading = false;
|
||||
API_Member.getMemberGroup(row.id).then((res) => {
|
||||
if (res && res.success && res.result) {
|
||||
this.formEdit = {
|
||||
id: res.result.id,
|
||||
groupName: res.result.groupName || "",
|
||||
description: res.result.description || "",
|
||||
};
|
||||
} else {
|
||||
this.formEdit = {
|
||||
id: row.id,
|
||||
groupName: row.groupName || "",
|
||||
description: row.description || "",
|
||||
};
|
||||
}
|
||||
});
|
||||
},
|
||||
submitEdit() {
|
||||
this.$refs.editForm.validate((valid) => {
|
||||
if (!valid) return;
|
||||
this.submitEditLoading = true;
|
||||
const { id, groupName, description } = this.formEdit;
|
||||
API_Member.updateMemberGroup(id, { groupName, description }).then((res) => {
|
||||
this.submitEditLoading = false;
|
||||
if (res && res.success) {
|
||||
this.$Message.success("修改成功");
|
||||
this.editFlag = false;
|
||||
this.getData();
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
remove(row) {
|
||||
this.$Modal.confirm({
|
||||
title: "提示",
|
||||
content: "<p>确定删除该分组?</p>",
|
||||
onOk: () => {
|
||||
API_Member.deleteMemberGroup(row.id).then((res) => {
|
||||
if (res && res.success) {
|
||||
this.$Message.success("删除成功");
|
||||
this.getData();
|
||||
} else if (res && res.message) {
|
||||
this.$Message.error(res.message);
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.init();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -3,28 +3,57 @@
|
||||
<Card>
|
||||
<Row @keydown.enter.native="handleSearch">
|
||||
<Form ref="searchForm" :model="searchForm" inline :label-width="70" class="search-form">
|
||||
<Form-item label="会员ID" prop="id">
|
||||
<Input type="text" v-model="searchForm.id" placeholder="请输入会员ID" clearable style="width: 240px" />
|
||||
</Form-item>
|
||||
|
||||
<Form-item label="会员名称" prop="username">
|
||||
<Input type="text" v-model="searchForm.username" placeholder="请输入会员名称" clearable style="width: 200px" />
|
||||
<Input type="text" v-model="searchForm.username" placeholder="请输入会员名称" clearable style="width: 240px" />
|
||||
</Form-item>
|
||||
|
||||
<Form-item label="会员昵称" prop="nickName">
|
||||
<Input type="text" v-model="searchForm.nickName" placeholder="请输入会员昵称" clearable style="width: 200px" />
|
||||
<Input type="text" v-model="searchForm.nickName" placeholder="请输入会员昵称" clearable style="width: 240px" />
|
||||
</Form-item>
|
||||
|
||||
<Form-item label="联系方式" prop="mobile">
|
||||
<Input type="text" v-model="searchForm.mobile" placeholder="请输入会员联系方式" clearable style="width: 200px" />
|
||||
<Input type="text" v-model="searchForm.mobile" placeholder="请输入会员联系方式" clearable style="width: 240px" />
|
||||
</Form-item>
|
||||
<Form-item label="会员分组" prop="groupId">
|
||||
<Select v-model="searchForm.groupId" clearable filterable style="width: 240px">
|
||||
<Option v-for="item in memberGroupList" :value="item.id" :key="item.id">{{ item.groupName }}</Option>
|
||||
</Select>
|
||||
</Form-item>
|
||||
<Form-item label="会员等级" prop="gradeId">
|
||||
<Select v-model="searchForm.gradeId" clearable filterable style="width: 240px">
|
||||
<Option v-for="item in memberGradeList" :value="item.id" :key="item.id">{{ item.gradeName }}</Option>
|
||||
</Select>
|
||||
</Form-item>
|
||||
<Button @click="handleSearch" class="search-btn" type="primary" icon="ios-search">搜索</Button>
|
||||
</Form>
|
||||
</Row>
|
||||
</Card>
|
||||
<Card>
|
||||
<Row class="operation padding-row" v-if="!selectedMember">
|
||||
<Button @click="addMember" type="primary">添加会员</Button>
|
||||
<Button
|
||||
style="margin-left: 10px;"
|
||||
type="primary"
|
||||
:disabled="selectedRows.length === 0"
|
||||
@click="openSetMemberGroup"
|
||||
>设定会员分组</Button>
|
||||
</Row>
|
||||
|
||||
<Table :loading="loading" border :columns="columns" class="mt_10" :data="data" ref="table"></Table>
|
||||
<Table
|
||||
:loading="loading"
|
||||
:columns="tableColumns"
|
||||
class="mt_10"
|
||||
:data="data"
|
||||
ref="table"
|
||||
@on-selection-change="onSelectionChange"
|
||||
></Table>
|
||||
<Row type="flex" justify="end" class="mt_10">
|
||||
<Page :current="searchForm.pageNumber" :total="total" :page-size="searchForm.pageSize" @on-change="changePage"
|
||||
@on-page-size-change="changePageSize" :page-size-opts="[10, 20, 50]" size="small" show-total show-elevator
|
||||
@on-page-size-change="changePageSize" :page-size-opts="[20, 50, 100]" size="small" show-total show-elevator
|
||||
show-sizer></Page>
|
||||
</Row>
|
||||
</Card>
|
||||
@@ -93,6 +122,47 @@
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Modal>
|
||||
<Modal v-model="walletIncreaseFlag" title="增加余额" width="420">
|
||||
<Form ref="walletIncreaseForm" :model="walletIncreaseForm" :rules="walletIncreaseRule" :label-width="90">
|
||||
<FormItem label="充值金额" prop="rechargeMoney">
|
||||
<InputNumber v-model="walletIncreaseForm.rechargeMoney" :min="0.01" :precision="2" style="width: 240px" />
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer">
|
||||
<Button @click="walletIncreaseFlag = false">取消</Button>
|
||||
<Button type="primary" :loading="walletIncreaseLoading" @click="submitWalletIncrease">确定</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
<Modal v-model="memberPointFlag" title="修改积分" width="420">
|
||||
<Form ref="memberPointForm" :model="memberPointForm" :rules="memberPointRule" :label-width="90">
|
||||
<FormItem label="类型" prop="type">
|
||||
<RadioGroup type="button" button-style="solid" v-model="memberPointForm.type">
|
||||
<Radio label="INCREASE">增加</Radio>
|
||||
<Radio label="REDUCE">减少</Radio>
|
||||
</RadioGroup>
|
||||
</FormItem>
|
||||
<FormItem label="积分" prop="point">
|
||||
<InputNumber v-model="memberPointForm.point" :min="1" :precision="0" style="width: 240px" />
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer">
|
||||
<Button @click="memberPointFlag = false">取消</Button>
|
||||
<Button type="primary" :loading="memberPointLoading" @click="submitMemberPoint">确定</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
<Modal v-model="memberGroupFlag" title="设定会员分组" width="420">
|
||||
<Form ref="memberGroupForm" :model="memberGroupForm" :rules="memberGroupRule" :label-width="90">
|
||||
<FormItem label="会员分组" prop="groupId">
|
||||
<Select v-model="memberGroupForm.groupId" clearable filterable style="width: 240px">
|
||||
<Option v-for="item in memberGroupList" :value="item.id" :key="item.id">{{ item.groupName }}</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer">
|
||||
<Button @click="memberGroupFlag = false">取消</Button>
|
||||
<Button type="primary" :loading="memberGroupLoading" @click="submitSetMemberGroup">确定</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
<Modal width="1200px" v-model="picModelFlag">
|
||||
<ossManage @callback="callbackSelected" :isComponent="true" :initialize="picModelFlag" ref="ossManage" />
|
||||
</Modal>
|
||||
@@ -112,6 +182,19 @@ export default {
|
||||
multipleMap,
|
||||
ossManage,
|
||||
},
|
||||
computed: {
|
||||
tableColumns() {
|
||||
if (this.selectedMember) return this.columns;
|
||||
return [
|
||||
{
|
||||
type: "selection",
|
||||
width: 60,
|
||||
align: "center",
|
||||
},
|
||||
...this.columns,
|
||||
];
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
defaultPic:require('@/assets/default.png'),
|
||||
@@ -129,14 +212,71 @@ export default {
|
||||
searchForm: {
|
||||
// 请求参数
|
||||
pageNumber: 1,
|
||||
pageSize: 10,
|
||||
pageSize: 20, // 页面大小
|
||||
order: "desc",
|
||||
id: "",
|
||||
username: "",
|
||||
mobile: "",
|
||||
disabled: "OPEN",
|
||||
groupId: "",
|
||||
},
|
||||
picModelFlag: false, // 选择图片
|
||||
form: {}, // 表单数据
|
||||
walletIncreaseFlag: false,
|
||||
walletIncreaseLoading: false,
|
||||
walletIncreaseForm: {
|
||||
memberId: "",
|
||||
rechargeMoney: null,
|
||||
},
|
||||
walletIncreaseRule: {
|
||||
rechargeMoney: [
|
||||
{ required: true, type: "number", message: "请输入充值金额", trigger: "change" },
|
||||
{
|
||||
validator: (rule, value, callback) => {
|
||||
if (typeof value !== "number" || value <= 0) {
|
||||
callback(new Error("充值金额必须大于0"));
|
||||
return;
|
||||
}
|
||||
callback();
|
||||
},
|
||||
trigger: "change",
|
||||
},
|
||||
],
|
||||
},
|
||||
memberPointFlag: false,
|
||||
memberPointLoading: false,
|
||||
memberPointForm: {
|
||||
memberId: "",
|
||||
point: null,
|
||||
type: "INCREASE",
|
||||
},
|
||||
selectedRows: [],
|
||||
memberGroupFlag: false,
|
||||
memberGroupLoading: false,
|
||||
memberGroupForm: {
|
||||
groupId: "",
|
||||
},
|
||||
memberGroupRule: {
|
||||
groupId: [{ required: true, message: "请选择会员分组", trigger: "change" }],
|
||||
},
|
||||
memberGroupList: [],
|
||||
memberGradeList: [],
|
||||
memberPointRule: {
|
||||
type: [{ required: true, message: "请选择类型", trigger: "change" }],
|
||||
point: [
|
||||
{ required: true, type: "number", message: "请输入积分", trigger: "change" },
|
||||
{
|
||||
validator: (rule, value, callback) => {
|
||||
if (typeof value !== "number" || value <= 0) {
|
||||
callback(new Error("积分必须大于0"));
|
||||
return;
|
||||
}
|
||||
callback();
|
||||
},
|
||||
trigger: "change",
|
||||
},
|
||||
],
|
||||
},
|
||||
addRule: {
|
||||
// 验证规则
|
||||
mobile: [
|
||||
@@ -151,19 +291,47 @@ export default {
|
||||
},
|
||||
ruleValidate: {}, //修改验证
|
||||
columns: [
|
||||
{
|
||||
title: "会员ID",
|
||||
key: "id",
|
||||
minWidth: 120, // 减少宽度
|
||||
tooltip: true,
|
||||
},
|
||||
{
|
||||
title: "头像",
|
||||
key: "face",
|
||||
minWidth: 80,
|
||||
align: "center",
|
||||
render: (h, params) => {
|
||||
return h("img", {
|
||||
attrs: {
|
||||
src: params.row.face || require('@/assets/default.png'),
|
||||
alt: "头像"
|
||||
},
|
||||
style: {
|
||||
width: "30px",
|
||||
height: "30px",
|
||||
borderRadius: "50%",
|
||||
objectFit: "cover"
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "会员名称",
|
||||
key: "username",
|
||||
tooltip: true,
|
||||
minWidth: 150, // 减少宽度
|
||||
},
|
||||
{
|
||||
title: "会员昵称",
|
||||
key: "nickName",
|
||||
tooltip: true,
|
||||
minWidth: 120, // 减少宽度
|
||||
},
|
||||
{
|
||||
title: "联系方式",
|
||||
width: 130,
|
||||
minWidth: 130,
|
||||
key: "mobile",
|
||||
render: (h, params) => {
|
||||
if (params.row.mobile == null) {
|
||||
@@ -176,13 +344,18 @@ export default {
|
||||
{
|
||||
title: "注册时间",
|
||||
key: "createTime",
|
||||
width: 180,
|
||||
minWidth: 160, // 减少宽度
|
||||
},
|
||||
{
|
||||
title: "最后登录时间",
|
||||
key: "lastLoginDate",
|
||||
minWidth: 160, // 减少宽度
|
||||
},
|
||||
|
||||
{
|
||||
title: "积分数量",
|
||||
align: "left",
|
||||
width: 100,
|
||||
minWidth: 120, // 增加宽度
|
||||
render: (h, params) => {
|
||||
return h(
|
||||
"div",
|
||||
@@ -191,13 +364,191 @@ export default {
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "经验值",
|
||||
key: "experience",
|
||||
minWidth: 100,
|
||||
render: (h, params) => {
|
||||
return h("div", {}, params.row.experience == null ? "0" : params.row.experience);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "会员等级",
|
||||
key: "gradeName",
|
||||
minWidth: 120,
|
||||
tooltip: true,
|
||||
render: (h, params) => {
|
||||
return h("div", {}, params.row.gradeName || "-");
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "余额",
|
||||
key: "memberWallet",
|
||||
width: 120,
|
||||
render: (h, params) => {
|
||||
return h("priceColorScheme", {props:{value:params.row.memberWallet}} );
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "操作",
|
||||
key: "action",
|
||||
align: "center",
|
||||
width: 200,
|
||||
minWidth: 160,
|
||||
fixed: "right",
|
||||
render: (h, params) => {
|
||||
if (this.selectedMember) {
|
||||
return h(
|
||||
"div",
|
||||
{
|
||||
style: {
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
},
|
||||
},
|
||||
[
|
||||
h(
|
||||
"a",
|
||||
{
|
||||
style: {
|
||||
color: "#2d8cf0",
|
||||
cursor: "pointer",
|
||||
textDecoration: "none",
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
this.callback(params.row, params.index);
|
||||
},
|
||||
},
|
||||
},
|
||||
params.row.___selected ? "已选择" : "选择"
|
||||
),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
const divider = h(
|
||||
"span",
|
||||
{
|
||||
style: {
|
||||
margin: "0 8px",
|
||||
color: "#dcdee2",
|
||||
},
|
||||
},
|
||||
"|"
|
||||
);
|
||||
|
||||
const viewLink = h(
|
||||
"a",
|
||||
{
|
||||
style: {
|
||||
color: "#2d8cf0",
|
||||
cursor: "pointer",
|
||||
textDecoration: "none",
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
this.detail(params.row);
|
||||
},
|
||||
},
|
||||
},
|
||||
"查看"
|
||||
);
|
||||
|
||||
const moreDropdown = h(
|
||||
"Dropdown",
|
||||
{
|
||||
props: {
|
||||
trigger: "click",
|
||||
transfer: true,
|
||||
},
|
||||
on: {
|
||||
"on-click": (name) => {
|
||||
if (name === "edit") {
|
||||
this.editPerm(params.row);
|
||||
}
|
||||
if (name === "disabled") {
|
||||
this.disabled(params.row);
|
||||
}
|
||||
if (name === "increaseWallet") {
|
||||
this.openWalletIncrease(params.row);
|
||||
}
|
||||
if (name === "updatePoint") {
|
||||
this.openMemberPoint(params.row);
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
[
|
||||
h(
|
||||
"a",
|
||||
{
|
||||
style: {
|
||||
color: "#2d8cf0",
|
||||
cursor: "pointer",
|
||||
textDecoration: "none",
|
||||
display: "inline-flex",
|
||||
alignItems: "center",
|
||||
},
|
||||
},
|
||||
[
|
||||
h("span", "更多"),
|
||||
h("Icon", {
|
||||
props: {
|
||||
type: "md-arrow-dropdown",
|
||||
},
|
||||
style: {
|
||||
marginLeft: "4px",
|
||||
},
|
||||
}),
|
||||
]
|
||||
),
|
||||
h(
|
||||
"DropdownMenu",
|
||||
{
|
||||
slot: "list",
|
||||
},
|
||||
[
|
||||
h(
|
||||
"DropdownItem",
|
||||
{
|
||||
props: {
|
||||
name: "edit",
|
||||
},
|
||||
},
|
||||
"编辑会员"
|
||||
),
|
||||
h(
|
||||
"DropdownItem",
|
||||
{
|
||||
props: {
|
||||
name: "increaseWallet",
|
||||
},
|
||||
},
|
||||
"增加余额"
|
||||
),
|
||||
h(
|
||||
"DropdownItem",
|
||||
{
|
||||
props: {
|
||||
name: "updatePoint",
|
||||
},
|
||||
},
|
||||
"修改积分"
|
||||
),
|
||||
h(
|
||||
"DropdownItem",
|
||||
{
|
||||
props: {
|
||||
name: "disabled",
|
||||
},
|
||||
},
|
||||
"禁用会员"
|
||||
),
|
||||
]
|
||||
),
|
||||
]
|
||||
);
|
||||
|
||||
return h(
|
||||
"div",
|
||||
{
|
||||
@@ -206,86 +557,7 @@ export default {
|
||||
justifyContent: "center",
|
||||
},
|
||||
},
|
||||
[
|
||||
h(
|
||||
"Button",
|
||||
{
|
||||
props: {
|
||||
size: "small",
|
||||
type: params.row.___selected ? "primary" : "default",
|
||||
},
|
||||
style: {
|
||||
marginRight: "5px",
|
||||
display: this.selectedMember ? "block" : "none",
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
this.callback(params.row, params.index);
|
||||
},
|
||||
},
|
||||
},
|
||||
params.row.___selected ? "已选择" : "选择"
|
||||
),
|
||||
|
||||
h(
|
||||
"Button",
|
||||
{
|
||||
props: {
|
||||
type: "info",
|
||||
size: "small",
|
||||
},
|
||||
style: {
|
||||
marginRight: "5px",
|
||||
display: this.selectedMember ? "none" : "block",
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
this.detail(params.row);
|
||||
},
|
||||
},
|
||||
},
|
||||
"查看"
|
||||
),
|
||||
h(
|
||||
"Button",
|
||||
{
|
||||
props: {
|
||||
type: "info",
|
||||
size: "small",
|
||||
ghost: true,
|
||||
},
|
||||
style: {
|
||||
marginRight: "5px",
|
||||
display: this.selectedMember ? "none" : "block",
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
this.editPerm(params.row);
|
||||
},
|
||||
},
|
||||
},
|
||||
"编辑"
|
||||
),
|
||||
h(
|
||||
"Button",
|
||||
{
|
||||
props: {
|
||||
size: "small",
|
||||
type: "error",
|
||||
},
|
||||
style: {
|
||||
marginRight: "5px",
|
||||
display: this.selectedMember ? "none" : "block",
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
this.disabled(params.row);
|
||||
},
|
||||
},
|
||||
},
|
||||
"禁用"
|
||||
),
|
||||
]
|
||||
[viewLink, divider, moreDropdown]
|
||||
);
|
||||
},
|
||||
},
|
||||
@@ -321,6 +593,59 @@ export default {
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
onSelectionChange(selection) {
|
||||
this.selectedRows = selection || [];
|
||||
},
|
||||
openSetMemberGroup() {
|
||||
this.memberGroupFlag = true;
|
||||
this.memberGroupLoading = false;
|
||||
this.memberGroupForm = { groupId: "" };
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.memberGroupForm) this.$refs.memberGroupForm.resetFields();
|
||||
});
|
||||
this.loadMemberGroupList();
|
||||
},
|
||||
loadMemberGroupList() {
|
||||
API_Member.getMemberGroupByPage({ pageNumber: 1, pageSize: 1000 }).then((res) => {
|
||||
if (res && res.success && res.result) {
|
||||
this.memberGroupList = res.result.records || [];
|
||||
}
|
||||
});
|
||||
},
|
||||
loadMemberGradeList() {
|
||||
API_Member.getMemberGradeByPage({ pageNumber: 1, pageSize: 1000 }).then((res) => {
|
||||
if (res && res.success && res.result) {
|
||||
this.memberGradeList = res.result || [];
|
||||
}
|
||||
});
|
||||
},
|
||||
clearSelection() {
|
||||
if (this.$refs.table && this.$refs.table.clearSelection) {
|
||||
this.$refs.table.clearSelection();
|
||||
}
|
||||
},
|
||||
submitSetMemberGroup() {
|
||||
if (this.selectedRows.length === 0) {
|
||||
this.$Message.warning("请先选择会员");
|
||||
return;
|
||||
}
|
||||
this.$refs.memberGroupForm.validate((valid) => {
|
||||
if (!valid) return;
|
||||
const memberIds = this.selectedRows.map((item) => item.id);
|
||||
this.memberGroupLoading = true;
|
||||
API_Member.addMemberGroupUsers(this.memberGroupForm.groupId, memberIds).then((res) => {
|
||||
this.memberGroupLoading = false;
|
||||
if (res && res.success) {
|
||||
this.$Message.success("设置成功");
|
||||
this.memberGroupFlag = false;
|
||||
this.selectedRows = [];
|
||||
this.clearSelection();
|
||||
} else if (res && res.message) {
|
||||
this.$Message.error(res.message);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
// 回调给父级
|
||||
callback(val, index) {
|
||||
this.selectMember.forEach(item=>{item.___selected = false})
|
||||
@@ -373,7 +698,7 @@ export default {
|
||||
// 搜索
|
||||
handleSearch() {
|
||||
this.searchForm.pageNumber = 1;
|
||||
this.searchForm.pageSize = 10;
|
||||
this.searchForm.pageSize = 20;
|
||||
this.getData();
|
||||
},
|
||||
//查看详情修改
|
||||
@@ -400,6 +725,11 @@ export default {
|
||||
|
||||
//查询会员列表
|
||||
getData() {
|
||||
this.loading = true;
|
||||
if (!this.selectedMember) {
|
||||
this.selectedRows = [];
|
||||
this.clearSelection();
|
||||
}
|
||||
API_Member.getMemberListData(this.searchForm).then((res) => {
|
||||
if (res.result.records) {
|
||||
this.loading = false;
|
||||
@@ -472,6 +802,69 @@ export default {
|
||||
});
|
||||
},
|
||||
|
||||
openWalletIncrease(row) {
|
||||
this.walletIncreaseLoading = false;
|
||||
this.$set(this, "walletIncreaseForm", { memberId: row.id, rechargeMoney: null });
|
||||
this.walletIncreaseFlag = true;
|
||||
this.$nextTick(() => {
|
||||
this.$refs.walletIncreaseForm && this.$refs.walletIncreaseForm.resetFields();
|
||||
});
|
||||
},
|
||||
submitWalletIncrease() {
|
||||
this.$refs.walletIncreaseForm.validate((valid) => {
|
||||
if (!valid) return;
|
||||
this.walletIncreaseLoading = true;
|
||||
API_Member.increaseMemberWallet({
|
||||
memberId: this.walletIncreaseForm.memberId,
|
||||
rechargeMoney: this.walletIncreaseForm.rechargeMoney,
|
||||
})
|
||||
.then((res) => {
|
||||
if (res && res.success) {
|
||||
this.$Message.success("充值成功");
|
||||
this.walletIncreaseFlag = false;
|
||||
this.getData();
|
||||
} else {
|
||||
this.$Message.error((res && res.message) || "充值失败");
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.walletIncreaseLoading = false;
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
openMemberPoint(row) {
|
||||
this.memberPointLoading = false;
|
||||
this.$set(this, "memberPointForm", { memberId: row.id, point: null, type: "INCREASE" });
|
||||
this.memberPointFlag = true;
|
||||
this.$nextTick(() => {
|
||||
this.$refs.memberPointForm && this.$refs.memberPointForm.resetFields();
|
||||
});
|
||||
},
|
||||
submitMemberPoint() {
|
||||
this.$refs.memberPointForm.validate((valid) => {
|
||||
if (!valid) return;
|
||||
this.memberPointLoading = true;
|
||||
API_Member.updateMemberPoint({
|
||||
memberId: this.memberPointForm.memberId,
|
||||
point: this.memberPointForm.point,
|
||||
type: this.memberPointForm.type,
|
||||
})
|
||||
.then((res) => {
|
||||
if (res && res.success) {
|
||||
this.$Message.success("修改成功");
|
||||
this.memberPointFlag = false;
|
||||
this.getData();
|
||||
} else {
|
||||
this.$Message.error((res && res.message) || "修改失败");
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.memberPointLoading = false;
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
// 提交修改数据
|
||||
handleSubmitModal() {
|
||||
const { nickName, sex, username, face, newPassword,id,regionId,region } = this.form;
|
||||
@@ -482,7 +875,7 @@ export default {
|
||||
regionId,
|
||||
region,
|
||||
nickName,
|
||||
username,
|
||||
|
||||
sex,
|
||||
birthday,
|
||||
face,
|
||||
@@ -502,14 +895,18 @@ export default {
|
||||
},
|
||||
mounted() {
|
||||
this.getData();
|
||||
if (!this.selectedMember) {
|
||||
this.loadMemberGroupList();
|
||||
this.loadMemberGradeList();
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
/deep/ .ivu-table-wrapper {
|
||||
::v-deep .ivu-table-wrapper {
|
||||
width: 100%;
|
||||
}
|
||||
/deep/ .ivu-card {
|
||||
::v-deep .ivu-card {
|
||||
width: 100%;
|
||||
}
|
||||
.face {
|
||||
@@ -517,4 +914,5 @@ export default {
|
||||
height: 60px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@@ -93,14 +93,14 @@
|
||||
:current="pointSearchForm.pageNumber"
|
||||
:total="pointTotal"
|
||||
:page-size="pointSearchForm.pageSize"
|
||||
@on-change="pointChangePage"
|
||||
@on-page-size-change="pointChangePageSize"
|
||||
:page-size-opts="[10, 20, 50]"
|
||||
size="small"
|
||||
show-total
|
||||
show-elevator
|
||||
show-sizer
|
||||
></Page>
|
||||
@on-change="pointChangePage"
|
||||
@on-page-size-change="pointChangePageSize"
|
||||
:page-size-opts="[20, 50, 100]"
|
||||
size="small"
|
||||
show-total
|
||||
show-elevator
|
||||
show-sizer
|
||||
></Page>
|
||||
</Row>
|
||||
</div>
|
||||
</TabPane>
|
||||
@@ -180,14 +180,14 @@
|
||||
:current="orderSearchForm.pageNumber"
|
||||
:total="orderTotal"
|
||||
:page-size="orderSearchForm.pageSize"
|
||||
@on-change="orderChangePage"
|
||||
@on-page-size-change="orderChangePageSize"
|
||||
:page-size-opts="[10, 20, 50]"
|
||||
size="small"
|
||||
show-total
|
||||
show-elevator
|
||||
show-sizer
|
||||
></Page>
|
||||
@on-change="orderChangePage"
|
||||
@on-page-size-change="orderChangePageSize"
|
||||
:page-size-opts="[20, 50, 100]"
|
||||
size="small"
|
||||
show-total
|
||||
show-elevator
|
||||
show-sizer
|
||||
></Page>
|
||||
</Row>
|
||||
</div>
|
||||
</TabPane>
|
||||
@@ -210,7 +210,7 @@
|
||||
:page-size="addressSearchForm.pageSize"
|
||||
@on-change="addressChangePage"
|
||||
@on-page-size-change="addressChangePageSize"
|
||||
:page-size-opts="[10, 20, 50]"
|
||||
:page-size-opts="[20, 50, 100]"
|
||||
size="small"
|
||||
show-total
|
||||
show-elevator
|
||||
@@ -259,7 +259,7 @@
|
||||
:page-size="walletSearchForm.pageSize"
|
||||
@on-change="walletChangePage"
|
||||
@on-page-size-change="walletChangePageSize"
|
||||
:page-size-opts="[10, 20, 50]"
|
||||
:page-size-opts="[20, 50, 100]"
|
||||
size="small"
|
||||
show-total
|
||||
show-elevator
|
||||
@@ -304,7 +304,7 @@
|
||||
:page-size="receiptRecordSearchForm.pageSize"
|
||||
@on-change="walletChangePage"
|
||||
@on-page-size-change="walletChangePageSize"
|
||||
:page-size-opts="[10, 20, 50]"
|
||||
:page-size-opts="[20, 50, 100]"
|
||||
size="small"
|
||||
show-total
|
||||
show-elevator
|
||||
@@ -438,7 +438,7 @@
|
||||
//历史积分数据查询form
|
||||
pointSearchForm: {
|
||||
pageNumber: 1, // 当前页数
|
||||
pageSize: 10, // 页面大小
|
||||
pageSize: 20, // 页面大小
|
||||
},
|
||||
orderColumns: [
|
||||
{
|
||||
@@ -584,13 +584,12 @@
|
||||
}
|
||||
}, [
|
||||
h(
|
||||
"Button",
|
||||
"a",
|
||||
{
|
||||
props: {
|
||||
type: "info",
|
||||
size: "small",
|
||||
},
|
||||
style: {
|
||||
color: "#2d8cf0",
|
||||
cursor: "pointer",
|
||||
textDecoration: "none",
|
||||
marginRight: "5px",
|
||||
},
|
||||
on: {
|
||||
@@ -611,7 +610,7 @@
|
||||
//TA的订单form
|
||||
orderSearchForm: {
|
||||
pageNumber: 1, // 当前页数
|
||||
pageSize: 10, // 页面大小
|
||||
pageSize: 20, // 页面大小
|
||||
payStatus: "",
|
||||
orderSn: "",
|
||||
orderType: "",
|
||||
@@ -672,7 +671,7 @@
|
||||
//TA的收货地址form
|
||||
addressSearchForm: {
|
||||
pageNumber: 1, // 当前页数
|
||||
pageSize: 10, // 页面大小
|
||||
pageSize: 20, // 页面大小
|
||||
},
|
||||
//消费记录
|
||||
walletColumns: [
|
||||
@@ -726,7 +725,7 @@
|
||||
//TA的余额消费记录
|
||||
walletSearchForm: {
|
||||
pageNumber: 1, // 当前页数
|
||||
pageSize: 10, // 页面大小
|
||||
pageSize: 20, // 页面大小
|
||||
sort: "createTime", // 默认排序字段
|
||||
order: "desc", // 默认排序方式
|
||||
},
|
||||
@@ -735,7 +734,7 @@
|
||||
//TA的发票记录
|
||||
receiptRecordSearchForm: {
|
||||
pageNumber: 1, // 当前页数
|
||||
pageSize: 10, // 页面大小
|
||||
pageSize: 20, // 页面大小
|
||||
sort: "createTime", // 默认排序字段
|
||||
order: "desc", // 默认排序方式
|
||||
},
|
||||
@@ -854,6 +853,8 @@
|
||||
//查询TA的发票记录
|
||||
getReceiptRecordData(){
|
||||
this.loading = true;
|
||||
this.receiptRecordSearchForm.pageNumber = 1;
|
||||
this.receiptRecordSearchForm.pageSize = 20;
|
||||
this.receiptRecordSearchForm.memberId = this.id
|
||||
API_Order.getReceiptPage(this.receiptRecordSearchForm).then((res) => {
|
||||
this.loading = false;
|
||||
@@ -868,6 +869,8 @@
|
||||
//查询TA的订单
|
||||
getOrderData() {
|
||||
this.loading = true;
|
||||
this.orderSearchForm.pageNumber = 1;
|
||||
this.orderSearchForm.pageSize = 20;
|
||||
this.orderSearchForm.memberId = this.id
|
||||
API_Order.getOrderList(this.orderSearchForm).then((res) => {
|
||||
this.loading = false;
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
v-model="searchForm.username"
|
||||
placeholder="请输入会员名称"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
style="width: 240px"
|
||||
/>
|
||||
</Form-item>
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
v-model="searchForm.mobile"
|
||||
placeholder="请输入会员联系方式"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
style="width: 240px"
|
||||
/>
|
||||
</Form-item>
|
||||
<Button
|
||||
@@ -38,6 +38,8 @@
|
||||
>
|
||||
</Form>
|
||||
</Row>
|
||||
</Card>
|
||||
<Card>
|
||||
<Table
|
||||
:loading="loading"
|
||||
border
|
||||
@@ -55,7 +57,7 @@
|
||||
:page-size="searchForm.pageSize"
|
||||
@on-change="changePage"
|
||||
@on-page-size-change="changePageSize"
|
||||
:page-size-opts="[10, 20, 50]"
|
||||
:page-size-opts="[20, 50, 100]"
|
||||
size="small"
|
||||
show-total
|
||||
show-elevator
|
||||
@@ -169,7 +171,7 @@ export default {
|
||||
searchForm: {
|
||||
// 请求参数
|
||||
pageNumber: 1,
|
||||
pageSize: 10,
|
||||
pageSize: 20,
|
||||
order: "desc",
|
||||
username: "",
|
||||
mobile: "",
|
||||
@@ -228,92 +230,56 @@ export default {
|
||||
width: 200,
|
||||
fixed: "right",
|
||||
render: (h, params) => {
|
||||
const linkStyle = {
|
||||
color: "#2d8cf0",
|
||||
cursor: "pointer",
|
||||
textDecoration: "none",
|
||||
};
|
||||
const sep = h(
|
||||
"span",
|
||||
{ style: { margin: "0 8px", color: "#dcdee2" } },
|
||||
"|"
|
||||
);
|
||||
const children = [];
|
||||
if (this.selectedMember) {
|
||||
children.push(
|
||||
h(
|
||||
"a",
|
||||
{ style: linkStyle, on: { click: () => this.callback(params.row) } },
|
||||
"选择"
|
||||
)
|
||||
);
|
||||
children.push(sep);
|
||||
}
|
||||
children.push(
|
||||
h(
|
||||
"a",
|
||||
{ style: linkStyle, on: { click: () => this.detail(params.row) } },
|
||||
"查看"
|
||||
)
|
||||
);
|
||||
if (!this.selectedMember) {
|
||||
children.push(sep);
|
||||
children.push(
|
||||
h(
|
||||
"a",
|
||||
{ style: linkStyle, on: { click: () => this.enable(params.row) } },
|
||||
"启用"
|
||||
)
|
||||
);
|
||||
children.push(sep);
|
||||
children.push(
|
||||
h(
|
||||
"a",
|
||||
{ style: linkStyle, on: { click: () => this.editPerm(params.row) } },
|
||||
"编辑"
|
||||
)
|
||||
);
|
||||
}
|
||||
return h(
|
||||
"div",
|
||||
{
|
||||
style: {
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
},
|
||||
},
|
||||
[
|
||||
h(
|
||||
"Button",
|
||||
{
|
||||
props: {
|
||||
size: "small",
|
||||
},
|
||||
style: {
|
||||
marginRight: "5px",
|
||||
display: this.selectedMember ? "block" : "none",
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
this.callback(params.row);
|
||||
},
|
||||
},
|
||||
},
|
||||
"选择"
|
||||
),
|
||||
h(
|
||||
"Button",
|
||||
{
|
||||
props: {
|
||||
type: "info",
|
||||
size: "small",
|
||||
},
|
||||
style: {
|
||||
marginRight: "5px",
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
this.detail(params.row);
|
||||
},
|
||||
},
|
||||
},
|
||||
"查看"
|
||||
),
|
||||
|
||||
h(
|
||||
"Button",
|
||||
{
|
||||
props: {
|
||||
size: "small",
|
||||
type: "success",
|
||||
},
|
||||
style: {
|
||||
marginRight: "5px",
|
||||
display: this.selectedMember ? "none" : "block",
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
this.enable(params.row);
|
||||
},
|
||||
},
|
||||
},
|
||||
"启用"
|
||||
),
|
||||
|
||||
h(
|
||||
"Button",
|
||||
{
|
||||
props: {
|
||||
type: "info",
|
||||
size: "small",
|
||||
ghost: true,
|
||||
},
|
||||
style: {
|
||||
marginRight: "5px",
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
this.editPerm(params.row);
|
||||
},
|
||||
},
|
||||
},
|
||||
"编辑"
|
||||
),
|
||||
]
|
||||
{ class: "ops", style: { display: "flex", justifyContent: "center" } },
|
||||
children
|
||||
);
|
||||
},
|
||||
},
|
||||
@@ -345,7 +311,7 @@ export default {
|
||||
// 搜索
|
||||
handleSearch() {
|
||||
this.searchForm.pageNumber = 1;
|
||||
this.searchForm.pageSize = 10;
|
||||
this.searchForm.pageSize = 20;
|
||||
this.getData();
|
||||
},
|
||||
//查看详情修改
|
||||
@@ -435,7 +401,7 @@ export default {
|
||||
regionId:regionId,
|
||||
region: region,
|
||||
nickName,
|
||||
username,
|
||||
|
||||
sex,
|
||||
birthday,
|
||||
face: face || "",
|
||||
@@ -463,4 +429,14 @@ export default {
|
||||
height: 60px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
.ops a {
|
||||
color: #2d8cf0;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
}
|
||||
.ops span {
|
||||
display: inline-block;
|
||||
margin: 0 8px;
|
||||
color: #dcdee2;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
:page-size="weChatSearchForm.pageSize"
|
||||
@on-change="changePage"
|
||||
@on-page-size-change="changePageSize"
|
||||
:page-size-opts="[10,20,50]"
|
||||
:page-size-opts="[20, 50, 100]"
|
||||
size="small"
|
||||
></Page>
|
||||
</Row>
|
||||
@@ -82,7 +82,7 @@
|
||||
:page-size="weChatMPSearchForm.pageSize"
|
||||
@on-change="changePage"
|
||||
@on-page-size-change="changePageSize"
|
||||
:page-size-opts="[10,20,50]"
|
||||
:page-size-opts="[20, 50, 100]"
|
||||
size="small"
|
||||
></Page>
|
||||
</Row>
|
||||
@@ -126,12 +126,12 @@ export default {
|
||||
weChatSearchForm: {
|
||||
// 搜索框对应data对象
|
||||
pageNumber: 1, // 当前页数
|
||||
pageSize: 10, // 页面大小
|
||||
pageSize: 20, // 页面大小
|
||||
},
|
||||
weChatMPSearchForm: {
|
||||
// 搜索框对应data对象
|
||||
pageNumber: 1, // 当前页数
|
||||
pageSize: 10, // 页面大小
|
||||
pageSize: 20, // 页面大小
|
||||
},
|
||||
weChatColumns: [
|
||||
{
|
||||
@@ -178,14 +178,12 @@ export default {
|
||||
render: (h, params) => {
|
||||
return h("div", [
|
||||
h(
|
||||
"Button",
|
||||
"a",
|
||||
{
|
||||
props: {
|
||||
type: "primary",
|
||||
size: "small"
|
||||
},
|
||||
style: {
|
||||
marginRight: "5px"
|
||||
color: "#2d8cf0",
|
||||
cursor: "pointer",
|
||||
textDecoration: "none"
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
@@ -196,14 +194,17 @@ export default {
|
||||
"编辑"
|
||||
),
|
||||
h(
|
||||
"Button",
|
||||
"span",
|
||||
{ style: { margin: "0 8px", color: "#dcdee2" } },
|
||||
"|"
|
||||
),
|
||||
h(
|
||||
"a",
|
||||
{
|
||||
props: {
|
||||
type: "error",
|
||||
size: "small"
|
||||
},
|
||||
style: {
|
||||
marginRight: "5px"
|
||||
color: "#2d8cf0",
|
||||
cursor: "pointer",
|
||||
textDecoration: "none"
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
|
||||
@@ -1,72 +1,186 @@
|
||||
<template>
|
||||
<div class="search">
|
||||
<Card style="padding:0 10px 10px 0">
|
||||
<Form
|
||||
@keydown.enter.native="handleSearch"
|
||||
ref="searchForm"
|
||||
:model="searchForm"
|
||||
inline
|
||||
style="margin-top:10px"
|
||||
:label-width="70"
|
||||
@submit.native.prevent
|
||||
class="search-form"
|
||||
>
|
||||
<Form-item label="会员名称" prop="username">
|
||||
<Input
|
||||
type="text"
|
||||
v-model="searchForm.memberName"
|
||||
placeholder="请输入会员名称"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
/>
|
||||
</Form-item>
|
||||
<Button @click="handleSearch" class="search-btn" type="primary" icon="ios-search">搜索</Button >
|
||||
</Form>
|
||||
<Table
|
||||
:loading="loading"
|
||||
border
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
ref="table"
|
||||
class="mt_10"
|
||||
>
|
||||
</Table>
|
||||
<Row type="flex" justify="end" class="mt_10">
|
||||
<Page
|
||||
:current="searchForm.pageNumber"
|
||||
:total="total"
|
||||
:page-size="searchForm.pageSize"
|
||||
@on-change="changePage"
|
||||
@on-page-size-change="changePageSize"
|
||||
:page-size-opts="[10, 20, 50]"
|
||||
size="small"
|
||||
show-total
|
||||
show-elevator
|
||||
show-sizer
|
||||
></Page>
|
||||
<Card class="points-statistics-card">
|
||||
<Row type="flex" justify="space-around" align="middle" class="points-statistics">
|
||||
<Col :xs="24" :sm="12" class="points-statistics-item">
|
||||
<div class="points-statistics-title">已发放积分数</div>
|
||||
<div class="points-statistics-subtitle">历史累计发放积分数</div>
|
||||
<div class="points-statistics-value">{{ formatNumber(pointsStatistics.totalPoint) }}</div>
|
||||
</Col>
|
||||
<Col :xs="24" :sm="12" class="points-statistics-item">
|
||||
<div class="points-statistics-title">未使用积分数</div>
|
||||
<div class="points-statistics-subtitle">会员账户未使用积分数</div>
|
||||
<div class="points-statistics-value">{{ formatNumber(pointsStatistics.unUsedPoint) }}</div>
|
||||
</Col>
|
||||
</Row>
|
||||
</Card>
|
||||
<div class="point-tabs-wrap">
|
||||
<Tabs v-model="activeTab" class="point-tabs">
|
||||
<TabPane label="积分列表" name="pointList">
|
||||
<Card class="point-content-card">
|
||||
<Form
|
||||
@keydown.enter.native="handleMemberSearch"
|
||||
ref="memberSearchForm"
|
||||
:model="memberSearchForm"
|
||||
inline
|
||||
:label-width="70"
|
||||
@submit.native.prevent
|
||||
class="search-form"
|
||||
>
|
||||
<Form-item label="客户名称" prop="nickName">
|
||||
<Input
|
||||
v-model="memberSearchForm.nickName"
|
||||
placeholder="请输入客户名称"
|
||||
clearable
|
||||
style="width: 180px"
|
||||
/>
|
||||
</Form-item>
|
||||
<Form-item label="客户账号" prop="username">
|
||||
<Input
|
||||
v-model="memberSearchForm.username"
|
||||
placeholder="请输入客户账号"
|
||||
clearable
|
||||
style="width: 180px"
|
||||
/>
|
||||
</Form-item>
|
||||
<Form-item label="账号状态" prop="disabled">
|
||||
<Select
|
||||
v-model="memberSearchForm.disabled"
|
||||
clearable
|
||||
placeholder="请选择账号状态"
|
||||
style="width: 160px"
|
||||
>
|
||||
<Option value="OPEN">启用</Option>
|
||||
<Option value="CLOSE">禁用</Option>
|
||||
</Select>
|
||||
</Form-item>
|
||||
<Form-item label="积分值">
|
||||
<InputNumber
|
||||
v-model="memberSearchForm.minPoint"
|
||||
:min="0"
|
||||
:precision="0"
|
||||
placeholder="最小积分值"
|
||||
style="width: 140px"
|
||||
/>
|
||||
<span class="point-range-separator">-</span>
|
||||
<InputNumber
|
||||
v-model="memberSearchForm.maxPoint"
|
||||
:min="0"
|
||||
:precision="0"
|
||||
placeholder="最大积分值"
|
||||
style="width: 140px"
|
||||
/>
|
||||
</Form-item>
|
||||
<Button @click="handleMemberSearch" class="search-btn" type="primary" icon="ios-search">搜索</Button>
|
||||
</Form>
|
||||
</Card>
|
||||
<Card class="point-content-card member-list-card">
|
||||
<div slot="title" class="card-title">用户列表</div>
|
||||
<Table
|
||||
:loading="memberLoading"
|
||||
:columns="memberColumns"
|
||||
:data="memberData"
|
||||
class="member-table"
|
||||
>
|
||||
</Table>
|
||||
<Row type="flex" justify="end" class="mt_10">
|
||||
<Page
|
||||
:current="memberSearchForm.pageNumber"
|
||||
:total="memberTotal"
|
||||
:page-size="memberSearchForm.pageSize"
|
||||
@on-change="changeMemberPage"
|
||||
@on-page-size-change="changeMemberPageSize"
|
||||
:page-size-opts="[20, 50, 100]"
|
||||
size="small"
|
||||
show-total
|
||||
show-elevator
|
||||
show-sizer
|
||||
></Page>
|
||||
</Row>
|
||||
</Card>
|
||||
</TabPane>
|
||||
<TabPane label="积分增减记录" name="pointChangeRecord">
|
||||
<Card class="point-content-card">
|
||||
<Form
|
||||
@keydown.enter.native="handleSearch"
|
||||
ref="searchForm"
|
||||
:model="searchForm"
|
||||
inline
|
||||
:label-width="70"
|
||||
@submit.native.prevent
|
||||
class="search-form"
|
||||
>
|
||||
<Form-item label="会员名称" prop="username">
|
||||
<Input
|
||||
type="text"
|
||||
v-model="searchForm.memberName"
|
||||
placeholder="请输入会员名称"
|
||||
clearable
|
||||
style="width: 240px"
|
||||
/>
|
||||
</Form-item>
|
||||
<Button @click="handleSearch" class="search-btn" type="primary" icon="ios-search">搜索</Button>
|
||||
</Form>
|
||||
</Card>
|
||||
<Card class="point-content-card">
|
||||
<Table
|
||||
:loading="loading"
|
||||
border
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
ref="table"
|
||||
class="mt_10 point-table"
|
||||
>
|
||||
</Table>
|
||||
<Row type="flex" justify="end" class="mt_10">
|
||||
<Page
|
||||
:current="searchForm.pageNumber"
|
||||
:total="total"
|
||||
:page-size="searchForm.pageSize"
|
||||
@on-change="changePage"
|
||||
@on-page-size-change="changePageSize"
|
||||
:page-size-opts="[20, 50, 100]"
|
||||
size="small"
|
||||
show-total
|
||||
show-elevator
|
||||
show-sizer
|
||||
></Page>
|
||||
</Row>
|
||||
</Card>
|
||||
</TabPane>
|
||||
</Tabs>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import * as API_Member from "@/api/member.js";
|
||||
import ossManage from "@/views/sys/oss-manage/ossManage";
|
||||
|
||||
export default {
|
||||
// 积分历史页面
|
||||
name: "point",
|
||||
components: {
|
||||
|
||||
ossManage,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
activeTab: "pointList",
|
||||
loading: true, // 表单加载状态
|
||||
memberLoading: false,
|
||||
pointsStatistics: {
|
||||
totalPoint: 0,
|
||||
unUsedPoint: 0,
|
||||
},
|
||||
searchForm: { // 请求参数
|
||||
pageNumber: 1,
|
||||
pageSize: 10,
|
||||
pageSize: 20,
|
||||
},
|
||||
memberSearchForm: {
|
||||
pageNumber: 1,
|
||||
pageSize: 20,
|
||||
nickName: "",
|
||||
username: "",
|
||||
disabled: "",
|
||||
minPoint: null,
|
||||
maxPoint: null,
|
||||
},
|
||||
columns: [
|
||||
{
|
||||
@@ -78,20 +192,20 @@
|
||||
{
|
||||
title: "操作内容",
|
||||
key: "content",
|
||||
minWidth: 180,
|
||||
minWidth: 200,
|
||||
tooltip: true
|
||||
},
|
||||
|
||||
{
|
||||
title: "之前积分",
|
||||
key: "beforePoint",
|
||||
width: 110,
|
||||
width: 200,
|
||||
},
|
||||
|
||||
{
|
||||
title: "变动积分",
|
||||
key: "variablePoint",
|
||||
width: 110,
|
||||
width: 200,
|
||||
render: (h, params) => {
|
||||
if (params.row.pointType == 'INCREASE') {
|
||||
return h("priceColorScheme", {props:{value:params.row.variablePoint,color:'green',unit:"+"}} );
|
||||
@@ -103,16 +217,88 @@
|
||||
{
|
||||
title: "当前积分",
|
||||
key: "point",
|
||||
width: 110,
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
title: "操作时间",
|
||||
key: "createTime",
|
||||
width: 170
|
||||
width: 200
|
||||
},
|
||||
|
||||
],
|
||||
memberColumns: [
|
||||
{
|
||||
title: "客户名称",
|
||||
key: "nickName",
|
||||
width: 180,
|
||||
tooltip: true,
|
||||
render: (h, params) => {
|
||||
return h("span", params.row.nickName || "-");
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "客户账号",
|
||||
key: "username",
|
||||
width: 180,
|
||||
tooltip: true,
|
||||
render: (h, params) => {
|
||||
return h("span", params.row.username || "-");
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "账号状态",
|
||||
key: "disabled",
|
||||
width: 180,
|
||||
render: (h, params) => {
|
||||
const enabled = params.row.disabled === true;
|
||||
return h(
|
||||
"Tag",
|
||||
{
|
||||
props: {
|
||||
color: enabled ? "success" : "default",
|
||||
},
|
||||
},
|
||||
enabled ? "启用" : "禁用"
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "积分余额",
|
||||
key: "point",
|
||||
width: 180,
|
||||
render: (h, params) => {
|
||||
const point = params.row.point == null ? 0 : params.row.point;
|
||||
return h("span", point);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "操作",
|
||||
key: "action",
|
||||
width: 100,
|
||||
align: "center",
|
||||
render: (h, params) => {
|
||||
return h(
|
||||
"a",
|
||||
{
|
||||
style: {
|
||||
color: "#2d8cf0",
|
||||
cursor: "pointer",
|
||||
textDecoration: "none",
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
this.detail(params.row);
|
||||
},
|
||||
},
|
||||
},
|
||||
"详情"
|
||||
);
|
||||
},
|
||||
},
|
||||
],
|
||||
data: [], // 表单数据
|
||||
memberData: [],
|
||||
memberTotal: 0,
|
||||
total: 0, // 表单数据总数
|
||||
};
|
||||
},
|
||||
@@ -121,10 +307,31 @@
|
||||
callback(val) {
|
||||
this.$emit("callback", val);
|
||||
},
|
||||
// 查看会员详情
|
||||
detail(row) {
|
||||
this.$options.filters.customRouterPush({ name: "member-detail", query: { id: row.id } });
|
||||
},
|
||||
// 初始化数据
|
||||
init() {
|
||||
this.getStatistics();
|
||||
this.getMemberList();
|
||||
this.getData();
|
||||
},
|
||||
getStatistics() {
|
||||
API_Member.queryMemberPointsStatistics().then((res) => {
|
||||
if (res && res.success && res.result) {
|
||||
this.pointsStatistics = {
|
||||
totalPoint: res.result.totalPoint || 0,
|
||||
unUsedPoint: res.result.unUsedPoint || 0,
|
||||
};
|
||||
}
|
||||
});
|
||||
},
|
||||
formatNumber(value) {
|
||||
const numericValue = Number(value || 0);
|
||||
if (!Number.isFinite(numericValue)) return "0";
|
||||
return numericValue.toLocaleString();
|
||||
},
|
||||
// 分页 改变页码
|
||||
changePage(v) {
|
||||
this.searchForm.pageNumber = v;
|
||||
@@ -139,9 +346,43 @@
|
||||
// 搜索
|
||||
handleSearch() {
|
||||
this.searchForm.pageNumber = 1;
|
||||
this.searchForm.pageSize = 10;
|
||||
this.searchForm.pageSize = 20;
|
||||
this.getData();
|
||||
},
|
||||
handleMemberSearch() {
|
||||
this.memberSearchForm.pageNumber = 1;
|
||||
this.getMemberList();
|
||||
},
|
||||
changeMemberPage(v) {
|
||||
this.memberSearchForm.pageNumber = v;
|
||||
this.getMemberList();
|
||||
},
|
||||
changeMemberPageSize(v) {
|
||||
this.memberSearchForm.pageNumber = 1;
|
||||
this.memberSearchForm.pageSize = v;
|
||||
this.getMemberList();
|
||||
},
|
||||
getMemberList() {
|
||||
this.memberLoading = true;
|
||||
const params = {
|
||||
pageNumber: this.memberSearchForm.pageNumber,
|
||||
pageSize: this.memberSearchForm.pageSize,
|
||||
nickName: this.memberSearchForm.nickName || undefined,
|
||||
username: this.memberSearchForm.username || undefined,
|
||||
disabled: this.memberSearchForm.disabled || undefined,
|
||||
minPoint: this.memberSearchForm.minPoint,
|
||||
maxPoint: this.memberSearchForm.maxPoint,
|
||||
};
|
||||
API_Member.getMemberListData(params).then((res) => {
|
||||
this.memberLoading = false;
|
||||
if (res && res.success && res.result && res.result.records) {
|
||||
this.memberData = res.result.records;
|
||||
this.memberTotal = res.result.total;
|
||||
}
|
||||
}).catch(() => {
|
||||
this.memberLoading = false;
|
||||
});
|
||||
},
|
||||
//查新积分列表
|
||||
getData() {
|
||||
this.loading = true;
|
||||
@@ -161,6 +402,114 @@
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.points-statistics-card {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.point-tabs-wrap {
|
||||
padding: 12px 16px 16px;
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 10px rgba(23, 35, 61, 0.04);
|
||||
}
|
||||
|
||||
.point-tabs {
|
||||
::v-deep .ivu-tabs-bar {
|
||||
margin-bottom: 16px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
::v-deep .ivu-tabs-nav .ivu-tabs-tab {
|
||||
padding: 8px 18px;
|
||||
color: #515a6e;
|
||||
background: #fff;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
::v-deep .ivu-tabs-nav .ivu-tabs-tab-active {
|
||||
color: #2d8cf0;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
::v-deep .ivu-tabs-ink-bar {
|
||||
height: 2px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.points-statistics {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.points-statistics-item {
|
||||
padding: 10px 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.points-statistics-title {
|
||||
font-size: 14px;
|
||||
color: #17233d;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.points-statistics-subtitle {
|
||||
font-size: 12px;
|
||||
color: #808695;
|
||||
line-height: 18px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.points-statistics-value {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #fa6419;
|
||||
line-height: 26px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.point-table {
|
||||
::v-deep .ivu-table-border th,
|
||||
::v-deep .ivu-table-border td {
|
||||
border-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.point-content-card {
|
||||
margin-bottom: 12px;
|
||||
|
||||
::v-deep .ivu-card-body {
|
||||
padding: 18px 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.member-list-card {
|
||||
::v-deep .ivu-card-head {
|
||||
border-bottom: 1px solid #f5f5f5;
|
||||
}
|
||||
}
|
||||
|
||||
.card-title {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: #17233d;
|
||||
}
|
||||
|
||||
.member-table {
|
||||
::v-deep .ivu-table-header th {
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
::v-deep .ivu-tag {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.point-range-separator {
|
||||
display: inline-block;
|
||||
margin: 0 8px;
|
||||
color: #808695;
|
||||
}
|
||||
|
||||
.face {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
:page-size="searchForm.pageSize"
|
||||
@on-change="changePage"
|
||||
@on-page-size-change="changePageSize"
|
||||
:page-size-opts="[10, 20, 50]"
|
||||
:page-size-opts="[20, 50, 100]"
|
||||
size="small"
|
||||
show-total
|
||||
show-elevator
|
||||
@@ -46,7 +46,7 @@
|
||||
:page-size="searchForm.pageSize"
|
||||
@on-change="changePage"
|
||||
@on-page-size-change="changePageSize"
|
||||
:page-size-opts="[10, 20, 50]"
|
||||
:page-size-opts="[20, 50, 100]"
|
||||
size="small"
|
||||
show-total
|
||||
show-elevator
|
||||
@@ -72,7 +72,7 @@
|
||||
:page-size="searchForm.pageSize"
|
||||
@on-change="changePage"
|
||||
@on-page-size-change="changePageSize"
|
||||
:page-size-opts="[10, 20, 50]"
|
||||
:page-size-opts="[20, 50, 100]"
|
||||
size="small"
|
||||
show-total
|
||||
show-elevator
|
||||
@@ -99,7 +99,7 @@
|
||||
:page-size="searchForm.pageSize"
|
||||
@on-change="changePage"
|
||||
@on-page-size-change="changePageSize"
|
||||
:page-size-opts="[10, 20, 50]"
|
||||
:page-size-opts="[20, 50, 100]"
|
||||
size="small"
|
||||
show-total
|
||||
show-elevator
|
||||
@@ -155,7 +155,7 @@
|
||||
searchForm: {
|
||||
// 搜索框初始化对象
|
||||
pageNumber: 1, // 当前页数
|
||||
pageSize: 10, // 页面大小
|
||||
pageSize: 20, // 页面大小
|
||||
sort: "createTime", // 默认排序字段
|
||||
order: "desc", // 默认排序方式
|
||||
serviceType: "RETURN_MONEY"
|
||||
@@ -181,43 +181,48 @@
|
||||
key: "action",
|
||||
align: "center",
|
||||
width: 200,
|
||||
render: (h, params) => {
|
||||
return h("div", [
|
||||
h(
|
||||
"Button",
|
||||
{
|
||||
props: {
|
||||
type: "info",
|
||||
size: "small",
|
||||
},
|
||||
style: {
|
||||
marginRight: "5px"
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
this.edit(params.row);
|
||||
}
|
||||
}
|
||||
render: (h, params) => {
|
||||
return h("div", [
|
||||
h(
|
||||
"a",
|
||||
{
|
||||
style: {
|
||||
color: "#2d8cf0",
|
||||
cursor: "pointer",
|
||||
textDecoration: "none",
|
||||
marginRight: "5px"
|
||||
},
|
||||
"编辑"
|
||||
),
|
||||
h(
|
||||
"Button",
|
||||
{
|
||||
props: {
|
||||
type: "error",
|
||||
size: "small",
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
this.remove(params.row);
|
||||
}
|
||||
on: {
|
||||
click: () => {
|
||||
this.edit(params.row);
|
||||
}
|
||||
}
|
||||
},
|
||||
"编辑"
|
||||
),
|
||||
h(
|
||||
"span",
|
||||
{ style: { margin: "0 8px", color: "#dcdee2" } },
|
||||
"|"
|
||||
),
|
||||
h(
|
||||
"a",
|
||||
{
|
||||
style: {
|
||||
color: "#2d8cf0",
|
||||
cursor: "pointer",
|
||||
textDecoration: "none"
|
||||
},
|
||||
"删除"
|
||||
)
|
||||
]);
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
this.remove(params.row);
|
||||
}
|
||||
}
|
||||
},
|
||||
"删除"
|
||||
)
|
||||
]);
|
||||
},
|
||||
},
|
||||
],
|
||||
data: [], // 表单数据
|
||||
@@ -241,7 +246,7 @@
|
||||
//切换tab
|
||||
handleClickType(v) {
|
||||
this.searchForm.pageNumber = 1 // 当前页数
|
||||
this.searchForm.pageSize = 10 // 页面大小
|
||||
this.searchForm.pageSize = 20 // 页面大小
|
||||
//退款
|
||||
if (v == "RETURN_MONEY") {
|
||||
this.searchForm.serviceType = "RETURN_MONEY"
|
||||
|
||||
@@ -9,13 +9,23 @@
|
||||
:label-width="70"
|
||||
class="search-form"
|
||||
>
|
||||
<Form-item label="关键字" prop="keywords" style="display: block; width: 100%;">
|
||||
<Input
|
||||
type="text"
|
||||
v-model="searchForm.keywords"
|
||||
placeholder="请输入商品名称、订单编号搜索"
|
||||
clearable
|
||||
style="width: 240px"
|
||||
/>
|
||||
</Form-item>
|
||||
<br>
|
||||
<Form-item label="订单编号" prop="orderSn">
|
||||
<Input
|
||||
type="text"
|
||||
v-model="searchForm.orderSn"
|
||||
placeholder="请输入订单编号"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
style="width: 240px"
|
||||
/>
|
||||
</Form-item>
|
||||
<Form-item label="售后单号" prop="sn">
|
||||
@@ -24,7 +34,7 @@
|
||||
v-model="searchForm.sn"
|
||||
placeholder="请输入售后单号"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
style="width: 240px"
|
||||
/>
|
||||
</Form-item>
|
||||
<Form-item label="申请时间">
|
||||
@@ -35,7 +45,7 @@
|
||||
clearable
|
||||
@on-change="selectDateRange"
|
||||
placeholder="选择起始时间"
|
||||
style="width: 200px"
|
||||
style="width: 240px"
|
||||
></DatePicker>
|
||||
</Form-item>
|
||||
<Form-item label="商家名称" prop="storeName">
|
||||
@@ -44,7 +54,7 @@
|
||||
v-model="searchForm.storeName"
|
||||
placeholder="请输入商家名称"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
style="width: 240px"
|
||||
/>
|
||||
</Form-item>
|
||||
<Form-item label="会员名称" prop="memberName">
|
||||
@@ -53,7 +63,7 @@
|
||||
v-model="searchForm.memberName"
|
||||
placeholder="请输入会员名称"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
style="width: 240px"
|
||||
/>
|
||||
</Form-item>
|
||||
<Form-item label="售后类型">
|
||||
@@ -61,7 +71,7 @@
|
||||
v-model="searchForm.serviceType"
|
||||
placeholder="全部"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
style="width: 240px"
|
||||
>
|
||||
<Option value="RETURN_MONEY">退款</Option>
|
||||
<Option value="RETURN_GOODS">退货</Option>
|
||||
@@ -76,16 +86,17 @@
|
||||
>
|
||||
</Form>
|
||||
</Row>
|
||||
|
||||
</Card>
|
||||
<Card>
|
||||
<div class="order-tab">
|
||||
<div v-for="(item,index) in serviceStatus" :key="index" :class="{'current': currentStatus === item.value}" @click="serviceStatusClick(item)">
|
||||
{{item.title}}
|
||||
</div>
|
||||
<Tabs v-model="currentStatus" @on-click="serviceStatusClick">
|
||||
<TabPane v-for="item in serviceStatusWithCount" :key="item.value" :label="item.title" :name="item.value">
|
||||
</TabPane>
|
||||
</Tabs>
|
||||
</div>
|
||||
|
||||
<Table
|
||||
:loading="loading"
|
||||
border
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
ref="table"
|
||||
@@ -95,31 +106,16 @@
|
||||
<template slot="goodsSlot" slot-scope="{ row }">
|
||||
<div style="margin-top: 5px; height: 80px; display: flex">
|
||||
<div style="">
|
||||
<img :src="row.goodsImage" style="height: 60px; margin-top: 3px" />
|
||||
<img :src="row.goodsImage" style="width: 60px; height: 60px; margin-top: 3px; object-fit: cover; border-radius: 4px;" />
|
||||
</div>
|
||||
|
||||
<div style="margin-left: 13px">
|
||||
<div class="div-zoom">
|
||||
<a @click="linkTo(row.goodsId, row.skuId)">{{ row.goodsName }}</a>
|
||||
</div>
|
||||
<Poptip trigger="hover" title="扫码在手机中查看" transfer>
|
||||
<div slot="content">
|
||||
<vue-qr
|
||||
:text="wapLinkTo(row.goodsId, row.skuId)"
|
||||
:margin="0"
|
||||
colorDark="#000"
|
||||
colorLight="#fff"
|
||||
:size="150"
|
||||
></vue-qr>
|
||||
</div>
|
||||
<img
|
||||
src="../../../assets/qrcode.svg"
|
||||
class="hover-pointer"
|
||||
width="20"
|
||||
height="20"
|
||||
alt=""
|
||||
/>
|
||||
</Poptip>
|
||||
<div style="color: #999; font-size: 12px; margin-top: 5px;">
|
||||
商品ID: {{ row.goodsId }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -131,7 +127,7 @@
|
||||
:page-size="searchForm.pageSize"
|
||||
@on-change="changePage"
|
||||
@on-page-size-change="changePageSize"
|
||||
:page-size-opts="[10, 20, 50]"
|
||||
:page-size-opts="[20, 50, 100]"
|
||||
size="small"
|
||||
show-total
|
||||
show-elevator
|
||||
@@ -156,7 +152,7 @@ export default {
|
||||
searchForm: {
|
||||
// 搜索框初始化对象
|
||||
pageNumber: 1, // 当前页数
|
||||
pageSize: 10, // 页面大小
|
||||
pageSize: 20, // 页面大小
|
||||
sort: "createTime", // 默认排序字段
|
||||
order: "desc", // 默认排序方式
|
||||
startDate: "", // 起始时间
|
||||
@@ -166,6 +162,7 @@ export default {
|
||||
serviceStatus: "",
|
||||
storeName: "",
|
||||
sn: "",
|
||||
keywords: "", // 新增关键字搜索字段
|
||||
},
|
||||
selectDate: null, // 选择时间段
|
||||
form: {
|
||||
@@ -189,6 +186,13 @@ export default {
|
||||
minWidth: 120,
|
||||
tooltip: true,
|
||||
},
|
||||
// 移除这个独立的商品ID列
|
||||
// {
|
||||
// title: "商品ID",
|
||||
// key: "goodsId",
|
||||
// minWidth: 120,
|
||||
// tooltip: true,
|
||||
// },
|
||||
{
|
||||
title: "商品",
|
||||
key: "goodsName",
|
||||
@@ -196,15 +200,21 @@ export default {
|
||||
tooltip: true,
|
||||
slot: "goodsSlot",
|
||||
},
|
||||
{
|
||||
title: "会员ID",
|
||||
key: "memberId",
|
||||
minWidth: 120,
|
||||
tooltip: true,
|
||||
},
|
||||
{
|
||||
title: "会员名称",
|
||||
key: "memberName",
|
||||
width: 140,
|
||||
},
|
||||
{
|
||||
title: "商家名称",
|
||||
title: "店铺名称",
|
||||
key: "storeName",
|
||||
minWidth: 100,
|
||||
width: 100,
|
||||
tooltip: true,
|
||||
},
|
||||
{
|
||||
@@ -233,7 +243,7 @@ export default {
|
||||
{
|
||||
title: "售后状态",
|
||||
key: "serviceStatus",
|
||||
width: 150,
|
||||
width: 180,
|
||||
render: (h, params) => {
|
||||
if (params.row.serviceStatus == "APPLY") {
|
||||
return h("div", [h("tag", { props: { color: "blue" } }, "申请中")]);
|
||||
@@ -272,14 +282,12 @@ export default {
|
||||
render: (h, params) => {
|
||||
return h("div", [
|
||||
h(
|
||||
"Button",
|
||||
"a",
|
||||
{
|
||||
props: {
|
||||
type: "info",
|
||||
size: "small",
|
||||
},
|
||||
style: {
|
||||
marginRight: "5px",
|
||||
color: "#2d8cf0",
|
||||
cursor: "pointer",
|
||||
textDecoration: "none"
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
@@ -306,13 +314,15 @@ export default {
|
||||
{title: '卖家终止售后', value: 'SELLER_TERMINATION'},
|
||||
{title: '买家取消售后', value: 'BUYER_CANCEL'}
|
||||
],
|
||||
currentStatus: ''
|
||||
currentStatus: '',
|
||||
afterSaleNumData: {} // 售后数量统计数据
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
// 初始化数据
|
||||
init() {
|
||||
this.getDataList();
|
||||
this.getAfterSaleNumData();
|
||||
},
|
||||
// 分页 改变页码
|
||||
changePage(v) {
|
||||
@@ -328,8 +338,9 @@ export default {
|
||||
// 搜索
|
||||
handleSearch() {
|
||||
this.searchForm.pageNumber = 1;
|
||||
this.searchForm.pageSize = 10;
|
||||
this.searchForm.pageSize = 20;
|
||||
this.getDataList();
|
||||
this.getAfterSaleNumData();
|
||||
},
|
||||
// 开始结束时间分别赋值
|
||||
selectDateRange(v) {
|
||||
@@ -348,9 +359,19 @@ export default {
|
||||
this.total = res.result.total;
|
||||
}
|
||||
});
|
||||
// 获取售后状态数量
|
||||
this.total = this.data.length;
|
||||
this.loading = false;
|
||||
},
|
||||
// 获取售后数量统计
|
||||
getAfterSaleNumData() {
|
||||
const { serviceStatus, ...searchParams } = this.searchForm;
|
||||
API_Order.getAfterSaleNumVO(searchParams).then((res) => {
|
||||
if (res.success) {
|
||||
this.afterSaleNumData = res.result;
|
||||
}
|
||||
});
|
||||
},
|
||||
// 跳转售后详情
|
||||
detail(v) {
|
||||
let sn = v.sn;
|
||||
@@ -361,37 +382,44 @@ export default {
|
||||
},
|
||||
// 售后筛选
|
||||
serviceStatusClick(item) {
|
||||
this.currentStatus = item.value;
|
||||
this.searchForm.serviceStatus = item.value;
|
||||
this.currentStatus = item;
|
||||
// 如果是全部(空字符串),则删除serviceStatus字段
|
||||
if (item === 0) {
|
||||
delete this.searchForm.serviceStatus;
|
||||
} else {
|
||||
this.searchForm.serviceStatus = item;
|
||||
}
|
||||
this.getDataList();
|
||||
this.getAfterSaleNumData();
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.init();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
.order-tab {
|
||||
|
||||
width: 950px;
|
||||
height: 36px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background-color: #f0f0f0;
|
||||
padding: 0 10px;
|
||||
margin: 10px 20px 10px 0;
|
||||
div {
|
||||
text-align: center;
|
||||
padding: 4px 12px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
computed: {
|
||||
// 带数量的售后状态
|
||||
serviceStatusWithCount() {
|
||||
return [
|
||||
{title: '全部', value: ''},
|
||||
{title: `申请售后${this.afterSaleNumData.applyNum ? '(' + this.afterSaleNumData.applyNum + ')' : ''}`, value: 'APPLY'},
|
||||
{title: `通过售后${this.afterSaleNumData.passNum ? '(' + this.afterSaleNumData.passNum + ')' : ''}`, value: 'PASS'},
|
||||
{title: `拒绝售后${this.afterSaleNumData.refuseNum ? '(' + this.afterSaleNumData.refuseNum + ')' : ''}`, value: 'REFUSE'},
|
||||
{title: `待收货${this.afterSaleNumData.buyerReturnNum ? '(' + this.afterSaleNumData.buyerReturnNum + ')' : ''}`, value: 'BUYER_RETURN'},
|
||||
{title: `确认收货${this.afterSaleNumData.sellerConfirmNum ? '(' + this.afterSaleNumData.sellerConfirmNum + ')' : ''}`, value: 'SELLER_CONFIRM'},
|
||||
{title: `完成售后${this.afterSaleNumData.completeNum ? '(' + this.afterSaleNumData.completeNum + ')' : ''}`, value: 'COMPLETE'},
|
||||
{title: `卖家终止售后${this.afterSaleNumData.sellerTerminationNum ? '(' + this.afterSaleNumData.sellerTerminationNum + ')' : ''}`, value: 'SELLER_TERMINATION'},
|
||||
{title: `买家取消售后${this.afterSaleNumData.buyerCancelNum ? '(' + this.afterSaleNumData.buyerCancelNum + ')' : ''}`, value: 'BUYER_CANCEL'},
|
||||
{title: `等待平台退款${this.afterSaleNumData.waitRefundNum ? '(' + this.afterSaleNumData.waitRefundNum + ')' : ''}`, value: 'WAIT_REFUND'}
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
.current {
|
||||
background-color: #ffffff;
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
// Tab组件样式
|
||||
.order-tab {
|
||||
::v-deep .ivu-tabs-tab {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
</dd>
|
||||
</dl>
|
||||
<dl>
|
||||
<dt>退货状态</dt>
|
||||
<dt>售后状态</dt>
|
||||
<dd>{{ afterSaleInfo.serviceName }}</dd>
|
||||
</dl>
|
||||
<dl>
|
||||
@@ -376,11 +376,11 @@ export default {
|
||||
status: "APPLY",
|
||||
},
|
||||
{
|
||||
name: "通过",
|
||||
name: "通过售后",
|
||||
status: "PASS",
|
||||
},
|
||||
{
|
||||
name: "拒绝",
|
||||
name: "拒绝售后",
|
||||
status: "REFUSE",
|
||||
},
|
||||
{
|
||||
@@ -404,7 +404,7 @@ export default {
|
||||
status: "COMPLETE",
|
||||
},
|
||||
{
|
||||
name: "等待平台退款",
|
||||
name: "待平台退款",
|
||||
status: "WAIT_REFUND",
|
||||
},
|
||||
],
|
||||
@@ -511,7 +511,7 @@ export default {
|
||||
const ob = this.afterSaleStatusList.filter((e) => {
|
||||
return e.status === status;
|
||||
});
|
||||
return ob[0].name;
|
||||
return ob.length > 0 ? ob[0].name : status;
|
||||
},
|
||||
// 根据订单状态判断是否显示物流信息
|
||||
showDelivery(status) {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
v-model="searchForm.orderSn"
|
||||
placeholder="请输入订单编号"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
style="width: 240px"
|
||||
/>
|
||||
</Form-item>
|
||||
<Form-item label="会员名称" prop="memberName">
|
||||
@@ -18,11 +18,11 @@
|
||||
v-model="searchForm.memberName"
|
||||
placeholder="请输入会员名称"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
style="width: 240px"
|
||||
/>
|
||||
</Form-item>
|
||||
<Form-item label="状态" prop="status">
|
||||
<Select v-model="searchForm.status" placeholder="请选择" clearable style="width: 200px">
|
||||
<Select v-model="searchForm.status" placeholder="请选择" clearable style="width: 240px">
|
||||
<Option value="NEW">新投诉</Option>
|
||||
<Option value="CANCEL">已撤销</Option>
|
||||
<Option value="WAIT_APPEAL">待申诉</Option>
|
||||
@@ -34,6 +34,8 @@
|
||||
<Button @click="handleSearch" type="primary" icon="ios-search" class="search-btn">搜索</Button>
|
||||
</Form>
|
||||
</Row>
|
||||
</Card>
|
||||
<Card>
|
||||
<Table
|
||||
:loading="loading"
|
||||
border
|
||||
@@ -59,7 +61,7 @@
|
||||
:page-size="searchForm.pageSize"
|
||||
@on-change="changePage"
|
||||
@on-page-size-change="changePageSize"
|
||||
:page-size-opts="[10, 20, 50]"
|
||||
:page-size-opts="[20, 50, 100]"
|
||||
size="small"
|
||||
show-total
|
||||
show-elevator
|
||||
@@ -84,7 +86,7 @@
|
||||
searchForm: {
|
||||
// 搜索框初始化对象
|
||||
pageNumber: 1, // 当前页数
|
||||
pageSize: 10, // 页面大小
|
||||
pageSize: 20, // 页面大小
|
||||
sort: "createTime", // 默认排序字段
|
||||
order: "desc", // 默认排序方式
|
||||
},
|
||||
@@ -142,24 +144,22 @@
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
title: "操作",
|
||||
key: "action",
|
||||
align: "center",
|
||||
fixed: "right",
|
||||
width: 150,
|
||||
render: (h, params) => {
|
||||
{
|
||||
title: "操作",
|
||||
key: "action",
|
||||
align: "center",
|
||||
fixed: "right",
|
||||
width: 150,
|
||||
render: (h, params) => {
|
||||
if(params.row.complainStatus === "COMPLETE"){
|
||||
return h("div", [
|
||||
h(
|
||||
"Button",
|
||||
"a",
|
||||
{
|
||||
props: {
|
||||
type: "info",
|
||||
size: "small",
|
||||
},
|
||||
style: {
|
||||
marginRight: "5px",
|
||||
color: "#2d8cf0",
|
||||
cursor: "pointer",
|
||||
textDecoration: "none",
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
@@ -173,14 +173,12 @@
|
||||
}else{
|
||||
return h("div", [
|
||||
h(
|
||||
"Button",
|
||||
"a",
|
||||
{
|
||||
props: {
|
||||
type: "primary",
|
||||
size: "small",
|
||||
},
|
||||
style: {
|
||||
marginRight: "5px",
|
||||
color: "#2d8cf0",
|
||||
cursor: "pointer",
|
||||
textDecoration: "none",
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
@@ -225,7 +223,7 @@
|
||||
// 搜索
|
||||
handleSearch() {
|
||||
this.searchForm.pageNumber = 1;
|
||||
this.searchForm.pageSize = 10;
|
||||
this.searchForm.pageSize = 20;
|
||||
this.getDataList();
|
||||
},
|
||||
// 获取列表数据
|
||||
|
||||
@@ -2,35 +2,34 @@
|
||||
<div class="search">
|
||||
<Card>
|
||||
<Row @keydown.enter.native="handleSearch">
|
||||
<Form ref="searchForm" :model="searchForm" inline :label-width="100" class="search-form">
|
||||
<Form ref="searchForm" :model="searchForm" inline :label-width="70" class="search-form">
|
||||
<Form-item label="订单号" prop="sn">
|
||||
<Input type="text" v-model="searchForm.sn" placeholder="订单/交易号" clearable style="width: 200px" />
|
||||
<Input type="text" v-model="searchForm.sn" placeholder="订单/交易号" clearable style="width: 240px" />
|
||||
</Form-item>
|
||||
<Form-item label="付款状态" prop="orderStatus">
|
||||
<Select v-model="searchForm.payStatus" placeholder="请选择" clearable style="width: 200px">
|
||||
<Select v-model="searchForm.payStatus" placeholder="请选择" clearable style="width: 240px">
|
||||
<Option value="UNPAID">未付款</Option>
|
||||
<Option value="PAID">已付款</Option>
|
||||
</Select>
|
||||
</Form-item>
|
||||
<Form-item label="支付方式" prop="orderStatus">
|
||||
<Select v-model="searchForm.paymentMethod" placeholder="请选择" clearable style="width: 200px">
|
||||
<Select v-model="searchForm.paymentMethod" placeholder="请选择" clearable style="width: 240px">
|
||||
<Option value="">全部</Option>
|
||||
<Option value="WECHAT">微信</Option>
|
||||
<Option value="ALIPAY">支付宝</Option>
|
||||
<Option value="WALLET">余额</Option>
|
||||
<Option value="BANK_TRANSFER">银行转账</Option>
|
||||
|
||||
</Select>
|
||||
</Form-item>
|
||||
<Form-item label="订单创建时间">
|
||||
<DatePicker v-model="times" type="datetimerange" format="yyyy-MM-dd HH:mm" clearable @on-change="changeDate" placeholder="选择支付时间" style="width: 200px"></DatePicker>
|
||||
</Form-item>
|
||||
|
||||
<Button @click="handleSearch" type="primary" icon="ios-search" class="search-btn">搜索</Button>
|
||||
</Form>
|
||||
</Row>
|
||||
</Card>
|
||||
<Card>
|
||||
<Table :loading="loading" border :columns="columns" :data="data" ref="table" class="mt_10"></Table>
|
||||
<Row type="flex" justify="end" class="mt_10">
|
||||
<Page :current="searchForm.pageNumber" :total="total" :page-size="searchForm.pageSize" @on-change="changePage" @on-page-size-change="changePageSize" :page-size-opts="[10, 20, 50]" size="small"
|
||||
<Page :current="searchForm.pageNumber" :total="total" :page-size="searchForm.pageSize" @on-change="changePage" @on-page-size-change="changePageSize" :page-size-opts="[20, 50, 100]" size="small"
|
||||
show-total show-elevator show-sizer></Page>
|
||||
</Row>
|
||||
</Card>
|
||||
@@ -48,7 +47,7 @@ export default {
|
||||
searchForm: {
|
||||
// 搜索框初始化对象
|
||||
pageNumber: 1, // 当前页数
|
||||
pageSize: 10, // 页面大小
|
||||
pageSize: 20, // 页面大小
|
||||
sort: "createTime", // 默认排序字段
|
||||
order: "desc", // 默认排序方式
|
||||
sn: "",
|
||||
@@ -185,7 +184,7 @@ export default {
|
||||
// 搜索
|
||||
handleSearch() {
|
||||
this.searchForm.pageNumber = 1;
|
||||
this.searchForm.pageSize = 10;
|
||||
this.searchForm.pageSize = 20;
|
||||
this.getDataList();
|
||||
},
|
||||
changeDate(val) {
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
v-model="searchForm.orderSn"
|
||||
placeholder="订单/交易号"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
style="width: 240px"
|
||||
/>
|
||||
</Form-item>
|
||||
<Form-item label="退款状态">
|
||||
@@ -23,7 +23,7 @@
|
||||
v-model="searchForm.isRefund"
|
||||
placeholder="请选择"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
style="width: 240px"
|
||||
>
|
||||
<Option value="false">未退款</Option>
|
||||
<Option value="true">已退款</Option>
|
||||
@@ -37,7 +37,7 @@
|
||||
clearable
|
||||
@on-change="selectDateRange"
|
||||
placeholder="选择起始时间"
|
||||
style="width: 200px"
|
||||
style="width: 240px"
|
||||
></DatePicker>
|
||||
</Form-item>
|
||||
<Button
|
||||
@@ -49,6 +49,8 @@
|
||||
>
|
||||
</Form>
|
||||
</Row>
|
||||
</Card>
|
||||
<Card>
|
||||
<Table
|
||||
:loading="loading"
|
||||
border
|
||||
@@ -91,7 +93,7 @@
|
||||
:page-size="searchForm.pageSize"
|
||||
@on-change="changePage"
|
||||
@on-page-size-change="changePageSize"
|
||||
:page-size-opts="[10, 20, 50]"
|
||||
:page-size-opts="[20, 50, 100]"
|
||||
size="small"
|
||||
show-total
|
||||
show-elevator
|
||||
@@ -113,7 +115,7 @@ export default {
|
||||
searchForm: {
|
||||
// 搜索框初始化对象
|
||||
pageNumber: 1, // 当前页数
|
||||
pageSize: 10, // 页面大小
|
||||
pageSize: 20, // 页面大小
|
||||
sort: "createTime", // 默认排序字段
|
||||
order: "desc", // 默认排序方式
|
||||
startDate: "", // 起始时间
|
||||
@@ -194,7 +196,7 @@ export default {
|
||||
// 搜索
|
||||
handleSearch() {
|
||||
this.searchForm.pageNumber = 1;
|
||||
this.searchForm.pageSize = 10;
|
||||
this.searchForm.pageSize = 20;
|
||||
this.getDataList();
|
||||
},
|
||||
// 起止时间从新赋值
|
||||
|
||||
@@ -4,41 +4,33 @@
|
||||
<Row @keydown.enter.native="handleSearch">
|
||||
<Form ref="searchForm" :model="searchForm" inline :label-width="70" class="search-form">
|
||||
<Form-item label="订单号" prop="orderSn">
|
||||
<Input type="text" v-model="searchForm.orderSn" placeholder="请输入订单号" clearable style="width: 200px" />
|
||||
<Input type="text" v-model="searchForm.orderSn" placeholder="请输入订单号" clearable style="width: 240px" />
|
||||
</Form-item>
|
||||
<Form-item label="会员名称" prop="buyerName">
|
||||
<Input type="text" v-model="searchForm.buyerName" placeholder="请输入会员名称" clearable style="width: 200px" />
|
||||
<Input type="text" v-model="searchForm.buyerName" placeholder="请输入会员名称" clearable style="width: 240px" />
|
||||
</Form-item>
|
||||
<!-- <Form-item label="订单状态" prop="orderStatus">-->
|
||||
<!-- <Select v-model="searchForm.orderStatus" placeholder="请选择" clearable style="width: 200px">-->
|
||||
<!-- <Option value="NEW">新订单</Option>-->
|
||||
<!-- <Option value="CONFIRM">已确认</Option>-->
|
||||
<!-- <Option value="TAKE">待核验</Option>-->
|
||||
<!-- <Option value="COMPLETE">已完成</Option>-->
|
||||
<!-- <Option value="WAIT_PINTUAN">待成团</Option>-->
|
||||
<!-- <Option value="CANCELLED">已关闭</Option>-->
|
||||
<!-- </Select>-->
|
||||
<!-- </Form-item>-->
|
||||
<Form-item label="下单时间">
|
||||
<DatePicker v-model="selectDate" type="datetimerange" format="yyyy-MM-dd" clearable
|
||||
@on-change="selectDateRange" placeholder="选择起始时间" style="width: 200px"></DatePicker>
|
||||
@on-change="selectDateRange" placeholder="选择起始时间" style="width: 240px"></DatePicker>
|
||||
</Form-item>
|
||||
<Button @click="handleSearch" type="primary" icon="ios-search" class="search-btn">搜索</Button>
|
||||
|
||||
</Form>
|
||||
</Row>
|
||||
|
||||
</Card>
|
||||
<Card>
|
||||
<div class="order-tab">
|
||||
<div v-for="(item,index) in orderStatus" :key="index" :class="{'current': currentStatus === item.value}" @click="orderStatusClick(item)">
|
||||
{{item.title}}
|
||||
</div>
|
||||
<Tabs v-model="currentStatus" @on-click="orderStatusClick">
|
||||
<TabPane v-for="(item,index) in orderStatus" :key="index" :label="item.title" :name="item.value">
|
||||
</TabPane>
|
||||
</Tabs>
|
||||
</div>
|
||||
|
||||
<Table :loading="loading" border :columns="columns" :data="data" ref="table" class="mt_10" sortable="custom"
|
||||
@on-sort-change="changeSort"></Table>
|
||||
<Row type="flex" justify="end" class="mt_10">
|
||||
<Page :current="searchForm.pageNumber" :total="total" :page-size="searchForm.pageSize" @on-change="changePage"
|
||||
@on-page-size-change="changePageSize" :page-size-opts="[10, 20, 50]" size="small" show-total show-elevator
|
||||
@on-page-size-change="changePageSize" :page-size-opts="[20, 50, 100]" size="small" show-total show-elevator
|
||||
show-sizer></Page>
|
||||
</Row>
|
||||
</Card>
|
||||
@@ -56,7 +48,7 @@ export default {
|
||||
searchForm: {
|
||||
// 搜索框初始化对象
|
||||
pageNumber: 1, // 当前页数
|
||||
pageSize: 10, // 页面大小
|
||||
pageSize: 20, // 页面大小
|
||||
sort: "", // 默认排序字段
|
||||
order: "", // 默认排序方式
|
||||
startDate: "", // 起始时间
|
||||
@@ -215,7 +207,7 @@ export default {
|
||||
// 搜索
|
||||
handleSearch () {
|
||||
this.searchForm.pageNumber = 1;
|
||||
this.searchForm.pageSize = 10;
|
||||
this.searchForm.pageSize = 20;
|
||||
this.getDataList();
|
||||
},
|
||||
// 列表排序
|
||||
@@ -275,8 +267,8 @@ export default {
|
||||
},
|
||||
// 订单筛选
|
||||
orderStatusClick(item) {
|
||||
this.currentStatus = item.value;
|
||||
this.searchForm.orderStatus = item.value;
|
||||
this.currentStatus = item; // 使用参数 item
|
||||
this.searchForm.orderStatus = item; // 使用参数 item
|
||||
this.getDataList();
|
||||
},
|
||||
},
|
||||
@@ -288,23 +280,11 @@ export default {
|
||||
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// Tab组件样式
|
||||
.order-tab {
|
||||
margin: 10px 20px 10px 0;
|
||||
width: 950px;
|
||||
height: 36px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background-color: #f0f0f0;
|
||||
padding: 0 10px;
|
||||
div {
|
||||
text-align: center;
|
||||
padding: 4px 12px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.current {
|
||||
background-color: #ffffff;
|
||||
margin-top: 20px;
|
||||
::v-deep .ivu-tabs-tab {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -9,13 +9,22 @@
|
||||
:label-width="70"
|
||||
class="search-form"
|
||||
>
|
||||
<Form-item label="关键字" prop="keywords" style="display: block; width: 100%;">
|
||||
<Input
|
||||
type="text"
|
||||
v-model="searchForm.keywords"
|
||||
placeholder="请输入商品名称/收货人/收货人手机号/店铺名称"
|
||||
clearable
|
||||
style="width: 500px"
|
||||
/>
|
||||
</Form-item>
|
||||
<Form-item label="订单号" prop="orderSn">
|
||||
<Input
|
||||
type="text"
|
||||
v-model="searchForm.orderSn"
|
||||
placeholder="请输入订单号"
|
||||
clearable
|
||||
style="width: 160px"
|
||||
style="width: 240px"
|
||||
/>
|
||||
</Form-item>
|
||||
<Form-item label="会员名称" prop="buyerName">
|
||||
@@ -24,16 +33,33 @@
|
||||
v-model="searchForm.buyerName"
|
||||
placeholder="请输入会员名称"
|
||||
clearable
|
||||
style="width: 160px"
|
||||
style="width: 240px"
|
||||
/>
|
||||
</Form-item>
|
||||
<Form-item label="商品名称" prop="goodsName">
|
||||
<Input
|
||||
type="text"
|
||||
v-model="searchForm.goodsName"
|
||||
placeholder="请输入商品名称"
|
||||
clearable
|
||||
style="width: 240px"
|
||||
/>
|
||||
</Form-item>
|
||||
<Form-item label="收货人" prop="shipName">
|
||||
<Input
|
||||
type="text"
|
||||
v-model="searchForm.shipName"
|
||||
placeholder="请输入收货人姓名"
|
||||
clearable
|
||||
style="width: 240px"
|
||||
/>
|
||||
</Form-item>
|
||||
|
||||
<Form-item label="订单类型" prop="orderType">
|
||||
<Select
|
||||
v-model="searchForm.orderPromotionType"
|
||||
placeholder="请选择"
|
||||
clearable
|
||||
style="width: 160px"
|
||||
style="width: 240px"
|
||||
>
|
||||
<Option value="NORMAL">普通订单</Option>
|
||||
<Option value="PINTUAN">拼团订单</Option>
|
||||
@@ -42,6 +68,19 @@
|
||||
<Option value="KANJIA">砍价订单</Option>
|
||||
</Select>
|
||||
</Form-item>
|
||||
<Form-item label="支付方式" prop="paymentMethod">
|
||||
<Select
|
||||
v-model="searchForm.paymentMethod"
|
||||
placeholder="请选择支付方式"
|
||||
clearable
|
||||
style="width: 240px"
|
||||
>
|
||||
<Option value="WECHAT">微信支付</Option>
|
||||
<Option value="ALIPAY">支付宝</Option>
|
||||
<Option value="WALLET">余额支付</Option>
|
||||
<Option value="BANK_TRANSFER">线下转账</Option>
|
||||
</Select>
|
||||
</Form-item>
|
||||
<Form-item label="下单时间">
|
||||
<DatePicker
|
||||
v-model="selectDate"
|
||||
@@ -50,26 +89,9 @@
|
||||
clearable
|
||||
@on-change="selectDateRange"
|
||||
placeholder="选择起始时间"
|
||||
style="width: 160px"
|
||||
style="width: 240px"
|
||||
></DatePicker>
|
||||
</Form-item>
|
||||
<!-- <Form-item label="订单状态" prop="orderStatus">-->
|
||||
<!-- <Select-->
|
||||
<!-- v-model="searchForm.orderStatus"-->
|
||||
<!-- placeholder="请选择"-->
|
||||
<!-- clearable-->
|
||||
<!-- style="width: 160px"-->
|
||||
<!-- >-->
|
||||
<!-- <Option value="UNPAID">未付款</Option>-->
|
||||
<!-- <Option value="PAID">已付款</Option>-->
|
||||
<!-- <Option value="UNDELIVERED">待发货</Option>-->
|
||||
<!-- <Option value="DELIVERED">已发货</Option>-->
|
||||
<!-- <Option value="COMPLETED">已完成</Option>-->
|
||||
<!-- <Option value="TAKE">待核验</Option>-->
|
||||
<!-- <Option value="CANCELLED">已关闭</Option>-->
|
||||
<!-- <Option value="STAY_PICKED_UP">待自提</Option>-->
|
||||
<!-- </Select>-->
|
||||
<!-- </Form-item>-->
|
||||
<Button
|
||||
@click="handleSearch"
|
||||
type="primary"
|
||||
@@ -78,19 +100,19 @@
|
||||
>搜索</Button
|
||||
>
|
||||
</Form>
|
||||
</Card>
|
||||
<Card>
|
||||
<div class="order-tab">
|
||||
<Tabs v-model="currentStatus" @on-click="orderStatusClick">
|
||||
<TabPane v-for="(item,index) in orderStatusWithCount" :key="index" :label="item.title" :name="item.value">
|
||||
</TabPane>
|
||||
</Tabs>
|
||||
</div>
|
||||
<div>
|
||||
<Button @click="exportOrder" type="info" class="export">导出订单</Button>
|
||||
</div>
|
||||
|
||||
<div class="order-tab">
|
||||
<div v-for="(item,index) in orderStatus" :key="index" :class="{'current': currentStatus === item.value}" @click="orderStatusClick(item)">
|
||||
{{item.title}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Table
|
||||
:loading="loading"
|
||||
border
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
ref="table"
|
||||
@@ -104,7 +126,7 @@
|
||||
:page-size="searchForm.pageSize"
|
||||
@on-change="changePage"
|
||||
@on-page-size-change="changePageSize"
|
||||
:page-size-opts="[10, 20, 50]"
|
||||
:page-size-opts="[20, 50, 100]"
|
||||
size="small"
|
||||
show-total
|
||||
show-elevator
|
||||
@@ -163,15 +185,19 @@ export default {
|
||||
searchForm: {
|
||||
// 搜索框初始化对象
|
||||
pageNumber: 1, // 当前页数
|
||||
pageSize: 10, // 页面大小
|
||||
pageSize: 20, // 页面大小
|
||||
sort: "createTime", // 默认排序字段
|
||||
order: "desc", // 默认排序方式
|
||||
startDate: "", // 起始时间
|
||||
endDate: "", // 终止时间
|
||||
orderType: "",
|
||||
orderSn: "",
|
||||
keywords: "", // 新增关键字搜索字段
|
||||
buyerName: "",
|
||||
goodsName: "", // 新增商品名称筛选字段
|
||||
shipName: "", // 新增收货人筛选字段
|
||||
orderStatus: "",
|
||||
paymentMethod: "", // 新增支付方式筛选字段
|
||||
},
|
||||
selectDate: null,
|
||||
columns: [
|
||||
@@ -181,7 +207,6 @@ export default {
|
||||
minWidth: 240,
|
||||
tooltip: true,
|
||||
},
|
||||
|
||||
{
|
||||
title: "订单来源",
|
||||
key: "clientType",
|
||||
@@ -234,6 +259,19 @@ export default {
|
||||
minWidth: 130,
|
||||
tooltip: true,
|
||||
},
|
||||
|
||||
{
|
||||
title: "会员ID",
|
||||
key: "memberId",
|
||||
minWidth: 120,
|
||||
tooltip: true,
|
||||
},
|
||||
{
|
||||
title: "店铺名称",
|
||||
key: "storeName",
|
||||
minWidth: 150,
|
||||
tooltip: true,
|
||||
},
|
||||
|
||||
{
|
||||
title: "订单金额",
|
||||
@@ -245,7 +283,24 @@ export default {
|
||||
},
|
||||
|
||||
},
|
||||
|
||||
{
|
||||
title: "支付方式",
|
||||
key: "paymentMethod",
|
||||
width: 120,
|
||||
render: (h, params) => {
|
||||
if (params.row.paymentMethod == "WECHAT") {
|
||||
return h("div", {}, "微信支付");
|
||||
} else if (params.row.paymentMethod == "ALIPAY") {
|
||||
return h("div", {}, "支付宝");
|
||||
} else if (params.row.paymentMethod == "WALLET") {
|
||||
return h("div", {}, "余额支付");
|
||||
} else if (params.row.paymentMethod == "BANK_TRANSFER") {
|
||||
return h("div", {}, "线下转账");
|
||||
} else {
|
||||
return h("div", {}, params.row.paymentMethod || "-");
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "订单状态",
|
||||
key: "orderStatus",
|
||||
@@ -302,23 +357,33 @@ export default {
|
||||
width: 100,
|
||||
render: (h, params) => {
|
||||
return h(
|
||||
"Button",
|
||||
{
|
||||
props: { type: "info", size: "small" },
|
||||
style: { marginRight: "5px" },
|
||||
on: {
|
||||
click: () => {
|
||||
this.detail(params.row);
|
||||
"div",
|
||||
{ class: "ops" },
|
||||
[
|
||||
h(
|
||||
"a",
|
||||
{
|
||||
style: {
|
||||
color: "#2d8cf0",
|
||||
cursor: "pointer",
|
||||
textDecoration: "none",
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
this.detail(params.row);
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"查看"
|
||||
"查看"
|
||||
),
|
||||
]
|
||||
);
|
||||
},
|
||||
},
|
||||
],
|
||||
data: [], // 表单数据
|
||||
total: 0, // 表单数据总数
|
||||
orderNumData: {}, // 新增:订单数量统计数据
|
||||
orderStatus: [
|
||||
{title: '全部', value: ''},
|
||||
{title: '未付款', value: 'UNPAID'},
|
||||
@@ -330,15 +395,32 @@ export default {
|
||||
{title: '待自提', value: 'STAY_PICKED_UP'},
|
||||
{title: '已完成', value: 'COMPLETED'},
|
||||
{title: '已关闭', value: 'CANCELLED'},
|
||||
|
||||
],
|
||||
currentStatus: ''
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
// 新增:带数量的订单状态选项
|
||||
orderStatusWithCount() {
|
||||
return [
|
||||
{title: '全部', value: ''},
|
||||
{title: `未付款${this.orderNumData.waitPayNum ? '(' + this.orderNumData.waitPayNum + ')' : ''}`, value: 'UNPAID'},
|
||||
{title: `已付款${this.orderNumData.waitDeliveryNum ? '(' + this.orderNumData.waitDeliveryNum + ')' : ''}`, value: 'PAID'},
|
||||
{title: `待发货${this.orderNumData.waitShipNum ? '(' + this.orderNumData.waitShipNum + ')' : ''}`, value: 'UNDELIVERED'},
|
||||
{title: `部分发货${this.orderNumData.partsDeliveredNumNum ? '(' + this.orderNumData.partsDeliveredNumNum + ')' : ''}`, value: 'PARTS_DELIVERED'},
|
||||
{title: `待收货${this.orderNumData.deliveredNum ? '(' + this.orderNumData.deliveredNum + ')' : ''}`, value: 'DELIVERED'},
|
||||
{title: `待核验${this.orderNumData.waitCheckNum ? '(' + this.orderNumData.waitCheckNum + ')' : ''}`, value: 'TAKE'},
|
||||
{title: `待自提${this.orderNumData.waitSelfPickNum ? '(' + this.orderNumData.waitSelfPickNum + ')' : ''}`, value: 'STAY_PICKED_UP'},
|
||||
{title: `已完成${this.orderNumData.finishNum ? '(' + this.orderNumData.finishNum + ')' : ''}`, value: 'COMPLETED'},
|
||||
{title: `已关闭${this.orderNumData.closeNum ? '(' + this.orderNumData.closeNum + ')' : ''}`, value: 'CANCELLED'},
|
||||
];
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 初始化数据
|
||||
init() {
|
||||
this.getDataList();
|
||||
this.getOrderNumData(); // 新增:获取订单数量统计
|
||||
},
|
||||
// 分页 改变页码
|
||||
changePage(v) {
|
||||
@@ -354,8 +436,9 @@ export default {
|
||||
// 搜索
|
||||
handleSearch() {
|
||||
this.searchForm.pageNumber = 1;
|
||||
this.searchForm.pageSize = 10;
|
||||
this.searchForm.pageSize = 20;
|
||||
this.getDataList();
|
||||
this.getOrderNumData(); // 新增:搜索时也更新数量统计
|
||||
},
|
||||
// 起止时间从新赋值
|
||||
selectDateRange(v) {
|
||||
@@ -419,11 +502,29 @@ export default {
|
||||
|
||||
},
|
||||
// 订单筛选
|
||||
orderStatusClick(item) {
|
||||
this.currentStatus = item.value;
|
||||
this.searchForm.orderStatus = item.value;
|
||||
orderStatusClick(name) {
|
||||
if (name === 0) {
|
||||
// 点击"全部"时,设置为空字符串,在getDataList中会被过滤掉
|
||||
this.searchForm.orderStatus = '';
|
||||
} else {
|
||||
// 其他状态正常赋值
|
||||
this.searchForm.orderStatus = name;
|
||||
}
|
||||
this.currentStatus = name;
|
||||
|
||||
this.getDataList();
|
||||
},
|
||||
getOrderNumData() {
|
||||
// 创建一个不包含orderStatus字段的搜索参数
|
||||
const { orderStatus, ...searchParams } = this.searchForm;
|
||||
API_Order.getOrderNum(searchParams).then((res) => {
|
||||
if (res.success) {
|
||||
this.orderNumData = res.result;
|
||||
}
|
||||
}).catch((err) => {
|
||||
console.error('获取订单数量统计失败:', err);
|
||||
});
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.init();
|
||||
@@ -437,23 +538,21 @@ export default {
|
||||
.export-excel-wrapper {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
// Tab组件样式
|
||||
.order-tab {
|
||||
width: 950px;
|
||||
height: 36px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background-color: #f0f0f0;
|
||||
padding: 0 10px;
|
||||
margin-bottom: 10px;
|
||||
div {
|
||||
text-align: center;
|
||||
padding: 4px 12px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.current {
|
||||
background-color: #ffffff;
|
||||
::v-deep .ivu-tabs-tab {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
.ops a {
|
||||
color: #2d8cf0;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
}
|
||||
.ops span {
|
||||
display: inline-block;
|
||||
margin: 0 8px;
|
||||
color: #dcdee2;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
:total="total"
|
||||
show-sizer
|
||||
size="small"
|
||||
:page-size-opts="[10, 20, 50]"
|
||||
:page-size-opts="[20, 50, 100]"
|
||||
show-elevator
|
||||
style="float: right; overflow: hidden"
|
||||
@on-change="changePageNum"
|
||||
@@ -109,7 +109,7 @@ export default {
|
||||
},
|
||||
searchForm: {
|
||||
pageNumber: 1,
|
||||
pageSize: 10,
|
||||
pageSize: 20,
|
||||
sort: "createTime",
|
||||
order: "desc",
|
||||
pageType: "INDEX",
|
||||
|
||||
@@ -371,7 +371,7 @@ export default {
|
||||
.search {
|
||||
width: 460px;
|
||||
margin: 0 auto;
|
||||
/deep/ .ivu-input.ivu-input-large {
|
||||
::v-deep .ivu-input.ivu-input-large {
|
||||
border: 2px solid $theme_color;
|
||||
font-size: 12px;
|
||||
height: 34px;
|
||||
@@ -379,7 +379,7 @@ export default {
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
/deep/ .ivu-input-group-append {
|
||||
::v-deep .ivu-input-group-append {
|
||||
border: 1px solid $theme_color;
|
||||
border-left: none;
|
||||
height: 30px;
|
||||
|
||||
@@ -104,6 +104,7 @@ export default {
|
||||
pageData: JSON.stringify(modelForm),
|
||||
// 如果是专题页面永远关闭
|
||||
pageShow: this.$route.query.pageType === 'SPECIAL' ? 'CLOSE' : pageShow,
|
||||
pageClientType: 'PC',
|
||||
};
|
||||
API_floor.updateHome(this.$route.query.id, data).then((res) => {
|
||||
this.submitLoading = false
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/deep/ .ivu-modal-mask,
|
||||
::v-deep .ivu-modal-mask,
|
||||
.ivu-modal-wrap {
|
||||
z-index: 800;
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
line-height: 2;
|
||||
/deep/ img {
|
||||
::v-deep img {
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
:current="params.pageNumber"
|
||||
:page-size="params.pageSize"
|
||||
show-sizer
|
||||
:page-size-opts="[10, 20, 50]"
|
||||
:page-size-opts="[20, 50, 100]"
|
||||
@on-page-size-change="changePageSize"
|
||||
/>
|
||||
</Card>
|
||||
@@ -95,7 +95,7 @@ export default {
|
||||
params: {
|
||||
// 请求参数
|
||||
pageNumber: 1,
|
||||
pageSize: 10,
|
||||
pageSize: 20,
|
||||
sort: "createTime",
|
||||
order: "desc",
|
||||
pageType: "INDEX",
|
||||
|
||||
@@ -19,29 +19,21 @@
|
||||
primary-key="id"
|
||||
>
|
||||
<template slot="action" slot-scope="scope">
|
||||
<Button
|
||||
type="info"
|
||||
<a
|
||||
style="color:#2d8cf0;cursor:pointer;text-decoration:none;margin-right:5px"
|
||||
@click="edit(scope.row)"
|
||||
size="small"
|
||||
style="margin-right: 5px"
|
||||
>编辑
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
type="error"
|
||||
>编辑</a>
|
||||
<span style="margin:0 8px;color:#dcdee2">|</span>
|
||||
<a
|
||||
style="color:#2d8cf0;cursor:pointer;text-decoration:none;margin-right:5px"
|
||||
@click="remove(scope.row)"
|
||||
size="small"
|
||||
style="margin-right: 5px"
|
||||
>删除
|
||||
</Button>
|
||||
<Button
|
||||
>删除</a>
|
||||
<span v-show="scope.row.level != 1" style="margin:0 8px;color:#dcdee2">|</span>
|
||||
<a
|
||||
v-show="scope.row.level != 1"
|
||||
type="success"
|
||||
style="color:#2d8cf0;cursor:pointer;text-decoration:none"
|
||||
@click="addChildren(scope.row)"
|
||||
size="small"
|
||||
style="margin-right: 5px"
|
||||
>添加子分类
|
||||
</Button>
|
||||
>添加子分类</a>
|
||||
</template>
|
||||
</tree-table>
|
||||
</Card>
|
||||
|
||||
@@ -128,7 +128,7 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
/deep/ .ivu-input {
|
||||
::v-deep .ivu-input {
|
||||
width: 70px !important;
|
||||
}
|
||||
|
||||
@@ -138,7 +138,7 @@ export default {
|
||||
}
|
||||
|
||||
.label-btns {
|
||||
/deep/ .ivu-btn {
|
||||
::v-deep .ivu-btn {
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user