新增核销记录

This commit is contained in:
dengbw
2023-02-23 15:50:29 +08:00
parent d925d7d69c
commit 23cf8a7e36
10 changed files with 996 additions and 6 deletions
+69
View File
@@ -0,0 +1,69 @@
import request from '@/utils/request';
/**
* 查询订单列表
* @param params 查询条件
*/
export async function listGroupsExchange(params) {
const res = await request.get('/sylive/groupsExchange/', {
params
});
if (res.data.code === 0) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 导出订单
* @param params 查询条件
*/
export async function exportGroupsExchange(params) {
const res = await request.get('/sylive/groupsExchange/export', {
params
});
if (res.data.code === 0) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 操作详情
* @param params 查询条件
*/
export async function getGroupsExchangeDetail(params) {
const res = await request.get('/sylive/groupsExchange/detail', {
params
});
if (res.data.code === 0) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 修改使用状态
* @param data 操作信息
*/
export async function updateGroupsExchangeUseStatus(data) {
const res = await request.put('/sylive/groupsExchange/status', data);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 导入用户
* @param file excel文件
*/
export async function importGroupsExchange(file) {
const formData = new FormData();
formData.append('file', file);
const res = await request.post('/sylive/groupsExchange/import', formData);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
@@ -1,7 +1,7 @@
<!-- 编辑弹窗 -->
<template>
<ele-modal
width="900px"
width="930px"
:visible="visible"
:append-to-body="true"
:close-on-click-modal="true"
@@ -75,8 +75,16 @@
<el-table-column label="参与抽奖" width="100px" align="center">
<template v-slot="{ row }">
<el-select v-model="row.show" class="ele-fluid">
<el-option label="是" value="1" />
<el-option label="否" value="0" />
<el-option label="是" value="1" />
</el-select>
</template>
</el-table-column>
<el-table-column label="需核销码" width="100px" align="center">
<template v-slot="{ row }">
<el-select v-model="row.ifCode" class="ele-fluid">
<el-option label="否" value="0" />
<el-option label="是" value="1" />
</el-select>
</template>
</el-table-column>
@@ -279,6 +287,7 @@
show: '1',
tag: '',
itemIds: '',
ifCode: '0',
img: []
});
},
+10 -4
View File
@@ -69,11 +69,14 @@
<i class="el-icon-arrow-down"></i>
</el-link>
<template v-slot:dropdown>
<el-dropdown-menu>
<el-dropdown-menu v-if="row.groups == 1">
<el-dropdown-item command="order">订单列表</el-dropdown-item>
<el-dropdown-item command="win">中奖名单</el-dropdown-item>
<el-dropdown-item command="exchange">核销记录</el-dropdown-item>
<el-dropdown-item command="code">活动链接</el-dropdown-item>
</el-dropdown-menu>
<el-dropdown-menu v-else>
<el-dropdown-item command="order">订单列表</el-dropdown-item>
<el-dropdown-item command="win" v-if="row.groups == 1">
中奖名单
</el-dropdown-item>
<el-dropdown-item command="code">活动链接</el-dropdown-item>
</el-dropdown-menu>
</template>
@@ -321,6 +324,9 @@
} else if (command === 'win') {
url = '/sylive/groups-win?id=' + row.activityId;
this.$router.replace(url);
} else if (command === 'exchange') {
url = '/sylive/groups-exchange?id=' + row.activityId;
this.$router.replace(url);
} else if (command === 'code') {
this.current = row;
this.showCode = true;
@@ -80,6 +80,12 @@
class="ele-fluid"
/>
</el-form-item>
<el-form-item label="需核销码:">
<el-radio-group v-model="form.ifCode">
<el-radio :label="0"></el-radio>
<el-radio :label="1"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="收货地址:">
<el-radio-group v-model="form.ifAddress">
<el-radio :label="0">不需要</el-radio>
@@ -141,6 +147,7 @@
useRange: '',
sort: 0,
ifAddress: 0,
ifCode: 0,
descrip: ''
};
return {
@@ -0,0 +1,92 @@
<!-- 详情弹窗 -->
<template>
<ele-modal
title="操作详情"
width="680px"
:visible="visible"
@update:visible="updateVisible"
>
<el-form
v-for="(item, index) in data"
:key="index"
size="mini"
label-width="82px"
class="ele-form-detail"
>
<el-row :gutter="15">
<el-col v-bind="styleResponsive ? { sm: 12 } : { span: 12 }">
<el-form-item label="审核人:">
<div class="ele-text-secondary">
{{ item.adminName }}
</div>
</el-form-item>
<el-form-item label="审核时间:">
<div class="ele-text-secondary">
{{ item.adminTime }}
</div>
</el-form-item>
<el-form-item label="审核状态:">
<div class="ele-text-secondary">
{{ item.ifCheckName }}
</div>
</el-form-item>
</el-col>
<el-col v-bind="styleResponsive ? { sm: 12 } : { span: 12 }">
<el-form-item label="申请人:">
<div class="ele-text-secondary">
{{ item.cfName }}
</div>
</el-form-item>
<el-form-item label="申请时间:">
<div class="ele-text-secondary">
{{ item.cfTime }}
</div>
</el-form-item>
<el-form-item label="描述:" v-if="item.descrip">
<el-input
disabled="true"
v-model="item.descrip"
:rows="2"
type="textarea"
/>
</el-form-item>
</el-col>
</el-row>
<el-form-item v-if="item.logistics.length > 0" label="物流信息:">
<text-ellipsis :content="item.logistics" class="ele-text-secondary" />
</el-form-item>
<div style="margin: 12px 0" v-if="index != 0">
<el-divider />
</div>
</el-form>
<template v-slot:footer>
<el-button @click="updateVisible(false)">关闭</el-button>
</template>
</ele-modal>
</template>
<script>
import TextEllipsis from './text-ellipsis.vue';
export default {
components: { TextEllipsis },
props: {
// 弹窗是否打开
visible: Boolean,
// 数据
data: []
},
computed: {
// 是否开启响应式布局
styleResponsive() {
return this.$store.state.theme.styleResponsive;
}
},
methods: {
/* 更新visible */
updateVisible(value) {
this.$emit('update:visible', value);
}
}
};
</script>
@@ -0,0 +1,99 @@
<!-- 用户导入弹窗 -->
<template>
<ele-modal
width="520px"
title="导入审核"
:visible="visible"
@update:visible="updateVisible"
>
<el-upload
drag
action=""
class="ele-block"
v-loading="loading"
accept=".xls,.xlsx"
:show-file-list="false"
:before-upload="doUpload"
>
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处, <em>点击上传</em></div>
<template v-slot:tip>
<div class="el-upload__tip ele-text-center">
<span>只能上传xlsxlsx文件, </span>
<el-link
download
:href="url"
type="primary"
:underline="false"
style="vertical-align: baseline"
>
下载模板
</el-link>
</div>
</template>
</el-upload>
</ele-modal>
</template>
<script>
import { importGroupsExchange } from '@/api/sylive/groups-exchange';
export default {
props: {
// 是否打开弹窗
visible: Boolean
},
data() {
return {
// 导入请求状态
loading: false,
// 导入模板下载地址
url: 'http://market.dev.liche.cn/temp/exchange.xlsx'
};
},
methods: {
/* 上传 */
doUpload(file) {
if (
![
'application/vnd.ms-excel',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
].includes(file.type)
) {
this.$message.error('只能选择 excel 文件');
return false;
}
if (file.size / 1024 / 1024 > 5) {
this.$message.error('大小不能超过 5MB');
return false;
}
this.loading = true;
importGroupsExchange(file)
.then((msg) => {
this.loading = false;
this.$message.success(msg);
this.updateVisible(false);
this.$emit('done');
})
.catch((e) => {
this.loading = false;
this.$message.error(e.message);
});
return false;
},
/* 更新visible */
updateVisible(value) {
this.$emit('update:visible', value);
}
}
};
</script>
<style lang="scss" scoped>
.ele-block {
:deep(.el-upload),
:deep(.el-upload-dragger) {
width: 100%;
}
}
</style>
@@ -0,0 +1,183 @@
<!-- 搜索表单 -->
<template>
<el-form
label-width="77px"
class="ele-form-search"
@keyup.enter.native="search"
@submit.native.prevent
>
<el-row :gutter="15">
<el-col v-bind="styleResponsive ? { lg: 5, md: 10 } : { span: 5 }">
<el-form-item label="门店:">
<ele-tree-select
:data="groupsList"
label-key="groupsName"
value-key="groupsId"
v-model="where.bizId"
:clearable="true"
placeholder="请选择"
:disabled="false"
:default-expand-all="false"
:expand-on-click-node="false"
/>
</el-form-item>
</el-col>
<el-col v-bind="styleResponsive ? { lg: 5, md: 10 } : { span: 5 }">
<el-form-item label="商品:">
<el-select
clearable
v-model="where.itemId"
placeholder="请选择"
class="ele-fluid"
>
<el-option
v-for="item in goodsList"
:key="item.itemId"
:value="item.itemId"
:label="item.title"
/>
</el-select>
</el-form-item>
</el-col>
<el-col v-bind="styleResponsive ? { lg: 5, md: 10 } : { span: 5 }">
<el-form-item label="姓名:">
<el-input clearable v-model="where.uname" placeholder="请输入" />
</el-form-item>
</el-col>
<el-col v-bind="styleResponsive ? { lg: 5, md: 10 } : { span: 5 }">
<el-form-item label="手机号:">
<el-input clearable v-model="where.mobile" placeholder="请输入" />
</el-form-item>
</el-col>
<el-col v-bind="styleResponsive ? { lg: 5, md: 10 } : { span: 5 }">
<el-form-item label="核销类型:">
<el-select
clearable
v-model="where.useType"
placeholder="请选择"
class="ele-fluid"
>
<el-option label="订单" :value="0" />
<el-option label="抽奖" :value="1" />
</el-select>
</el-form-item>
</el-col>
<el-col v-bind="styleResponsive ? { lg: 5, md: 10 } : { span: 5 }">
<el-form-item label="状态:">
<el-select
clearable
v-model="where.useStatus"
placeholder="请选择"
class="ele-fluid"
>
<el-option label="审核中" :value="1" />
<el-option label="通过" :value="2" />
<el-option label="驳回" :value="3" />
</el-select>
</el-form-item>
</el-col>
<el-col v-bind="styleResponsive ? { lg: 4, md: 8 } : { span: 4 }">
<div class="ele-form-actions">
<el-button
type="primary"
icon="el-icon-search"
class="ele-btn-icon"
@click="search"
>
查询
</el-button>
<el-button @click="reset">重置</el-button>
</div>
</el-col>
</el-row>
</el-form>
</template>
<script>
import { listGroups } from '@/api/sylive/groups';
import { listGoods } from '@/api/sylive/goods';
export default {
data() {
// 默认表单数据
const defaultWhere = {
uname: '',
mobile: '',
useType: 0,
bizId: ''
};
return {
activityId: null,
// 门店数据
groupsList: [],
// 商品数据
goodsList: [],
// 表单数据
where: { ...defaultWhere }
};
},
computed: {
// 是否开启响应式布局
styleResponsive() {
return this.$store.state.theme.styleResponsive;
}
},
created() {},
methods: {
/* 搜索 */
search() {
this.$emit('search', this.where);
},
/* 重置 */
reset() {
this.where = { ...this.defaultWhere };
this.search();
},
/* 查询分组 */
groupsQuery() {
listGroups({ activityId: this.activityId })
.then((list) => {
this.groupsList = this.$util.toTreeData({
data: list,
idField: 'groupsId',
parentIdField: 'parentId'
});
})
.catch((e) => {
this.$message.error(e.message);
});
},
/* 查询商品 */
goodsQuery() {
listGoods({ activityId: this.activityId })
.then((list) => {
this.goodsList = list;
})
.catch((e) => {
this.$message.error(e.message);
});
}
},
watch: {
$route: {
handler(route) {
const { path } = route;
if (path !== '/sylive/groups-exchange') {
return;
}
const activityId = this.$route.query.id;
if (!activityId || activityId == this.activityId) {
return;
}
this.activityId = activityId;
if (this.$refs.table) {
this.$refs.table.reload({ page: 1 });
}
this.groupsQuery();
this.goodsQuery();
},
immediate: true
}
}
};
</script>
@@ -0,0 +1,114 @@
<!-- 用户编辑弹窗 -->
<template>
<ele-modal
width="750px"
:visible="visible"
:append-to-body="true"
:close-on-click-modal="true"
custom-class="ele-dialog-form"
:title="form.useStatus == 2 ? '审核通过' : '审核驳回'"
@update:visible="updateVisible"
>
<el-form ref="form" :model="form" label-width="82px">
<el-form-item label="物流单号:" prop="title" v-if="form.useStatus == 2">
<el-input
clearable
:maxlength="60"
v-model="form.descrip"
placeholder="请输入物流单号"
/>
</el-form-item>
<el-form-item label="驳回理由:" prop="title" v-else>
<el-input
clearable
v-model="form.descrip"
:rows="2"
type="textarea"
placeholder="请输入驳回理由"
/>
</el-form-item>
</el-form>
<template v-slot:footer>
<el-button @click="updateVisible(false)">取消</el-button>
<el-button type="primary" :loading="loading" @click="save">
保存
</el-button>
</template>
</ele-modal>
</template>
<script>
import { updateGroupsExchangeUseStatus } from '@/api/sylive/groups-exchange';
export default {
props: {
// 弹窗是否打开
visible: Boolean,
// 修改回显的数据
data: Object
},
data() {
const defaultForm = {
cfId: null,
type: null,
useStatus: 0,
descrip: ''
};
return {
defaultForm,
// 表单数据
form: { ...defaultForm },
// 提交状态
loading: false
};
},
computed: {
// 是否开启响应式布局
styleResponsive() {
return this.$store.state.theme.styleResponsive;
}
},
methods: {
/* 保存编辑 */
save() {
this.$refs.form.validate((valid) => {
if (!valid) {
return false;
}
this.loading = true;
const data = {
...this.form
};
updateGroupsExchangeUseStatus(data)
.then((msg) => {
this.loading = false;
this.$message.success(msg);
this.updateVisible(false);
this.$emit('done');
})
.catch((e) => {
this.loading = false;
this.$message.error(e.message);
});
});
},
/* 更新visible */
updateVisible(value) {
this.$emit('update:visible', value);
}
},
watch: {
visible(visible) {
if (visible) {
if (this.data.cfId) {
this.$util.assignObject(this.form, {
...this.data
});
}
} else {
this.$refs.form.clearValidate();
this.form = { ...this.defaultForm };
}
}
}
};
</script>
@@ -0,0 +1,69 @@
<!-- 文本超出隐藏 -->
<template>
<div
:class="[
'demo-text-ellipsis ele-bg-white ele-border-lighter',
{ expanded: expanded }
]"
>
<div>
<table>
<tr v-for="(item, index) in content" :key="index">
<td>
<b>{{ item.time }}</b>{{ item.status }}
</td>
</tr>
</table>
</div>
<div
class="demo-text-ellipsis-footer ele-border-lighter ele-bg-white"
@click="expanded = !expanded"
>
<i :class="expanded ? 'el-icon-arrow-up' : 'el-icon-arrow-down'"></i>
</div>
</div>
</template>
<script>
export default {
props: {
content: []
},
data() {
return {
expanded: false
};
}
};
</script>
<style lang="scss" scoped>
.demo-text-ellipsis {
border-radius: 4px;
padding: 6px 12px 20px 12px;
position: relative;
border-width: 1px;
border-style: solid;
word-break: break-all;
&:not(.expanded) {
max-height: 128px;
overflow: hidden;
}
}
.demo-text-ellipsis-footer {
border-top-width: 1px;
border-top-style: solid;
position: absolute;
bottom: 0;
left: 0;
right: 0;
line-height: 1.3;
text-align: center;
font-size: 14px;
cursor: pointer;
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
}
</style>
+342
View File
@@ -0,0 +1,342 @@
<template>
<div class="ele-body">
<el-card shadow="never">
<!-- 搜索表单 -->
<gro-exchange-search @search="reload" />
<!-- 数据表格 -->
<ele-pro-table
ref="table"
:columns="columns"
:datasource="datasource"
cache-key="syliveExchangeTable"
>
<!-- 表头工具栏 -->
<template v-slot:toolbar>
<el-button
size="small"
type="primary"
class="ele-btn-icon"
icon="el-icon-dexchangeload"
@click="exportData"
>
导出核销
</el-button>
<el-button
size="small"
icon="el-icon-upload2"
class="ele-btn-icon"
@click="openImport"
>
导入审核
</el-button>
</template>
<template v-slot:useStatus="{ row }">
<span
:class="row.useStatus == 2 ? 'ele-text-success' : 'ele-text-danger'"
>
{{ row.useStatusName }}
</span>
</template>
<template v-slot:action="{ row }">
<el-link
v-if="row.useStatus != 1"
type="primary"
:underline="false"
icon="el-icon-view"
@click="openDetail(row)"
>
详情
</el-link>
<el-link
v-if="row.useStatus == 1"
type="primary"
:underline="false"
icon="el-icon-finished"
@click="setStatus(row, 2)"
>
通过
</el-link>
<el-link
v-if="row.useStatus == 1"
type="danger"
:underline="false"
icon="el-icon-circle-close"
@click="setStatus(row, 3)"
>
驳回
</el-link>
</template>
</ele-pro-table>
</el-card>
<!-- 详情弹窗 -->
<gro-exchange-detail :visible.sync="showDetail" :data="current" />
<!-- 导入弹窗 -->
<gro-exchange-import :visible.sync="showImport" @done="reload" />
<!-- 审核弹窗 -->
<gro-exchange-status
:visible.sync="showStatus"
:data="currentStatus"
@done="reload"
/>
</div>
</template>
<script>
import { setPageTabTitle } from '@/utils/page-tab-util';
import GroExchangeSearch from './components/gro-exchange-search.vue';
import { getActivity } from '@/api/sylive/activity';
import {
getGroupsExchangeDetail,
listGroupsExchange,
exportGroupsExchange
} from '@/api/sylive/groups-exchange';
import { utils, writeFile } from 'xlsx';
import GroExchangeDetail from './components/gro-exchange-detail.vue';
import GroExchangeStatus from './components/gro-exchange-status';
import GroExchangeImport from './components/gro-exchange-import';
const ROUTE_PATH = '/sylive/groups-exchange';
export default {
name: 'syliveGroupsExchange',
components: {
GroExchangeImport,
GroExchangeStatus,
GroExchangeDetail,
GroExchangeSearch
},
data() {
return {
activityId: null,
// 加载状态
title: '核销记录',
loading: true,
showDetail: false,
showStatus: false,
showImport: false,
current: [],
currentStatus: {},
useType: 0,
// 表格列配置
columns: [
{
prop: 'id',
label: 'ID',
minWidth: 45,
align: 'center',
showOverflowTooltip: true,
fixed: 'left'
},
{
prop: 'uname',
label: '姓名',
showOverflowTooltip: true,
minWidth: 60
},
{
prop: 'mobile',
label: '手机号',
showOverflowTooltip: true,
minWidth: 80
},
{
prop: 'itemTitle',
label: '商品标题',
showOverflowTooltip: true,
minWidth: 130
},
{
prop: 'totalPrice',
label: '订单价格',
showOverflowTooltip: true,
minWidth: 60
},
{
prop: 'consultant',
label: '顾问',
showOverflowTooltip: true,
minWidth: 60
},
{
prop: 'levelName1',
label: '战区',
showOverflowTooltip: true,
minWidth: 80
},
{
prop: 'levelName2',
label: '战队',
showOverflowTooltip: true,
minWidth: 80
},
{
prop: 'stores',
label: '门店',
showOverflowTooltip: true,
minWidth: 80
},
{
prop: 'exchangeName',
label: '核销类型',
align: 'center',
showOverflowTooltip: true,
minWidth: 60
},
{
prop: 'useStatus',
label: '状态',
align: 'center',
showOverflowTooltip: true,
minWidth: 60,
slot: 'useStatus'
},
{
columnKey: 'action',
label: '操作',
align: 'center',
showOverflowTooltip: true,
width: 150,
resizable: false,
slot: 'action'
}
]
};
},
methods: {
/* 打开导入弹窗 */
openImport() {
this.showImport = true;
},
/* 详情 */
openDetail(row) {
getGroupsExchangeDetail({ cfId: row.id, type: this.useType })
.then((list) => {
this.current = list;
})
.catch((e) => {
this.$message.error(e.message);
});
this.showDetail = true;
},
setStatus(row, status) {
this.showStatus = true;
this.currentStatus = {
cfId: row.id,
type: this.useType,
useStatus: status,
descrip: ''
};
},
/* 表格数据源 */
datasource({ page, limit, where, order }) {
const activityId = this.activityId;
this.useType = where ? where.useType : 0;
return listGroupsExchange({
...where,
...order,
page,
limit,
activityId
});
},
query() {
this.loading = true;
getActivity(Number(this.activityId))
.then((data) => {
this.loading = false;
// 修改页签标题
if (this.$route.path === ROUTE_PATH) {
this.title = data.title + '的核销记录';
setPageTabTitle(this.title);
}
})
.catch((e) => {
this.loading = false;
this.$message.error(e.message);
});
},
/* 刷新表格 */
reload(where) {
this.useType = where ? where.useType : 0;
this.$refs.table.reload({ page: 1, where: where });
},
/* 导出数据 */
exportData() {
const array = [
[
'订单号',
'姓名',
'手机号',
'商品标题',
'订单价格',
'顾问',
'战区',
'战队',
'门店',
'核销类型',
'状态',
'所选经销商',
'地址'
]
];
const loading = this.$loading({ lock: true });
this.$refs.table.doRequest(({ where, order }) => {
const activityId = this.activityId;
exportGroupsExchange({ ...where, ...order, activityId })
.then((data) => {
loading.close();
data.forEach((d) => {
array.push([
d.sid,
d.uname,
d.mobile,
d.itemTitle,
d.totalPrice,
d.consultant,
d.levelName1,
d.levelName2,
d.stores,
d.exchangeName,
d.useStatusName,
d.biz,
d.address
]);
});
writeFile(
{
SheetNames: ['Sheet1'],
Sheets: {
Sheet1: utils.aoa_to_sheet(array)
}
},
this.title + '.xlsx'
);
})
.catch((e) => {
loading.close();
this.$message.error(e.message);
});
});
}
},
watch: {
$route: {
handler(route) {
const { path } = route;
if (path !== ROUTE_PATH) {
return;
}
const activityId = this.$route.query.id;
if (!activityId || activityId == this.activityId) {
return;
}
this.activityId = activityId;
this.query();
if (this.$refs.table) {
this.$refs.table.reload({ page: 1 });
}
},
immediate: true
}
}
};
</script>