增加发送优惠券

This commit is contained in:
lccsw
2025-12-05 14:59:44 +08:00
parent d6db947a6f
commit fd6ce7c799
4 changed files with 520 additions and 321 deletions
+16
View File
@@ -99,3 +99,19 @@ export async function exportProduct(params) {
}
return Promise.reject(new Error(res.data.message));
}
/**
* 优惠券列表
* @param params
* @returns {Promise<*>}
*/
export async function pageCouponList(params) {
const res = await request.get('/car/product/couponList', {
params
});
if (res.data.code === 0) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
+13
View File
@@ -98,3 +98,16 @@ export async function updateLevel(data) {
}
return Promise.reject(new Error(res.data.message));
}
/**
* 发送优惠券
* @param data
* @returns {Promise<*>}
*/
export async function sendCoupon(data) {
const res = await request.post('/receiver/clues/sendCoupon', data);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
@@ -0,0 +1,152 @@
<!-- 用户导入弹窗 -->
<template>
<ele-modal
width="520px"
title="发送优惠券"
:visible="visible"
@update:visible="updateVisible"
>
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
<el-form-item label="线索编号:" prop="title">
<el-input
:maxlength="60"
v-model="form.sid"
placeholder=""
readonly
/>
</el-form-item>
<el-form-item label="用户手机号:" prop="title">
<el-input
:maxlength="60"
v-model="form.mobile"
placeholder=""
readonly
/>
</el-form-item>
<el-form-item label="品牌:">
<brand-select
v-model="brands"
type="provinceCity"
:props="{ multiple: false }"
/>
</el-form-item>
<el-form-item label="优惠券:" prop="couponId">
<el-select v-model="form.couponId" filterable clearable>
<el-option
v-for="item in couponList"
:key="item.id"
:value="item.id"
:label="item.title"
/>
</el-select>
</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 { pageCouponList } from '@/api/car/product'
import { sendCoupon } from '@/api/receiver/clues'
import BrandSelect from '@/components/BrandSelect/index.vue'
export default {
components: { BrandSelect },
props: {
// 是否打开弹窗
visible: Boolean,
// 修改回显的数据
data: Object
},
data() {
const defaultForm = {
id: null,
cityId: '',
sid: '',
mobile: '',
couponId: ''
}
return {
defaultForm,
editVersion: false,
form: { ...defaultForm },
// 表单验证规则
rules: {
couponId: [
{
required: true,
message: '请选择优惠券',
trigger: 'blur'
}
]
},
loading: false,
brands: [],
couponList: [],
}
},
methods: {
save() {
this.$refs.form.validate((valid) => {
if (!valid) {
return false
}
this.loading = true
sendCoupon(this.form).then((msg) => {
this.$message.success(msg)
this.updateVisible(false);
}).catch((e) => {
this.$message.error(e.message)
}).finally(() => {
this.loading = false
})
})
},
//加载优惠券
loadCouponList() {
this.couponList = []
this.form.couponId = ''
if (this.brands && this.brands.length > 0) {
pageCouponList({ brands: this.brands, cityId: this.form.cityId }).then((data) => {
this.couponList = data
}).catch((e) => {
this.$message.error(e.message)
})
}
},
/* 更新visible */
updateVisible(value) {
this.$emit('update:visible', value)
}
},
watch: {
visible(visible) {
this.editVersion = false
if (visible) {
this.editVersion = true
if (this.data) {
this.$util.assignObject(this.form, {
...this.data
})
}
} else {
this.$refs.form.clearValidate()
this.form = { ...this.defaultForm }
}
},
brands() {
this.loadCouponList()
}
}
}
</script>
<style lang="scss" scoped>
</style>
+339 -321
View File
@@ -147,7 +147,8 @@
icon="el-icon-download"
type="primary"
@click="exportData"
>导出</el-button
>导出
</el-button
>
</div>
</el-col>
@@ -182,12 +183,13 @@
</template>
<template v-slot:brandSeries="{ row }">
<div v-for="(item, index) in row.brandList" :key="index">{{
item
}}</div>
item
}}
</div>
</template>
<template v-slot:status="{ row }">
{{ row.statusCn }}
<template v-if="row.isUnlock"> <br />{{ row.isUnlock }} </template>
<template v-if="row.isUnlock"><br/>{{ row.isUnlock }}</template>
</template>
<template v-slot:level="{ row }">
<el-select
@@ -213,342 +215,358 @@
>
拨打电话
</el-button>
<el-button
size="small"
type="primary"
:underline="false"
@click="showSendCoupon(row)"
>
发券
</el-button>
</template>
</ele-pro-table>
<send-coupon :visible.sync="visibleSendCoupon" :data="current"/>
</el-card>
</div>
</template>
<script>
import {
pageClues,
getSearch,
callPhone,
exportClues,
updateLevel
} from '@/api/receiver/clues';
import RegionsSelect from '@/components/RegionsSelect/index.vue';
import BrandSelect from '@/components/BrandSelect/index.vue';
import { pageCenterList, pageOrgNameList } from '@/api/auto';
import { utils, writeFile } from 'xlsx';
import {
pageClues,
getSearch,
callPhone,
exportClues,
updateLevel
} from '@/api/receiver/clues'
import RegionsSelect from '@/components/RegionsSelect/index.vue'
import BrandSelect from '@/components/BrandSelect/index.vue'
import sendCoupon from '@/views/receiver/clues/components/send-coupon.vue'
import { pageCenterList, pageOrgNameList } from '@/api/auto'
import { utils, writeFile } from 'xlsx'
export default {
name: 'receiverClues',
components: { RegionsSelect, BrandSelect },
data() {
return {
where: {
title: '',
citys: [],
brands: [],
belong: [],
userCode: '',
centerNumber: '',
orgName: '',
level: ''
export default {
name: 'receiverClues',
components: { RegionsSelect, BrandSelect, sendCoupon },
data() {
return {
where: {
title: '',
citys: [],
brands: [],
belong: [],
userCode: '',
centerNumber: '',
orgName: '',
level: ''
},
// 表格列配置
columns: [
{
prop: 'customer',
label: '线索',
width: 220,
align: 'center',
fixed: 'left',
slot: 'customer'
},
// 表格列配置
columns: [
{
prop: 'level',
label: '客户等级',
align: 'center',
showOverflowTooltip: true,
width: 100,
slot: 'level'
},
{
prop: 'belongUserName',
label: '归属',
align: 'center',
showOverflowTooltip: true,
minWidth: 150,
slot: 'belongUserName'
},
{
prop: 'centerNumber',
label: '中心',
align: 'center',
showOverflowTooltip: true,
width: 100,
slot: 'centerNumber'
},
{
prop: 'orgName',
label: '机构',
align: 'center',
showOverflowTooltip: true,
width: 100,
slot: 'orgName'
},
{
prop: 'brandSeries',
label: '关注车型',
align: 'center',
minWidth: 200,
resizable: false,
showOverflowTooltip: true,
slot: 'brandSeries'
},
{
prop: 'statusCn',
label: '状态',
align: 'center',
showOverflowTooltip: true,
width: 130,
slot: 'status'
},
{
prop: 'poi',
label: '所属地区',
align: 'center',
minWidth: 120
},
{
prop: 'enTime',
label: '入池时间',
align: 'center',
minWidth: 100,
resizable: false
},
{
prop: 'action',
label: '操作',
align: 'center',
width: 170,
slot: 'action',
fixed: 'right'
}
],
// 表格选中数据
selection: [],
// 当前编辑数据
current: null,
// 是否显示编辑弹窗
showEdit: false,
// 日期时间选择器快捷项
pickerOptions: {
shortcuts: [
{
prop: 'customer',
label: '线索',
width: 220,
align: 'center',
fixed: 'left',
slot: 'customer'
},
{
prop: 'level',
label: '客户等级',
align: 'center',
showOverflowTooltip: true,
width: 100,
slot: 'level'
},
{
prop: 'belongUserName',
label: '归属',
align: 'center',
showOverflowTooltip: true,
minWidth: 150,
slot: 'belongUserName'
},
{
prop: 'centerNumber',
label: '中心',
align: 'center',
showOverflowTooltip: true,
width: 100,
slot: 'centerNumber'
},
{
prop: 'orgName',
label: '机构',
align: 'center',
showOverflowTooltip: true,
width: 100,
slot: 'orgName'
},
{
prop: 'brandSeries',
label: '关注车型',
align: 'center',
minWidth: 200,
resizable: false,
showOverflowTooltip: true,
slot: 'brandSeries'
},
{
prop: 'statusCn',
label: '状态',
align: 'center',
showOverflowTooltip: true,
width: 130,
slot: 'status'
},
{
prop: 'poi',
label: '所属地区',
align: 'center',
minWidth: 120
},
{
prop: 'enTime',
label: '入池时间',
align: 'center',
minWidth: 100,
resizable: false
},
{
prop: 'action',
label: '操作',
align: 'center',
width: 100,
slot: 'action',
fixed: 'right'
}
],
// 表格选中数据
selection: [],
// 当前编辑数据
current: null,
// 是否显示编辑弹窗
showEdit: false,
// 日期时间选择器快捷项
pickerOptions: {
shortcuts: [
{
text: '今天',
onClick(picker) {
const end = new Date();
const start = new Date();
picker.$emit('pick', [start, end]);
}
},
{
text: '昨天',
onClick(picker) {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24);
end.setTime(end.getTime() - 3600 * 1000 * 24);
picker.$emit('pick', [start, end]);
}
},
{
text: '最近一周',
onClick(picker) {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
picker.$emit('pick', [start, end]);
}
},
{
text: '最近一个月',
onClick(picker) {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
picker.$emit('pick', [start, end]);
}
},
{
text: '最近三个月',
onClick(picker) {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
picker.$emit('pick', [start, end]);
}
text: '今天',
onClick(picker) {
const end = new Date()
const start = new Date()
picker.$emit('pick', [start, end])
}
]
},
belongOptions: [],
statusList: [],
centerList: [],
orgNameList: [],
levelList: [],
title: '线索列表'
};
},
{
text: '昨天',
onClick(picker) {
const end = new Date()
const start = new Date()
start.setTime(start.getTime() - 3600 * 1000 * 24)
end.setTime(end.getTime() - 3600 * 1000 * 24)
picker.$emit('pick', [start, end])
}
},
{
text: '最近一周',
onClick(picker) {
const end = new Date()
const start = new Date()
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)
picker.$emit('pick', [start, end])
}
},
{
text: '最近一个月',
onClick(picker) {
const end = new Date()
const start = new Date()
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
picker.$emit('pick', [start, end])
}
},
{
text: '最近三个月',
onClick(picker) {
const end = new Date()
const start = new Date()
start.setTime(start.getTime() - 3600 * 1000 * 24 * 90)
picker.$emit('pick', [start, end])
}
}
]
},
belongOptions: [],
statusList: [],
centerList: [],
orgNameList: [],
levelList: [],
title: '线索列表',
visibleSendCoupon: false
}
},
created() {
this.loadSearch()
this.loadCenterList()
this.loadOrgNameList()
},
computed: {
// 是否开启响应式布局
styleResponsive() {
return this.$store.state.theme.styleResponsive
}
},
methods: {
loadOrgNameList() {
pageOrgNameList()
.then((data) => {
this.orgNameList = data
})
.catch((e) => {
this.$message.error(e.message)
})
},
created() {
this.loadSearch();
this.loadCenterList();
this.loadOrgNameList();
loadCenterList() {
pageCenterList()
.then((data) => {
this.centerList = data
})
.catch((e) => {
this.$message.error(e.message)
})
},
computed: {
// 是否开启响应式布局
styleResponsive() {
return this.$store.state.theme.styleResponsive;
loadSearch() {
getSearch()
.then((data) => {
this.statusList = data.statusList
this.belongOptions = data.belongList
this.levelList = data.levelList
})
.catch((e) => {
this.$message.error(e.message)
})
},
/* 下拉按钮点击 */
dropClick(command, row) {
if (command === 'edit') {
this.current = row
this.showEdit = true
} else if (command === 'brokerage') {
this.current = row
this.showEditBrokerage = true
} else if (command === 'coupon') {
const path = '/car/product/coupon'
this.$nextTick(() => {
this.$router.push({
path,
query: row ? { id: row.id, title: row.title } : undefined
})
})
}
},
methods: {
loadOrgNameList() {
pageOrgNameList()
.then((data) => {
this.orgNameList = data;
})
.catch((e) => {
this.$message.error(e.message);
});
},
loadCenterList() {
pageCenterList()
.then((data) => {
this.centerList = data;
})
.catch((e) => {
this.$message.error(e.message);
});
},
loadSearch() {
getSearch()
.then((data) => {
this.statusList = data.statusList;
this.belongOptions = data.belongList;
this.levelList = data.levelList;
})
.catch((e) => {
this.$message.error(e.message);
});
},
/* 下拉按钮点击 */
dropClick(command, row) {
if (command === 'edit') {
this.current = row;
this.showEdit = true;
} else if (command === 'brokerage') {
this.current = row;
this.showEditBrokerage = true;
} else if (command === 'coupon') {
const path = '/car/product/coupon';
this.$nextTick(() => {
this.$router.push({
path,
query: row ? { id: row.id, title: row.title } : undefined
});
});
}
},
goDetail(row) {
const path = '/receiver/clues/detail';
this.$router.push({
path,
query: row ? { id: row.id, title: row.title } : undefined
});
},
/* 表格数据源 */
datasource({ page, limit, where, order }) {
return pageClues({ ...where, ...order, page, limit });
},
/* 刷新表格 */
reload() {
this.$refs.table.reload({ page: 1, where: this.where });
},
/* 重置搜索 */
reset() {
this.where = {};
this.reload();
},
/* 拨打电话 */
call(row) {
this.$confirm('确定拨打电话【' + row.mobile + '】吗?', '提示', {
type: 'warning'
})
.then(() => {
const loading = this.$loading({ lock: true });
callPhone({ id: row.id })
.then((msg) => {
loading.close();
this.$message.success(msg);
})
.catch((e) => {
loading.close();
this.$message.error(e.message);
});
})
.catch(() => {});
},
exportData() {
const loading = this.$loading({ lock: true });
this.$refs.table.doRequest(({ where, order }) => {
exportClues({ ...where, ...order })
.then((data) => {
loading.close();
const array = [data.columns];
data.list.forEach((d) => {
let arrayItem = [];
for (let key in d) {
arrayItem.push(d[key]);
}
array.push(arrayItem);
});
writeFile(
{
SheetNames: ['Sheet1'],
Sheets: {
Sheet1: utils.aoa_to_sheet(array)
}
},
this.title + '.xlsx'
);
goDetail(row) {
const path = '/receiver/clues/detail'
this.$router.push({
path,
query: row ? { id: row.id, title: row.title } : undefined
})
},
/* 表格数据源 */
datasource({ page, limit, where, order }) {
return pageClues({ ...where, ...order, page, limit })
},
/* 刷新表格 */
reload() {
this.$refs.table.reload({ page: 1, where: this.where })
},
/* 重置搜索 */
reset() {
this.where = {}
this.reload()
},
/* 拨打电话 */
call(row) {
this.$confirm('确定拨打电话【' + row.mobile + '】吗?', '提示', {
type: 'warning'
})
.then(() => {
const loading = this.$loading({ lock: true })
callPhone({ id: row.id })
.then((msg) => {
loading.close()
this.$message.success(msg)
})
.catch((e) => {
loading.close();
this.$message.error(e.message);
});
});
},
handleLevelChange(value, row) {
this.$confirm(
`确定要将【"${row.mobile}"】客户等级修改为"${value}"吗?`,
'提示',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}
)
.then(() => {
updateLevel({ id: row.id, level: value })
.then((msg) => {
this.$message.success(msg);
})
.catch((e) => {
this.$message.error(e.message);
});
loading.close()
this.$message.error(e.message)
})
})
.catch(() => {
})
},
exportData() {
const loading = this.$loading({ lock: true })
this.$refs.table.doRequest(({ where, order }) => {
exportClues({ ...where, ...order })
.then((data) => {
loading.close()
const array = [data.columns]
data.list.forEach((d) => {
let arrayItem = []
for (let key in d) {
arrayItem.push(d[key])
}
array.push(arrayItem)
})
writeFile(
{
SheetNames: ['Sheet1'],
Sheets: {
Sheet1: utils.aoa_to_sheet(array)
}
},
this.title + '.xlsx'
)
})
.catch(() => {
// 用户取消操作,恢复原值
});
}
.catch((e) => {
loading.close()
this.$message.error(e.message)
})
})
},
handleLevelChange(value, row) {
this.$confirm(
`确定要将【"${row.mobile}"】客户等级修改为"${value}"吗?`,
'提示',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}
)
.then(() => {
updateLevel({ id: row.id, level: value })
.then((msg) => {
this.$message.success(msg)
})
.catch((e) => {
this.$message.error(e.message)
})
})
.catch(() => {
// 用户取消操作,恢复原值
})
},
showSendCoupon(row) {
this.current = row
this.visibleSendCoupon = true
}
};
}
}
</script>
<style scoped>
::v-deep .el-cascader__tags input::-webkit-input-placeholder {
color: white;
opacity: 0;
}
::v-deep .el-cascader__tags input::-webkit-input-placeholder {
color: white;
opacity: 0;
}
</style>