完成积分模块
This commit is contained in:
159
src/api/points/index.js
Normal file
159
src/api/points/index.js
Normal file
@@ -0,0 +1,159 @@
|
||||
import request from "@/utils/request";
|
||||
const market_baseURL = "/market";
|
||||
const order_baseURL = "/order";
|
||||
|
||||
/**
|
||||
* 积分:配置:详情
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function pointsConfigGet(params) {
|
||||
return request({
|
||||
url: `${market_baseURL}/admin/points/config`,
|
||||
method: "get",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 积分:配置:新增/更新
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function pointsConfigPost(data) {
|
||||
return request({
|
||||
url: `${market_baseURL}/admin/points/config`,
|
||||
method: "post",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 积分:商品:新增/修改
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function pointsGoodsPost(data) {
|
||||
return request({
|
||||
url: `${market_baseURL}/admin/pointsGoods`,
|
||||
method: "post",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 积分:商品:列表
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function pointsGoodsPage(params) {
|
||||
return request({
|
||||
url: `${market_baseURL}/admin/pointsGoods/page`,
|
||||
method: "get",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 积分-商品-删除
|
||||
* @param {*} id
|
||||
* @returns
|
||||
*/
|
||||
export function pointsGoodsDel(id) {
|
||||
return request({
|
||||
url: `${market_baseURL}/admin/pointsGoods/${id}`,
|
||||
method: "delete"
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 积分:积分商品:兑换记录
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function goodsRecordPage(params) {
|
||||
return request({
|
||||
url: `${order_baseURL}/admin/points/goodsRecord/page`,
|
||||
method: "get",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 积分:积分商品:兑换统计
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function goodsRecordTotal(params) {
|
||||
return request({
|
||||
url: `${order_baseURL}/admin/points/goodsRecord/total`,
|
||||
method: "get",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 积分:积分商品:兑换统计
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function pointsUserPage(params) {
|
||||
return request({
|
||||
url: `${market_baseURL}/admin/points/userPage`,
|
||||
method: "get",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 积分:用户:积分详情
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function pointsUserRecord(params) {
|
||||
return request({
|
||||
url: `${market_baseURL}/admin/points/userRecord`,
|
||||
method: "get",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 积分:商品:商家核销
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function goodsRecordCheckout(data) {
|
||||
return request({
|
||||
url: `${order_baseURL}/admin/points/goodsRecord/checkout`,
|
||||
method: "post",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 积分:商家 退单/同意退单
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function goodsRecordAgreeRefund(data) {
|
||||
return request({
|
||||
url: `${order_baseURL}/admin/points/goodsRecord/agreeRefund`,
|
||||
method: "post",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 积分:商家 驳回退单
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function goodsRecordRejectRefund(data) {
|
||||
return request({
|
||||
url: `${order_baseURL}/admin/points/goodsRecord/rejectRefund`,
|
||||
method: "post",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<template>
|
||||
<el-upload v-model:file-list="fileList" list-type="picture-card" :before-upload="handleBeforeUpload"
|
||||
:http-request="handleUpload" :on-success="handleSuccess" :on-progress="handleProgress" :on-error="handleError"
|
||||
:on-exceed="handleExceed" :accept="props.accept" :limit="props.limit" multiple>
|
||||
:on-exceed="handleExceed" :accept="props.accept" :limit="props.limit" multiple :auto-upload="true">
|
||||
<el-icon>
|
||||
<Plus />
|
||||
</el-icon>
|
||||
@@ -12,7 +12,9 @@
|
||||
<span class="el-upload-list__item-actions">
|
||||
<!-- 预览 -->
|
||||
<span @click="handlePreviewImage(file.url!)">
|
||||
<el-icon><zoom-in /></el-icon>
|
||||
<el-icon>
|
||||
<ZoomIn />
|
||||
</el-icon>
|
||||
</span>
|
||||
<!-- 删除 -->
|
||||
<span @click="handleRemove(file.url!)">
|
||||
@@ -28,104 +30,86 @@
|
||||
<el-image-viewer v-if="previewVisible" :zoom-rate="1.2" :initial-index="previewImageIndex" :url-list="modelValue"
|
||||
@close="handlePreviewClose" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, watch, onMounted, PropType, computed } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { UploadRawFile, UploadRequestOptions, UploadUserFile } from "element-plus";
|
||||
import FileAPI, { FileInfo } from "@/api/account/common";
|
||||
|
||||
// 定义Props
|
||||
const props = defineProps({
|
||||
/**
|
||||
* 请求携带的额外参数
|
||||
*/
|
||||
data: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
default: () => ({}),
|
||||
},
|
||||
/**
|
||||
* 上传文件的参数名
|
||||
*/
|
||||
name: {
|
||||
type: String,
|
||||
default: "file",
|
||||
},
|
||||
/**
|
||||
* 文件上传数量限制
|
||||
*/
|
||||
limit: {
|
||||
type: Number,
|
||||
default: 10,
|
||||
},
|
||||
/**
|
||||
* 单个文件的最大允许大小
|
||||
*/
|
||||
maxFileSize: {
|
||||
type: Number,
|
||||
default: 10,
|
||||
default: 10, // 单位:M
|
||||
},
|
||||
/**
|
||||
* 上传文件类型
|
||||
*/
|
||||
accept: {
|
||||
type: String,
|
||||
default: "image/*", // 默认支持所有图片格式 ,如果需要指定格式,格式如下:'.png,.jpg,.jpeg,.gif,.bmp'
|
||||
default: "image/*",
|
||||
},
|
||||
});
|
||||
const emit = defineEmits(['upDataEvent'])
|
||||
const previewVisible = ref(false); // 是否显示预览
|
||||
const previewImageIndex = ref(0); // 预览图片的索引
|
||||
|
||||
// 定义Emits
|
||||
const emit = defineEmits(['upDataEvent', 'uploadAllSuccess']); // 新增:所有图片上传完成事件
|
||||
|
||||
// 响应式数据
|
||||
const previewVisible = ref(false);
|
||||
const previewImageIndex = ref(0);
|
||||
const progress = ref(0);
|
||||
const modelValue = defineModel("modelValue", {
|
||||
type: [Array] as PropType<string[]>,
|
||||
// 修复:defineModel 类型定义
|
||||
const modelValue = defineModel<string[]>("modelValue", {
|
||||
type: Array as PropType<string[]>,
|
||||
required: true,
|
||||
default: () => [],
|
||||
});
|
||||
|
||||
const fileList = ref<UploadUserFile[]>([]);
|
||||
// 新增:批量上传计数
|
||||
const pendingUploadCount = ref(0); // 待上传文件数
|
||||
const completedUploadCount = ref(0); // 已完成上传数
|
||||
|
||||
/**
|
||||
* 删除图片
|
||||
*/
|
||||
function handleRemove(imageUrl: string) {
|
||||
// FileAPI.delete(imageUrl).then(() => {
|
||||
// const index = modelValue.value.indexOf(imageUrl);
|
||||
// if (index !== -1) {
|
||||
// // 直接修改数组避免触发整体更新
|
||||
// modelValue.value.splice(index, 1);
|
||||
// fileList.value.splice(index, 1); // 同步更新 fileList
|
||||
// }
|
||||
// });
|
||||
const index = modelValue.value.indexOf(imageUrl);
|
||||
if (index !== -1) {
|
||||
// 直接修改数组避免触发整体更新
|
||||
modelValue.value.splice(index, 1);
|
||||
fileList.value.splice(index, 1); // 同步更新 fileList
|
||||
fileList.value.splice(index, 1);
|
||||
}
|
||||
}
|
||||
function handleProgress(event: any, file: any, fileList: any) {
|
||||
// console.log("handleProgress", evt, file, fileList);
|
||||
// this.progress = Math.round(event.percent); // Element UI 已计算好百分比
|
||||
// console.log(`文件 ${file.name} 上传进度: ${this.progress}%`);
|
||||
// progress.value = Math.round(event.percent);
|
||||
|
||||
/**
|
||||
* 上传进度
|
||||
*/
|
||||
function handleProgress(event: any) {
|
||||
console.log("文件上传进度", Math.round(event.percent));
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传前校验
|
||||
* 上传前校验 & 初始化待上传文件
|
||||
*/
|
||||
function handleBeforeUpload(file: UploadRawFile) {
|
||||
|
||||
// 校验文件类型:虽然 accept 属性限制了用户在文件选择器中可选的文件类型,但仍需在上传时再次校验文件实际类型,确保符合 accept 的规则
|
||||
// 1. 文件类型校验
|
||||
const acceptTypes = props.accept.split(",").map((type) => type.trim());
|
||||
// 检查文件格式是否符合 accept
|
||||
const isValidType = acceptTypes.some((type) => {
|
||||
if (type === "image/*") {
|
||||
// 如果是 image/*,检查 MIME 类型是否以 "image/" 开头
|
||||
return file.type.startsWith("image/");
|
||||
} else if (type.startsWith(".")) {
|
||||
// 如果是扩展名 (.png, .jpg),检查文件名是否以指定扩展名结尾
|
||||
return file.name.toLowerCase().endsWith(type);
|
||||
} else {
|
||||
// 如果是具体的 MIME 类型 (image/png, image/jpeg),检查是否完全匹配
|
||||
return file.type === type;
|
||||
}
|
||||
});
|
||||
@@ -135,29 +119,42 @@ function handleBeforeUpload(file: UploadRawFile) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 限制文件大小
|
||||
// 2. 文件大小校验
|
||||
if (file.size > props.maxFileSize * 1024 * 1024) {
|
||||
ElMessage.warning("上传图片不能大于" + props.maxFileSize + "M");
|
||||
ElMessage.warning(`上传图片不能大于${props.maxFileSize}M`);
|
||||
return false;
|
||||
}
|
||||
emit('upDataEvent', true)
|
||||
|
||||
// 3. 新增:初始化待上传文件到fileList,确保uid匹配
|
||||
const uploadFile: UploadUserFile = {
|
||||
uid: file.uid, // 关键:复用文件原生uid
|
||||
name: file.name,
|
||||
status: "ready",
|
||||
raw: file,
|
||||
};
|
||||
fileList.value.push(uploadFile);
|
||||
|
||||
// 4. 新增:增加待上传计数
|
||||
pendingUploadCount.value++;
|
||||
emit('upDataEvent', true); // 开始上传,触发loading
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* 上传文件
|
||||
/**
|
||||
* 自定义上传逻辑
|
||||
*/
|
||||
function handleUpload(options: UploadRequestOptions) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const file = options.file;
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append(props.name, file);
|
||||
|
||||
// 处理附加参数
|
||||
// 附加参数
|
||||
Object.keys(props.data).forEach((key) => {
|
||||
formData.append(key, props.data[key]);
|
||||
});
|
||||
|
||||
FileAPI.upload(formData)
|
||||
.then((data) => {
|
||||
resolve(data);
|
||||
@@ -169,23 +166,38 @@ function handleUpload(options: UploadRequestOptions) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传文件超出限制
|
||||
* 超出数量限制
|
||||
*/
|
||||
function handleExceed(files: File[], uploadFiles: UploadUserFile[]) {
|
||||
ElMessage.warning("最多只能上传" + props.limit + "张图片");
|
||||
ElMessage.warning(`最多只能上传${props.limit}张图片`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传成功回调
|
||||
* 单文件上传成功回调
|
||||
*/
|
||||
const handleSuccess = (fileInfo: FileInfo, uploadFile: UploadUserFile) => {
|
||||
ElMessage.success("上传成功");
|
||||
emit('upDataEvent', false)
|
||||
// 1. 修复:通过uid精准匹配文件
|
||||
const index = fileList.value.findIndex((file) => file.uid === uploadFile.uid);
|
||||
if (index !== -1) {
|
||||
fileList.value[index].url = fileInfo;
|
||||
fileList.value[index].url = fileInfo as string; // 确保fileInfo是字符串类型
|
||||
fileList.value[index].status = "success";
|
||||
modelValue.value[index] = fileInfo;
|
||||
// 同步更新modelValue(若index超出当前长度,push;否则替换)
|
||||
if (index >= modelValue.value.length) {
|
||||
modelValue.value.push(fileInfo as string);
|
||||
} else {
|
||||
modelValue.value[index] = fileInfo as string;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 新增:完成计数+判断所有上传完成
|
||||
completedUploadCount.value++;
|
||||
if (completedUploadCount.value === pendingUploadCount.value) {
|
||||
ElMessage.success("所有图片上传成功!");
|
||||
emit('uploadAllSuccess', modelValue.value); // 所有图片上传完成,emit成功事件
|
||||
// 重置计数
|
||||
pendingUploadCount.value = 0;
|
||||
completedUploadCount.value = 0;
|
||||
emit('upDataEvent', false); // 结束loading
|
||||
}
|
||||
};
|
||||
|
||||
@@ -193,9 +205,12 @@ const handleSuccess = (fileInfo: FileInfo, uploadFile: UploadUserFile) => {
|
||||
* 上传失败回调
|
||||
*/
|
||||
const handleError = (error: any) => {
|
||||
console.log("handleError");
|
||||
emit('upDataEvent', false)
|
||||
ElMessage.error("上传失败: " + error.message);
|
||||
console.error("上传失败:", error);
|
||||
ElMessage.error("上传失败: " + (error.message || "未知错误"));
|
||||
// 重置计数+结束loading
|
||||
pendingUploadCount.value = 0;
|
||||
completedUploadCount.value = 0;
|
||||
emit('upDataEvent', false);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -212,12 +227,24 @@ const handlePreviewImage = (imageUrl: string) => {
|
||||
const handlePreviewClose = () => {
|
||||
previewVisible.value = false;
|
||||
};
|
||||
|
||||
// 监听modelValue同步fileList
|
||||
watch(modelValue, (newValue) => {
|
||||
fileList.value = newValue.map((url) => ({ url }) as UploadUserFile);
|
||||
});
|
||||
fileList.value = newValue.map((url) => ({
|
||||
url,
|
||||
uid: Date.now() + Math.random(), // 为已有图片生成唯一uid
|
||||
status: "success"
|
||||
}) as UploadUserFile);
|
||||
}, { immediate: true });
|
||||
|
||||
onMounted(() => {
|
||||
fileList.value = modelValue.value.map((url) => ({ url }) as UploadUserFile);
|
||||
// 初始化fileList
|
||||
fileList.value = modelValue.value.map((url) => ({
|
||||
url,
|
||||
uid: Date.now() + Math.random(),
|
||||
status: "success"
|
||||
}) as UploadUserFile);
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<el-dialog title="选择优惠劵" top="5vh" :visible.sync="dialogVisible">
|
||||
<el-dialog title="选择优惠券" top="5vh" :visible.sync="dialogVisible">
|
||||
<div class="head-container">
|
||||
<el-table ref="table" :data="tableData.list" height="500" v-loading="tableData.loading">
|
||||
<!-- <el-table-column type="selection" width="55" align="center" v-if="!radio"></el-table-column> -->
|
||||
|
||||
@@ -259,4 +259,44 @@ export const multiplyAndFormat = (num1: any, num2: any = 1): string => {
|
||||
console.error('计算错误:', error);
|
||||
return '0.00'; // 出错时返回默认值
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* 判断目标值是否包含指定字符串
|
||||
* @param {string|number|array} target - 目标值(字符串/数字/数组)
|
||||
* @param {string} searchStr - 要查找的子字符串
|
||||
* @param {object} [options] - 可选配置
|
||||
* @param {boolean} [options.ignoreCase=false] - 是否忽略大小写
|
||||
* @param {boolean} [options.allowEmpty=false] - 当 searchStr 为空时,是否返回 true(默认 false)
|
||||
* @returns {boolean} 是否包含指定字符串
|
||||
*/
|
||||
export function includesString(target, searchStr, options = {}) {
|
||||
// 解构配置,设置默认值
|
||||
const { ignoreCase = false, allowEmpty = false } = options;
|
||||
|
||||
// 1. 处理 searchStr 为空的情况
|
||||
if (searchStr === '' || searchStr === null || searchStr === undefined) {
|
||||
return allowEmpty;
|
||||
}
|
||||
|
||||
// 2. 统一将目标值转为字符串(兼容数字/数组等)
|
||||
let targetStr = '';
|
||||
if (typeof target === 'string') {
|
||||
targetStr = target;
|
||||
} else if (typeof target === 'number') {
|
||||
targetStr = String(target);
|
||||
} else if (Array.isArray(target)) {
|
||||
// 数组:拼接为字符串(也可改为 "数组中某一项包含",根据需求调整)
|
||||
targetStr = target.join(',');
|
||||
} else {
|
||||
// 其他类型(对象/布尔等):转为字符串或返回 false
|
||||
targetStr = String(target);
|
||||
}
|
||||
|
||||
// 3. 处理大小写忽略
|
||||
const processedTarget = ignoreCase ? targetStr.toLowerCase() : targetStr;
|
||||
const processedSearch = ignoreCase ? searchStr.toLowerCase() : searchStr;
|
||||
|
||||
// 4. 执行包含判断
|
||||
return processedTarget.includes(processedSearch);
|
||||
}
|
||||
@@ -3,12 +3,7 @@
|
||||
<div class="search-bar">
|
||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
||||
<el-form-item label="关键字" prop="title">
|
||||
<el-input
|
||||
v-model="queryParams.title"
|
||||
placeholder="菜单名称"
|
||||
clearable
|
||||
@keyup.enter="handleQuery"
|
||||
/>
|
||||
<el-input v-model="queryParams.title" placeholder="菜单名称" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="search" @click="handleQuery">搜索</el-button>
|
||||
@@ -19,27 +14,15 @@
|
||||
|
||||
<el-card shadow="never">
|
||||
<div class="mb-10px">
|
||||
<el-button
|
||||
v-hasPerm="['sys:menu:add']"
|
||||
type="success"
|
||||
icon="plus"
|
||||
@click="handleOpenDialog('0')"
|
||||
>
|
||||
<el-button v-hasPerm="['sys:menu:add']" type="success" icon="plus" @click="handleOpenDialog('0')">
|
||||
新增
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
:data="menuTableData"
|
||||
highlight-current-row
|
||||
row-key="menuId"
|
||||
:tree-props="{
|
||||
children: 'children',
|
||||
hasChildren: 'hasChildren',
|
||||
}"
|
||||
@row-click="handleRowClick"
|
||||
>
|
||||
<el-table v-loading="loading" :data="menuTableData" highlight-current-row row-key="menuId" :tree-props="{
|
||||
children: 'children',
|
||||
hasChildren: 'hasChildren',
|
||||
}" @row-click="handleRowClick">
|
||||
<el-table-column label="菜单名称" min-width="140">
|
||||
<template #default="scope">
|
||||
{{ scope.row.title }}
|
||||
@@ -60,20 +43,14 @@
|
||||
</el-table-column>
|
||||
<el-table-column label="类型" align="center" width="80">
|
||||
<template #default="scope">
|
||||
<el-tag
|
||||
v-if="scope.row.type === MenuTypeEnum.MENU && scope.row.path.startsWith('/')"
|
||||
type="warning"
|
||||
>
|
||||
<el-tag v-if="scope.row.type === MenuTypeEnum.MENU && scope.row.path.startsWith('/')" type="warning">
|
||||
目录
|
||||
</el-tag>
|
||||
<el-tag
|
||||
v-if="scope.row.type === MenuTypeEnum.MENU && !scope.row.path.startsWith('/')"
|
||||
type="success"
|
||||
>
|
||||
<el-tag v-if="scope.row.type === MenuTypeEnum.MENU && !scope.row.path.startsWith('/')" type="success">
|
||||
菜单
|
||||
</el-tag>
|
||||
<el-tag v-if="scope.row.type === MenuTypeEnum.BUTTON" type="danger">按钮</el-tag>
|
||||
<el-tag v-if="scope.row.type === MenuTypeEnum.EXTLINK" type="info">外链</el-tag>
|
||||
<el-tag v-if="scope.row.type === MenuTypeEnum.EXTLINK" type="info">接口</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="排序" align="left" width="150" prop="menuSort" />
|
||||
@@ -101,36 +78,17 @@
|
||||
</el-table-column>
|
||||
<el-table-column fixed="right" align="center" label="操作" width="220">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
v-if="scope.row.type == 0"
|
||||
v-hasPerm="['sys:menu:add']"
|
||||
type="primary"
|
||||
link
|
||||
size="small"
|
||||
icon="plus"
|
||||
@click.stop="handleOpenDialog(scope.row.menuId)"
|
||||
>
|
||||
<el-button v-if="scope.row.type == 0" v-hasPerm="['sys:menu:add']" type="primary" link size="small"
|
||||
icon="plus" @click.stop="handleOpenDialog(scope.row.menuId)">
|
||||
新增
|
||||
</el-button>
|
||||
|
||||
<el-button
|
||||
v-hasPerm="['sys:menu:edit']"
|
||||
type="primary"
|
||||
link
|
||||
size="small"
|
||||
icon="edit"
|
||||
@click.stop="handleOpenDialog(undefined, scope.row.menuId)"
|
||||
>
|
||||
<el-button v-hasPerm="['sys:menu:edit']" type="primary" link size="small" icon="edit"
|
||||
@click.stop="handleOpenDialog(undefined, scope.row.menuId)">
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button
|
||||
v-hasPerm="['sys:menu:delete']"
|
||||
type="danger"
|
||||
link
|
||||
size="small"
|
||||
icon="delete"
|
||||
@click.stop="handleDelete(scope.row.menuId)"
|
||||
>
|
||||
<el-button v-hasPerm="['sys:menu:delete']" type="danger" link size="small" icon="delete"
|
||||
@click.stop="handleDelete(scope.row.menuId)">
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
@@ -141,14 +99,8 @@
|
||||
<el-drawer v-model="dialog.visible" :title="dialog.title" size="50%" @close="handleCloseDialog">
|
||||
<el-form ref="editRequestRef" :model="formData" :rules="rules" label-width="100px">
|
||||
<el-form-item label="父级菜单" prop="pid">
|
||||
<el-tree-select
|
||||
v-model="formData.pid"
|
||||
placeholder="选择上级菜单"
|
||||
:data="menuOptions"
|
||||
filterable
|
||||
check-strictly
|
||||
:render-after-expand="false"
|
||||
/>
|
||||
<el-tree-select v-model="formData.pid" placeholder="选择上级菜单" :data="menuOptions" filterable check-strictly
|
||||
:render-after-expand="false" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="菜单名称" prop="title">
|
||||
@@ -162,14 +114,9 @@
|
||||
<el-radio :value="2">接口</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否外链" >
|
||||
<el-switch
|
||||
v-model="formData.iFrame"
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
active-text="是"
|
||||
inactive-text="否"
|
||||
/>
|
||||
<el-form-item label="是否外链">
|
||||
<el-switch v-model="formData.iFrame" :active-value="1" :inactive-value="0" active-text="是"
|
||||
inactive-text="否" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item v-if="formData.type == MenuTypeEnum.MENU" prop="name">
|
||||
@@ -204,11 +151,7 @@
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
<el-input
|
||||
v-if="formData.type == MenuTypeEnum.MENU"
|
||||
v-model="formData.path"
|
||||
placeholder="system"
|
||||
/>
|
||||
<el-input v-if="formData.type == MenuTypeEnum.MENU" v-model="formData.path" placeholder="system" />
|
||||
<el-input v-else v-model="formData.path" placeholder="user" />
|
||||
</el-form-item>
|
||||
|
||||
@@ -240,10 +183,7 @@
|
||||
<el-input v-model="formData.miniComponent" placeholder="小程序组件名称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="小程序图标">
|
||||
<single-image-upload
|
||||
style="width: 100px; height: 100px"
|
||||
v-model="formData.miniIcon"
|
||||
></single-image-upload>
|
||||
<single-image-upload style="width: 100px; height: 100px" v-model="formData.miniIcon"></single-image-upload>
|
||||
</el-form-item>
|
||||
<el-form-item label="接口路径" prop="miniPage">
|
||||
<div class="w-full">
|
||||
@@ -253,11 +193,7 @@
|
||||
<div class="u-flex u-m-t-10" v-for="(item, index) in formData.apiInfo" :key="index">
|
||||
<el-form-item label="请求方式" label-position="left">
|
||||
<el-select v-model="item.method" style="width: 100px">
|
||||
<el-option
|
||||
v-for="(item, index) in apiMethodOptions"
|
||||
:key="index"
|
||||
:value="item.value"
|
||||
>
|
||||
<el-option v-for="(item, index) in apiMethodOptions" :key="index" :value="item.value">
|
||||
{{ item.label }}
|
||||
</el-option>
|
||||
</el-select>
|
||||
@@ -265,12 +201,7 @@
|
||||
<el-form-item label="接口地址" style="flex: 1">
|
||||
<el-input v-model="item.url" placeholder="支持通配符*和?" />
|
||||
</el-form-item>
|
||||
<el-icon
|
||||
style="margin-left: 10px"
|
||||
size="20"
|
||||
color="#F56c6c"
|
||||
@click="formData.apiInfo.splice(index, 1)"
|
||||
>
|
||||
<el-icon style="margin-left: 10px" size="20" color="#F56c6c" @click="formData.apiInfo.splice(index, 1)">
|
||||
<RemoveFilled />
|
||||
</el-icon>
|
||||
</div>
|
||||
@@ -291,20 +222,11 @@
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="排序" prop="menuSort">
|
||||
<el-input-number
|
||||
v-model="formData.menuSort"
|
||||
style="width: 100px"
|
||||
controls-position="right"
|
||||
:min="0"
|
||||
/>
|
||||
<el-input-number v-model="formData.menuSort" style="width: 100px" controls-position="right" :min="0" />
|
||||
</el-form-item>
|
||||
|
||||
<!-- 权限标识 -->
|
||||
<el-form-item
|
||||
v-if="formData.type == MenuTypeEnum.BUTTON"
|
||||
label="权限标识"
|
||||
prop="permission"
|
||||
>
|
||||
<el-form-item v-if="formData.type == MenuTypeEnum.BUTTON" label="权限标识" prop="permission">
|
||||
<el-input v-model="formData.permission" placeholder="sys:user:add" />
|
||||
</el-form-item>
|
||||
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
<template>
|
||||
<div style="padding: 15px;">
|
||||
<el-tabs type="border-card" v-model="datas.activeName" @tab-click="handleClick">
|
||||
<el-tab-pane label="基本设置" name="BasicSettings">
|
||||
<BasicSettings v-if="datas.activeName == 'BasicSettings'" />
|
||||
<el-tab-pane label="基本设置" name="BasicSettings" key="BasicSettings">
|
||||
<BasicSettings />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="商品设置" name="ProductSettings">
|
||||
<ProductSettings v-if="datas.activeName == 'ProductSettings'" />
|
||||
<el-tab-pane label="商品设置" name="ProductSettings" key="ProductSettings">
|
||||
<ProductSettings />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="兑换记录" name="Exchangerecords">
|
||||
<Exchangerecords v-if="datas.activeName == 'Exchangerecords'" />
|
||||
<el-tab-pane label="兑换记录" name="Exchangerecords" key="Exchangerecords">
|
||||
<Exchangerecords />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="会员积分" name="Memberpoints">
|
||||
<Memberpoints v-if="datas.activeName == 'Memberpoints'" />
|
||||
<el-tab-pane label="用户积分" name="Memberpoints" key="Memberpoints">
|
||||
<Memberpoints />
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
@@ -23,7 +23,6 @@ import Memberpoints from './pointsconfig/Memberpoints.vue'
|
||||
import ProductSettings from './pointsconfig/ProductSettings.vue'
|
||||
let datas = reactive({
|
||||
activeName: "BasicSettings",
|
||||
|
||||
})
|
||||
function handleClick(tab) {
|
||||
datas.activeName = tab.props.name;
|
||||
|
||||
@@ -1,72 +1,64 @@
|
||||
<template>
|
||||
<!-- 基本设置 -->
|
||||
<el-form :model="Elform" label-width="150px">
|
||||
<el-form ref="formRef" :model="form" :rules="rules" label-width="150px">
|
||||
<el-form-item label="是否消费赠送积分">
|
||||
<el-switch v-model="Elform.enableRewards" :active-value="1" :inactive-value="0" />
|
||||
<div class="center">
|
||||
<el-switch v-model="form.enableRewards" :active-value="1" :inactive-value="0" />
|
||||
<span class="tips">开启后,所有用户可通过消费获得积分及可用积分抵扣支付</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="适用群体">
|
||||
<el-radio-group v-model="Elform.rewardsGroup">
|
||||
<!-- <el-form-item label="适用群体">
|
||||
<el-radio-group v-model="form.rewardsGroup">
|
||||
<el-radio label="全部" value="all" />
|
||||
<el-radio label="仅会员" value="vip" />
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="消费赠送积分">
|
||||
</el-form-item> -->
|
||||
<el-form-item label="消费送积分" prop="consumeAmount">
|
||||
<el-col :span="7">
|
||||
<el-input v-model="Elform.consumeAmount" type="number" placeholder="">
|
||||
<el-input v-model="form.consumeAmount" :maxlength="8" @input="e => form.consumeAmount = filterNumberInput(e)"
|
||||
:input-style="{ textAlign: 'center' }">
|
||||
<template #prepend>每消费</template>
|
||||
<template #append>元赠送1积分</template>
|
||||
</el-input>
|
||||
</el-col>
|
||||
</el-form-item>
|
||||
<el-form-item label="开启下单积分抵扣">
|
||||
<el-switch v-model="Elform.enableDeduction" :active-value="1" :inactive-value="0" />
|
||||
<!-- <el-form-item label="开启下单积分抵扣">
|
||||
<el-switch v-model="form.enableDeduction" :active-value="1" :inactive-value="0" />
|
||||
</el-form-item>
|
||||
<el-form-item label="适用群体">
|
||||
<el-radio-group v-model="Elform.deductionGroup">
|
||||
<el-radio-group v-model="form.deductionGroup">
|
||||
<el-radio label="全部" value="all" />
|
||||
<el-radio label="仅会员" value="vip" />
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="下单实付抵扣门槛">
|
||||
</el-form-item> -->
|
||||
<el-form-item label="下单实付抵扣门槛" prop="minPaymentAmount">
|
||||
<el-col :span="3">
|
||||
<el-input v-model="Elform.minPaymentAmount" type="number" placeholder="">
|
||||
<el-input v-model="form.minPaymentAmount" :maxlength="8"
|
||||
@input="e => form.minPaymentAmount = filterNumberInput(e)">
|
||||
<template #append>元</template>
|
||||
</el-input>
|
||||
</el-col>
|
||||
</el-form-item>
|
||||
<el-form-item label="下单最高抵扣比例">
|
||||
<el-input-number
|
||||
v-model="Elform.maxDeductionRatio"
|
||||
type="number"
|
||||
placeholder=""
|
||||
:min="0"
|
||||
:max="100"
|
||||
></el-input-number>
|
||||
<el-input-number v-model="form.maxDeductionRatio" type="number" placeholder="" :min="1"
|
||||
:max="100"></el-input-number>
|
||||
<span class="u-m-l-10 color-999">%</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="下单抵扣积分比例">
|
||||
<el-col :span="7">
|
||||
<span class="color-999">1元等于</span>
|
||||
<el-input-number
|
||||
class="u-m-l-10 u-m-r-10"
|
||||
v-model="Elform.equivalentPoints"
|
||||
type="number"
|
||||
placeholder=""
|
||||
min="1"
|
||||
></el-input-number>
|
||||
<el-input-number class="u-m-l-10 u-m-r-10" v-model="form.equivalentPoints" type="number" placeholder=""
|
||||
min="1"></el-input-number>
|
||||
<span class="color-999">积分</span>
|
||||
</el-col>
|
||||
</el-form-item>
|
||||
<div class="form_header">开启积分商城</div>
|
||||
<el-form-item label="开启积分商城">
|
||||
<el-switch v-model="Elform.enablePointsMall" :active-value="1" :inactive-value="0" />
|
||||
<el-switch v-model="form.enablePointsMall" :active-value="1" :inactive-value="0" />
|
||||
</el-form-item>
|
||||
<el-form-item label="显示样式">
|
||||
<!-- <el-form-item label="显示样式">
|
||||
<div class="style_wrap">
|
||||
<div
|
||||
class="item style1"
|
||||
:class="{ active: Elform.browseMode == 'list' }"
|
||||
@click="Elform.browseMode = 'list'"
|
||||
>
|
||||
<div class="item style1" :class="{ active: form.browseMode == 'list' }" @click="form.browseMode = 'list'">
|
||||
<div class="row">
|
||||
<div class="cover"></div>
|
||||
<div class="info">
|
||||
@@ -84,11 +76,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="item style2"
|
||||
:class="{ active: Elform.browseMode == 'grid' }"
|
||||
@click="Elform.browseMode = 'grid'"
|
||||
>
|
||||
<div class="item style2" :class="{ active: form.browseMode == 'grid' }" @click="form.browseMode = 'grid'">
|
||||
<div class="row">
|
||||
<div class="cover"></div>
|
||||
<div class="line"></div>
|
||||
@@ -107,48 +95,122 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form-item> -->
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="onSubmit">确定</el-button>
|
||||
<el-button type="primary" :loading="loading" @click="onSubmit">确定</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { reactive } from "vue";
|
||||
import API from "../index";
|
||||
// do not use same name with ref
|
||||
const Elform = reactive({
|
||||
enableRewards: 0,
|
||||
rewardsGroup: "all",
|
||||
consumeAmount: 0,
|
||||
enableDeduction: 0,
|
||||
deductionGroup: "all",
|
||||
minPaymentAmount: 0,
|
||||
maxDeductionRatio: 0,
|
||||
equivalentPoints: 0,
|
||||
enablePointsMall: 0,
|
||||
browseMode: "list",
|
||||
import { ref } from "vue";
|
||||
import { pointsConfigGet, pointsConfigPost } from '@/api/points'
|
||||
import { filterNumberInput } from '@/utils'
|
||||
|
||||
const form = ref({
|
||||
enableRewards: 0, // 开启消费赠送积分 1-开启 0-关闭 开启后,所有用户可通过消费获得积分及可用积分抵扣支付
|
||||
consumeAmount: '', // 每消费xx元赠送1积分
|
||||
minPaymentAmount: '', // 下单实付抵扣门槛
|
||||
maxDeductionRatio: '', // 下单最高抵扣比例
|
||||
equivalentPoints: '', // 下单抵扣积分比例 1元=?积分
|
||||
enablePointsMall: '', // 开启积分商城
|
||||
});
|
||||
onMounted(() => {
|
||||
getList();
|
||||
});
|
||||
async function getList() {
|
||||
const res = await API.getBasicSetting({});
|
||||
Object.assign(Elform, res);
|
||||
}
|
||||
async function onSubmit() {
|
||||
const res = await API.BasicSettingadd(Elform);
|
||||
if (res.code == 200) {
|
||||
ElMessage({
|
||||
message: "成功",
|
||||
type: "success",
|
||||
});
|
||||
|
||||
const rules = ref({
|
||||
consumeAmount: [
|
||||
{
|
||||
required: true,
|
||||
validator: (rule, value, callback) => {
|
||||
if (form.value.consumeAmount === '') {
|
||||
callback(new Error('请输入'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
},
|
||||
triiger: 'blur'
|
||||
}
|
||||
],
|
||||
minPaymentAmount: [
|
||||
{
|
||||
required: true,
|
||||
validator: (rule, value, callback) => {
|
||||
if (form.value.minPaymentAmount === '') {
|
||||
callback(new Error('请输入'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
},
|
||||
triiger: 'blur'
|
||||
}
|
||||
],
|
||||
maxDeductionRatio: [
|
||||
{
|
||||
required: true,
|
||||
message: ' ',
|
||||
triiger: 'blur'
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
// 积分:配置:详情
|
||||
async function pointsConfigGetAjax() {
|
||||
const res = await pointsConfigGet();
|
||||
if (res) {
|
||||
form.value = res
|
||||
formRef.value.clearValidate('consumeAmount');
|
||||
formRef.value.clearValidate('minPaymentAmount');
|
||||
}
|
||||
}
|
||||
|
||||
const formRef = ref(null)
|
||||
const loading = ref(false)
|
||||
function onSubmit() {
|
||||
formRef.value.validate(async vaild => {
|
||||
try {
|
||||
if (vaild) {
|
||||
loading.value = true
|
||||
await pointsConfigPost(form.value);
|
||||
ElMessage({
|
||||
message: "保存成功",
|
||||
type: "success",
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
setTimeout(() => {
|
||||
loading.value = false
|
||||
}, 500);
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
pointsConfigGetAjax();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.center {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
|
||||
.tips {
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.form_header {
|
||||
padding: 14px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 16px;
|
||||
color: #333;
|
||||
background-color: #F8F8F8;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
.style_wrap {
|
||||
display: flex;
|
||||
width: 350px;
|
||||
|
||||
@@ -1,13 +1,206 @@
|
||||
<template>
|
||||
<!-- 会员积分模块 -->
|
||||
<div style="padding: 15px;">
|
||||
<!-- 搜索 -->
|
||||
<Search></Search>
|
||||
<!-- 表格 -->
|
||||
<Content></Content>
|
||||
<div>
|
||||
<div class="row">
|
||||
<el-table :data="tableData.list" stripe border v-loading="tableData.loading">
|
||||
<el-table-column label="用户ID" prop="id" width="100"></el-table-column>
|
||||
<el-table-column label="用户" prop="nickName">
|
||||
<template v-slot="scope">
|
||||
<div class="user_info">
|
||||
<el-avatar :src="scope.row.headImg" :size="35"></el-avatar>
|
||||
<span class="name">{{ scope.row.nickName }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="手机号" prop="phone"></el-table-column>
|
||||
<el-table-column label="账户积分" prop="pointBalance"></el-table-column>
|
||||
<el-table-column label="操作" width="100">
|
||||
<template v-slot="scope">
|
||||
<el-button link type="primary" @click="showRecord(scope.row)">查看明细</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<div class="row mt14">
|
||||
<el-pagination v-model:current-page="tableData.page" v-model:page-size="tableData.size"
|
||||
:page-sizes="[10, 30, 50, 100]" background layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="tableData.total" @size-change="handleSizeChange" @current-change="handleCurrentChange" />
|
||||
</div>
|
||||
<el-dialog title="积分明细" width="800px" v-model="visible" @closed="selectUserTableDataReset">
|
||||
<div class="content">
|
||||
<div class="header">
|
||||
<div class="item">
|
||||
<span class="t1">用户</span>
|
||||
<span class="t2">{{ selectRow.nickName }} {{ selectRow.phone }}</span>
|
||||
</div>
|
||||
<div class="item">
|
||||
<span class="t1">账户积分</span>
|
||||
<span class="t2">{{ selectRow.pointBalance }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt14">
|
||||
<el-table :data="selectUserTableData.list" border stripe v-loading="selectUserTableData.loading"
|
||||
height="50vh">
|
||||
<el-table-column label="变动类型" prop="floatType" width="100">
|
||||
<template v-slot="scope">
|
||||
<span v-if="scope.row.floatType == 'add'">累加</span>
|
||||
<span v-if="scope.row.floatType == 'subtract'">扣减</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="变动积分" prop="floatPoints" width="100"></el-table-column>
|
||||
<el-table-column label="变动原因" prop="content"></el-table-column>
|
||||
<el-table-column label="变动时间" prop="createTime" width="200"></el-table-column>
|
||||
<el-table-column label="变动后积分" prop="balancePoints" width="100"></el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<div class="row mt14">
|
||||
<el-pagination v-model:current-page="selectUserTableData.page" v-model:page-size="selectUserTableData.size"
|
||||
:page-sizes="[10, 30, 50, 100]" background layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="selectUserTableData.total" @size-change="selectUserTableDataSizeChange"
|
||||
@current-change="selectUserTableDataCurrentChange" />
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import Search from './Memberpointsconfig/Search.vue'
|
||||
import Content from './Memberpointsconfig/Content.vue'
|
||||
</script>
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { pointsUserPage, pointsUserRecord } from '@/api/points'
|
||||
|
||||
const tableData = reactive({
|
||||
loading: false,
|
||||
list: [],
|
||||
page: 1,
|
||||
size: 10,
|
||||
total: 0
|
||||
})
|
||||
|
||||
// 分页大小发生变化
|
||||
function handleSizeChange(e) {
|
||||
tableData.size = e;
|
||||
goodsRecordPageAjax();
|
||||
goodsRecordTotalAjax()
|
||||
}
|
||||
|
||||
// 分页发生变化
|
||||
function handleCurrentChange(e) {
|
||||
tableData.page = e;
|
||||
goodsRecordPageAjax();
|
||||
goodsRecordTotalAjax()
|
||||
}
|
||||
|
||||
// 积分:用户:列表
|
||||
async function pointsUserPageAjax() {
|
||||
try {
|
||||
tableData.loading = true
|
||||
const res = await pointsUserPage({
|
||||
page: tableData.page,
|
||||
size: tableData.size
|
||||
})
|
||||
tableData.list = res.records
|
||||
tableData.total = res.totalRow
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
setTimeout(() => {
|
||||
tableData.loading = false
|
||||
}, 500);
|
||||
}
|
||||
|
||||
const visible = ref(false)
|
||||
const selectRow = ref({})
|
||||
function showRecord(row) {
|
||||
selectRow.value = row
|
||||
visible.value = true
|
||||
pointsUserRecordAjax()
|
||||
}
|
||||
|
||||
// 积分:用户:积分详情
|
||||
const selectUserTableData = reactive({
|
||||
loading: false,
|
||||
page: 1,
|
||||
size: 10,
|
||||
total: 0,
|
||||
list: []
|
||||
})
|
||||
|
||||
// 分页大小发生变化
|
||||
function selectUserTableDataSizeChange(e) {
|
||||
selectUserTableData.size = e;
|
||||
pointsUserRecordAjax()
|
||||
}
|
||||
|
||||
// 分页发生变化
|
||||
function selectUserTableDataCurrentChange(e) {
|
||||
selectUserTableData.page = e;
|
||||
pointsUserRecordAjax()
|
||||
}
|
||||
|
||||
function selectUserTableDataReset() {
|
||||
selectUserTableData.page = 1
|
||||
selectUserTableData.list = []
|
||||
}
|
||||
|
||||
async function pointsUserRecordAjax() {
|
||||
try {
|
||||
selectUserTableData.loading = true
|
||||
const res = await pointsUserRecord({
|
||||
page: 1,
|
||||
size: 10,
|
||||
id: selectRow.value.id
|
||||
})
|
||||
selectUserTableData.list = res.records
|
||||
selectUserTableData.total = res.totalRow
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
setTimeout(() => {
|
||||
selectUserTableData.loading = false
|
||||
}, 500);
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
pointsUserPageAjax()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.row {
|
||||
&.mt14 {
|
||||
margin-top: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.user_info {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
|
||||
.name {
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
.header {
|
||||
display: flex;
|
||||
|
||||
.item {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
|
||||
.t1 {
|
||||
font-size: 16px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.t2 {
|
||||
font-size: 16px;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<!-- 会员积分模块 -->
|
||||
<div style="padding: 15px;">
|
||||
<!-- 搜索 -->
|
||||
<Search></Search>
|
||||
<!-- 表格 -->
|
||||
<Content></Content>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import Search from './Memberpointsconfig/Search.vue'
|
||||
import Content from './Memberpointsconfig/Content.vue'
|
||||
</script>
|
||||
@@ -1,10 +1,170 @@
|
||||
<template>
|
||||
<!-- 会员商品设置模块 -->
|
||||
<div style="padding: 15px;">
|
||||
<!-- 表格 -->
|
||||
<Content></Content>
|
||||
<div>
|
||||
<div class="row">
|
||||
<el-button type="primary" @click="addProduceDialogRef.show()">添加</el-button>
|
||||
</div>
|
||||
<div class="row mt14">
|
||||
<el-table :data="tableData.list" border stripe v-loading="tableData.loading">
|
||||
<el-table-column label="商品" width="250">
|
||||
<template v-slot="scope">
|
||||
<div class="goods_info" v-if="includesString(scope.row.goodsCategory, '其它商品')">
|
||||
<el-image class="icon" :src="scope.row.goodsImageUrl" fit="cover"></el-image>
|
||||
<div class="info">
|
||||
<div class="name">{{ scope.row.goodsName }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="coupon_info" v-if="includesString(scope.row.goodsCategory, '优惠券')">
|
||||
<div class="icon">
|
||||
<CouponIcon :item="scope.row.couponInfo" />
|
||||
</div>
|
||||
<div class="info">
|
||||
<div class="name">
|
||||
{{ scope.row.goodsName }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="所需积分" prop="requiredPoints"></el-table-column>
|
||||
<el-table-column label="额外价格(元)" prop="extraPrice" width="130"></el-table-column>
|
||||
<el-table-column label="累计兑换次数" prop="totalExchangeCount"></el-table-column>
|
||||
<el-table-column label="库存" prop="quantity"></el-table-column>
|
||||
<el-table-column label="状态" prop="status" width="100">
|
||||
<template v-slot="scope">
|
||||
<el-switch v-model="scope.row.status" :active-value="1" :inactive-value="0"
|
||||
@change="statusChange($event, scope.row)"></el-switch>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="创建时间" prop="createTime" width="180"></el-table-column>
|
||||
<el-table-column label="操作" width="150" fixed="right">
|
||||
<template v-slot="scope">
|
||||
<el-button type="primary" link @click="addProduceDialogRef.show(scope.row)">编辑</el-button>
|
||||
<el-popconfirm title="确认要删除吗?" @confirm="deleteHandle(scope.row)">
|
||||
<template #reference>
|
||||
<el-button type="danger" link>删除</el-button>
|
||||
</template>
|
||||
</el-popconfirm>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<div class="row mt14">
|
||||
<el-pagination v-model:current-page="tableData.page" v-model:page-size="tableData.size"
|
||||
:page-sizes="[10, 30, 50, 100]" background layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="tableData.total" @size-change="handleSizeChange" @current-change="handleCurrentChange" />
|
||||
</div>
|
||||
<addProduceDialog ref="addProduceDialogRef" @success="pointsGoodsPageAjax" />
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import Content from './ProductSettingsconfig/Content.vue'
|
||||
</script>
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { pointsGoodsPage, pointsGoodsDel, pointsGoodsPost } from '@/api/points'
|
||||
import addProduceDialog from './addProduceDialog.vue';
|
||||
import CouponIcon from './coupon-icon.vue';
|
||||
import { includesString } from '@/utils'
|
||||
|
||||
const addProduceDialogRef = ref(null)
|
||||
|
||||
const tableData = reactive({
|
||||
page: 1,
|
||||
size: 10,
|
||||
total: 0,
|
||||
list: [],
|
||||
loading: false
|
||||
})
|
||||
|
||||
// 分页大小发生变化
|
||||
function handleSizeChange(e) {
|
||||
tableData.size = e;
|
||||
pointsGoodsPageAjax();
|
||||
}
|
||||
|
||||
// 分页发生变化
|
||||
function handleCurrentChange(e) {
|
||||
tableData.page = e;
|
||||
pointsGoodsPageAjax();
|
||||
}
|
||||
|
||||
// 积分:商品:列表
|
||||
async function pointsGoodsPageAjax() {
|
||||
try {
|
||||
tableData.loading = true
|
||||
const res = await pointsGoodsPage({
|
||||
page: tableData.page,
|
||||
size: tableData.size
|
||||
})
|
||||
tableData.list = res.records
|
||||
tableData.total = res.totalRow
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
setTimeout(() => {
|
||||
tableData.loading = false
|
||||
}, 500);
|
||||
}
|
||||
|
||||
// 删除
|
||||
async function deleteHandle(row) {
|
||||
try {
|
||||
await pointsGoodsDel(row.id)
|
||||
ElNotification({
|
||||
title: '注意',
|
||||
message: '已删除',
|
||||
type: 'success'
|
||||
})
|
||||
pointsGoodsPageAjax()
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 修改状态
|
||||
async function statusChange(e, row) {
|
||||
try {
|
||||
await pointsGoodsPost(row)
|
||||
pointsGoodsPageAjax()
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
pointsGoodsPageAjax()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.row {
|
||||
&.mt14 {
|
||||
margin-top: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.goods_info,
|
||||
.coupon_info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
|
||||
.icon {
|
||||
$size: 70px;
|
||||
width: $size;
|
||||
height: $size;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 1px solid #ececec;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.name {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -13,7 +13,7 @@
|
||||
<el-form-item label="奖品类型">
|
||||
<el-radio-group v-model="datas.DialogForm.goodsCategory">
|
||||
<el-radio label="实物" value="physical" />
|
||||
<el-radio label="优惠劵" value="coupon" />
|
||||
<el-radio label="优惠券" value="coupon" />
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品图片" required prop="goodsImageUrl">
|
||||
|
||||
@@ -0,0 +1,272 @@
|
||||
<!-- 添加商品 -->
|
||||
<template>
|
||||
<el-dialog :title="form.id ? '编辑商品' : '添加商品'" top="4vh" width="600px" v-model="visible" @closed="reset">
|
||||
<div class="content">
|
||||
<el-form ref="formRef" :model="form" :rules="rules" label-width="120px" label-position="left">
|
||||
<el-form-item label="商品类型">
|
||||
<el-radio-group v-model="form.goodsCategory">
|
||||
<el-radio label="优惠券" value="优惠券"></el-radio>
|
||||
<el-radio label="其它商品" value="其它商品"></el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="赠送优惠券" v-if="form.goodsCategory == '优惠券'" prop="couponId">
|
||||
<el-select v-model="form.couponId" placeholder="请选择优惠券" style="width: 200px;" @change="selectCoupon">
|
||||
<el-option v-for="item in couponList" :key="item.id" :label="item.title" :value="item.id"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<div v-if="form.goodsCategory == '其它商品'">
|
||||
<el-form-item label="商品名称" prop="goodsName">
|
||||
<el-input v-model="form.goodsName" placeholder="请输入商品名称" :maxlength="30" clearable
|
||||
style="width: 200px;"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品图片" prop="goodsImageUrl">
|
||||
<SingleImageUpload v-model="form.goodsImageUrl" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
<el-form-item label="所需积分" prop="requiredPoints">
|
||||
<el-input v-model="form.requiredPoints" :maxlength="8"
|
||||
@input="e => form.requiredPoints = filterNumberInput(e, 1)" style="width: 200px;">
|
||||
<template #append>积分</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="额外价格">
|
||||
<el-input v-model="form.extraPrice" :maxlength="8" @input="e => form.extraPrice = filterNumberInput(e)"
|
||||
style="width: 200px;">
|
||||
<template #append>元</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="数量" prop="quantity">
|
||||
<el-input v-model="form.quantity" :maxlength="8" @input="e => form.quantity = filterNumberInput(e, 1)"
|
||||
style="width: 200px;">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="排序">
|
||||
<el-input v-model="form.sort" :maxlength="8" @input="e => form.sort = filterNumberInput(e, 0)"
|
||||
style="width: 200px;">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否上架">
|
||||
<div class="center">
|
||||
<el-switch v-model="form.status" :active-value="1" :inactive-value="0" />
|
||||
<!-- <span class="tips">开启后,所有用户可通过消费获得积分及可用积分抵扣支付</span> -->
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="发放方式">
|
||||
<div class="center">
|
||||
<span class="tips">系统发放</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="每人限购" prop="limitQuota">
|
||||
<div class="center">
|
||||
<el-switch v-model="limitQuotaSwitch" @change="limitQuotaSwitchChange" />
|
||||
<el-input v-model="form.limitQuota" placeholder="请输入限购数量"
|
||||
@input="e => form.limitQuota = filterNumberInput(e, 1)" v-if="limitQuotaSwitch"></el-input>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品详情">
|
||||
<MultiImageUpload v-model="goodsDescription" @up-data-event="multiImgSuccess" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="visible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="submitHandle" :loading="confirmLoading">确 定</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { pointsGoodsPost } from '@/api/points'
|
||||
import couponApi from "@/api/market/coupon";
|
||||
import { filterNumberInput } from '@/utils'
|
||||
// 单图上传
|
||||
import SingleImageUpload from '@/components/Upload/SingleImageUpload.vue';
|
||||
// 多图上传
|
||||
import MultiImageUpload from '@/components/Upload/MultiImageUpload.vue';
|
||||
|
||||
const visible = ref(false)
|
||||
|
||||
const formRef = ref(null)
|
||||
|
||||
const limitQuotaSwitch = ref(false)
|
||||
const confirmLoading = ref(false)
|
||||
const goodsDescription = ref([])
|
||||
const formObj = {
|
||||
id: '',
|
||||
goodsCategory: '优惠券', // 商品类型 优惠券 其它商品
|
||||
couponId: '', // 优惠券id
|
||||
goodsName: '', // 商品名称/优惠券名称
|
||||
goodsImageUrl: '', // 商品图片URL
|
||||
requiredPoints: '', // 所需积分
|
||||
extraPrice: '', // 额外价格
|
||||
quantity: '', // 数量
|
||||
sort: 0,
|
||||
status: 1, // 是否上架 1-是 0-否
|
||||
receiveType: '', // 领取方式 店内自取、系统发放
|
||||
limitQuota: '', // 限购数量
|
||||
goodsDescription: '', // 商品详情
|
||||
}
|
||||
const form = ref({ ...formObj })
|
||||
|
||||
function reset() {
|
||||
limitQuotaSwitch.value = false
|
||||
goodsDescription.value = []
|
||||
form.value = { ...formObj }
|
||||
}
|
||||
|
||||
const rules = ref({
|
||||
couponId: [
|
||||
{
|
||||
required: true,
|
||||
validator: (rule, value, callback) => {
|
||||
if (form.value.couponId === '') {
|
||||
return callback(new Error('请选择优惠券'))
|
||||
} else {
|
||||
return callback()
|
||||
}
|
||||
},
|
||||
blur: ['change']
|
||||
}
|
||||
],
|
||||
goodsName: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入商品名称',
|
||||
blur: ['change']
|
||||
}
|
||||
],
|
||||
goodsImageUrl: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择商品图片',
|
||||
blur: ['change']
|
||||
}
|
||||
],
|
||||
requiredPoints: [
|
||||
{
|
||||
required: true,
|
||||
validator: (rule, value, callback) => {
|
||||
if (form.value.requiredPoints === '') {
|
||||
return callback(new Error('请输入所需积分'))
|
||||
} else {
|
||||
return callback()
|
||||
}
|
||||
},
|
||||
blur: ['blur']
|
||||
}
|
||||
],
|
||||
quantity: [
|
||||
{
|
||||
required: true,
|
||||
validator: (rule, value, callback) => {
|
||||
if (form.value.quantity === '') {
|
||||
return callback(new Error('请输入数量'))
|
||||
} else {
|
||||
return callback()
|
||||
}
|
||||
},
|
||||
blur: ['blur']
|
||||
}
|
||||
],
|
||||
limitQuota: [
|
||||
{
|
||||
validator: (rule, value, callback) => {
|
||||
if (limitQuotaSwitch.value && form.value.limitQuota === '') {
|
||||
return callback(new Error('请输入限购数量'))
|
||||
} else {
|
||||
return callback()
|
||||
}
|
||||
},
|
||||
blur: ['blur', 'change']
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
const couponList = ref([])
|
||||
|
||||
// 选择优惠券
|
||||
function selectCoupon(e) {
|
||||
let obj = couponList.value.find(item => item.id == e)
|
||||
form.value.goodsName = obj.title
|
||||
}
|
||||
|
||||
function limitQuotaSwitchChange() {
|
||||
form.value.limitQuota = ''
|
||||
}
|
||||
|
||||
// 多图片上传成功
|
||||
async function multiImgSuccess(response) {
|
||||
if (!response && goodsDescription.value.length > 0) {
|
||||
await nextTick()
|
||||
form.value.goodsDescription = JSON.stringify(goodsDescription.value)
|
||||
console.log('onSuccess.selectItem.value', form.value);
|
||||
}
|
||||
}
|
||||
|
||||
const emits = defineEmits(['success'])
|
||||
function submitHandle() {
|
||||
try {
|
||||
formRef.value.validate(async vaild => {
|
||||
if (vaild) {
|
||||
confirmLoading.value = true
|
||||
await pointsGoodsPost(form.value)
|
||||
ElNotification({
|
||||
title: '注意',
|
||||
message: '保存成功',
|
||||
type: 'success'
|
||||
})
|
||||
visible.value = false
|
||||
emits('success')
|
||||
}
|
||||
})
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
setTimeout(() => {
|
||||
confirmLoading.value = false
|
||||
}, 500);
|
||||
}
|
||||
|
||||
function show(obj) {
|
||||
visible.value = true
|
||||
if (obj && obj.id) {
|
||||
form.value = { ...obj }
|
||||
if (obj.goodsDescription !== '') {
|
||||
goodsDescription.value = JSON.parse(obj.goodsDescription)
|
||||
}
|
||||
if (obj.limitQuota !== '' && obj.limitQuota !== null) {
|
||||
limitQuotaSwitch.value = true
|
||||
} else {
|
||||
limitQuotaSwitch.value = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
show
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
couponApi.getList({ size: 999 }).then((res) => {
|
||||
if (res) {
|
||||
couponList.value = res.records || [];
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.center {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
|
||||
.tips {
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,138 @@
|
||||
<!-- 优惠券图标 -->
|
||||
<template>
|
||||
<div class="container">
|
||||
<div class="icon icon1" v-if="props.item.couponType == 1">
|
||||
<div class="top">
|
||||
<span class="i">¥</span>
|
||||
<span class="num">{{ props.item.discountAmount }}</span>
|
||||
</div>
|
||||
<div class="intro">
|
||||
<span class="t">满{{ props.item.fullAmount }}可用</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="icon icon2" v-if="props.item.couponType == 2">
|
||||
<div class="top">
|
||||
<span class="i">{{ props.item.discountNum }}件</span>
|
||||
<span class="num">商品兑换</span>
|
||||
</div>
|
||||
<div class="intro">
|
||||
<span class="t">满{{ props.item.fullAmount }}可用</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="icon icon3" v-if="props.item.couponType == 3">
|
||||
<div class="top">
|
||||
<span class="num">{{ props.item.discountRate / 10 }}折</span>
|
||||
</div>
|
||||
<div class="intro">
|
||||
<span class="t">满{{ props.item.fullAmount }}可用</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="icon icon2" v-if="props.item.couponType == 4">
|
||||
<div class="top">
|
||||
<span class="i">第二件</span>
|
||||
<span class="num">半价券</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="icon icon2" v-if="props.item.couponType == 6">
|
||||
<div class="top">
|
||||
<span class="i">买一送</span>
|
||||
<span class="num">一券</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
item: {
|
||||
type: Object,
|
||||
default: {}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
$color: #ff1c1c;
|
||||
|
||||
.container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.icon {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
&.icon1 {
|
||||
.top {
|
||||
.i {
|
||||
color: $color;
|
||||
font-size: 24upx;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.num {
|
||||
color: $color;
|
||||
font-size: 72upx;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.icon2 {
|
||||
.top {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.i {
|
||||
color: $color;
|
||||
font-size: 34upx;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.num {
|
||||
color: $color;
|
||||
font-size: 34upx;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.icon3 {
|
||||
.top {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.i {
|
||||
color: $color;
|
||||
font-size: 34upx;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.num {
|
||||
color: $color;
|
||||
font-size: 52upx;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.intro {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
.t {
|
||||
font-size: 22upx;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,16 +1,408 @@
|
||||
<template>
|
||||
<!-- 兑换记录模块 -->
|
||||
<div style="padding: 15px;">
|
||||
<!-- 搜索 -->
|
||||
<Search></Search>
|
||||
<!-- 数据统计 -->
|
||||
<DataStatistics></DataStatistics>
|
||||
<!-- 表格 -->
|
||||
<Content></Content>
|
||||
<div>
|
||||
<div class="row">
|
||||
<el-form :mode="queryForm" inline>
|
||||
<el-form-item label="商品类型">
|
||||
<el-select v-model="queryForm.goodsCategory" style="width: 150px;">
|
||||
<el-option label="优惠券" value="优惠券"></el-option>
|
||||
<el-option label="其它商品" value="其它商品"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态">
|
||||
<el-select v-model="queryForm.status" style="width: 150px;">
|
||||
<el-option v-for="item in statusList" :key="item.label" :label="item.label" :value="item.label"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="搜索">
|
||||
<el-input v-model="queryForm.pointsGoodsName" placeholder="搜索关键词"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-date-picker v-model="time" type="daterange" range-separator="至" start-placeholder="开始时间"
|
||||
end-placeholder="结束时间" @change="timeChange" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="searchHandle">搜索</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="total_info">
|
||||
<div class="item">
|
||||
<img class="icon" src="@/assets/applocation/dds.png">
|
||||
<div class="info">
|
||||
<span class="t1">总订单数</span>
|
||||
<span class="t2">{{ totalInfo.count }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<img class="icon" src="@/assets/applocation/ddje.png">
|
||||
<div class="info">
|
||||
<span class="t1">已支付金额(元)</span>
|
||||
<span class="t2">¥ {{ multiplyAndFormat(totalInfo.totalAmount) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt14">
|
||||
<el-table :data="tableData.list" border stripe v-loading="tableData.loading">
|
||||
<el-table-column label="订单号" prop="orderNo" width="200"></el-table-column>
|
||||
<el-table-column label="用户" prop="orderNo" width="200">
|
||||
<template v-slot="scope">
|
||||
<div class="column">
|
||||
<span class="t1">{{ scope.row.nickName }}</span>
|
||||
<span class="t2">{{ scope.row.phone }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="商品" prop="pointsGoodsName" width="200">
|
||||
<template v-slot="scope">
|
||||
<div class="goods_info" v-if="includesString(scope.row.goodsCategory, '其它商品')">
|
||||
<el-image class="icon" :src="scope.row.goodsImageUrl" fit="cover"></el-image>
|
||||
<div class="info">
|
||||
<div class="name">{{ scope.row.pointsGoodsName }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="coupon_info" v-if="includesString(scope.row.goodsCategory, '优惠券')">
|
||||
<div class="icon">
|
||||
<CouponIcon :item="scope.row.couponInfo" />
|
||||
</div>
|
||||
<div class="info">
|
||||
<div class="name">
|
||||
{{ scope.row.pointsGoodsName }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="商品类型" prop="goodsCategory"></el-table-column>
|
||||
<el-table-column label="消耗积分" prop="spendPoints"></el-table-column>
|
||||
<el-table-column label="支付金额" prop="extraPaymentAmount"></el-table-column>
|
||||
<el-table-column label="状态" prop="status" width="100">
|
||||
<template v-slot="scope">
|
||||
<el-tag :type="statusFilter(scope.row.status).type" disable-transitions>
|
||||
{{ statusFilter(scope.row.status).label }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="下单时间" prop="createTime"></el-table-column>
|
||||
<el-table-column label="兑换码" prop="couponCode"></el-table-column>
|
||||
<el-table-column label="核销时间" prop="checkoutTime"></el-table-column>
|
||||
<el-table-column label="操作" width="120" fixed="right">
|
||||
<template v-slot="scope">
|
||||
<el-button link type="primary" @click="goodsRecordCheckoutHandle(scope.row)"
|
||||
v-if="includesString(scope.row.status, '待核销')">核销</el-button>
|
||||
<el-button link type="danger" @click="returnCostHandle(scope.row)"
|
||||
v-if="includesString(scope.row.status, '退款中')">审核</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<div class="row mt14">
|
||||
<el-pagination v-model:current-page="tableData.page" v-model:page-size="tableData.size"
|
||||
:page-sizes="[10, 30, 50, 100]" background layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="tableData.total" @size-change="handleSizeChange" @current-change="handleCurrentChange" />
|
||||
</div>
|
||||
<el-dialog title="退款" width="600px" v-model="returnVisable">
|
||||
<el-form :model="returnForm" label-width="150" label-position="left">
|
||||
<el-form-item label="是否同意">
|
||||
<el-radio-group v-model="returnForm.type">
|
||||
<el-radio label="同意" :value="1"></el-radio>
|
||||
<el-radio label="驳回" :value="0"></el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="驳回原因" v-if="returnForm.type === 0">
|
||||
<el-input type="textarea" v-model="returnForm.reason" placeholder="请输入驳回原因"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="returnVisable = false">取消</el-button>
|
||||
<el-button type="primary" @click="returnCostConfirmHandle" :loading="returnLoading">同意</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import Search from './exchangerecordsconfig/Search.vue'
|
||||
import DataStatistics from './exchangerecordsconfig/DataStatistics.vue'
|
||||
import Content from './exchangerecordsconfig/Content.vue'
|
||||
</script>
|
||||
import dayjs from 'dayjs'
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { goodsRecordPage, goodsRecordTotal, goodsRecordCheckout, goodsRecordAgreeRefund, goodsRecordRejectRefund } from '@/api/points'
|
||||
import CouponIcon from './coupon-icon.vue';
|
||||
import { includesString, multiplyAndFormat } from '@/utils'
|
||||
import { ElMessageBox } from 'element-plus'
|
||||
|
||||
const time = ref([])
|
||||
const queryForm = reactive({
|
||||
startTime: '',
|
||||
endTime: '',
|
||||
pointsGoodsName: '',
|
||||
goodsCategory: '', // 商品类型 优惠券 其它商品
|
||||
receiveType: '', // 领取方式 店内自取、系统发放
|
||||
status: ''
|
||||
})
|
||||
|
||||
function timeChange(e) {
|
||||
if (e && e.length) {
|
||||
queryForm.startTime = dayjs(e[0]).format("YYYY-MM-DD 00:00:00");
|
||||
queryForm.endTime = dayjs(e[1]).format("YYYY-MM-DD 23:59:59");
|
||||
} else {
|
||||
queryForm.startTime = "";
|
||||
queryForm.endTime = "";
|
||||
}
|
||||
}
|
||||
|
||||
const statusList = ref([
|
||||
{
|
||||
label: '待支付',
|
||||
type: 'info'
|
||||
},
|
||||
{
|
||||
label: '待核销',
|
||||
type: 'primary'
|
||||
},
|
||||
{
|
||||
label: '已完成',
|
||||
type: 'success'
|
||||
},
|
||||
{
|
||||
label: '退款中',
|
||||
type: 'warning'
|
||||
},
|
||||
{
|
||||
label: '已退款',
|
||||
type: 'info'
|
||||
},
|
||||
])
|
||||
|
||||
function statusFilter(status) {
|
||||
const obj = statusList.value.find(item => item.label == status)
|
||||
if (obj) {
|
||||
return obj
|
||||
} else {
|
||||
return {
|
||||
label: status,
|
||||
type: 'info'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const tableData = reactive({
|
||||
loading: false,
|
||||
page: 1,
|
||||
size: 10,
|
||||
total: 0,
|
||||
list: []
|
||||
})
|
||||
|
||||
const totalInfo = reactive({
|
||||
count: 0,
|
||||
totalAmount: 0
|
||||
})
|
||||
|
||||
function searchHandle() {
|
||||
tableData.page = 1
|
||||
goodsRecordPageAjax();
|
||||
goodsRecordTotalAjax()
|
||||
}
|
||||
|
||||
// 分页大小发生变化
|
||||
function handleSizeChange(e) {
|
||||
tableData.size = e;
|
||||
goodsRecordPageAjax();
|
||||
goodsRecordTotalAjax()
|
||||
}
|
||||
|
||||
// 分页发生变化
|
||||
function handleCurrentChange(e) {
|
||||
tableData.page = e;
|
||||
goodsRecordPageAjax();
|
||||
goodsRecordTotalAjax()
|
||||
}
|
||||
|
||||
// 积分:积分商品:兑换统计
|
||||
async function goodsRecordTotalAjax() {
|
||||
try {
|
||||
const res = await goodsRecordTotal({
|
||||
...queryForm,
|
||||
page: tableData.page,
|
||||
size: tableData.size
|
||||
})
|
||||
totalInfo.count = res.count || 0
|
||||
totalInfo.totalAmount = res.totalAmount || 0
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 积分:积分商品:兑换记录
|
||||
async function goodsRecordPageAjax() {
|
||||
try {
|
||||
tableData.loading = true
|
||||
const res = await goodsRecordPage({
|
||||
...queryForm,
|
||||
page: tableData.page,
|
||||
size: tableData.size
|
||||
})
|
||||
tableData.list = res.records
|
||||
tableData.total = res.totalRow
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
setTimeout(() => {
|
||||
tableData.loading = false
|
||||
}, 500);
|
||||
}
|
||||
|
||||
// 核销
|
||||
function goodsRecordCheckoutHandle(row) {
|
||||
ElMessageBox.confirm('确认要核销吗?').then(async () => {
|
||||
try {
|
||||
await goodsRecordCheckout(row.couponCode)
|
||||
ElNotification({
|
||||
title: '注意',
|
||||
message: '核销成功',
|
||||
type: 'success'
|
||||
})
|
||||
goodsRecordPageAjax()
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}).catch(() => {
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
// 退款操作
|
||||
const returnVisable = ref(false)
|
||||
const returnLoading = ref(false)
|
||||
const returnForm = ref({
|
||||
type: 1,
|
||||
recordId: '',
|
||||
orderNo: '',
|
||||
reason: '',
|
||||
})
|
||||
function returnCostHandle(row) {
|
||||
returnForm.value.recordId = row.id
|
||||
returnForm.value.orderNo = row.orderNo
|
||||
returnVisable.value = true
|
||||
}
|
||||
|
||||
// 退款操作
|
||||
async function returnCostConfirmHandle() {
|
||||
try {
|
||||
returnLoading.value = true
|
||||
if (returnForm.value.type == 1) {
|
||||
// 同意
|
||||
await goodsRecordAgreeRefund(returnForm.value)
|
||||
} else {
|
||||
// 驳回
|
||||
await goodsRecordRejectRefund(returnForm.value)
|
||||
}
|
||||
returnVisable.value = false
|
||||
ElNotification({
|
||||
title: '注意',
|
||||
message: '操作成功',
|
||||
type: 'success'
|
||||
})
|
||||
goodsRecordPageAjax()
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
setTimeout(() => {
|
||||
returnLoading.value = false
|
||||
}, 500);
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
goodsRecordPageAjax()
|
||||
goodsRecordTotalAjax()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.goods_info,
|
||||
.coupon_info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
|
||||
.icon {
|
||||
$size: 70px;
|
||||
width: $size;
|
||||
height: $size;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 1px solid #ececec;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.name {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.row {
|
||||
&.mt14 {
|
||||
margin-top: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.column {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.t1 {
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.t2 {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
|
||||
.total_info {
|
||||
display: flex;
|
||||
gap: 14px;
|
||||
|
||||
.item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 14px;
|
||||
background-color: #fff;
|
||||
border: 1px solid #ececec;
|
||||
border-radius: 8px;
|
||||
|
||||
.icon {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
}
|
||||
|
||||
.info {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
flex-direction: column;
|
||||
|
||||
.t1 {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.t2 {
|
||||
color: #333;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,16 @@
|
||||
<template>
|
||||
<!-- 兑换记录模块 -->
|
||||
<div style="padding: 15px;">
|
||||
<!-- 搜索 -->
|
||||
<Search></Search>
|
||||
<!-- 数据统计 -->
|
||||
<DataStatistics></DataStatistics>
|
||||
<!-- 表格 -->
|
||||
<Content></Content>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import Search from './exchangerecordsconfig/Search.vue'
|
||||
import DataStatistics from './exchangerecordsconfig/DataStatistics.vue'
|
||||
import Content from './exchangerecordsconfig/Content.vue'
|
||||
</script>
|
||||
@@ -360,7 +360,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item item6">
|
||||
<!-- <div class="item item6">
|
||||
<div class="row_wrap">
|
||||
<div class="row">
|
||||
<div class="title">净利润</div>
|
||||
@@ -375,7 +375,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -447,8 +447,15 @@
|
||||
<div class="item">
|
||||
<div class="header">
|
||||
<div class="rate_title">
|
||||
<span class="t1">毛利率/净利率</span>
|
||||
<span class="t2">今天 {{ initInterestRateTime }} 更新</span>
|
||||
<div class="column">
|
||||
<span class="t1">毛利率</span>
|
||||
<span class="t2">今天 {{ initInterestRateTime }} 更新</span>
|
||||
</div>
|
||||
<!-- <span class="t1">毛利率/净利率</span> -->
|
||||
<el-radio-group v-model="interestRateDay" @change="profitRateBarChart">
|
||||
<el-radio-button value="7">近7天</el-radio-button>
|
||||
<el-radio-button value="30">30天</el-radio-button>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
</div>
|
||||
<div ref="initInterestRate" v-loading="initInterestRateLoading" class="chart" style="height: 350px" />
|
||||
@@ -457,8 +464,14 @@
|
||||
<div class="item">
|
||||
<div class="header">
|
||||
<div class="rate_title">
|
||||
<span class="t1">成本(元)</span>
|
||||
<span class="t2">今天 {{ costUpdateTime }} 更新</span>
|
||||
<div class="column">
|
||||
<span class="t1">成本(元)</span>
|
||||
<span class="t2">今天 {{ costUpdateTime }} 更新</span>
|
||||
</div>
|
||||
<el-radio-group v-model="costDay" @change="costLineChart">
|
||||
<el-radio-button value="7">近7天</el-radio-button>
|
||||
<el-radio-button value="30">30天</el-radio-button>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
</div>
|
||||
<div ref="costRef" v-loading="costLoading" class="chart" style="height: 350px" />
|
||||
@@ -615,7 +628,9 @@ export default {
|
||||
initInterestRateTime: '',
|
||||
costLoading: true,
|
||||
costRef: null,
|
||||
costUpdateTime: ''
|
||||
costUpdateTime: '',
|
||||
interestRateDay: '7',
|
||||
costDay: '7'
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -686,14 +701,21 @@ export default {
|
||||
* 获取分店列表
|
||||
*/
|
||||
async geiShopList() {
|
||||
let res = await ShopApi.getBranchList()
|
||||
this.branchList = res;
|
||||
this.shopId = res[0].shopId
|
||||
try {
|
||||
let res = await ShopApi.getBranchList()
|
||||
this.branchList = res;
|
||||
this.shopId = res[0].shopId
|
||||
} catch (error) {
|
||||
console.log('获取分店列表===', error);
|
||||
}
|
||||
},
|
||||
shopChange() {
|
||||
this.summarytrade();
|
||||
this.lineChartTypeChange(this.lineChartType)
|
||||
this.dateProduct()
|
||||
|
||||
this.profitRateBarChart()
|
||||
this.costLineChart()
|
||||
},
|
||||
// 切换时间
|
||||
timeChange(e, index = 0) {
|
||||
@@ -1071,7 +1093,6 @@ export default {
|
||||
],
|
||||
});
|
||||
},
|
||||
// 初始化毛利率/净利率图表
|
||||
initInterestRateChart(time, data) {
|
||||
// 销毁旧实例,避免重复创建
|
||||
if (this.initInterestRate) {
|
||||
@@ -1100,7 +1121,6 @@ export default {
|
||||
return `
|
||||
<div style="margin-bottom:4px;">${xName}</div>
|
||||
<div><span style="display:inline-block;width:8px;height:8px;background:${color1};margin-right:6px;border-radius:2px;"></span>毛利率:${profitRate}%</div>
|
||||
<div><span style="display:inline-block;width:8px;height:8px;background:${color2};margin-right:6px;border-radius:2px;"></span>净利率:${netProfitRate}%</div>
|
||||
`;
|
||||
},
|
||||
// 保留你原有的提示框样式
|
||||
@@ -1146,17 +1166,96 @@ export default {
|
||||
barGap: "0%", // 保持柱子紧贴
|
||||
barWidth: time.length <= 7 ? "50%" : "30%",
|
||||
data: profitRateData, // 预处理后的毛利率数据
|
||||
},
|
||||
{
|
||||
name: '净利率',
|
||||
type: "bar",
|
||||
barGap: "0%",
|
||||
barWidth: time.length <= 7 ? "50%" : "30%",
|
||||
data: netProfitRateData, // 预处理后的净利率数据
|
||||
},
|
||||
}
|
||||
],
|
||||
});
|
||||
},
|
||||
// 初始化毛利率/净利率图表
|
||||
// initInterestRateChart(time, data) {
|
||||
// // 销毁旧实例,避免重复创建
|
||||
// if (this.initInterestRate) {
|
||||
// this.initInterestRate.dispose();
|
||||
// }
|
||||
// this.initInterestRate = echarts.init(this.$refs.initInterestRate);
|
||||
|
||||
// // 预处理数据:将毛利率和净利率按索引对应(关键,用于手动匹配)
|
||||
// const profitRateData = data.map(item => item.profitRate || 0);
|
||||
// const netProfitRateData = data.map(item => item.netProfitRate || 0);
|
||||
|
||||
// this.initInterestRate.setOption({
|
||||
// tooltip: {
|
||||
// trigger: "item", // 保留 item 模式(确保能触发,之前已验证有效)
|
||||
// // 核心:手动查找当前 X 轴索引对应的另一个系列数据,拼接显示
|
||||
// formatter: (params) => {
|
||||
// const index = params.dataIndex; // 获取当前数据的索引(X轴位置)
|
||||
// const xName = time[index]; // 当前 X 轴分类名称(如时间)
|
||||
// const color1 = "#165DFF"; // 毛利率颜色(与 series 一致)
|
||||
// const color2 = "#14C9C9"; // 净利率颜色(与 series 一致)
|
||||
// // 当前系列数据 + 另一个系列数据(按索引匹配)
|
||||
// const profitRate = profitRateData[index].toFixed(2);
|
||||
// const netProfitRate = netProfitRateData[index].toFixed(2);
|
||||
|
||||
// // 拼接提示框内容(彩色方块 + 两个指标)
|
||||
// return `
|
||||
// <div style="margin-bottom:4px;">${xName}</div>
|
||||
// <div><span style="display:inline-block;width:8px;height:8px;background:${color1};margin-right:6px;border-radius:2px;"></span>毛利率:${profitRate}%</div>
|
||||
// <div><span style="display:inline-block;width:8px;height:8px;background:${color2};margin-right:6px;border-radius:2px;"></span>净利率:${netProfitRate}%</div>
|
||||
// `;
|
||||
// },
|
||||
// // 保留你原有的提示框样式
|
||||
// padding: 10,
|
||||
// textStyle: { fontSize: 11 },
|
||||
// backgroundColor: "#fff",
|
||||
// borderColor: "#eee",
|
||||
// borderWidth: 1,
|
||||
// boxShadow: "0 2px 8px rgba(0,0,0,0.08)"
|
||||
// },
|
||||
// xAxis: [
|
||||
// {
|
||||
// type: "category",
|
||||
// data: time,
|
||||
// axisTick: { alignWithLabel: true },
|
||||
// axisLine: { lineStyle: { color: "#999" } },
|
||||
// axisLabel: {
|
||||
// rotate: time.length <= 7 ? 0 : 45,
|
||||
// interval: 0,
|
||||
// fontSize: "9",
|
||||
// },
|
||||
// },
|
||||
// ],
|
||||
// color: ["#165DFF", "#14C9C9", "#F98B26"], // 系列颜色不变
|
||||
// yAxis: [
|
||||
// {
|
||||
// type: "value",
|
||||
// axisLine: { lineStyle: { color: "#999" } },
|
||||
// splitLine: { lineStyle: { type: "dashed", color: "#ececec" } },
|
||||
// axisLabel: { formatter: "{value}%" }, // Y轴加百分号
|
||||
// },
|
||||
// ],
|
||||
// grid: {
|
||||
// top: '5%',
|
||||
// right: '5%',
|
||||
// bottom: '8%',
|
||||
// left: '8%',
|
||||
// },
|
||||
// series: [
|
||||
// {
|
||||
// name: "毛利率",
|
||||
// type: "bar",
|
||||
// barGap: "0%", // 保持柱子紧贴
|
||||
// barWidth: time.length <= 7 ? "50%" : "30%",
|
||||
// data: profitRateData, // 预处理后的毛利率数据
|
||||
// },
|
||||
// {
|
||||
// name: '净利率',
|
||||
// type: "bar",
|
||||
// barGap: "0%",
|
||||
// barWidth: time.length <= 7 ? "50%" : "30%",
|
||||
// data: netProfitRateData, // 预处理后的净利率数据
|
||||
// },
|
||||
// ],
|
||||
// });
|
||||
// },
|
||||
// 初始化销售额图表
|
||||
initPayChart(data) {
|
||||
this.payChart = echarts.init(this.$refs.payChart);
|
||||
@@ -1230,7 +1329,7 @@ export default {
|
||||
async profitRateBarChart() {
|
||||
try {
|
||||
this.initInterestRateLoading = true;
|
||||
const res = await dataSummaryApi.profitRateBarChart({ day: this.saleActive, shopId: this.shopId });
|
||||
const res = await dataSummaryApi.profitRateBarChart({ day: this.interestRateDay, shopId: this.shopId });
|
||||
|
||||
this.initInterestRateTime = dayjs().format('HH:mm')
|
||||
|
||||
@@ -1254,7 +1353,7 @@ export default {
|
||||
async costLineChart() {
|
||||
try {
|
||||
this.costLoading = true;
|
||||
const res = await dataSummaryApi.costLineChart({ day: this.saleActive, shopId: this.shopId });
|
||||
const res = await dataSummaryApi.costLineChart({ day: this.costDay, shopId: this.shopId });
|
||||
|
||||
this.costUpdateTime = dayjs().format('HH:mm')
|
||||
|
||||
@@ -1903,6 +2002,11 @@ export default {
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
.column {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.t1 {
|
||||
font-size: 16px;
|
||||
color: #111;
|
||||
|
||||
@@ -330,6 +330,7 @@ const handleImageError = (item) => {
|
||||
|
||||
.name {
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.intro {
|
||||
|
||||
@@ -236,7 +236,8 @@ export default {
|
||||
tableData: [],
|
||||
selectItem: {},
|
||||
imageUrl: "",
|
||||
imgList: []
|
||||
imgList: [],
|
||||
shopName: ''
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
@@ -261,6 +262,9 @@ export default {
|
||||
},
|
||||
// 多图上传成功
|
||||
async MultiOnSuccess(response) {
|
||||
console.log(response);
|
||||
console.log(this.imgList);
|
||||
|
||||
if (!response && this.imgList.length > 0) {
|
||||
console.log(this.imgList);
|
||||
await nextTick()
|
||||
@@ -301,6 +305,8 @@ export default {
|
||||
this.selectItem = { autoKey, id, name, value };
|
||||
if (this.isJsonArrayString(value)) {
|
||||
this.imgList = JSON.parse(value)
|
||||
} else {
|
||||
this.imgList = []
|
||||
}
|
||||
console.log(this.selectItem);
|
||||
},
|
||||
|
||||
@@ -29,10 +29,10 @@
|
||||
<el-form-item label="数量">
|
||||
<el-input-number v-model="form.num" controls-position="right" :min="1"></el-input-number>
|
||||
</el-form-item>
|
||||
<el-form-item label="选择优惠劵" v-if="form.isGiftCoupon == 1">
|
||||
<el-form-item label="选择优惠券" v-if="form.isGiftCoupon == 1">
|
||||
<div>
|
||||
<el-button type="primary" icon="el-icon-plus" @click="$refs.coupon.show([...productIds])">
|
||||
添加优惠劵
|
||||
添加优惠券
|
||||
</el-button>
|
||||
</div>
|
||||
<div class="shop_list">
|
||||
@@ -145,7 +145,7 @@ export default {
|
||||
if (this.form.isGiftCoupon == 1) {
|
||||
if (this.productIds.length == 0) {
|
||||
this.$message({
|
||||
message: "请选择优惠劵",
|
||||
message: "请选择优惠券",
|
||||
type: "warning",
|
||||
});
|
||||
return false;
|
||||
@@ -190,7 +190,7 @@ export default {
|
||||
this.dialogVisible = true;
|
||||
if (obj && obj.id) {
|
||||
this.form = { ...obj };
|
||||
// 留着以后说不定多个优惠劵
|
||||
// 留着以后说不定多个优惠券
|
||||
// let res = await activate(obj.id)
|
||||
// this.productIds = res
|
||||
if (obj.couponId) {
|
||||
|
||||
Reference in New Issue
Block a user