Merge remote-tracking branch 'origin/master' into feature/vue3

This commit is contained in:
xingyu4j
2022-11-14 09:15:19 +08:00
307 changed files with 12436 additions and 5278 deletions

View File

@ -1,54 +0,0 @@
import request from '@/utils/request'
// 创建优惠券模板
export function create(data) {
return request({
url: '/coupon/template/create',
method: 'post',
data: data
})
}
// 更新优惠券模板
export function update(data) {
return request({
url: '/coupon/template/update',
method: 'put',
data: data
})
}
// 删除优惠券模板
export function deleteCouponTemplete (id) {
return request({
url: '/coupon/template/delete?id=' + id,
method: 'delete'
})
}
// 获得优惠券模板
export function get(id) {
return request({
url: '/coupon/template/get?id=' + id,
method: 'get'
})
}
// 获得优惠券模板分页
export function getPage(query) {
return request({
url: '/coupon/template/page',
method: 'get',
params: query
})
}
// 导出优惠券模板 Excel
export function exportExcel(query) {
return request({
url: '/coupon/template/export-excel',
method: 'get',
params: query,
responseType: 'blob'
})
}

View File

@ -43,6 +43,25 @@ export function getPropertyPage(query) {
})
}
// 获得规格名称列表
export function getPropertyList(query) {
return request({
url: '/product/property/list',
method: 'get',
params: query
})
}
// 获得规格名称列表
export function getPropertyListAndValue(query) {
return request({
url: '/product/property/listAndValue',
method: 'get',
params: query
})
}
// 导出规格名称 Excel
export function exportPropertyExcel(query) {
return request({
@ -52,3 +71,49 @@ export function exportPropertyExcel(query) {
responseType: 'blob'
})
}
// ------------------------ 规格名称值 -------------------
// 获得规格名称值分页
export function getPropertyValuePage(query) {
return request({
url: '/product/property/value/page',
method: 'get',
params: query
})
}
// 获得规格名称值
export function getPropertyValue(id) {
return request({
url: '/product/property/value/get?id=' + id,
method: 'get'
})
}
// 创建规格名称值
export function createPropertyValue(data) {
return request({
url: '/product/property/value/create',
method: 'post',
data: data
})
}
// 更新规格名称值
export function updatePropertyValue(data) {
return request({
url: '/product/property/value/update',
method: 'put',
data: data
})
}
// 删除规格名称
export function deletePropertyValue(id) {
return request({
url: '/product/property/value/delete?id=' + id,
method: 'delete'
})
}

View File

@ -0,0 +1,9 @@
import request from '@/utils/request'
// 获得商品 SKU 选项的列表
export function getSkuOptionList() {
return request({
url: '/product/sku/get-option-list',
method: 'get',
})
}

View File

@ -1,6 +1,6 @@
import request from '@/utils/request'
// 创建商品spu
// 创建商品 SPU
export function createSpu(data) {
return request({
url: '/product/spu/create',
@ -9,7 +9,7 @@ export function createSpu(data) {
})
}
// 更新商品spu
// 更新商品 SPU
export function updateSpu(data) {
return request({
url: '/product/spu/update',
@ -18,7 +18,7 @@ export function updateSpu(data) {
})
}
// 删除商品spu
// 删除商品 SPU
export function deleteSpu(id) {
return request({
url: '/product/spu/delete?id=' + id,
@ -34,7 +34,15 @@ export function getSpu(id) {
})
}
// 获得商品spu分页
// 获得商品 SPU 详情
export function getSpuDetail(id) {
return request({
url: '/product/spu/get/detail?id=' + id,
method: 'get'
})
}
// 获得商品 SPU 分页
export function getSpuPage(query) {
return request({
url: '/product/spu/page',
@ -42,3 +50,11 @@ export function getSpuPage(query) {
params: query
})
}
// 获得商品 SPU 精简列表
export function getSpuSimpleList() {
return request({
url: '/product/spu/get-simple-list',
method: 'get',
})
}

View File

@ -0,0 +1,18 @@
import request from '@/utils/request'
// 删除优惠劵
export function deleteCoupon(id) {
return request({
url: '/promotion/coupon/delete?id=' + id,
method: 'delete'
})
}
// 获得优惠劵分页
export function getCouponPage(query) {
return request({
url: '/promotion/coupon/page',
method: 'get',
params: query
})
}

View File

@ -0,0 +1,67 @@
import request from '@/utils/request'
// 创建优惠劵模板
export function createCouponTemplate(data) {
return request({
url: '/promotion/coupon-template/create',
method: 'post',
data: data
})
}
// 更新优惠劵模板
export function updateCouponTemplate(data) {
return request({
url: '/promotion/coupon-template/update',
method: 'put',
data: data
})
}
// 更新优惠劵模板的状态
export function updateCouponTemplateStatus(id, status) {
const data = {
id,
status
}
return request({
url: '/promotion/coupon-template/update-status',
method: 'put',
data: data
})
}
// 删除优惠劵模板
export function deleteCouponTemplate(id) {
return request({
url: '/promotion/coupon-template/delete?id=' + id,
method: 'delete'
})
}
// 获得优惠劵模板
export function getCouponTemplate(id) {
return request({
url: '/promotion/coupon-template/get?id=' + id,
method: 'get'
})
}
// 获得优惠劵模板分页
export function getCouponTemplatePage(query) {
return request({
url: '/promotion/coupon-template/page',
method: 'get',
params: query
})
}
// 导出优惠劵模板 Excel
export function exportCouponTemplateExcel(query) {
return request({
url: '/promotion/coupon-template/export-excel',
method: 'get',
params: query,
responseType: 'blob'
})
}

View File

@ -0,0 +1,52 @@
import request from '@/utils/request'
// 创建限时折扣活动
export function createDiscountActivity(data) {
return request({
url: '/promotion/discount-activity/create',
method: 'post',
data: data
})
}
// 更新限时折扣活动
export function updateDiscountActivity(data) {
return request({
url: '/promotion/discount-activity/update',
method: 'put',
data: data
})
}
// 关闭限时折扣活动
export function closeDiscountActivity(id) {
return request({
url: '/promotion/discount-activity/close?id=' + id,
method: 'put'
})
}
// 删除限时折扣活动
export function deleteDiscountActivity(id) {
return request({
url: '/promotion/discount-activity/delete?id=' + id,
method: 'delete'
})
}
// 获得限时折扣活动
export function getDiscountActivity(id) {
return request({
url: '/promotion/discount-activity/get?id=' + id,
method: 'get'
})
}
// 获得限时折扣活动分页
export function getDiscountActivityPage(query) {
return request({
url: '/promotion/discount-activity/page',
method: 'get',
params: query
})
}

View File

@ -0,0 +1,52 @@
import request from '@/utils/request'
// 创建满减送活动
export function createRewardActivity(data) {
return request({
url: '/promotion/reward-activity/create',
method: 'post',
data: data
})
}
// 更新满减送活动
export function updateRewardActivity(data) {
return request({
url: '/promotion/reward-activity/update',
method: 'put',
data: data
})
}
// 关闭满减送活动
export function closeRewardActivity(id) {
return request({
url: '/promotion/reward-activity/close?id=' + id,
method: 'put'
})
}
// 删除满减送活动
export function deleteRewardActivity(id) {
return request({
url: '/promotion/reward-activity/delete?id=' + id,
method: 'delete'
})
}
// 获得满减送活动
export function getRewardActivity(id) {
return request({
url: '/promotion/reward-activity/get?id=' + id,
method: 'get'
})
}
// 获得满减送活动分页
export function getRewardActivityPage(query) {
return request({
url: '/promotion/reward-activity/page',
method: 'get',
params: query
})
}

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1668244964043" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3750" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><path d="M451.673935 994.395699C478.883834 1025.019147 524.254807 1024.808979 551.400292 993.928851 553.755808 991.387908 558.821323 985.796762 565.872444 977.84835 577.572838 964.659017 590.597131 949.62432 604.615947 932.998315 644.662065 885.504506 684.708678 834.717818 722.129538 782.646447 759.658524 730.424619 792.492213 679.709274 819.314991 631.458462 868.685946 542.646317 896 465.543426 896 402.285715 896 180.109449 719.301715 0 501.333333 0 283.364952 0 106.666667 180.109449 106.666667 402.285715 106.666667 465.598716 134.05152 542.80573 183.54613 631.762622 210.371803 679.976529 243.193308 730.651876 280.699364 782.833154 318.155192 834.94455 358.239268 885.77421 398.322835 933.311031 412.354743 949.952073 425.391185 965.00073 437.102468 978.202579 444.160087 986.158466 449.230214 991.754921 451.982775 994.736706L451.673935 994.395699ZM486.822684 961.321348C484.281231 958.568254 479.425084 953.207989 472.585916 945.498359 461.135889 932.591017 448.364015 917.847761 434.602351 901.527215 395.275714 854.888073 355.949587 805.019548 319.289224 754.014863 282.808749 703.260452 250.983685 654.123578 225.158316 607.707522 179.388826 525.445805 154.50505 455.290161 154.50505 402.285715 154.50505 207.039905 309.785362 48.761905 501.333333 48.761905 692.881306 48.761905 848.161617 207.039905 848.161617 402.285715 848.161617 455.246022 823.345286 525.298263 777.693969 607.419251 751.873483 653.867066 720.038415 703.039925 683.537446 753.831262 646.912604 804.794967 607.624538 854.619674 568.335977 901.215038 554.587654 917.520243 541.828177 932.24925 530.389289 945.143797 523.556841 952.845711 518.705521 958.200435 516.166694 960.950526 507.543772 970.748911 495.255793 970.80583 487.131524 961.662353L486.822684 961.321348Z" p-id="3751"></path><path d="M714.955981 467.028806C723.919106 442.627955 728.565658 416.668998 728.565658 390.095238 728.565658 268.908183 632.184774 170.666667 513.29293 170.666667 394.401086 170.666667 298.020202 268.908183 298.020202 390.095238 298.020202 511.282291 394.401086 609.52381 513.29293 609.52381 549.003859 609.52381 583.510052 600.631947 614.373097 583.874409 626.032316 577.543868 630.449257 562.77782 624.238611 550.893519 618.027966 539.009218 603.541579 534.507006 591.882359 540.837549 567.900883 553.858639 541.111735 560.761905 513.29293 560.761905 420.821495 560.761905 345.858586 484.351836 345.858586 390.095238 345.858586 295.838641 420.821495 219.428572 513.29293 219.428572 605.764365 219.428572 680.727273 295.838641 680.727273 390.095238 680.727273 410.807981 677.117041 430.977316 670.154965 449.930592 665.522846 462.540883 671.796821 476.591108 684.168282 481.312651 696.53974 486.034191 710.323861 479.639095 714.955981 467.028806L714.955981 467.028806Z" p-id="3752"></path></svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -0,0 +1,211 @@
<template>
<div class="editPage__video">
<el-upload
class="uploader"
list-type="picture-card"
:action="uploadUrl"
:on-success="handleSuccess"
:before-upload="beforeUpload"
:headers="headers"
:on-error="handleError"
:show-file-list="false"
>
<div v-if="uploadFlag" @mouseenter="mouseover" @mouseleave="mouseout">
<i class="el-icon-success success-icon"></i>
<div :class="{'hide': activeHover, 'success': !activeHover}">
<span class="item-actions">
<span
class="item-preview"
@click.stop="handlePreview()"
>
<i class="el-icon-zoom-in"></i>
</span>
<span
class="item-delete"
@click.stop="handleRemove()"
>
<i class="el-icon-delete"></i>
</span>
</span>
</div>
</div>
<i v-else-if="uploadFlag === null" class="el-icon-plus uploader-icon"></i>
<i v-else-if="!uploadFlag" class="el-icon-circle-close uploader-icon" style="color: red"></i>
</el-upload>
<!-- 上传提示 -->
<div class="el-upload__tip" slot="tip" v-if="showTip">
请上传
<template v-if="fileSize"> 大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b> </template>
<template v-if="fileType"> 格式为 <b style="color: #f56c6c">{{ fileType.join("/") }}</b> </template>
的文件
</div>
<el-dialog :visible.sync="dialogVisible" append-to-body width="800" title="预览">
<video width="100%" v-if="videoUrl" controls="controls" :key="menuKey">
<source :src="videoUrl" type="video/mp4" />
</video>
</el-dialog>
</div>
</template>
<script>
import { getAccessToken } from "@/utils/auth";
export default {
props: {
value: [String, Object],
// 大小限制(MB)
fileSize: {
type: Number,
default: 300,
},
// 文件类型, 例如"video/mp4"
fileType: {
type: [String, Array],
default: () =>["video/mp4"],
},
// 是否显示提示
isShowTip: {
type: Boolean,
default: true
}
},
data() {
return {
uploadFlag: null,
activeHover: true,
dialogVisible: false,
videoUrl: null,
// 视频上传
uploadUrl: process.env.VUE_APP_BASE_API + "/admin-api/infra/file/upload", // 请求地址
headers: { Authorization: "Bearer " + getAccessToken() }, // 设置上传的请求头部
// 应付多个组件的情况 记录当前组件的key值
menuKey: 1, // 用来强制刷新,
}
},
watch: {
value: {
handler(val) {
if (val) {
this.videoUrl = val;
this.uploadFlag = true;
}
},
deep: true,
immediate: true
}
},
computed: {
// 是否显示提示
showTip() {
return this.isShowTip && (this.fileType || this.fileSize);
},
},
methods: {
// 上传成功的函数
handleSuccess(res) {
++this.menuKey;
if(res.code === 0){
this.uploadFlag = true;
this.videoUrl = res.data;
this.$emit("input", this.videoUrl);
}else{
this.uploadFlag = false;
this.$message.error("错误!"+ res.msg);
}
},
handleError(){
this.uploadFlag = false;
},
beforeUpload(file) {
const isMp4 = this.fileType.includes(file.type);
const isLt300MB = file.size / 1024 / 1024 < 300;
if (!isMp4) {
this.$message.error("视频只能是"+ this.fileType.join("/") +"格式!");
}
if (!isLt300MB) {
this.$message.error("上传视频大小不能超过 300MB!");
}
return isMp4 && isLt300MB;
},
// 预览
handlePreview() {
this.dialogVisible = true;
},
// 删除视频
handleRemove() {
this.videoUrl = null;
this.uploadFlag = null;
this.$emit("input", null);
},
mouseover(){
this.activeHover = false;
},
mouseout(){
this.activeHover = true;
}
}
}
</script>
<style lang="scss">
.editPage__video {
.hide{
visibility:hidden;
}
.success{
position: relative;
width: 78px;
height: 78px;
line-height: 78px;
background-color: rgba(0,0,0,.5);
transition: opacity .3s;
cursor: default;
.item-preview .el-icon-zoom-in{
width: 30px;
font-size: 20px;
color: #f2f2f2;
cursor: pointer;
}
.item-delete .el-icon-delete{
width: 30px;
font-size: 20px;
color: #f2f2f2;
cursor: pointer;
}
}
.uploader-icon {
font-size: 28px;
color: #8c939d;
width: 80px;
height: 80px;
line-height: 80px;
text-align: center;
position: absolute;
left: 0;
}
.success-icon {
font-size: 28px;
color: green;
width: 80px;
height: 80px;
line-height: 80px;
text-align: center;
position: absolute;
left: 0;
}
.el-upload{
width: 80px;
height: 80px;
}
}
</style>

View File

@ -0,0 +1,24 @@
<template>
<transition-group name="fade-transform" mode="out-in">
<inner-link
v-for="(item, index) in iframeViews"
:key="item.path"
:iframeId="'iframe' + index"
v-show="$route.path === item.path"
:src="item.meta.link"
></inner-link>
</transition-group>
</template>
<script>
import InnerLink from "../InnerLink/index.vue"
export default {
components: { InnerLink },
computed: {
iframeViews() {
return this.$store.state.tagsView.iframeViews
}
}
}
</script>

View File

@ -0,0 +1,47 @@
<template>
<div :style="'height:' + height" v-loading="loading" element-loading-text="正在加载页面,请稍候!">
<iframe
:id="iframeId"
style="width: 100%; height: 100%"
:src="src"
frameborder="no"
></iframe>
</div>
</template>
<script>
export default {
props: {
src: {
type: String,
default: "/"
},
iframeId: {
type: String
}
},
data() {
return {
loading: false,
height: document.documentElement.clientHeight - 94.5 + "px;"
};
},
mounted() {
var _this = this;
const iframeId = ("#" + this.iframeId).replace(/\//g, "\\/");
const iframe = document.querySelector(iframeId);
// iframe页面loading控制
if (iframe.attachEvent) {
this.loading = true;
iframe.attachEvent("onload", function () {
_this.loading = false;
});
} else {
this.loading = true;
iframe.onload = function () {
_this.loading = false;
};
}
}
};
</script>

View File

@ -98,6 +98,17 @@ export const constantRoutes = [
meta: {title: '字典数据', icon: '', activeMenu: '/system/dict'}
}
]
}, {
path: '/property',
component: Layout,
hidden: true,
children: [{
path: 'value/:propertyId(\\d+)',
component: (resolve) => require(['@/views/mall/product/property/value'], resolve),
name: 'PropertyValue',
meta: {title: '规格数据', icon: '', activeMenu: '/product/property'}
}
]
}, {
path: '/job',
component: Layout,
@ -120,6 +131,23 @@ export const constantRoutes = [
meta: {title: '修改生成配置', activeMenu: '/infra/codegen'}
}
]
}, {
path: '/spu',
component: Layout,
hidden: true,
children: [{
path: 'edit/:spuId(\\d+)',
component: (resolve) => require(['@/views/mall/product/spu/save'], resolve),
name: 'SpuEdit',
meta: {title: '修改商品', activeMenu: '/product/spu'}
},
{
path: 'add',
component: (resolve) => require(['@/views/mall/product/spu/save'], resolve),
name: 'SpuAdd',
meta: {title: '添加商品', activeMenu: '/product/spu'}
}
]
}, {
path: '/bpm',
component: Layout,
@ -168,6 +196,28 @@ export const constantRoutes = [
meta: {title: '流程详情', activeMenu: '/bpm/task/my'}
}
]
},
{
path: '/order',
component: Layout,
name: '订单管理',
meta: { title: '订单管理' },
alwaysShow: true,
children: [
{
path: '/mall/trade/order',
name: '商品订单',
meta: { title: '商品订单' },
component: (resolve) => require(['@/views/mall/trade/order'], resolve)
},
{
path: '/mall/trade/order/detail',
name: '订单详情',
hidden: true,
meta: { title: '订单详情' },
component: (resolve) => require(['@/views/mall/trade/order/detail'], resolve)
}
]
}
]

View File

@ -185,37 +185,132 @@ export const PayOrderRefundStatusEnum = {
* 支付退款订单状态枚举
*/
export const PayRefundStatusEnum = {
CREATE:{
status:0,
CREATE: {
status: 0,
name: '退款订单生成'
},
SUCCESS:{
status:1,
SUCCESS: {
status: 1,
name: '退款成功'
},
FAILURE:{
status:2,
FAILURE: {
status: 2,
name: '退款失败'
},
PROCESSING_NOTIFY:{
status:3,
PROCESSING_NOTIFY: {
status: 3,
name: '退款中,渠道通知结果'
},
PROCESSING_QUERY:{
status:4,
PROCESSING_QUERY: {
status: 4,
name: '退款中,系统查询结果'
},
UNKNOWN_RETRY:{
status:5,
UNKNOWN_RETRY: {
status: 5,
name: '状态未知,请重试'
},
UNKNOWN_QUERY:{
status:6,
UNKNOWN_QUERY: {
status: 6,
name: '状态未知,系统查询结果'
},
CLOSE:{
status:99,
CLOSE: {
status: 99,
name: '退款关闭'
}
}
/**
* 商品 SPU 状态
*/
export const ProductSpuStatusEnum = {
RECYCLE: {
status: -1,
name: '回收站'
},
DISABLE: {
status: 0,
name: '下架'
},
ENABLE: {
status: 1,
name: '上架'
},
}
/**
* 优惠类型枚举
*/
export const PromotionDiscountTypeEnum = {
PRICE: {
type: 1,
name: '满减'
},
PERCENT: {
type: 2,
name: '折扣'
}
}
/**
* 优惠劵模板的有限期类型的枚举
*/
export const CouponTemplateValidityTypeEnum = {
DATE: {
type: 1,
name: '固定日期可用'
},
TERM: {
type: 2,
name: '领取之后可用'
}
}
/**
* 营销的商品范围枚举
*/
export const PromotionProductScopeEnum = {
ALL: {
scope: 1,
name: '全部商品参与'
},
SPU: {
scope: 2,
name: '指定商品参与'
}
}
/**
* 营销的条件类型枚举
*/
export const PromotionConditionTypeEnum = {
PRICE: {
type: 10,
name: '满 N 元'
},
COUNT: {
type: 20,
name: '满 N 件'
}
}
/**
* 促销活动的状态枚举
*/
export const PromotionActivityStatusEnum = {
WAIT: {
type: 10,
name: '未开始'
},
RUN: {
type: 20,
name: '进行中'
},
END: {
type: 30,
name: '已结束'
},
CLOSE: {
type: 40,
name: '已关闭'
}
}

View File

@ -56,6 +56,18 @@ export const DICT_TYPE = {
PAY_ORDER_REFUND_STATUS: 'pay_order_refund_status', // 商户支付订单退款状态
PAY_REFUND_ORDER_STATUS: 'pay_refund_order_status', // 退款订单状态
PAY_REFUND_ORDER_TYPE: 'pay_refund_order_type', // 退款订单类别
// ========== MALL - PRODUCT 模块 ==========
PRODUCT_SPU_STATUS: 'product_spu_status', // 商品 SPU 状态
// ========== MALL - PROMOTION 模块 ==========
PROMOTION_DISCOUNT_TYPE: 'promotion_discount_type', // 优惠类型
PROMOTION_PRODUCT_SCOPE: 'promotion_product_scope', // 营销的商品范围
PROMOTION_COUPON_TEMPLATE_VALIDITY_TYPE: 'promotion_coupon_template_validity_type', // 优惠劵模板的有限期类型
PROMOTION_COUPON_STATUS: 'promotion_coupon_status', // 优惠劵的状态
PROMOTION_COUPON_TAKE_TYPE: 'promotion_coupon_take_type', // 优惠劵的领取方式
PROMOTION_ACTIVITY_STATUS: 'promotion_activity_status', // 优惠活动的状态
PROMOTION_CONDITION_TYPE: 'promotion_condition_type', // 营销的条件类型枚举
}
/**
@ -114,6 +126,3 @@ export function getDictDataLabel(dictType, value) {
const dict = getDictData(dictType, value);
return dict ? dict.label : '';
}
export class getDictDataL {
}

View File

@ -1,460 +0,0 @@
<template>
<div class="app-container">
<!-- 搜索工作栏 -->
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="优惠券类" prop="type">
<el-select v-model="queryParams.type" placeholder="请选择优惠券类型 reward-满减 discount-折扣 random-随机" clearable size="small">
<el-option label="请选择字典生成" value="" />
</el-select>
</el-form-item>
<el-form-item label="优惠券名称" prop="name">
<el-input v-model="queryParams.name" placeholder="请输入优惠券名称" clearable @keyup.enter.native="handleQuery"/>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="请选择状态1进行中2已结束-1已关闭" clearable size="small">
<el-option label="请选择字典生成" value="" />
</el-select>
</el-form-item>
<el-form-item label="有效日期结束时间" prop="endTime">
<el-date-picker v-model="queryParams.endTime" style="width: 240px" value-format="yyyy-MM-dd HH:mm:ss" type="daterange"
range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" :default-time="['00:00:00', '23:59:59']" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<!-- 操作工具栏 -->
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
v-hasPermi="['CouponTemplete::create']">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport" :loading="exportLoading"
v-hasPermi="['CouponTemplete::export']">导出</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<!-- 列表 -->
<el-table v-loading="loading" :data="list">
<!-- todo 优惠券类型-->
<el-table-column label="优惠券类型" align="center" prop="type" />
<el-table-column label="优惠券名称" align="center" prop="name" />
<el-table-column label="优惠券图片" align="center" prop="image" />
<el-table-column label="发放数量" align="center" prop="count" />
<el-table-column label="已领取数量" align="center" prop="leadCount" />
<el-table-column label="已使用数量" align="center" prop="usedCount" />
<!-- todo 适用商品类型-->
<!-- <el-table-column label="适用商品类型" align="center" prop="goodsType" />-->
<!-- todo 使用门槛0-无门槛 1-有门槛-->
<el-table-column label="使用门槛" align="center" prop="hasUseLimit" />
<!-- <el-table-column label="满多少元使用 0代表无限制" align="center" prop="atLeast" />-->
<!-- todo 发放面额 折扣-->
<el-table-column label="优惠金额/折扣" align="center" prop="money" />
<!-- <el-table-column label="1 =< 折扣 <= 9.9 当type为discount时需要添加" align="center" prop="discount" />-->
<!-- <el-table-column label="最多折扣金额 当type为discount时可选择性添加" align="center" prop="discountLimit" />-->
<!-- <el-table-column label="最低金额 当type为radom时需要添加" align="center" prop="minMoney" />-->
<!-- <el-table-column label="最大金额 当type为radom时需要添加" align="center" prop="maxMoney" />-->
<!-- todo 1-时间范围过期 2-领取之日固定日期后过期 3-领取次日固定日期后过期 -->
<el-table-column label="有效期限" align="center" prop="validityType" />
<!-- <el-table-column label="使用开始日期 过期类型1时必填" align="center" prop="startUseTime" width="180">-->
<!-- <template v-slot="scope">-->
<!-- <span>{{ parseTime(scope.row.startUseTime) }}</span>-->
<!-- </template>-->
<!-- </el-table-column>-->
<!-- <el-table-column label="使用结束日期 过期类型1时必填" align="center" prop="endUseTime" width="180">-->
<!-- <template v-slot="scope">-->
<!-- <span>{{ parseTime(scope.row.endUseTime) }}</span>-->
<!-- </template>-->
<!-- </el-table-column>-->
<!-- <el-table-column label="有效日期结束时间" align="center" prop="endTime" width="180">-->
<!-- <template v-slot="scope">-->
<!-- <span>{{ parseTime(scope.row.endTime) }}</span>-->
<!-- </template>-->
<!-- </el-table-column>-->
<!-- <el-table-column label="当validity_type为2或者3时需要添加 领取之日起或者次日N天内有效" align="center" prop="fixedTerm" />-->
<!-- <el-table-column label="是否无限制0-否 1是" align="center" prop="whetherLimitless" />-->
<el-table-column label="领取上限" align="center" prop="maxFetch" />
<!-- todo 0-不限制 1- 优惠券仅原价购买商品时可用-->
<el-table-column label="优惠叠加" align="center" prop="whetherForbidPreference" />
<el-table-column label="是否显示" align="center" prop="whetherShow" />
<el-table-column label="订单的优惠总金额" align="center" prop="discountOrderMoney" />
<el-table-column label="用券总成交额" align="center" prop="orderMoney" />
<el-table-column label="是否禁止发放" align="center" prop="whetherForbidden" />
<el-table-column label="使用优惠券购买的商品数量" align="center" prop="orderGoodsNum" />
<el-table-column label="状态" align="center" prop="status" />
<el-table-column label="备注" align="center" prop="couponNameRemark" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #scope>
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
v-hasPermi="['CouponTemplete::update']">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
v-hasPermi="['CouponTemplete::delete']">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页组件 -->
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
@pagination="getList"/>
<!-- 对话框(添加 / 修改) -->
<el-dialog :title="title" :visible.sync="open" width="800px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="150px">
<el-form-item label="优惠券类型" prop="type">
<el-select v-model="form.type" placeholder="请选择优惠券类型 reward-满减 discount-折扣 random-随机">
<el-option label="请选择字典生成" value="" />
</el-select>
</el-form-item>
<el-form-item label="优惠券名称" prop="name">
<el-input v-model="form.name" placeholder="请输入优惠券名称" />
</el-form-item>
<el-form-item label="名称备注" prop="couponNameRemark">
<el-input v-model="form.couponNameRemark" placeholder="请输入名称备注" />
</el-form-item>
<el-form-item label="发放数量" prop="count">
<el-input v-model="form.count" placeholder="请输入发放数量" />
</el-form-item>
<el-form-item label="适用商品类型" prop="goodsType">
<el-radio-group v-model="form.goodsType">
<el-radio label="1">请选择字典生成</el-radio>
</el-radio-group>
</el-form-item>
<!-- todo 请输入适用商品id-->
<el-form-item label="适用商品id" prop="productIds">
<el-input v-model="form.productIds" placeholder="请输入适用商品id" />
</el-form-item>
<el-form-item label="使用门槛" prop="hasUseLimit">
<el-radio-group v-model="form.hasUseLimit">
<el-radio label="1">请选择字典生成</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="满多少元使用" prop="atLeast">
<el-input v-model="form.atLeast" placeholder="请输入满多少元使用 0代表无限制" />
</el-form-item>
<el-form-item label="发放面额" prop="money">
<el-input v-model="form.money" placeholder="请输入发放面额 当type为reward时需要添加" />
</el-form-item>
<el-form-item label="1 =< 折扣 <= 9.9" prop="discount">
<el-input v-model="form.discount" placeholder="请输入1 =< 折扣 <= 9.9 当type为discount时需要添加" />
</el-form-item>
<el-form-item label="最多折扣金额" prop="discountLimit">
<el-input v-model="form.discountLimit" placeholder="请输入最多折扣金额 当type为discount时可选择性添加" />
</el-form-item>
<el-form-item label="最低金额" prop="minMoney">
<el-input v-model="form.minMoney" placeholder="请输入最低金额 当type为radom时需要添加" />
</el-form-item>
<el-form-item label="最大金额" prop="maxMoney">
<el-input v-model="form.maxMoney" placeholder="请输入最大金额 当type为radom时需要添加" />
</el-form-item>
<el-form-item label="过期类型" prop="validityType">
<el-radio-group v-model="form.validityType">
<el-radio label="1">请选择字典生成</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="使用开始日期 过期类型1时必填" prop="startUseTime">
<el-date-picker clearable v-model="form.startUseTime" type="date" value-format="timestamp" placeholder="选择使用开始日期 过期类型1时必填" />
</el-form-item>
<el-form-item label="使用结束日期 过期类型1时必填" prop="endUseTime">
<el-date-picker clearable v-model="form.endUseTime" type="date" value-format="timestamp" placeholder="选择使用结束日期 过期类型1时必填" />
</el-form-item>
<el-form-item label="当validity_type为2或者3时需要添加 领取之日起或者次日N天内有效" prop="fixedTerm">
<el-input v-model="form.fixedTerm" placeholder="请输入当validity_type为2或者3时需要添加 领取之日起或者次日N天内有效" />
</el-form-item>
<el-form-item label="是否无限制0-否 1是" prop="whetherLimitless">
<el-radio-group v-model="form.whetherLimitless">
<el-radio label="1">请选择字典生成</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="每人最大领取个数" prop="maxFetch">
<el-input v-model="form.maxFetch" placeholder="请输入每人最大领取个数" />
</el-form-item>
<el-form-item label="是否开启过期提醒0-不开启 1-开启" prop="whetherExpireNotice">
<el-radio-group v-model="form.whetherExpireNotice">
<el-radio label="1">请选择字典生成</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="过期前N天提醒" prop="expireNoticeFixedTerm">
<el-input v-model="form.expireNoticeFixedTerm" placeholder="请输入过期前N天提醒" />
</el-form-item>
<el-form-item label="优惠叠加 0-不限制 1- 优惠券仅原价购买商品时可用" prop="whetherForbidPreference">
<el-radio-group v-model="form.whetherForbidPreference">
<el-radio label="1">请选择字典生成</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="是否显示" prop="whetherShow">
<el-input v-model="form.whetherShow" placeholder="请输入是否显示" />
</el-form-item>
<el-form-item label="订单的优惠总金额" prop="discountOrderMoney">
<el-input v-model="form.discountOrderMoney" placeholder="请输入订单的优惠总金额" />
</el-form-item>
<el-form-item label="用券总成交额" prop="orderMoney">
<el-input v-model="form.orderMoney" placeholder="请输入用券总成交额" />
</el-form-item>
<el-form-item label="是否禁止发放0-否 1-是" prop="whetherForbidden">
<el-radio-group v-model="form.whetherForbidden">
<el-radio label="1">请选择字典生成</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="使用优惠券购买的商品数量" prop="orderGoodsNum">
<el-input v-model="form.orderGoodsNum" placeholder="请输入使用优惠券购买的商品数量" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-radio-group v-model="form.status">
<el-radio label="1">请选择字典生成</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="有效日期结束时间" prop="endTime">
<el-date-picker clearable v-model="form.endTime" type="date" value-format="timestamp" placeholder="选择有效日期结束时间" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { create, update, deleteCouponTemplete, get, getPage, exportExcel } from "@/api/mall/CouponTemplete/CouponTemplete.js";
import {getDictDatas} from "@/utils/dict";
export default {
name: "",
components: {
},
data() {
return {
// 遮罩层
loading: true,
// 导出遮罩层
exportLoading: false,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 优惠券模板列表
list: [],
// 弹出层标题
title: "",
// 是否显示弹出层
open: false,
// 查询参数
queryParams: {
pageNo: 1,
pageSize: 10,
type: null,
name: null,
couponNameRemark: null,
image: null,
count: null,
leadCount: null,
usedCount: null,
goodsType: null,
productIds: null,
hasUseLimit: null,
atLeast: null,
money: null,
discount: null,
discountLimit: null,
minMoney: null,
maxMoney: null,
validityType: null,
startUseTime: [],
endUseTime: [],
fixedTerm: null,
whetherLimitless: null,
maxFetch: null,
whetherExpireNotice: null,
expireNoticeFixedTerm: null,
whetherForbidPreference: null,
whetherShow: null,
discountOrderMoney: null,
orderMoney: null,
whetherForbidden: null,
orderGoodsNum: null,
status: null,
endTime: [],
createTime: [],
},
//数据字典
datas:getDictDatas(),
// 表单参数
form: {},
// 表单校验
rules: {
type: [{ required: true, message: "优惠券类型 reward-满减 discount-折扣 random-随机不能为空", trigger: "change" }],
name: [{ required: true, message: "优惠券名称不能为空", trigger: "blur" }],
count: [{ required: true, message: "发放数量不能为空", trigger: "blur" }],
leadCount: [{ required: true, message: "已领取数量不能为空", trigger: "blur" }],
usedCount: [{ required: true, message: "已使用数量不能为空", trigger: "blur" }],
goodsType: [{ required: true, message: "适用商品类型1-全部商品可用2-指定商品可用3-指定商品不可用不能为空", trigger: "blur" }],
hasUseLimit: [{ required: true, message: "使用门槛0-无门槛 1-有门槛不能为空", trigger: "blur" }],
atLeast: [{ required: true, message: "满多少元使用 0代表无限制不能为空", trigger: "blur" }],
money: [{ required: true, message: "发放面额 当type为reward时需要添加不能为空", trigger: "blur" }],
discount: [{ required: true, message: "1 =< 折扣 <= 9.9 当type为discount时需要添加不能为空", trigger: "blur" }],
discountLimit: [{ required: true, message: "最多折扣金额 当type为discount时可选择性添加不能为空", trigger: "blur" }],
minMoney: [{ required: true, message: "最低金额 当type为radom时需要添加不能为空", trigger: "blur" }],
maxMoney: [{ required: true, message: "最大金额 当type为radom时需要添加不能为空", trigger: "blur" }],
validityType: [{ required: true, message: "过期类型1-时间范围过期 2-领取之日固定日期后过期 3-领取次日固定日期后过期不能为空", trigger: "blur" }],
fixedTerm: [{ required: true, message: "当validity_type为2或者3时需要添加 领取之日起或者次日N天内有效不能为空", trigger: "blur" }],
whetherLimitless: [{ required: true, message: "是否无限制0-否 1是不能为空", trigger: "blur" }],
maxFetch: [{ required: true, message: "每人最大领取个数不能为空", trigger: "blur" }],
whetherExpireNotice: [{ required: true, message: "是否开启过期提醒0-不开启 1-开启不能为空", trigger: "blur" }],
expireNoticeFixedTerm: [{ required: true, message: "过期前N天提醒不能为空", trigger: "blur" }],
whetherForbidPreference: [{ required: true, message: "优惠叠加 0-不限制 1- 优惠券仅原价购买商品时可用不能为空", trigger: "blur" }],
whetherShow: [{ required: true, message: "是否显示不能为空", trigger: "blur" }],
discountOrderMoney: [{ required: true, message: "订单的优惠总金额不能为空", trigger: "blur" }],
orderMoney: [{ required: true, message: "用券总成交额不能为空", trigger: "blur" }],
whetherForbidden: [{ required: true, message: "是否禁止发放0-否 1-是不能为空", trigger: "blur" }],
orderGoodsNum: [{ required: true, message: "使用优惠券购买的商品数量不能为空", trigger: "blur" }],
status: [{ required: true, message: "状态1进行中2已结束-1已关闭不能为空", trigger: "blur" }],
}
};
},
created() {
this.getList();
},
methods: {
/** 查询列表 */
getList() {
this.loading = true;
// 执行查询
getPage(this.queryParams).then(response => {
this.list = response.data.list;
this.total = response.data.total;
this.loading = false;
});
},
/** 取消按钮 */
cancel() {
this.open = false;
this.reset();
},
/** 表单重置 */
reset() {
this.form = {
id: undefined,
type: undefined,
name: undefined,
couponNameRemark: undefined,
image: undefined,
count: undefined,
leadCount: undefined,
usedCount: undefined,
goodsType: undefined,
productIds: undefined,
hasUseLimit: undefined,
atLeast: undefined,
money: undefined,
discount: undefined,
discountLimit: undefined,
minMoney: undefined,
maxMoney: undefined,
validityType: undefined,
startUseTime: undefined,
endUseTime: undefined,
fixedTerm: undefined,
whetherLimitless: undefined,
maxFetch: undefined,
whetherExpireNotice: undefined,
expireNoticeFixedTerm: undefined,
whetherForbidPreference: undefined,
whetherShow: undefined,
discountOrderMoney: undefined,
orderMoney: undefined,
whetherForbidden: undefined,
orderGoodsNum: undefined,
status: undefined,
endTime: undefined,
};
this.resetForm("form");
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNo = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.title = "添加优惠券模板";
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
const id = row.id;
get(id).then(response => {
this.form = response.data;
this.open = true;
this.title = "修改优惠券模板";
});
},
/** 提交按钮 */
submitForm() {
this.$refs["form"].validate(valid => {
if (!valid) {
return;
}
// 修改的提交
if (this.form.id != null) {
update(this.form).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
});
return;
}
// 添加的提交
create(this.form).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
});
});
},
/** 删除按钮操作 */
handleDelete(row) {
const id = row.id;
this.$modal.confirm('是否确认删除优惠券模板编号为"' + id + '"的数据项?').then(function() {
return deleteCouponTemplete(id);
}).then(() => {
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {});
},
/** 导出按钮操作 */
handleExport() {
// 处理查询参数
let params = {...this.queryParams};
params.pageNo = undefined;
params.pageSize = undefined;
this.$modal.confirm('是否确认导出所有优惠券模板数据项?').then(() => {
this.exportLoading = true;
return exportExcel(params);
}).then(response => {
this.$download.excel(response, '优惠券模板.xls');
this.exportLoading = false;
}).catch(() => {});
}
}
};
</script>

View File

@ -1,8 +1,7 @@
<template>
<div class="app-container">
<!-- 搜索工作栏 -->
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
« <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="品牌名称" prop="name">
<el-input v-model="queryParams.name" placeholder="请输入品牌名称" clearable @keyup.enter.native="handleQuery"/>
</el-form-item>

View File

@ -6,7 +6,7 @@
<el-form-item label="规格名称" prop="name">
<el-input v-model="queryParams.name" placeholder="请输入规格名称" clearable @keyup.enter.native="handleQuery"/>
</el-form-item>
<el-form-item label="开启状态" prop="status">
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="请选择开启状态" clearable size="small">
<el-option v-for="dict in this.getDictDatas(DICT_TYPE.COMMON_STATUS)"
:key="dict.value" :label="dict.label" :value="dict.value"/>
@ -33,24 +33,27 @@
<!-- 列表 -->
<el-table v-loading="loading" :data="list">
<el-table-column label="规格名称" align="center" prop="name" />
<el-table-column label="规格名称" align="center" prop="propertyValueList">
<template v-slot="scope">
<span>{{formatList(scope.row.propertyValueList)}}</span>
<el-table-column label="规格id" align="center" prop="id" />
<el-table-column label="规格名称" align="center" :show-overflow-tooltip="true">
<template slot-scope="scope">
<router-link :to="'/property/value/' + scope.row.id" class="link-type">
<span>{{ scope.row.name }}</span>
</router-link>
</template>
</el-table-column>
</el-table-column>
<el-table-column label="开启状态" align="center" prop="status">
<template v-slot="scope">
<template slot-scope="scope">
<dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status"/>
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template v-slot="scope">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="备注" align="center" prop="left" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template v-slot="scope">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
v-hasPermi="['product:property:update']">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
@ -65,6 +68,9 @@
<!-- 对话框(添加 / 修改) -->
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<el-form-item label="规格id" prop="id" v-if="form.id != null">
<el-input v-model="form.id" disabled />
</el-form-item>
<el-form-item label="规格名称" prop="name">
<el-input v-model="form.name" placeholder="请输入规格名称" />
</el-form-item>
@ -75,26 +81,9 @@
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="属性值">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="addPropertyValue()">添加</el-button>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" placeholder="备注" />
</el-form-item>
<el-form-item
v-for="(domain, index) in form.propertyValueList"
:key="domain.key"
:prop="'propertyValueList.' + index + '.name'"
:rules="{
required: true, message: '属性值不能为空', trigger: 'blur'
}"
>
<el-row>
<el-col :span="18">
<el-input v-model="domain.name" size="mini"></el-input>
</el-col>
<el-col :span="6">
<el-button style="margin-left: 20px;" size="mini" @click.prevent="removePropertyValue(domain)">删除</el-button>
</el-col>
</el-row>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
@ -139,12 +128,17 @@ export default {
form: {
name:'',
status:'',
propertyValueList: [{
name: ''
}],
remark:"",
id: null,
},
// 表单校验
rules: {
name: [
{ required: true, message: "规格不能为空", trigger: "blur" }
],
status: [
{ required: true, message: "状态不能为空", trigger: "blur" }
]
}
};
},
@ -170,12 +164,10 @@ export default {
/** 表单重置 */
reset() {
this.form = {
id: undefined,
name: undefined,
status: undefined,
propertyValueList: [{
name: ''
}]
name:'',
status:'',
remark:"",
id: null,
};
this.resetForm("form");
},
@ -253,27 +245,6 @@ export default {
this.exportLoading = false;
}).catch(() => {});
},
removePropertyValue(item) {
const index = this.form.propertyValueList.indexOf(item)
if (index !== -1) {
this.form.propertyValueList.splice(index, 1)
}
},
addPropertyValue() {
this.form.propertyValueList.push({
name: ''
});
},
formatList(list) {
let str = ''
for (let i = 0; i < list.length; i++) {
str += list[i].name;
if(i !== list.length-1){
str+="/";
}
}
return str
}
}
};
</script>

View File

@ -0,0 +1,267 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="规格名称" prop="propertyId">
<el-select v-model="queryParams.propertyId">
<el-option v-for="item in propertyOptions" :key="item.id" :label="item.id +'-'+ item.name" :value="item.id"/>
</el-select>
</el-form-item>
<el-form-item label="规格值" prop="name">
<el-input v-model="queryParams.name" placeholder="请输入规格值" clearable @keyup.enter.native="handleQuery"/>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="状态" clearable size="small">
<el-option v-for="dict in this.getDictDatas(DICT_TYPE.COMMON_STATUS)"
:key="dict.value" :label="dict.label" :value="dict.value"/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
v-hasPermi="['system:dict:create']">新增
</el-button>
</el-col>
<!-- <el-col :span="1.5">
<el-button type="warning" icon="el-icon-download" size="mini" @click="handleExport" :loading="exportLoading"
v-hasPermi="['system:dict:export']">导出</el-button>
</el-col> -->
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="dataList">
<el-table-column label="规格值id" align="center" prop="id"/>
<el-table-column label="规格值" align="center" prop="name"/>
<el-table-column label="状态" align="center" prop="status">
<template slot-scope="scope">
<dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status"/>
</template>
</el-table-column>
<el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true"/>
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
v-hasPermi="['system:dict:update']">修改
</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
v-hasPermi="['system:dict:delete']">删除
</el-button>
</template>
</el-table-column>
</el-table>
<pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
@pagination="getList"/>
<!-- 添加或修改参数配置对话框 -->
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="90px">
<el-form-item label="规格值编码">
<el-input v-model="form.propertyId" :disabled="true"/>
</el-form-item>
<el-form-item label="规格值" prop="name">
<el-input v-model="form.name" placeholder="请输入数据标签"/>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-radio-group v-model="form.status">
<el-radio v-for="dict in this.getDictDatas(DICT_TYPE.COMMON_STATUS)"
:key="dict.value" :label="parseInt(dict.value)">{{ dict.label }}
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import {
createPropertyValue,
deletePropertyValue,
getProperty,
getPropertyList,
getPropertyValue,
getPropertyValuePage,
updatePropertyValue
} from '@/api/mall/product/property'
export default {
name: "PropertyValue",
data() {
return {
// 遮罩层
loading: true,
// 导出遮罩层
exportLoading: false,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 字典表格数据
dataList: [],
// 默认字典类型
defaultPropertyId: "",
// 弹出层标题
title: "",
// 是否显示弹出层
open: false,
// 类型数据字典
propertyOptions: [],
// 查询参数
queryParams: {
pageNo: 1,
pageSize: 10,
propertyId: undefined,
name: undefined,
status: undefined
},
// 表单参数
form: {},
// 表单校验
rules: {
name: [
{required: true, message: "规格值不能为空", trigger: "blur"}
],
status: [
{required: true, message: "状态不能为空", trigger: "blur"}
]
},
};
},
created() {
const propertyId = this.$route.params && this.$route.params.propertyId;
this.getProperty(propertyId);
this.getPropertyList();
},
methods: {
/** 查询字典类型详细 */
getProperty(propertyId) {
getProperty(propertyId).then(response => {
this.queryParams.propertyId = response.data.id;
this.defaultPropertyId = response.data.id;
this.getList();
});
},
/** 查询字典类型列表 */
getPropertyList() {
getPropertyList().then(response => {
this.propertyOptions = response.data
});
},
/** 查询字典数据列表 */
getList() {
this.loading = true;
getPropertyValuePage(this.queryParams).then(response => {
this.dataList = response.data.list;
this.total = response.data.total;
this.loading = false;
});
},
// 取消按钮
cancel() {
this.open = false;
this.reset();
},
// 表单重置
reset() {
this.form = {
id: undefined,
propertyId: undefined,
name: undefined,
status: undefined,
remark: undefined
};
this.resetForm("form");
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNo = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.queryParams.propertyId = this.defaultPropertyId;
this.handleQuery();
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.title = "添加规格值";
this.form.propertyId = this.queryParams.propertyId;
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
const id = row.id || this.ids
getPropertyValue(id).then(response => {
this.form = response.data;
this.open = true;
this.title = "修改规格值";
});
},
/** 提交按钮 */
submitForm: function () {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.id !== undefined) {
updatePropertyValue(this.form).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
});
} else {
createPropertyValue(this.form).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
});
}
}
});
},
/** 删除按钮操作 */
handleDelete(row) {
const ids = row.id;
this.$modal.confirm('是否确认删除字典编码为"' + ids + '"的数据项?').then(function () {
return deletePropertyValue(ids);
}).then(() => {
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {
});
},
/** 导出按钮操作 */
handleExport() {
const queryParams = this.queryParams;
this.$modal.confirm('是否确认导出所有数据项?').then(() => {
this.exportLoading = true;
return exportData(queryParams);
}).then(response => {
this.$download.excel(response, '字典数据.xls');
this.exportLoading = false;
}).catch(() => {
});
}
}
};
</script>

View File

@ -1,27 +1,50 @@
<template>
<div class="app-container">
<!-- 搜索工作栏 -->
<!-- TODO @Luowenfeng参考界面https://v5.niuteam.cn/shop/goods/lists.html
商品名称商品编码商品分类商品品牌
商品销量商品价格
-->
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="商品名称" prop="name">
<el-input v-model="queryParams.name" placeholder="请输入商品名称" clearable @keyup.enter.native="handleQuery"/>
</el-form-item>
<el-form-item label="分类id" prop="categoryId">
<el-input v-model="queryParams.categoryId" placeholder="请输入分类id" clearable @keyup.enter.native="handleQuery"/>
<el-form-item label="商品编码" prop="code">
<el-input v-model="queryParams.code" placeholder="请输入商品编码" clearable @keyup.enter.native="handleQuery"/>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="请选择上下架状态" clearable size="small">
<el-option label="请选择字典生成" value="" />
<el-option label="上架" value="0" />
<el-option label="下架" value="1" />
<el-form-item label="商品分类" prop="categoryIds">
<el-cascader v-model="queryParams.categoryIds" placeholder="请输入商品分类"
:options="categoryList" :props="propName" clearable ref="category"/>
</el-form-item>
<el-form-item label="商品品牌" prop="brandId">
<el-select v-model="queryParams.brandId" placeholder="请输入商品品牌" clearable @keyup.enter.native="handleQuery">
<el-option v-for="item in brandList" :key="item.id" :label="item.name" :value="item.id"/>
</el-select>
</el-form-item>
<el-form-item label="创建时间">
<el-date-picker v-model="dateRangeCreateTime" style="width: 240px" value-format="yyyy-MM-dd" type="daterange"
range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"/>
<!-- TODO 待实现商品类型 -->
<!-- TODO 待实现商品标签 -->
<!-- TODO 待实现营销活动 -->
<!-- TODO 前端优化商品销量商品价格排的整齐一点 -->
<el-form-item label="商品销量">
<el-col :span="7" style="padding-left:0">
<el-form-item prop="salesCountMin">
<el-input v-model="queryParams.salesCountMin" placeholder="最低销量" clearable @keyup.enter.native="handleQuery"/>
</el-form-item>
</el-col>
<el-col :span="1">-</el-col>
<el-col :span="7" style="padding-left:0">
<el-form-item prop="salesCountMax">
<el-input v-model="queryParams.salesCountMax" placeholder="最高销量" clearable @keyup.enter.native="handleQuery"/>
</el-form-item>
</el-col>
</el-form-item>
<el-form-item label="商品价格" prop="code">
<el-col :span="7" style="padding-left:0">
<el-form-item prop="marketPriceMin">
<el-input v-model="queryParams.marketPriceMin" placeholder="最低价格" clearable @keyup.enter.native="handleQuery"/>
</el-form-item>
</el-col>
<el-col :span="1">-</el-col>
<el-col :span="7" style="padding-left:0">
<el-form-item prop="marketPriceMax">
<el-input v-model="queryParams.marketPriceMax" placeholder="最高价格" clearable @keyup.enter.native="handleQuery"/>
</el-form-item>
</el-col>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
@ -33,101 +56,185 @@
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
v-hasPermi="['product:spu:create']">新增</el-button>
v-hasPermi="['product:spu:create']">添加商品</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList" />
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"/>
</el-row>
<!-- 列表 -->
<el-table v-loading="loading" :data="list">
<!--
TODO @Luowenfeng参考界面
https://v5.niuteam.cn/shop/goods/lists.html
1. 字段商品信息价格库存销量排序创建时间状态操作
2. tab 分成全部销售中仓库中预警中
-->
<el-table-column label="主键" align="center" prop="id" />
<el-table-column label="商品名称" align="center" prop="name" />
<el-table-column label="分类id" align="center" prop="categoryId" />
<el-table-column label="商品主图地址" align="center" prop="picUrls">
<template v-slot="scope">
<img
v-if="scope.row.picUrls"
:src="scope.row.picUrls[0]"
alt="分类图片"
class="img-height"
/>
</template>
</el-table-column>
<el-table-column label="排序字段" align="center" prop="sort" />
<el-table-column label="点击量" align="center" prop="clickCount" />
<el-table-column label="价格区间" align="center" prop="price" />
<el-table-column label="总库存" align="center" prop="totalStock" />
<el-table-column label="状态" align="center" prop="status">
<template v-slot="scope">
<dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status"/>
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template v-slot="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template v-slot="scope">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
v-hasPermi="['product:spu:update']">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
v-hasPermi="['product:spu:delete']">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-tabs v-model="activeTabs" type="card" @tab-click="handleClick">
<!-- 全部 -->
<el-tab-pane label="全部" name="all">
<!-- 列表 -->
<el-table v-loading="loading" :data="list">
<el-table-column label="商品信息" align="center" width="260">
<template slot-scope="scope">
<div class="product-info">
<img v-if="scope.row.picUrls" :src="scope.row.picUrls[0]" alt="分类图片" class="img-height" />
<div class="message">{{ scope.row.name }}</div>
</div>
</template>
<!-- TODO 前端优化可以有个 + 点击后展示每个 sku -->
</el-table-column>
<el-table-column label="价格" align="center" prop="marketPrice" :formatter="formatPrice"/>
<el-table-column label="库存" align="center" prop="totalStock"/>
<el-table-column label="销量" align="center" prop="salesCount"/>
<el-table-column label="排序" align="center" prop="sort"/>
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="状态" align="center" prop="status">
<template slot-scope="scope">
<dict-tag :type="DICT_TYPE.PRODUCT_SPU_STATUS" :value="scope.row.status"/>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
v-hasPermi="['product:spu:update']">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
v-hasPermi="['product:spu:delete']">删除</el-button>
</template>
</el-table-column>
</el-table>
</el-tab-pane>
<!-- 销售中 -->
<el-tab-pane label="销售中" name="on">
<!-- 列表 -->
<el-table v-loading="loading" :data="list">
<el-table-column label="商品信息" align="center" width="260">
<template slot-scope="scope">
<div class="product-info">
<img v-if="scope.row.picUrls" :src="scope.row.picUrls[0]" alt="分类图片" class="img-height"/>
<div class="message">{{ scope.row.name }}</div>
</div>
</template>
</el-table-column>
<el-table-column label="价格" align="center" prop="marketPrice" :formatter="formatPrice"/>
<el-table-column label="库存" align="center" prop="totalStock"/>
<el-table-column label="销量" align="center" prop="salesCount"/>
<el-table-column label="排序" align="center" prop="sort"/>
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="状态" align="center" prop="status">
<template slot-scope="scope">
<dict-tag :type="DICT_TYPE.PRODUCT_SPU_STATUS" :value="scope.row.status"/>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
v-hasPermi="['product:spu:update']">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
v-hasPermi="['product:spu:delete']">删除</el-button>
</template>
</el-table-column>
</el-table>
</el-tab-pane>
<!-- 仓库中 -->
<el-tab-pane label="仓库中" name="off">
<!-- 列表 -->
<el-table v-loading="loading" :data="list">
<el-table-column label="商品信息" align="center" width="260">
<template slot-scope="scope">
<div class="product-info">
<img v-if="scope.row.picUrls" :src="scope.row.picUrls[0]" alt="分类图片" class="img-height"/>
<div class="message">{{ scope.row.name }}</div>
</div>
</template>
</el-table-column>
<el-table-column label="价格" align="center" prop="marketPrice" :formatter="formatPrice"/>
<el-table-column label="库存" align="center" prop="totalStock"/>
<el-table-column label="销量" align="center" prop="salesCount"/>
<el-table-column label="排序" align="center" prop="sort"/>
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="状态" align="center" prop="status">
<template slot-scope="scope">
<dict-tag :type="DICT_TYPE.PRODUCT_SPU_STATUS" :value="scope.row.status"/>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
v-hasPermi="['product:spu:update']">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
v-hasPermi="['product:spu:delete']">删除</el-button>
</template>
</el-table-column>
</el-table>
</el-tab-pane>
<!-- 预警中 -->
<el-tab-pane label="预警中" name="remind">
<!-- 列表 -->
<el-table v-loading="loading" :data="list">
<el-table-column label="商品信息" align="center" width="260">
<template slot-scope="scope">
<div class="product-info">
<img v-if="scope.row.picUrls" :src="scope.row.picUrls[0]" alt="分类图片" class="img-height"/>
<div class="message">{{ scope.row.name }}</div>
</div>
</template>
</el-table-column>
<el-table-column label="价格" align="center" prop="marketPrice" :formatter="formatPrice"/>
<el-table-column label="库存" align="center" prop="totalStock"/>
<el-table-column label="销量" align="center" prop="salesCount"/>
<el-table-column label="排序" align="center" prop="sort"/>
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="状态" align="center" prop="status">
<template slot-scope="scope">
<dict-tag :type="DICT_TYPE.PRODUCT_SPU_STATUS" :value="scope.row.status"/>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
v-hasPermi="['product:spu:update']">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
v-hasPermi="['product:spu:delete']">删除</el-button>
</template>
</el-table-column>
</el-table>
</el-tab-pane>
</el-tabs>
<!-- 分页组件 -->
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
@pagination="getList"/>
<el-dialog :title="title" :visible.sync="open" width="900px" append-to-body destroy-on-close :close-on-click-modal="false" >
<save @closeDialog="closeDialog" :type="dialogType" :obj="dialogObj" v-if="open" />
</el-dialog>
</div>
</template>
<script>
import {
deleteSpu,
getSpuPage,
} from "@/api/mall/product/spu";
import Editor from "@/components/Editor";
import ImageUpload from "@/components/ImageUpload";
import save from "./save";
// 1. TODO @Luowenfeng商品的添加、修改走一个单独的页面不走弹窗https://v5.niuteam.cn/shop/goods/addgoods.html
// 2. TODO
import {deleteSpu, getSpuPage,} from "@/api/mall/product/spu";
import {getProductCategoryList} from "@/api/mall/product/category";
import {getBrandList} from "@/api/mall/product/brand";
import {ProductSpuStatusEnum} from "@/utils/constants";
export default {
name: "Spu",
components: {
Editor,
ImageUpload,
save,
},
data() {
return {
tableLeftTitles: [],
dbTagValues: [],
allhistoryTags: [],
unUseTags: [],
propertyPageList: [],
isShowTagInput: false,
addTagInput: {
name: "",
propertyId: "",
selectValues: [],
selectValueIds: [],
selectObect: [],
activeTabs: "all",
propName: {
checkStrictly: true,
label: "name",
value: "id",
},
skuTags: [],
brandList: [],
categoryList: [],
// 遮罩层
loading: true,
@ -139,59 +246,60 @@ export default {
total: 0,
// 商品spu列表
list: [],
// 弹出层标题
title: "",
// 是否显示弹出层
open: false,
// 弹出层类型
dialogType: "add",
// 弹出层参数
dialogObj:{},
dateRangeCreateTime: [],
// 查询参数
queryParams: {
pageNo: 1,
pageSize: 10,
name: null,
sellPoint: null,
description: null,
code: null,
categoryIds: [],
categoryId: null,
picUrls: null,
sort: null,
likeCount: null,
price: null,
quantity: null,
brandId: null,
status: null,
salesCountMin: null,
salesCountMax: null,
marketPriceMin: null,
marketPriceMax: null,
},
tagIndex: 0,
};
},
created() {
this.getList();
this.getListCategory()
this.getListBrand()
},
methods: {
/** 查询分类列表 */
getListCategory() {
// 执行查询
getProductCategoryList().then((response) => {
this.categoryList = this.handleTree(response.data, "id", "parentId");
});
},
/** 查询品牌列表 */
getListBrand() {
// 执行查询
getBrandList().then((response) => {
this.brandList = response.data;
});
},
/** 查询列表 */
getList() {
this.loading = true;
// 处理查询参数
let params = { ...this.queryParams };
let params = {...this.queryParams};
params.marketPriceMin = this.queryParams.marketPriceMin === null ? null : params.marketPriceMin * 100;
params.marketPriceMax = this.queryParams.marketPriceMax === null ? null : params.marketPriceMax * 100;
params.categoryId = this.queryParams.categoryIds[this.queryParams.categoryIds.length - 1];
this.addBeginAndEndTime(params, this.dateRangeCreateTime, "createTime");
// 执行查询
getSpuPage(params).then((response) => {
response.data.list.forEach(element => {
element.price = this.divide(element.minPrice, 100)+"~"+this.divide(element.maxPrice, 100)
});
this.list = response.data.list;
this.total = response.data.total;
this.loading = false;
});
},
/** 取消按钮 */
cancel() {
this.open = false;
this.reset();
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNo = 1;
@ -200,30 +308,19 @@ export default {
/** 重置按钮操作 */
resetQuery() {
this.dateRangeCreateTime = [];
this.$refs.category.$refs.panel.checkedValue = [];//也可以是指定的值,默认返回值是数组,也可以返回单个值
this.$refs.category.$refs.panel.activePath = [];
this.$refs.category.$refs.panel.syncActivePath();
this.resetForm("queryForm");
this.handleQuery();
},
/** 新增按钮操作 */
handleAdd() {
this.dialogType = "add";
this.dialogObj={};
this.open = true;
this.title = "添加商品spu";
this.$router.push({ name: 'SpuAdd'})
},
/** 修改按钮操作 */
handleUpdate(row) {
this.dialogType = "upd";
this.dialogObj.id = row.id;
this.open = true;
console.log("修改")
this.title = "修改商品spu";
},
closeDialog(){
console.log("关闭")
this.dialogType = "add";
this.dialogObj={};
this.open = false;
this.getList()
this.$router.push({ name: 'SpuEdit', params: { spuId: row.id }})
},
/** 删除按钮操作 */
handleDelete(row) {
@ -232,12 +329,31 @@ export default {
.confirm('是否确认删除商品spu编号为"' + id + '"的数据项?')
.then(function () {
return deleteSpu(id);
})
.then(() => {
}).then(() => {
this.getList();
this.$modal.msgSuccess("删除成功");
})
.catch(() => {});
}).catch(() => {
});
},
formatPrice(row, column, cellValue) {
return '¥' + this.divide(cellValue, 100);
},
// 选中 tab
handleClick(val) {
if (val.name === "all") {
this.queryParams.status = undefined;
this.queryParams.alarmStock = undefined;
} else if (val.name === "on") {
this.queryParams.status = ProductSpuStatusEnum.ENABLE.status;
this.queryParams.alarmStock = undefined;
} else if (val.name === "off") {
this.queryParams.status = ProductSpuStatusEnum.DISABLE.status;
this.queryParams.alarmStock = undefined;
} else if (val.name === "remind") {
this.queryParams.status = undefined;
this.queryParams.alarmStock = true;
}
this.getList();
}
},
};
@ -248,22 +364,27 @@ export default {
margin-left: 10px;
}
.button-new-tag {
margin-left: 10px;
height: 32px;
line-height: 30px;
padding-top: 0;
padding-bottom: 0;
.product-info {
display: flex;
.img-height {
height: 50px;
width: 50px;
}
.message {
margin-left: 10px;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
word-break: break-all;
-webkit-box-orient: vertical;
white-space: normal;
overflow: hidden;
height: 50px;
line-height: 25px;
}
}
.input-new-tag {
width: 90px;
margin-left: 10px;
vertical-align: bottom;
}
.img-height {
height: 65px;
}
}
</style>

View File

@ -1,58 +1,58 @@
<template>
<div class="container">
<el-tabs v-model="activeName" class="tabs" :before-leave="confirmLeave">
<!-- TODO 样式优化表单宽度表单项对齐hr 粗细 -->
<el-tabs v-model="activeName" class="tabs">
<!-- 基础设置 -->
<!-- TODO @luowenfeng基础设置分成基础信息配送信息 -->
<!-- TODO @luowenfengbase=basic 会更好哈 -->
<el-tab-pane label="基础设置" name="base">
<el-form ref="base" :model="baseForm" :rules="rules" label-width="100px" style="width: 95%">
<el-form-item label="商品名称" prop="name">
<el-input v-model="baseForm.name" placeholder="请输入商品名称"/>
<el-input v-model="baseForm.name" placeholder="请输入商品名称" />
</el-form-item>
<el-form-item label="商品卖点">
<el-input type="textarea" v-model="baseForm.sellPoint" placeholder="请输入商品卖点"/>
<el-form-item label="促销语">
<el-input type="textarea" v-model="baseForm.sellPoint" placeholder="请输入促销语"/>
</el-form-item>
<!-- TODO @Luowenfeng商品主图80 x 80 即可 -->
<el-form-item label="商品主图" prop="picUrls">
<ImageUpload v-model="baseForm.picUrls" :value="baseForm.picUrls" :limit="10"/>
<ImageUpload v-model="baseForm.picUrls" :value="baseForm.picUrls" :limit="10" class="mall-image"/>
</el-form-item>
<el-form-item label="商品视频" prop="videoUrl">
<VideoUpload v-model="baseForm.videoUrl" :value="baseForm.videoUrl"/>
</el-form-item>
<!-- TODO @Luowenfeng商品视频 -->
<el-form-item label="商品品牌" prop="brandId">
<el-select v-model="baseForm.brandId" placeholder="请选择商品品牌">
<el-option v-for="item in brandList" :key="item.id" :label="item.name" :value="item.id" />
<el-option v-for="item in brandList" :key="item.id" :label="item.name" :value="item.id"/>
</el-select>
</el-form-item>
<el-form-item label="商品分类" prop="categoryIds">
<el-cascader v-model="baseForm.categoryIds" placeholder="商品分类" style="width: 100%"
:options="categoryList" :props="propName" clearable />
:options="categoryList" :props="propName" clearable/>
</el-form-item>
<el-form-item label="是否上架" prop="status">
<el-radio-group v-model="baseForm.status">
<el-radio :label="0">立即上架</el-radio>
<el-radio :label="1">放入仓库</el-radio>
<el-radio :label="1">立即上架</el-radio>
<el-radio :label="0">放入仓库</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
</el-tab-pane>
<!-- 价格库存 -->
<!-- TODO @luowenfengrates=priceStack 会更好哈 -->
<el-tab-pane label="价格库存" name="rates" class="rates">
<el-form ref="rates" :model="ratesForm" :rules="rules">
<el-form-item label="启用多规格">
<!-- TODO @Luowenfeng改成开关的按钮关闭单规格开启多规格 -->
<el-radio-group v-model="ratesForm.spec" @change="changeRadio">
<el-radio :label="1">单规格</el-radio>
<el-radio :label="2">多规格</el-radio>
</el-radio-group>
<el-switch v-model="specSwitch" @change="changeSpecSwitch"/>
</el-form-item>
<!-- 动态添加规格属性 -->
<div v-show="ratesForm.spec === 2">
<div v-for="(specs, index) in dynamicSpec" :key="index" class="dynamic-spec">
<!-- 删除按钮 -->
<el-button type="danger" icon="el-icon-delete" circle class="spec-delete" @click="removeSpec(index)" />
<el-button type="danger" icon="el-icon-delete" circle class="spec-delete" @click="removeSpec(index)"/>
<div class="spec-header">
规格项
<el-select v-model="specs.specId" filterable placeholder="请选择" @change="changeSpec">
<el-option v-for="item in propertyPageList" :key="item.id" :label="item.name" :value="item.id" />
<el-option v-for="item in propertyPageList" :key="item.id" :label="item.name" :value="item.id"/>
</el-select>
</div>
<div class="spec-values">
@ -67,115 +67,121 @@
<!-- 规格明细 -->
<el-form-item label="规格明细">
<el-table :data="ratesForm.rates" border style="width: 100%" ref="ratesTable">
<template v-if="ratesForm.spec === 2">
<template v-if="this.specSwitch">
<el-table-column :key="index" v-for="(item, index) in dynamicSpec.filter(v => v.specName !== undefined)"
:label="item.specName">
<template v-slot="scope">
<el-input v-if="scope.row.spec" v-model="scope.row.spec[index]" disabled />
<template slot-scope="scope">
<el-input v-if="scope.row.spec" v-model="scope.row.spec[index]" disabled/>
</template>
</el-table-column>
</template>
<el-table-column label="规格图片" width="120px" :render-header="addRedStar" key="90">
<template v-slot="scope">
<ImageUpload v-model="scope.row.picUrl" :limit="1" :isShowTip="false"
style="width: 100px; height: 50px"/>
<template slot-scope="scope">
<ImageUpload v-model="scope.row.picUrl" :limit="1" :isShowTip="false" style="width: 100px; height: 50px"/>
</template>
</el-table-column>
<template v-if="ratesForm.spec === 2">
<el-table-column label="sku名称" :render-header="addRedStar" key="91">
<template v-slot="scope">
<template v-if="this.specSwitch">
<el-table-column label="sku名称" :render-header="addRedStar" key="91">
<template slot-scope="scope">
<el-form-item :prop="'rates.'+ scope.$index + '.name'" :rules="[{required: true, trigger: 'change'}]">
<el-input v-model="scope.row.name" />
<el-input v-model="scope.row.name"/>
</el-form-item>
</template>
</el-table-column>
</template>
<el-table-column label="市场价(元)" :render-header="addRedStar" key="92">
<template v-slot="scope">
<template slot-scope="scope">
<el-form-item :prop="'rates.'+ scope.$index + '.marketPrice'" :rules="[{required: true, trigger: 'change'}]">
<el-input v-model="scope.row.marketPrice"
oninput="value= value.match(/\d+(\.\d{0,2})?/) ? value.match(/\d+(\.\d{0,2})?/)[0] : ''"/>
oninput="value= value.match(/\d+(\.\d{0,2})?/) ? value.match(/\d+(\.\d{0,2})?/)[0] : ''"/>
</el-form-item>
</template>
</el-table-column>
<el-table-column label="销售价(元)" :render-header="addRedStar" key="93">
<template v-slot="scope">
<el-form-item :prop="'rates.'+ scope.$index + '.price'" :rules="[{required: true, trigger: 'change'}]">
<el-input v-model="scope.row.price" oninput="value= value.match(/\d+(\.\d{0,2})?/) ? value.match(/\d+(\.\d{0,2})?/)[0] : ''"></el-input>
<template slot-scope="scope">
<el-form-item :prop="'rates.'+ scope.$index + '.price'"
:rules="[{required: true, trigger: 'change'}]">
<el-input v-model="scope.row.price"
oninput="value= value.match(/\d+(\.\d{0,2})?/) ? value.match(/\d+(\.\d{0,2})?/)[0] : ''" />
</el-form-item>
</template>
</el-table-column>
<el-table-column label="成本价" :render-header="addRedStar" key="94">
<template v-slot="scope">
<el-form-item :prop="'rates.'+ scope.$index + '.costPrice'" :rules="[{required: true, trigger: 'change'}]">
<el-input
v-model="scope.row.costPrice"
oninput="value= value.match(/\d+(\.\d{0,2})?/) ? value.match(/\d+(\.\d{0,2})?/)[0] : ''"
></el-input>
<template slot-scope="scope">
<el-form-item :prop="'rates.'+ scope.$index + '.costPrice'"
:rules="[{required: true, trigger: 'change'}]">
<el-input v-model="scope.row.costPrice"
oninput="value= value.match(/\d+(\.\d{0,2})?/) ? value.match(/\d+(\.\d{0,2})?/)[0] : ''" />
</el-form-item>
</template>
</el-table-column>
<el-table-column label="库存" :render-header="addRedStar" key="95">
<template v-slot="scope">
<template slot-scope="scope">
<el-form-item :prop="'rates.'+ scope.$index + '.stock'" :rules="[{required: true, trigger: 'change'}]">
<el-input v-model="scope.row.stock" oninput="value=value.replace(/^(0+)|\D+/g,'')"></el-input>
<el-input v-model="scope.row.stock" oninput="value=value.replace(/^(0+)|[^\d]+/g,'')"></el-input>
</el-form-item>
</template>
</el-table-column>
<el-table-column label="预警库存" key="96">
<template v-slot="scope">
<el-input v-model="scope.row.warnStock" oninput="value=value.replace(/^(0+)|\D+/g,'')"></el-input>
<template slot-scope="scope">
<el-input v-model="scope.row.warnStock" oninput="value=value.replace(/^(0+)|[^\d]+/g,'')"></el-input>
</template>
</el-table-column>
<el-table-column label="体积" key="97">
<template v-slot="scope">
<el-input v-model="scope.row.volume" ></el-input>
<template slot-scope="scope">
<el-input v-model="scope.row.volume" />
</template>
</el-table-column>
<el-table-column label="重量" key="98">
<template v-slot="scope">
<el-input v-model="scope.row.weight" ></el-input>
<template slot-scope="scope">
<el-input v-model="scope.row.weight" />
</template>
</el-table-column>
<el-table-column label="条码" key="99">
<template v-slot="scope">
<el-input v-model="scope.row.barCode"></el-input>
<template slot-scope="scope">
<el-input v-model="scope.row.barCode" />
</template>
</el-table-column>
<template v-if="ratesForm.spec === 2">
<template v-if="this.specSwitch">
<el-table-column fixed="right" label="操作" width="50" key="100">
<template v-slot="scope">
<el-button @click="scope.row.status = 1" type="text" size="small" v-show="scope.row.status == 0 ">禁用</el-button>
<el-button @click="scope.row.status = 0" type="text" size="small" v-show="scope.row.status === 1"></el-button>
<template slot-scope="scope">
<el-button @click="scope.row.status = 1" type="text" size="small"
v-show="scope.row.status === undefined || scope.row.status === 0 ">
</el-button>
<el-button @click="scope.row.status = 0" type="text" size="small" v-show="scope.row.status === 1">
启用
</el-button>
</template>
</el-table-column>
</template>
</el-table>
</el-form-item>
<el-form-item label="虚拟销量" prop="virtualSalesCount">
<!-- TODO @Luowenfeng使用 input 类型即可 -->
<el-input v-model="baseForm.virtualSalesCount" placeholder="请输入虚拟销量" oninput="value=value.replace(/^(0+)|\D+/g,'')"/>
<el-input v-model="baseForm.virtualSalesCount" placeholder="请输入虚拟销量"
oninput="value=value.replace(/^(0+)|[^\d]+/g,'')"/>
</el-form-item>
</el-form>
</el-tab-pane>
<!-- 商品详情 -->
<!-- TODO @luowenfengthird=detail 会更好哈 -->
<el-tab-pane label="商品详情" name="third">
<el-form ref="third" :model="baseForm" :rules="rules">
<el-form-item prop="description">
<editor v-model="baseForm.description" :min-height="380"/>
</el-form-item>
</el-form>
<el-form ref="third" :model="baseForm" :rules="rules">
<el-form-item prop="description">
<editor v-model="baseForm.description" :min-height="380"/>
</el-form-item>
</el-form>
</el-tab-pane>
<!-- 销售设置 -->
<!-- TODO @luowenfengfourth=senior 会更好哈 -->
<el-tab-pane label="高级设置" name="fourth">
<el-form ref="fourth" :model="baseForm" :rules="rules" label-width="100px" style="width: 95%">
<el-form-item label="排序字段">
<el-input v-model="baseForm.sort" placeholder="请输入排序字段" oninput="value=value.replace(/^(0+)|\D+/g,'')"/>
<el-input v-model="baseForm.sort" placeholder="请输入排序字段" oninput="value=value.replace(/^(0+)|[^\d]+/g,'')"/>
</el-form-item>
<el-form-item label="是否展示库存" prop="showStock">
<el-radio-group v-model="baseForm.showStock">
<el-form-item label="是否展示库存" prop="showStock">
<el-radio-group v-model="baseForm.showStock">
<el-radio :label="true"></el-radio>
<el-radio :label="false"></el-radio>
</el-radio-group>
@ -196,26 +202,22 @@
import {getBrandList} from "@/api/mall/product/brand";
import {getProductCategoryList} from "@/api/mall/product/category";
import {createSpu, updateSpu, getSpu} from "@/api/mall/product/spu";
import {getPropertyPage,} from "@/api/mall/product/property";
import {createSpu, getSpuDetail, updateSpu} from "@/api/mall/product/spu";
import {getPropertyListAndValue,} from "@/api/mall/product/property";
import Editor from "@/components/Editor";
import ImageUpload from "@/components/ImageUpload";
import VideoUpload from "@/components/VideoUpload";
export default {
components: {
Editor,
ImageUpload
},
props:{//props列表
type:{
type:String,
default:"add" //定义参数默认值
},
obj: Object
ImageUpload,
VideoUpload
},
data() {
return {
activeName: "base", // TODO @Luowenfeng切换时不需要校验通过
specSwitch: false,
activeName: "base",
propName: {
checkStrictly: true,
label: "name",
@ -230,11 +232,13 @@ export default {
sort: null,
description: null,
picUrls: null,
videoUrl: null,
status: 0,
virtualSalesCount: 0,
showStock: true,
brandId: null
brandId: null,
},
categoryList: [],
// 价格库存
ratesForm: {
@ -258,12 +262,12 @@ export default {
// 表单校验
rules: {
name:[{required: true, message: "商品名称不能为空", trigger: "blur"},],
name: [{required: true, message: "商品名称不能为空", trigger: "blur"},],
description: [{required: true, message: "描述不能为空", trigger: "blur"},],
categoryIds: [{required: true, message: "分类id不能为空", trigger: "blur"},],
status: [{required: true, message: "商品状态不能为空", trigger: "blur"}],
brandId: [{required: true, message: "商品品牌不能为空", trigger: "blur"}],
picUrls: [{required: true, message: "商品轮播图地址不能为空", trigger: "blur"}],
virtualSalesCount: [{required: true, message: "虚拟销量不能为空", trigger: "blur"}],
},
};
},
@ -271,38 +275,31 @@ export default {
this.getListBrand();
this.getListCategory();
this.getPropertyPageList();
if(this.type === 'upd'){
this.updateType(this.obj.id)
const spuId = this.$route.params && this.$route.params.spuId;
if (spuId != null) {
this.updateType(spuId)
}
},
methods: {
removeSpec(index){
this.dynamicSpec.splice(index, 1);
this.changeRadio()
},
async confirmLeave(active, old){
await this.$refs[old].validate((valid) => {
console.log(valid)
if (!valid) {
return reject();
}
});
removeSpec(index) {
this.dynamicSpec.splice(index, 1);
this.changeSpecSwitch()
},
// 必选标识
addRedStar(h, { column }) {
addRedStar(h, {column}) {
return [
h('span', { style: 'color: #F56C6C' }, '*'),
h('span', {style: 'color: #F56C6C'}, '*'),
h('span', ' ' + column.label)
];
},
changeRadio() {
changeSpecSwitch() {
this.specSwitch ? this.ratesForm.spec = 2 : this.ratesForm.spec = 1;
this.$refs.ratesTable.doLayout();
if (this.ratesForm.spec === 1) {
this.ratesForm.rates = [{}]
} else {
this.ratesForm.rates = []
if (this.dynamicSpec.length > 0) {
console.log( this.dynamicSpec)
this.buildRatesFormRates()
}
}
@ -316,6 +313,7 @@ export default {
last.forEach(par1 => {
current.forEach(par2 => {
let v
// 当两个对象合并时,需使用[1,2]方式生成数组而当数组和对象合并时需使用concat
if (par1 instanceof Array) {
v = par1.concat(par2)
} else {
@ -327,7 +325,12 @@ export default {
return array;
})
.forEach(v => {
rates.push({spec: v, status: 0, name: Array.of(v).join()})
let spec = v;
// 当v为单个规格项时会变成字符串。造成表格只截取第一个字符串而不是数组的第一个元素
if (typeof v == 'string') {
spec = Array.of(v)
}
rates.push({spec: spec, status: 0, name: Array.of(v).join()})
});
this.ratesForm.rates = rates
},
@ -338,41 +341,51 @@ export default {
this.categoryList = this.handleTree(response.data, "id", "parentId");
});
},
/** 查询品牌列表 */
/** 查询品牌列表 */
getListBrand() {
// 执行查询
getBrandList().then((response) => {
this.brandList = response.data;
});
},
// 取消按钮
cancel() {
this.$emit("closeDialog");
var currentView = this.$store.state.tagsView.visitedViews[0]
for (currentView of this.$store.state.tagsView.visitedViews) {
if (currentView.path === this.$route.path) {
break
}
}
this.$store.dispatch('tagsView/delView', currentView)
.then(() => {
this.$router.push("/product/spu")
})
},
submit() {
this.$refs[this.activeName].validate((valid) => {
this.$refs[this.activeName].validate((valid) => {
if (!valid) {
return;
}
let rates = this.ratesForm.rates;
let rates = JSON.parse(JSON.stringify(this.ratesForm.rates));
// 价格元转分
rates.forEach(r=>{
r.marketPrice = r.marketPrice*100;
r.price = r.price*100;
r.costPrice = r.costPrice*100;
})
// 动态规格调整字段
if (this.ratesForm.spec === 2) {
// 价格元转分
rates.forEach(r => {
let properties = []
r.marketPrice = r.marketPrice * 100;
r.price = r.price * 100;
r.costPrice = r.costPrice * 100;
})
// 动态规格调整字段
if (this.specSwitch) {
rates.forEach(r => {
let properties = []
Array.of(r.spec).forEach(s => {
let obj;
if (s instanceof Array) {
obj = s;
}else{
obj = Array.of(s);
}
if (s instanceof Array) {
obj = s;
} else {
obj = Array.of(s);
}
obj.forEach((v, i) => {
let specValue = this.dynamicSpec[i].specValue.find(o => o.name === v);
let propertie = {};
@ -381,112 +394,119 @@ export default {
properties.push(propertie);
})
})
r.properties = properties;
})
}else{
rates[0].name = this.baseForm.name;
rates[0].status = this.baseForm.status;
}
let form = this.baseForm
r.properties = properties;
})
} else {
rates[0].name = this.baseForm.name;
rates[0].status = this.baseForm.status;
}
let form = this.baseForm
if (form.picUrls instanceof Array) {
form.picUrls = form.picUrls.flatMap(m => m.split(','))
} else if (form.picUrls.split(',') instanceof Array) {
form.picUrls = form.picUrls.split(',').flatMap(m => m.split(','))
} else {
form.picUrls = Array.of(form.picUrls)
}
form.skus = rates;
form.specType = this.ratesForm.spec;
if(form.picUrls instanceof Array){
form.picUrls = form.picUrls.flatMap(m=>m.split(','))
}else if(form.picUrls.split(',') instanceof Array){
form.picUrls = form.picUrls.split(',').flatMap(m=>m.split(','))
}else{
form.picUrls = Array.of(form.picUrls)
}
console.log(rates)
form.skus = rates;
form.specType = this.ratesForm.spec;
form.categoryId = form.categoryIds[this.baseForm.categoryIds.length - 1];
let category = form.categoryIds instanceof Array ? form.categoryIds: Array.of(form.categoryIds)
console.log(category)
form.categoryId = category[category.length - 1];
if(form.id == null){
createSpu(form).then((response) => {
this.$modal.msgSuccess("新增成功");
})
}else{
updateSpu(form).then((response) => {
this.$modal.msgSuccess("修改成功");
})
}
if (form.id == null) {
createSpu(form).then(() => {
this.$modal.msgSuccess("新增成功");
}).then(()=>{
this.cancel();
})
} else {
updateSpu(form).then(() => {
this.$modal.msgSuccess("修改成功");
}).then(()=>{
this.cancel();
})
}
});
this.$emit("closeDialog");
},
/** 查询规格 */
getPropertyPageList() {
// 执行查询
getPropertyPage().then((response) => {
this.propertyPageList = response.data.list;
getPropertyListAndValue().then((response) => {
this.propertyPageList = response.data;
});
},
// 添加规格项目
changeSpec(val) {
let obj = this.propertyPageList.find(o => o.id === val);
let dynamicSpec = this.dynamicSpec;
let spec = dynamicSpec.find(o => o.specId === val)
let spec = this.dynamicSpec.find(o => o.specId === val)
spec.specId = obj.id;
spec.specName = obj.name;
spec.specValue = obj.propertyValueList;
this.dynamicSpec = dynamicSpec;
spec.specValue = obj.values;
this.buildRatesFormRates();
},
updateType(id){
getSpu(id).then((response) =>{
let data = response.data;
this.baseForm.id=data.id;
this.baseForm.name=data.name;
this.baseForm.sellPoint=data.sellPoint;
this.baseForm.categoryIds=data.categoryIds;
this.baseForm.sort=data.sort;
this.baseForm.description=data.description;
this.baseForm.picUrls=data.picUrls;
this.baseForm.status=data.status;
this.baseForm.virtualSalesCount=data.virtualSalesCount;
this.baseForm.showStock=data.showStock;
this.baseForm.brandId=data.brandId;
this.ratesForm.spec=data.specType;
data.skus.forEach(r=>{
r.marketPrice = this.divide(r.marketPrice, 100)
r.price = this.divide(r.price, 100)
r.costPrice = this.divide(r.costPrice, 100)
})
if(this.ratesForm.spec === 2){
data.productPropertyViews.forEach(p=>{
let obj = {};
obj.specId = p.propertyId;
obj.specName = p.name;
obj.specValue = p.propertyValues;
this.dynamicSpec.push(obj);
})
data.skus.forEach(s=>{
s.spec = [];
s.properties.forEach(sp=>{
let spec = data.productPropertyViews.find(o=>o.propertyId === sp.propertyId).propertyValues.find(v=>v.id === sp.valueId).name;
s.spec.push(spec)
})
})
}
this.ratesForm.rates=data.skus
updateType(id) {
getSpuDetail(id).then((response) => {
let data = response.data;
this.baseForm.id = data.id;
this.baseForm.name = data.name;
this.baseForm.sellPoint = data.sellPoint;
this.baseForm.categoryIds = data.categoryId;
this.baseForm.videoUrl = data.videoUrl;
this.baseForm.sort = data.sort;
this.baseForm.description = data.description;
this.baseForm.picUrls = data.picUrls;
this.baseForm.status = data.status;
this.baseForm.virtualSalesCount = data.virtualSalesCount;
this.baseForm.showStock = data.showStock;
this.baseForm.brandId = data.brandId;
this.ratesForm.spec = data.specType;
data.skus.forEach(r => {
r.marketPrice = this.divide(r.marketPrice, 100)
r.price = this.divide(r.price, 100)
r.costPrice = this.divide(r.costPrice, 100)
})
}
if (this.ratesForm.spec === 2) {
this.specSwitch = true;
data.productPropertyViews.forEach(p => {
let obj = {};
obj.specId = p.propertyId;
obj.specName = p.name;
obj.specValue = p.propertyValues;
this.dynamicSpec.push(obj);
})
data.skus.forEach(s => {
s.spec = [];
s.properties.forEach(sp => {
let spec = data.productPropertyViews.find(o => o.propertyId === sp.propertyId).propertyValues.find(v => v.id === sp.valueId).name;
s.spec.push(spec)
})
})
}
this.ratesForm.rates = data.skus
})
},
},
};
</script>
<style lang="scss">
.spec-dialog {
width: 400px;
height: 300px;
.container{
padding: 20px;
}
.dynamic-spec {
background-color: #f2f2f2;
width: 85%;
margin: auto auto 10px;
margin: auto;
margin-bottom: 10px;
.spec-header {
padding: 30px 30px 20px;
padding: 30px;
padding-bottom: 20px;
.spec-name {
display: inline;
@ -499,8 +519,9 @@ export default {
.spec-values {
width: 84%;
padding: 25px;
margin: auto;
padding: 5px 25px 25px;
padding-top: 5px;
.spec-value {
display: inline-block;
@ -519,11 +540,9 @@ export default {
}
.tabs {
height: 500px;
border-bottom: 2px solid #f2f2f2;
.el-tab-pane {
height: 445px;
overflow-y: auto;
}
}
@ -556,4 +575,18 @@ export default {
margin-left: 15px;
}
}
.mall-image {
.el-upload--picture-card {
width: 80px;
height: 80px;
line-height: 90px;
}
.el-upload-list__item {
width: 80px;
height: 80px;
}
}
</style>

View File

@ -0,0 +1,162 @@
<template>
<div class="app-container">
<!-- 搜索工作栏 -->
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="会员昵称" prop="nickname">
<el-input v-model="queryParams.nickname" placeholder="请输入会员昵称" clearable @keyup.enter.native="handleQuery"/>
</el-form-item>
<el-form-item label="创建时间" prop="createTime">
<el-date-picker v-model="queryParams.createTime" style="width: 240px" value-format="yyyy-MM-dd HH:mm:ss" type="daterange"
range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" :default-time="['00:00:00', '23:59:59']" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<!-- 操作工具栏 -->
<el-row :gutter="10" class="mb8">
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<!-- Tab 选项真正的内容在 Lab -->
<el-tabs v-model="activeTab" type="card" @tab-click="tabClick" style="margin-top: -40px;">
<el-tab-pane v-for="tab in statusTabs" :key="tab.value" :label="tab.label" :name="tab.value" />
</el-tabs>
<!-- 列表 -->
<el-table v-loading="loading" :data="list">
<el-table-column label="会员信息" align="center" prop="nickname" /> <!-- TODO 芋艿以后支持头像支持跳转 -->
<el-table-column label="优惠劵" align="center" prop="name" />
<el-table-column label="优惠券类型" align="center" prop="discountType">
<template slot-scope="scope">
<dict-tag :type="DICT_TYPE.PROMOTION_DISCOUNT_TYPE" :value="scope.row.discountType" />
</template>
</el-table-column>
<el-table-column label="领取方式" align="center" prop="takeType">
<template slot-scope="scope">
<dict-tag :type="DICT_TYPE.PROMOTION_COUPON_TAKE_TYPE" :value="scope.row.takeType" />
</template>
</el-table-column>
<el-table-column label="状态" align="center" prop="status">
<template slot-scope="scope">
<dict-tag :type="DICT_TYPE.PROMOTION_COUPON_STATUS" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="领取时间" align="center" prop="createTime" width="180">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="使用时间" align="center" prop="useTime" width="180">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.useTime) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
v-hasPermi="['promotion:coupon:delete']">回收</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页组件 -->
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
@pagination="getList"/>
</div>
</template>
<script>
import { deleteCoupon, getCouponPage } from "@/api/mall/promotion/coupon";
import { DICT_TYPE, getDictDatas} from "@/utils/dict";
export default {
name: "Coupon",
components: {
},
data() {
return {
// 遮罩层
loading: true,
// 导出遮罩层
exportLoading: false,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 优惠劵列表
list: [],
// 弹出层标题
title: "",
// 是否显示弹出层
open: false,
// 查询参数
queryParams: {
pageNo: 1,
pageSize: 10,
createTime: [],
status: undefined,
},
// Tab 筛选
activeTab: 'all',
statusTabs: [{
label: '全部',
value: 'all'
}],
};
},
created() {
this.getList();
// 设置 statuses 过滤
for (const dict of getDictDatas(DICT_TYPE.PROMOTION_COUPON_STATUS)) {
this.statusTabs.push({
label: dict.label,
value: dict.value
})
}
},
methods: {
/** 查询列表 */
getList() {
this.loading = true;
// 执行查询
getCouponPage(this.queryParams).then(response => {
this.list = response.data.list;
this.total = response.data.total;
this.loading = false;
});
},
/** 取消按钮 */
cancel() {
this.open = false;
this.reset();
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNo = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
/** 删除按钮操作 */
handleDelete(row) {
const id = row.id;
this.$modal.confirm('回收将会收回会员领取的待使用的优惠券,已使用的将无法回收,确定要回收所选优惠券吗?').then(function() {
return deleteCoupon(id);
}).then(() => {
this.getList();
this.$modal.msgSuccess("回收成功");
}).catch(() => {});
},
/** tab 切换 */
tabClick(tab) {
this.queryParams.status = tab.name === 'all' ? undefined : tab.name;
this.getList();
}
}
};
</script>

View File

@ -0,0 +1,403 @@
<template>
<div class="app-container">
<!-- 搜索工作栏 -->
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="82px">
<el-form-item label="优惠券名称" prop="name">
<el-input v-model="queryParams.name" placeholder="请输入优惠劵名" clearable @keyup.enter.native="handleQuery"/>
</el-form-item>
<el-form-item label="优惠券类型" prop="discountType">
<el-select v-model="queryParams.discountType" placeholder="请选择优惠券类型" clearable size="small">
<el-option v-for="dict in this.getDictDatas(DICT_TYPE.PROMOTION_DISCOUNT_TYPE)"
:key="dict.value" :label="dict.label" :value="dict.value"/>
</el-select>
</el-form-item>
<el-form-item label="优惠券状态" prop="status">
<el-select v-model="queryParams.status" placeholder="请选择优惠券状态" clearable size="small">
<el-option v-for="dict in this.getDictDatas(DICT_TYPE.COMMON_STATUS)"
:key="dict.value" :label="dict.label" :value="dict.value"/>
</el-select>
</el-form-item>
<el-form-item label="创建时间" prop="createTime">
<el-date-picker v-model="queryParams.createTime" style="width: 240px" value-format="yyyy-MM-dd HH:mm:ss" type="daterange"
range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" :default-time="['00:00:00', '23:59:59']" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<!-- 操作工具栏 -->
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
v-hasPermi="['promotion:coupon-template:create']">新增</el-button>
<el-button type="info" plain icon="el-icon-s-operation" size="mini"
@click="() => this.$router.push('/promotion/coupon')"
v-hasPermi="['promotion:coupon:query']">会员优惠劵</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<!-- 列表 -->
<el-table v-loading="loading" :data="list">
<el-table-column label="优惠券名称" align="center" prop="name" />
<el-table-column label="优惠券类型" align="center" prop="discountType">
<template slot-scope="scope">
<dict-tag :type="DICT_TYPE.PROMOTION_DISCOUNT_TYPE" :value="scope.row.discountType" />
</template>
</el-table-column>
<el-table-column label="优惠金额 / 折扣" align="center" prop="discount" :formatter="discountFormat" />
<el-table-column label="发放数量" align="center" prop="totalCount" />
<el-table-column label="剩余数量" align="center" prop="totalCount" :formatter="row => (row.totalCount - row.takeCount)" />
<el-table-column label="领取上限" align="center" prop="takeLimitCount" :formatter="takeLimitCountFormat" />
<el-table-column label="有效期限" align="center" prop="validityType" width="180" :formatter="validityTypeFormat" />
<el-table-column label="状态" align="center" prop="status">
<template slot-scope="scope">
<el-switch v-model="scope.row.status" :active-value="0" :inactive-value="1" @change="handleStatusChange(scope.row)"/>
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
v-hasPermi="['promotion:coupon-template:update']">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
v-hasPermi="['promotion:coupon-template:delete']">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页组件 -->
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
@pagination="getList"/>
<!-- 对话框(添加 / 修改) -->
<el-dialog :title="title" :visible.sync="open" width="600px" v-dialogDrag append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="140px">
<el-form-item label="优惠券名称" prop="name">
<el-input v-model="form.name" placeholder="请输入优惠券名称" />
</el-form-item>
<el-form-item label="优惠券类型" prop="discountType">
<el-radio-group v-model="form.discountType">
<el-radio v-for="dict in this.getDictDatas(DICT_TYPE.PROMOTION_DISCOUNT_TYPE)"
:key="dict.value" :label="parseInt(dict.value)">{{dict.label}}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item v-if="form.discountType === PromotionDiscountTypeEnum.PRICE.type" label="优惠券面额" prop="discountPrice">
<el-input-number v-model="form.discountPrice" placeholder="请输入优惠金额,单位:元"
style="width: 400px" :precision="2" :min="0" />
</el-form-item>
<el-form-item v-if="form.discountType === PromotionDiscountTypeEnum.PERCENT.type" label="优惠券折扣" prop="discountPercent">
<el-input-number v-model="form.discountPercent" placeholder="优惠券折扣不能小于 1 折,且不可大于 9.9 折"
style="width: 400px" :precision="1" :min="1" :max="9.9" />
</el-form-item>
<el-form-item v-if="form.discountType === PromotionDiscountTypeEnum.PERCENT.type" label="最多优惠" prop="discountLimitPrice">
<el-input-number v-model="form.discountLimitPrice" placeholder="请输入最多优惠"
style="width: 400px" :precision="2" :min="0" />
</el-form-item>
<el-form-item label="满多少元可以使用" prop="usePrice">
<el-input-number v-model="form.usePrice" placeholder="无门槛请设为 0"
style="width: 400px" :precision="2" :min="0" />
</el-form-item>
<el-form-item label="领取方式" prop="takeType">
<el-radio-group v-model="form.takeType">
<el-radio :key="1" :label="1">直接领取</el-radio>
<el-radio :key="2" :label="2">指定发放</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item v-if="form.takeType === 1" label="发放数量" prop="totalCount">
<el-input-number v-model="form.totalCount" placeholder="发放数量,没有之后不能领取或发放,-1 为不限制"
style="width: 400px" :precision="0" :min="-1" />
</el-form-item>
<el-form-item v-if="form.takeType === 1" label="每人限领个数" prop="takeLimitCount">
<el-input-number v-model="form.takeLimitCount" placeholder="设置为 -1 时,可无限领取"
style="width: 400px" :precision="0" :min="-1" />
</el-form-item>
<el-form-item label="有效期类型" prop="validityType">
<el-radio-group v-model="form.validityType">
<el-radio v-for="dict in this.getDictDatas(DICT_TYPE.PROMOTION_COUPON_TEMPLATE_VALIDITY_TYPE)"
:key="dict.value" :label="parseInt(dict.value)">{{dict.label}}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item v-if="form.validityType === CouponTemplateValidityTypeEnum.DATE.type" label="固定日期" prop="validTimes">
<el-date-picker v-model="form.validTimes" style="width: 240px" value-format="yyyy-MM-dd HH:mm:ss" type="datetimerange"
:default-time="['00:00:00', '23:59:59']" />
</el-form-item>
<el-form-item v-if="form.validityType === CouponTemplateValidityTypeEnum.TERM.type" label="领取日期" prop="fixedStartTerm">
<el-input-number v-model="form.fixedStartTerm" placeholder="0 为今天生效"
style="width: 165px" :precision="0" :min="0"/>
<el-input-number v-model="form.fixedEndTerm" placeholder="请输入结束天数"
style="width: 165px" :precision="0" :min="0"/> 天有效
</el-form-item>
<el-form-item label="活动商品" prop="productScope">
<el-radio-group v-model="form.productScope">
<el-radio v-for="dict in this.getDictDatas(DICT_TYPE.PROMOTION_PRODUCT_SCOPE)"
:key="dict.value" :label="parseInt(dict.value)">{{dict.label}}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item v-if="form.productScope === PromotionProductScopeEnum.SPU.scope" prop="productSpuIds">
<el-select v-model="form.productSpuIds" placeholder="请选择活动商品" clearable size="small"
multiple filterable style="width: 400px">
<el-option v-for="item in productSpus" :key="item.id" :label="item.name" :value="item.id">
<span style="float: left">{{ item.name }}</span>
<span style="float: right; color: #8492a6; font-size: 13px">{{ (item.minPrice / 100.0).toFixed(2) }}</span>
</el-option>
</el-select>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import {
createCouponTemplate,
updateCouponTemplate,
deleteCouponTemplate,
getCouponTemplate,
getCouponTemplatePage,
updateCouponTemplateStatus
} from "@/api/mall/promotion/couponTemplate";
import {
CommonStatusEnum,
CouponTemplateValidityTypeEnum,
PromotionDiscountTypeEnum,
PromotionProductScopeEnum
} from "@/utils/constants";
import { getSpuSimpleList } from "@/api/mall/product/spu";
import { parseTime } from "@/utils/ruoyi";
import {changeRoleStatus} from "@/api/system/role";
export default {
name: "CouponTemplate",
components: {
},
data() {
return {
// 遮罩层
loading: true,
// 导出遮罩层
exportLoading: false,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 优惠劵列表
list: [],
// 弹出层标题
title: "",
// 是否显示弹出层
open: false,
// 查询参数
queryParams: {
pageNo: 1,
pageSize: 10,
name: null,
status: null,
type: null,
createTime: [],
},
// 表单参数
form: {},
// 表单校验
rules: {
name: [{ required: true, message: "优惠券名称不能为空", trigger: "blur" }],
discountType: [{ required: true, message: "优惠券类型不能为空", trigger: "change" }],
discountPrice: [{ required: true, message: "优惠券面额不能为空", trigger: "blur" }],
discountPercent: [{ required: true, message: "优惠券折扣不能为空", trigger: "blur" }],
discountLimitPrice: [{ required: true, message: "最多优惠不能为空", trigger: "blur" }],
usePrice: [{ required: true, message: "满多少元可以使用不能为空", trigger: "blur" }],
takeType: [{ required: true, message: "领取方式不能为空", trigger: "change" }],
totalCount: [{ required: true, message: "发放数量不能为空", trigger: "blur" }],
takeLimitCount: [{ required: true, message: "每人限领个数不能为空", trigger: "blur" }],
validityType: [{ required: true, message: "有效期类型不能为空", trigger: "change" }],
validTimes: [{ required: true, message: "固定日期不能为空", trigger: "change" }],
fixedStartTerm: [{ required: true, message: "开始领取天数不能为空", trigger: "blur" }],
fixedEndTerm: [{ required: true, message: "开始领取天数不能为空", trigger: "blur" }],
productScope: [{ required: true, message: "商品范围不能为空", trigger: "blur" }],
productSpuIds: [{ required: true, message: "商品范围不能为空", trigger: "blur" }],
},
// 商品列表
productSpus: [],
// 如下的变量,主要为了 v-if 判断可以使用到
PromotionProductScopeEnum: PromotionProductScopeEnum,
CouponTemplateValidityTypeEnum: CouponTemplateValidityTypeEnum,
PromotionDiscountTypeEnum: PromotionDiscountTypeEnum,
};
},
created() {
this.getList();
},
methods: {
/** 查询列表 */
getList() {
this.loading = true;
// 执行查询
getCouponTemplatePage(this.queryParams).then(response => {
this.list = response.data.list;
this.total = response.data.total;
this.loading = false;
});
// 查询商品列表
getSpuSimpleList().then(response => {
this.productSpus = response.data
})
},
/** 取消按钮 */
cancel() {
this.open = false;
this.reset();
},
/** 表单重置 */
reset() {
this.form = {
id: undefined,
name: undefined,
discountType: PromotionDiscountTypeEnum.PRICE.type,
discountPrice: undefined,
discountPercent: undefined,
discountLimitPrice: undefined,
usePrice: undefined,
takeType: 1,
totalCount: undefined,
takeLimitCount: undefined,
validityType: CouponTemplateValidityTypeEnum.DATE.type,
validTimes: [],
validStartTime: undefined,
validEndTime: undefined,
fixedStartTerm: undefined,
fixedEndTerm: undefined,
productScope: PromotionProductScopeEnum.ALL.scope,
productSpuIds: [],
};
this.resetForm("form");
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNo = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.title = "添加优惠劵";
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
const id = row.id;
getCouponTemplate(id).then(response => {
this.form = {
...response.data,
discountPrice: response.data.discountPrice !== undefined ? response.data.discountPrice / 100.0 : undefined,
discountPercent: response.data.discountPercent !== undefined ? response.data.discountPercent / 10.0 : undefined,
discountLimitPrice: response.data.discountLimitPrice !== undefined ? response.data.discountLimitPrice / 100.0 : undefined,
usePrice: response.data.usePrice !== undefined ? response.data.usePrice / 100.0 : undefined,
validTimes: [response.data.validStartTime, response.data.validEndTime]
}
this.open = true;
this.title = "修改优惠劵";
});
},
/** 提交按钮 */
submitForm() {
this.$refs["form"].validate(valid => {
if (!valid) {
return;
}
// 金额相关字段的缩放
let data = {
...this.form,
discountPrice: this.form.discountPrice !== undefined ? this.form.discountPrice * 100 : undefined,
discountPercent: this.form.discountPercent !== undefined ? this.form.discountPercent * 10 : undefined,
discountLimitPrice: this.form.discountLimitPrice !== undefined ? this.form.discountLimitPrice * 100 : undefined,
usePrice: this.form.usePrice !== undefined ? this.form.usePrice * 100 : undefined,
validStartTime: this.form.validTimes && this.form.validTimes.length === 2 ? this.form.validTimes[0] : undefined,
validEndTime: this.form.validTimes && this.form.validTimes.length === 2 ? this.form.validTimes[1] : undefined,
}
// 修改的提交
if (this.form.id != null) {
updateCouponTemplate(data).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
});
return;
}
// 添加的提交
createCouponTemplate(data).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
});
});
},
/** 优惠劵模板状态修改 */
handleStatusChange(row) {
// 此时row 已经变成目标状态了,所以可以直接提交请求和提示
let text = row.status === CommonStatusEnum.ENABLE ? "启用" : "停用";
this.$modal.confirm('确认要"' + text + '""' + row.name + '"优惠劵吗?').then(function() {
return updateCouponTemplateStatus(row.id, row.status);
}).then(() => {
this.$modal.msgSuccess(text + "成功");
}).catch(function() {
// 异常时,需要将 row.status 状态重置回之前的
row.status = row.status === CommonStatusEnum.ENABLE ? CommonStatusEnum.DISABLE
: CommonStatusEnum.ENABLE;
});
},
/** 删除按钮操作 */
handleDelete(row) {
const id = row.id;
this.$modal.confirm('是否确认删除优惠劵编号为"' + id + '"的数据项?').then(function() {
return deleteCouponTemplate(id);
}).then(() => {
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {});
},
// 格式化【优惠金额/折扣】
discountFormat(row, column) {
if (row.discountType === PromotionDiscountTypeEnum.PRICE.type) {
return `${(row.discountPrice / 100.0).toFixed(2)}`;
}
if (row.discountType === PromotionDiscountTypeEnum.PERCENT.type) {
return `${(row.discountPrice / 100.0).toFixed(2)}`;
}
return '未知【' + row.discountType + '】';
},
// 格式化【领取上限】
takeLimitCountFormat(row, column) {
if (row.takeLimitCount === -1) {
return '无领取限制';
}
return `${row.takeLimitCount} 张/人`
},
// 格式化【有效期限】
validityTypeFormat(row, column) {
if (row.validityType === CouponTemplateValidityTypeEnum.DATE.type) {
return `${parseTime(row.validStartTime)}${parseTime(row.validEndTime)}`
}
if (row.validityType === CouponTemplateValidityTypeEnum.TERM.type) {
return `领取后第 ${row.fixedStartTerm} - ${row.fixedEndTerm} 天内可用`
}
return '未知【' + row.validityType + '】';
}
}
};
</script>

View File

@ -0,0 +1,382 @@
<template>
<div class="app-container">
<!-- 搜索工作栏 -->
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="活动名称" prop="name">
<el-input v-model="queryParams.name" placeholder="请输入活动名称" clearable @keyup.enter.native="handleQuery"/>
</el-form-item>
<el-form-item label="活动状态" prop="status">
<el-select v-model="queryParams.status" placeholder="请选择活动状态" clearable size="small">
<el-option v-for="dict in this.getDictDatas(DICT_TYPE.PROMOTION_ACTIVITY_STATUS)"
:key="dict.value" :label="dict.label" :value="dict.value"/>
</el-select>
</el-form-item>
<el-form-item label="创建时间" prop="createTime">
<el-date-picker v-model="queryParams.createTime" style="width: 240px" value-format="yyyy-MM-dd HH:mm:ss" type="daterange"
range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" :default-time="['00:00:00', '23:59:59']" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<!-- 操作工具栏 -->
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
v-hasPermi="['promotion:discount-activity:create']">新增</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<!-- 列表 -->
<el-table v-loading="loading" :data="list">
<el-table-column label="活动名称" align="center" prop="name" />
<el-table-column label="活动时间" align="center" prop="startTime" width="240">
<template slot-scope="scope">
<div>开始{{ parseTime(scope.row.startTime) }}</div>
<div>结束{{ parseTime(scope.row.endTime) }}</div>
</template>
</el-table-column>
<el-table-column label="状态" align="center" prop="status">
<template slot-scope="scope">
<dict-tag :type="DICT_TYPE.PROMOTION_ACTIVITY_STATUS" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
v-if="scope.row.status !== PromotionActivityStatusEnum.CLOSE.type"
v-hasPermi="['promotion:discount-activity:update']">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleClose(scope.row)"
v-if="scope.row.status !== PromotionActivityStatusEnum.CLOSE.type &&
scope.row.status !== PromotionActivityStatusEnum.END.type"
v-hasPermi="['promotion:discount-activity:close']">关闭</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
v-if="scope.row.status === PromotionActivityStatusEnum.CLOSE.type"
v-hasPermi="['promotion:discount-activity:delete']">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页组件 -->
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
@pagination="getList"/>
<!-- 对话框(添加 / 修改) -->
<el-dialog :title="title" :visible.sync="open" width="1000px" v-dialogDrag append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<el-form-item label="活动名称" prop="name">
<el-input v-model="form.name" placeholder="请输入活动名称" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input type="textarea" v-model="form.remark" placeholder="请输入备注" />
</el-form-item>
<el-form-item label="活动时间" prop="startAndEndTime">
<el-date-picker clearable v-model="form.startAndEndTime" type="datetimerange" :default-time="['00:00:00', '23:59:59']"
value-format="timestamp" placeholder="选择开始时间" style="width: 880px" />
</el-form-item>
<el-form-item label="商品选择">
<el-select v-model="form.skuIds" placeholder="请选择活动商品" clearable size="small"
multiple filterable style="width: 880px" @change="changeFormSku">
<el-option v-for="item in productSkus" :key="item.id" :label="item.spuName + ' ' + item.name" :value="item.id">
<span style="float: left">{{ item.spuName }} &nbsp; {{ item.name}}</span>
<span style="float: right; color: #8492a6; font-size: 13px">¥{{ (item.price / 100.0).toFixed(2) }}</span>
</el-option>
</el-select>
<el-table v-loading="loading" :data="form.products">
<el-table-column label="商品名称" align="center" width="200">
<template slot-scope="scope">
{{ scope.row.spuName }} &nbsp; {{ scope.row.name}}
</template>
</el-table-column>
<el-table-column label="商品价格" align="center" prop="price">
<template slot-scope="scope">
¥{{ (scope.row.price / 100.0).toFixed(2) }}
</template>
</el-table-column>
<el-table-column label="库存" align="center" prop="stock" />
<el-table-column label="优惠类型" align="center" property="discountType">
<template slot-scope="scope">
<el-select v-model="scope.row.discountType" placeholder="请选择优惠类型">
<el-option v-for="dict in getDictDatas(DICT_TYPE.PROMOTION_DISCOUNT_TYPE)"
:key="dict.value" :label="dict.label" :value="parseInt(dict.value)"/>
</el-select>
</template>
</el-table-column>
<el-table-column label="优惠" align="center" prop="startTime" width="250">
<template slot-scope="scope">
<el-form-item v-if="scope.row.discountType === PromotionDiscountTypeEnum.PRICE.type" prop="discountPrice">
减 <el-input-number v-model="scope.row.discountPrice" placeholder="请输入优惠金额"
style="width: 190px" :precision="2" :min="0" :max="scope.row.price / 100.0 - 0.01" /> 元
</el-form-item>
<el-form-item v-if="scope.row.discountType === PromotionDiscountTypeEnum.PERCENT.type" prop="discountPercent">
打 <el-input-number v-model="scope.row.discountPercent" placeholder="请输入优惠折扣"
style="width: 190px" :precision="1" :min="1" :max="9.9" /> 折
</el-form-item>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-delete" @click="removeFormSku(scope.row.skuId)">删除</el-button>
</template>
</el-table-column>
</el-table>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm">确 定</el-button>
<el-button @click="cancel">取 消</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import {
createDiscountActivity,
updateDiscountActivity,
deleteDiscountActivity,
getDiscountActivity,
getDiscountActivityPage,
closeDiscountActivity
} from "@/api/mall/promotion/discountActivity";
import {
PromotionActivityStatusEnum, PromotionDiscountTypeEnum,
PromotionProductScopeEnum
} from "@/utils/constants";
import { getSkuOptionList } from "@/api/mall/product/sku";
import { deepClone } from "@/utils";
export default {
name: "DiscountActivity",
components: {
},
data() {
return {
// 遮罩层
loading: true,
// 导出遮罩层
exportLoading: false,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 限时折扣活动列表
list: [],
// 弹出层名称
title: "",
// 是否显示弹出层
open: false,
// 查询参数
queryParams: {
pageNo: 1,
pageSize: 10,
name: null,
status: null,
createTime: [],
},
// 表单参数
form: {
skuIds: [], // 选中的 SKU
products: [], // 商品信息
},
// 表单校验
rules: {
name: [{ required: true, message: "活动名称不能为空", trigger: "blur" }],
startAndEndTime: [{ required: true, message: "活动时间不能为空", trigger: "blur" }],
skuIds: [{ required: true, message: "选择商品不能为空", trigger: "blur" }],
},
// 商品 SKU 列表
productSkus: [],
// 如下的变量主要为了 v-if 判断可以使用到
PromotionProductScopeEnum: PromotionProductScopeEnum,
PromotionActivityStatusEnum: PromotionActivityStatusEnum,
PromotionDiscountTypeEnum: PromotionDiscountTypeEnum,
};
},
created() {
this.getList();
},
methods: {
/** 查询列表 */
getList() {
this.loading = true;
// 执行查询
getDiscountActivityPage(this.queryParams).then(response => {
this.list = response.data.list;
this.total = response.data.total;
this.loading = false;
});
// 获得 SKU 商品列表
getSkuOptionList().then(response => {
this.productSkus = response.data;
});
},
/** 取消按钮 */
cancel() {
this.open = false;
this.reset();
},
/** 表单重置 */
reset() {
this.form = {
id: undefined,
name: undefined,
startAndEndTime: undefined,
startTime: undefined,
endTime: undefined,
remark: undefined,
skuIds: [],
products: [],
};
this.resetForm("form");
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNo = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.title = "添加限时折扣活动";
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
const id = row.id;
getDiscountActivity(id).then(response => {
this.form = response.data;
// 修改数据
this.form.startAndEndTime = [response.data.startTime, response.data.endTime];
this.form.skuIds = response.data.products.map(item => item.skuId);
this.form.products.forEach(product => {
// 获得对应的 SKU 信息
const sku = this.productSkus.find(item => item.id === product.skuId);
if (!sku) {
return;
}
// 设置商品信息
product.name = sku.name;
product.spuName = sku.spuName;
product.price = sku.price;
product.stock = sku.stock;
product.discountPrice = product.discountPrice !== undefined ? product.discountPrice / 100.0 : undefined;
product.discountPercent = product.discountPercent !== undefined ? product.discountPercent / 10.0 : undefined;
});
// 打开弹窗
this.open = true;
this.title = "修改限时折扣活动";
});
},
/** 提交按钮 */
submitForm() {
this.$refs["form"].validate(valid => {
if (!valid) {
return;
}
// 处理数据
const data = deepClone(this.form); // 必须深拷贝,不然后面的 products 操作会有影响
data.startTime = this.form.startAndEndTime[0];
data.endTime = this.form.startAndEndTime[1];
data.products.forEach(product => {
product.discountPrice = product.discountPrice !== undefined ? product.discountPrice * 100 : undefined;
product.discountPercent = product.discountPercent !== undefined ? product.discountPercent * 10 : undefined;
});
if (!valid) {
return;
}
// 修改的提交
if (this.form.id != null) {
updateDiscountActivity(data).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
});
return;
}
// 添加的提交
createDiscountActivity(data).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
});
});
},
/** 删除按钮操作 */
handleDelete(row) {
const id = row.id;
this.$modal.confirm('是否确认删除限时折扣活动编号为"' + id + '"的数据项?').then(function() {
return deleteDiscountActivity(id);
}).then(() => {
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {});
},
/** 关闭按钮操作 */
handleClose(row) {
const id = row.id;
this.$modal.confirm('是否确认关闭限时折扣活动编号为"' + id + '"的数据项?').then(function() {
return closeDiscountActivity(id);
}).then(() => {
this.getList();
this.$modal.msgSuccess("关闭成功");
}).catch(() => {});
},
/** 当 Form 的 SKU 发生变化时 */
changeFormSku(skuIds) {
// 处理【新增】
skuIds.forEach(skuId => {
// 获得对应的 SKU 信息
const sku = this.productSkus.find(item => item.id === skuId);
if (!sku) {
return;
}
// 判断已存在,直接跳过
const product = this.form.products.find(item => item.skuId === skuId);
if (product) {
return;
}
this.form.products.push({
skuId: sku.id,
name: sku.name,
price: sku.price,
stock: sku.stock,
spuId: sku.spuId,
spuName: sku.spuName,
discountType: PromotionDiscountTypeEnum.PRICE.type,
});
});
// 处理【移除】
this.form.products.map((product, index) => {
if (!skuIds.includes(product.skuId)) {
this.form.products.splice(index, 1);
}
});
},
/** 移除 Form 的 SKU */
removeFormSku(skuId) {
this.form.skuIds.map((id, index) => {
if (skuId === id) {
this.form.skuIds.splice(index, 1);
}
});
this.changeFormSku(this.form.skuIds);
},
}
}
</script>

View File

@ -0,0 +1,305 @@
<template>
<div class="app-container">
<!-- 搜索工作栏 -->
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="活动名称" prop="name">
<el-input v-model="queryParams.name" placeholder="请输入活动名称" clearable @keyup.enter.native="handleQuery"/>
</el-form-item>
<el-form-item label="活动状态" prop="status">
<el-select v-model="queryParams.status" placeholder="请选择活动状态" clearable size="small">
<el-option v-for="dict in this.getDictDatas(DICT_TYPE.PROMOTION_ACTIVITY_STATUS)"
:key="dict.value" :label="dict.label" :value="dict.value"/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<!-- 操作工具栏 -->
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
v-hasPermi="['promotion:reward-activity:create']">新增</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<!-- 列表 -->
<el-table v-loading="loading" :data="list">
<el-table-column label="活动名称" align="center" prop="name" />
<el-table-column label="活动时间" align="center" prop="startTime" width="240">
<template slot-scope="scope">
<div>开始{{ parseTime(scope.row.startTime) }}</div>
<div>结束{{ parseTime(scope.row.endTime) }}</div>
</template>
</el-table-column>
<el-table-column label="状态" align="center" prop="status">
<template slot-scope="scope">
<dict-tag :type="DICT_TYPE.PROMOTION_ACTIVITY_STATUS" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
v-if="scope.row.status !== PromotionActivityStatusEnum.CLOSE.type"
v-hasPermi="['promotion:reward-activity:update']">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleClose(scope.row)"
v-if="scope.row.status !== PromotionActivityStatusEnum.CLOSE.type &&
scope.row.status !== PromotionActivityStatusEnum.END.type"
v-hasPermi="['promotion:reward-activity:close']">关闭</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
v-if="scope.row.status === PromotionActivityStatusEnum.CLOSE.type"
v-hasPermi="['promotion:reward-activity:delete']">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页组件 -->
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
@pagination="getList"/>
<!-- 对话框(添加 / 修改) -->
<el-dialog :title="title" :visible.sync="open" width="600px" v-dialogDrag append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<el-form-item label="活动名称" prop="name">
<el-input v-model="form.name" placeholder="请输入活动名称" />
</el-form-item>
<el-form-item label="活动时间" prop="startAndEndTime">
<el-date-picker clearable v-model="form.startAndEndTime" type="datetimerange" :default-time="['00:00:00', '23:59:59']"
value-format="timestamp" placeholder="选择开始时间" style="width: 480px" />
</el-form-item>
<el-form-item label="条件类型" prop="conditionType">
<el-radio-group v-model="form.conditionType">
<el-radio v-for="dict in this.getDictDatas(DICT_TYPE.PROMOTION_CONDITION_TYPE)"
:key="dict.value" :label="parseInt(dict.value)">{{dict.label}}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="优惠设置" prop="conditionType">
<!-- TODO 芋艿:待实现! -->
</el-form-item>
<el-form-item label="活动商品" prop="productScope">
<el-radio-group v-model="form.productScope">
<el-radio v-for="dict in this.getDictDatas(DICT_TYPE.PROMOTION_PRODUCT_SCOPE)"
:key="dict.value" :label="parseInt(dict.value)">{{dict.label}}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item v-if="form.productScope === PromotionProductScopeEnum.SPU.scope" prop="productSpuIds">
<el-select v-model="form.productSpuIds" placeholder="请选择活动商品" clearable size="small"
multiple filterable style="width: 400px">
<el-option v-for="item in productSpus" :key="item.id" :label="item.name" :value="item.id">
<span style="float: left">{{ item.name }}</span>
<span style="float: right; color: #8492a6; font-size: 13px">¥{{ (item.minPrice / 100.0).toFixed(2) }}</span>
</el-option>
</el-select>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" placeholder="请输入备注" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm">确 定</el-button>
<el-button @click="cancel">取 消</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import {
createRewardActivity,
updateRewardActivity,
deleteRewardActivity,
getRewardActivity,
getRewardActivityPage,
closeRewardActivity
} from "@/api/mall/promotion/rewardActivity";
import {
PromotionConditionTypeEnum,
PromotionProductScopeEnum,
PromotionActivityStatusEnum
} from "@/utils/constants";
import {getSpuSimpleList} from "@/api/mall/product/spu";
export default {
name: "RewardActivity",
components: {
},
data() {
return {
// 遮罩层
loading: true,
// 导出遮罩层
exportLoading: false,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 满减送活动列表
list: [],
// 弹出层标题
title: "",
// 是否显示弹出层
open: false,
// 查询参数
queryParams: {
pageNo: 1,
pageSize: 10,
name: null,
status: null,
},
// 表单参数
form: {},
// 表单校验
rules: {
name: [{ required: true, message: "活动名称不能为空", trigger: "blur" }],
startAndEndTime: [{ required: true, message: "活动时间不能为空", trigger: "blur" }],
conditionType: [{ required: true, message: "条件类型不能为空", trigger: "change" }],
productScope: [{ required: true, message: "商品范围不能为空", trigger: "blur" }],
productSpuIds: [{ required: true, message: "商品范围不能为空", trigger: "blur" }],
},
// 商品列表
productSpus: [],
// 如下的变量主要为了 v-if 判断可以使用到
PromotionProductScopeEnum: PromotionProductScopeEnum,
PromotionActivityStatusEnum: PromotionActivityStatusEnum,
};
},
created() {
this.getList();
// 查询商品列表
getSpuSimpleList().then(response => {
this.productSpus = response.data
})
},
methods: {
/** 查询列表 */
getList() {
this.loading = true;
// 执行查询
getRewardActivityPage(this.queryParams).then(response => {
this.list = response.data.list;
this.total = response.data.total;
this.loading = false;
});
},
/** 取消按钮 */
cancel() {
this.open = false;
this.reset();
},
/** 表单重置 */
reset() {
this.form = {
id: undefined,
name: undefined,
startAndEndTime: undefined,
startTime: undefined,
endTime: undefined,
conditionType: PromotionConditionTypeEnum.PRICE.type,
remark: undefined,
productScope: PromotionProductScopeEnum.ALL.scope,
productSpuIds: undefined,
rules: undefined,
};
this.resetForm("form");
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNo = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.title = "添加满减送活动";
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
const id = row.id;
getRewardActivity(id).then(response => {
this.form = response.data;
this.form.startAndEndTime = [response.data.startTime, response.data.endTime];
this.open = true;
this.title = "修改满减送活动";
});
},
/** 提交按钮 */
submitForm() {
this.$refs["form"].validate(valid => {
if (!valid) {
return;
}
this.form.startTime = this.form.startAndEndTime[0];
this.form.endTime = this.form.startAndEndTime[1];
// TODO 芋艿:临时实现
this.form.rules = [
{
limit: 1,
discountPrice: 10,
freeDelivery: true,
point: 10,
couponIds: [10, 20],
couponCounts: [1, 2]
}, {
limit: 2,
discountPrice: 20,
freeDelivery: false,
point: 20,
couponIds: [30, 40],
couponCounts: [3, 4]
}
];
// 修改的提交
if (this.form.id != null) {
updateRewardActivity(this.form).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
});
return;
}
// 添加的提交
createRewardActivity(this.form).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
});
});
},
/** 删除按钮操作 */
handleDelete(row) {
const id = row.id;
this.$modal.confirm('是否确认删除满减送活动编号为"' + id + '"的数据项?').then(function() {
return deleteRewardActivity(id);
}).then(() => {
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {});
},
/** 关闭按钮操作 */
handleClose(row) {
const id = row.id;
this.$modal.confirm('是否确认关闭满减送活动编号为"' + id + '"的数据项?').then(function() {
return closeRewardActivity(id);
}).then(() => {
this.getList();
this.$modal.msgSuccess("关闭成功");
}).catch(() => {});
}
}
};
</script>

View File

@ -0,0 +1,273 @@
<template>
<div class="app-container order-detail-page">
<template v-for="(group, index) in detailGroups">
<el-descriptions v-bind="group.groupProps" :key="`group_${index}`" :title="group.title">
<!-- 商品信息 -->
<el-descriptions-item v-if="group.key === 'goodsInfo'" labelClassName="no-colon">
<el-table border>
<el-table-column prop="date" label="商品" width="180"/>
<el-table-column prop="jg" label="价格"/>
<el-table-column prop="spbm" label="商品编码"/>
<el-table-column prop="xl" label="数量"/>
<el-table-column prop="xj" label="小计(元)"/>
<el-table-column prop="tkzt" label="退款状态"/>
<el-table-column prop="zt" label="状态"/>
</el-table>
</el-descriptions-item>
<!-- 订单操作日志 -->
<el-descriptions-item v-if="group.key === 'orderLog'" labelClassName="no-colon">
<el-timeline>
<el-timeline-item
v-for="(activity, index) in detailInfo[group.key]"
:key="index"
:timestamp="activity.timestamp"
>
{{activity.content}}
</el-timeline-item>
</el-timeline>
</el-descriptions-item>
<!-- 物流信息 -->
<el-descriptions-item v-if="group.key === 'expressInfo'" labelClassName="no-colon">
<el-tabs type="card">
<!-- 循环包裹物流信息 -->
<el-tab-pane v-for="(pkgInfo, pInIdx) in detailInfo[group.key]" :key="`pkgInfo_${pInIdx}`" :label="pkgInfo.label">
<!-- 包裹详情 -->
<el-descriptions>
<el-descriptions-item v-for="(pkgChild, pkgCIdx) in group.children" v-bind="pkgChild.childProps" :key="`pkgChild_${pkgCIdx}`" :label="pkgChild.label">
<!-- 包裹商品列表 -->
<template v-if="pkgChild.valueKey === 'goodsList' && pkgInfo[pkgChild.valueKey]">
<div v-for="(goodInfo, goodInfoIdx) in pkgInfo[pkgChild.valueKey]" :key="`goodInfo_${goodInfoIdx}`" style="display: flex;">
<el-image
style="width: 100px;height: 100px;flex: none"
:src="goodInfo.imgUrl">
</el-image>
<el-descriptions :column="1">
<el-descriptions-item labelClassName="no-colon">{{goodInfo.name}}</el-descriptions-item>
<el-descriptions-item label="数量">{{goodInfo.count}}</el-descriptions-item>
</el-descriptions>
</div>
</template>
<!-- 包裹物流详情 -->
<el-timeline v-else-if="pkgChild.valueKey==='wlxq'">
<el-timeline-item
v-for="(activity, index) in pkgInfo[pkgChild.valueKey]"
:key="index"
:timestamp="activity.timestamp"
>
{{activity.content}}
</el-timeline-item>
</el-timeline>
<template v-else>
{{pkgInfo[pkgChild.valueKey]}}
</template>
</el-descriptions-item>
</el-descriptions>
</el-tab-pane>
</el-tabs>
</el-descriptions-item>
<!--订单详情订单状态-->
<el-descriptions-item v-else v-for="(child, cIdx) in group.children" v-bind="child.childProps" :key="`child_${cIdx}`" :label="child.label">
<!-- 操作按钮(订单状态)-->
<template v-if="group.key === 'orderStatus' && child.valueKey === 'actions'" slot="label">
<el-button type="primary">备注</el-button>
<el-button type="primary">打印发货单</el-button>
</template>
<!-- 内容 -->
<template v-else>
{{detailInfo[child.valueKey]}}
<!--复制地址(订单详情) -->
<el-link v-if="child.valueKey==='shdz'" v-clipboard:copy="detailInfo[child.valueKey]" v-clipboard:success="clipboardSuccess" icon="el-icon-document-copy" type="primary"/>
</template>
</el-descriptions-item>
</el-descriptions>
</template>
</div>
</template>
<script>
export default {
name: "detail",
data () {
return {
detailGroups: [
{
title: '订单详情',
children: [
{ label: '交易流水号', valueKey: 'jylsh'},
{ label: '配送方式', valueKey: 'psfs'},
{ label: '营销活动', valueKey: 'yxhd'},
{ label: '订单编号', valueKey: 'ddbh'},
{ label: '收货人', valueKey: 'shr'},
{ label: '买家留言', valueKey: 'mjly'},
{ label: '订单类型', valueKey: 'ddlx'},
{ label: '联系电话', valueKey: 'lxdh'},
{ label: '备注', valueKey: 'bz'},
{ label: '订单来源', valueKey: 'ddly'},
{ label: '付款方式', valueKey: 'fkfs'},
{ label: '买家', valueKey: 'mj'},
{ label: '收货地址', valueKey: 'shdz'}
]
},
{
title: '订单状态',
key: 'orderStatus',
groupProps: {
column: 1
},
children: [
{ label: '订单状态', valueKey: 'ddzt', childProps: { contentStyle: { color: 'red' }}},
{ label: '', valueKey: 'actions', childProps: { labelClassName: 'no-colon'}},
{ label: '提醒', valueKey: 'tx', childProps: { labelStyle: { color: 'red' }}}
]
},
{
title: '物流信息',
key: 'expressInfo',
children: [
{ label: '发货时间', valueKey: 'fhsj'},
{ label: '物流公司', valueKey: 'wlgs'},
{ label: '运单号', valueKey: 'ydh'},
{ label: '商品信息', valueKey: 'goodsList', childProps: { span: 3 }},
{ label: '物流状态', valueKey: 'wlzt', childProps: { span: 3 }},
{ label: '物流详情', valueKey: 'wlxq'}
]
},
{
title: '商品信息',
key: 'goodsInfo'
},
{
title: '订单操作日志',
key: 'orderLog'
}
],
detailInfo: {
jylsh: '16674653573152181000',
psfs: '物流配送',
yxhd: '',
ddbh: '20221103164918001',
shr: '',
mjly: '',
ddlx: '',
lxdh: '',
bz: '',
ddly: '',
shdz: '陕西省-西安市-莲湖区-九座花园西区(莲湖区二环南路西段202)陕西省-西安市-莲湖区-九座花园西区(莲湖区二环南路西段202)',
fkfs: '',
mj: '',
ddzt: '已完成',
tx: '买家付款成功后,货款将直接进入您的商户号(微信、支付宝)请及时关注你发出的包裹状态,确保可以配送至买家手中如果买家表示没收到货或货物有问题,请及时联系买家处理,友好协商',
expressInfo: [ // 物流信息
{
label: '包裹1',
name: 'bg1',
fhsj: '2022-11-03 16:50:45',
wlgs: '极兔',
ydh: '2132123',
wlzt: '不支持此快递公司',
wlxq: [
{
content: '正在派送途中,请您准备签收(派件人:王涛,电话:13854563814)',
timestamp: '2018-04-15 15:00:16'
},
{
content: '快件到达 【烟台龙口东江村委营业点】',
timestamp: '2018-04-13 14:54:19'
},
{
content: '快件已发车',
timestamp: '2018-04-11 12:55:52'
},
{
content: '快件已发车',
timestamp: '2018-04-11 12:55:52'
},
{
content: '快件已发车',
timestamp: '2018-04-11 12:55:52'
}
],
goodsList: [ // 包裹下的商品列表
{
name: 'Otic 巴拉啦小魔仙联名麦克风儿童早教家用一体卡拉OK宝宝话筒唱歌 魔仙粉',
count: 6,
imgUrl: 'https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg'
}
]
},
{
label: '包裹2',
name: 'bg1',
fhsj: '',
wlgs: '',
ydh: '',
wlzt: '',
goodsInfo: {}
},
{
label: '包裹3',
name: 'bg1',
fhsj: '',
wlgs: '',
ydh: '',
wlzt: '',
goodsInfo: {}
}
],
orderLog: [ // 订单操作日志
{
content: '买家【乌鸦】关闭了订单',
timestamp: '2018-04-15 15:00:16'
},
{
content: '买家【乌鸦】下单了',
timestamp: '2018-04-15 15:00:16'
}
],
goodsInfo: [] // 商品详情tableData
}
}
},
methods: {
clipboardSuccess() {
this.$modal.msgSuccess("复制成功");
}
}
}
</script>
<style lang="scss" scoped>
::v-deep .el-descriptions{
&:not(:nth-child(1)) {
margin-top: 20px;
}
.el-descriptions__title{
display: flex;
align-items: center;
&::before{
content: '';
display: inline-block;
margin-right: 10px;
width: 3px;
height: 20px;
background-color: #409EFF;
}
}
.el-descriptions-item__container{
margin: 0 10px;
.no-colon{
margin: 0;
&::after{
content: ''
}
}
}
}
</style>

View File

@ -0,0 +1,375 @@
<template>
<div class="app-container">
<!-- 搜索工作栏 -->
<!-- TODO: inline 看看是不是需要; v-show= 那块逻辑还是要的 -->
<el-row :gutter="20">
<el-form :model="queryParams" label-width="68px" size="small">
<el-col :span="6" :xs="24">
<el-form-item label="搜索方式">
<el-input style="width: 240px">
<el-select v-model="queryParams.searchType" slot="prepend" clearable style="width: 100px">
<el-option v-for="dict in dicData.searchType" v-bind="dict" :key="dict.value"/>
</el-select>
</el-input>
</el-form-item>
</el-col>
<el-col :span="6" :xs="24">
<el-form-item label="订单类型">
<el-select v-model="queryParams.orderType" clearable style="width: 240px">
<el-option v-for="dict in dicData.orderType" v-bind="dict" :key="dict.value"/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6" :xs="24">
<el-form-item label="订单状态">
<el-select v-model="queryParams.orderStatus" clearable style="width: 240px">
<el-option v-for="dict in dicData.orderStatus" v-bind="dict" :key="dict.value"/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6" :xs="24">
<el-form-item label="订单来源">
<el-select v-model="queryParams.orderSource" clearable style="width: 240px">
<el-option v-for="dict in dicData.orderSource" v-bind="dict" :key="dict.value"/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6" :xs="24">
<el-form-item label="付款方式">
<el-select v-model="queryParams.payWay" clearable style="width: 240px">
<el-option v-for="dict in dicData.payWay" v-bind="dict" :key="dict.value"/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6" :xs="24">
<el-form-item label="营销类型">
<el-select v-model="queryParams.marketingType" clearable style="width: 240px">
<el-option v-for="dict in dicData.marketingType" v-bind="dict" :key="dict.value"/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6" :xs="24">
<el-form-item label="下单时间">
<el-date-picker v-model="queryParams.date" type="daterange" range-separator="至"
start-placeholder="开始日期" end-placeholder="结束日期" :picker-options="rangePickerOptions" style="width: 240px"/>
</el-form-item>
</el-col>
<el-col :span="6" :xs="24" style="line-height: 32px">
<el-button type="primary" icon="el-icon-search" size="mini">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini">重置</el-button>
<el-button icon="el-icon-document" size="mini">导出订单</el-button>
</el-col>
</el-form>
</el-row>
<!-- tab切换-->
<el-radio-group v-model="activeTabName">
<el-radio-button v-for="tabPane in tabPanes" :label="tabPane.label">{{tabPane.text}}</el-radio-button>
</el-radio-group>
<!-- table -->
<el-table :data="tableData" :show-header="false" class="order-table">
<el-table-column label="订单信息">
<template slot-scope="{ row }">
<el-row>
<el-col :span="5">
订单号{{row.orderNo}}
<el-popover title="支付流水号:" :content="row.payNo" ref="popover" placement="right" width="200" trigger="click"/>
<el-button type="text" v-popover:popover>更多</el-button>
</el-col>
<el-col :span="5">下单时间{{row.time}}</el-col>
<el-col :span="4">订单来源{{row.orderSource}}</el-col>
<el-col :span="4">支付方式{{row.payWay}}</el-col>
<el-col :span="6" align="right" type="flex">
<el-button type="text">关闭订单</el-button>
<el-button type="text">修改地址</el-button>
<el-button type="text">调整价格</el-button>
<el-dropdown style="margin-left: 10px">
<el-button type="text">
更多操作<i class="el-icon-arrow-down el-icon--right"></i>
</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item><el-button type="text">打印发货单</el-button></el-dropdown-item>
<el-dropdown-item><el-button type="text" @click="goToDetail(row)">详情</el-button></el-dropdown-item>
<el-dropdown-item><el-button type="text">备注</el-button></el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</el-col>
</el-row>
<!-- 订单下的商品 -->
<el-table :data="row.goods" border>
<el-table-column label="商品" prop="goods" header-align="center" width="360">
<template slot-scope="{ row, $index }">
<div class="goods-info">
<img :src="row.picture"/>
<span class="ellipsis-2" :title="row.name">{{row.name}}</span>
</div>
</template>
</el-table-column>
<el-table-column label="单价(元)/数量" prop="fee" align="center" width="115">
<template slot-scope="{ row }">
<div>{{row.price}}</div>
<div>{{row.count}}</div>
</template>
</el-table-column>
<el-table-column label="维权" prop="safeguard" align="center" width="115"/>
<el-table-column label="实付金额(元)" prop="amount" align="center" width="115"/>
<el-table-column label="买家/收货人" prop="buyer" header-align="center" width="360">
<template slot-scope="{ row }">
<div>{{row.buyer}}</div>
<div>{{row.receiver}}{{row.tel}}</div>
<div class="ellipsis-2" :title="row.address">{{row.address}}</div>
</template>
</el-table-column>
<el-table-column label="配送方式" prop="sendWay" align="center" width="115"/>
<el-table-column label="交易状态" prop="status" align="center"/>
</el-table>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
const dicData = {
searchType: [
{ label: '订单号', value: 'ddh' },
{ label: '交易流水号', value: 'jylsh' },
{ label: '订单备注', value: 'ddbz' },
{ label: '收货人姓名', value: 'shrxm' },
{ label: '商品名称', value: 'spmc' },
{ label: '收货人电话', value: 'shrdh' },
{ label: '会员昵称', value: 'hync' },
{ label: '商品编号', value: 'spbh' }
],
orderType: [
{ label: '全部', value: 'qb' },
{ label: '物流订单', value: 'wldd' },
{ label: '自提订单', value: 'ztdd' },
{ label: '外卖订单', value: 'wmdd' },
{ label: '虚拟订单', value: 'xndd' },
{ label: '收银订单', value: 'sydd' }
],
orderStatus: [
{ label: '全部', value: 'qb' },
{ label: '待支付', value: 'dzf' },
{ label: '待发货', value: 'dfh' },
{ label: '已发货', value: 'yfh' },
{ label: '已收货', value: 'ysh' },
{ label: '已完成', value: 'ywc' },
{ label: '已关闭', value: 'ygb' },
{ label: '退款中', value: 'tkz' }
],
orderSource: [
{ label: '全部', value: 'qb' },
{ label: '微信公众号', value: 'wxgzh' },
{ label: '微信小程序', value: 'wxxcx' },
{ label: 'PC', value: 'pc' },
{ label: 'H5', value: 'h5' },
{ label: 'APP', value: 'app' },
{ label: '收银台', value: 'syt' },
{ label: '代客下单', value: 'dkxd' }
],
payWay: [
{ label: '全部', value: 'qb' },
{ label: '在线支付', value: 'zxzf' },
{ label: '余额支付', value: 'yezf' },
{ label: '线下支付', value: 'xxzf' },
{ label: '积分兑换', value: 'jfdh' },
{ label: '支付宝支付', value: 'zfbzf' },
{ label: '微信支付', value: 'wxzf' }
],
marketingType: [
{ label: '全部', value: 'qb' },
{ label: '一口价', value: 'ykj' },
{ label: '专题', value: 'zt' },
{ label: '团购', value: 'tg' },
{ label: '拼团', value: 'pt' },
{ label: '拼团返利', value: 'ptfl' },
{ label: '盲盒', value: 'mh' },
{ label: '砍价', value: 'kj' },
{ label: '礼品卡优惠', value: 'lpkyh' },
{ label: '秒杀', value: 'ms' },
{ label: '积分兑换', value: 'jfdh' },
{ label: '组合套餐', value: 'zhtc' },
{ label: '预售', value: 'ys' }
]
}
const rangePickerOptions = {
shortcuts: [{
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]);
}
}]
}
export default {
name: "index",
data () {
return {
dicData,
rangePickerOptions,
queryParams: {
searchType: 'ddh',
orderType: ''
},
activeTabName: 'all',
tabPanes: [
{ text: '全部', label: 'all' },
{ text: '待支付', label: 'toBePay' },
{ text: '待发货', label: 'toBeSend' },
{ text: '已发货', label: 'send' },
{ text: '已收货', label: 'received' },
{ text: '已完成', label: 'finished' },
{ text: '已关闭', label: 'closed' },
{ text: '退款中', label: 'refund' }
],
tableData: [
{
orderInfo: '',
orderNo: '20221026220424001',
payNo: '20221026220424001',
time: '2022-10-26 22:04:20',
orderSource: 'PC',
payWay: '微信支付',
goods: [
{
name: '颜衫短袖男polo衫夏季翻领衣服潮牌休闲上衣夏天翻领半袖男士t恤',
picture: 'https://b2c-v5-yanshi.oss-cn-hangzhou.aliyuncs.com/upload/1/common/images/20220723/20220723115621165854858145027_SMALL.webp',
price: '199',
count: '5件',
amount: 460,
safeguard: '主动退款',
buyer: '小明',
receiver: '小花',
tel: '15823655095',
address: '北京市-北京市-东城区 观音桥',
sendWay: '物流配送',
status: '已完成'
},
{
name: '颜衫短袖男polo衫夏季翻领衣服潮牌休闲上衣夏天翻领半袖男士t恤',
picture: 'https://b2c-v5-yanshi.oss-cn-hangzhou.aliyuncs.com/upload/1/common/images/20220723/20220723115621165854858145027_SMALL.webp',
price: '199',
count: '5件',
amount: 460,
safeguard: '主动退款',
buyer: '小明',
receiver: '小花',
tel: '15823655095',
address: '北京市-北京市-东城区 观音桥',
sendWay: '物流配送',
status: '已完成'
}
]
},
{
orderInfo: '',
orderNo: '20221026220424001',
payNo: '20221026220424001',
time: '2022-10-26 22:04:20',
orderSource: 'PC',
payWay: '微信支付',
goods: [
{
name: '颜衫短袖男polo衫夏季翻领衣服潮牌休闲上衣夏天翻领半袖男士t恤',
picture: 'https://b2c-v5-yanshi.oss-cn-hangzhou.aliyuncs.com/upload/1/common/images/20220723/20220723115621165854858145027_SMALL.webp',
price: '199',
count: '5件',
amount: 460,
safeguard: '主动退款',
buyer: '小明',
receiver: '小花',
tel: '15823655095',
address: '北京市-北京市-东城区 观音桥',
sendWay: '物流配送',
status: '已完成'
},
{
name: '颜衫短袖男polo衫夏季翻领衣服潮牌休闲上衣夏天翻领半袖男士t恤',
picture: 'https://b2c-v5-yanshi.oss-cn-hangzhou.aliyuncs.com/upload/1/common/images/20220723/20220723115621165854858145027_SMALL.webp',
price: '199',
count: '5件',
amount: 460,
safeguard: '主动退款',
buyer: '小明',
receiver: '小花',
tel: '15823655095',
address: '北京市-北京市-东城区 观音桥',
sendWay: '物流配送',
status: '已完成'
}
]
}
]
}
},
methods: {
goToDetail (row) {
this.$router.push({ path: '/mall/trade/order/detail', query: { orderNo: row.orderNo }})
}
}
}
</script>
<style lang="scss" scoped>
::v-deep .order-table{
margin-top: 20px;
border-bottom: none;
&::before{
height: 0;
}
.el-table__row{
.el-table__cell{
border-bottom: none;
.cell{
.el-table {
.el-table__row{
>.el-table__cell{
.goods-info{
display: flex;
img{
margin-right: 10px;
width: 60px;
height: 60px;
border: 1px solid #e2e2e2;
}
}
.ellipsis-2{
display: -webkit-box;
overflow: hidden;
text-overflow: ellipsis;
white-space: normal;
-webkit-line-clamp: 2; /* 要显示的行数 */
-webkit-box-orient: vertical;
word-break: break-all;
line-height: 22px !important;
max-height: 44px !important;
}
}
}
}
}
}
}
}
</style>

View File

@ -43,23 +43,23 @@
<el-table-column label="角色名称" prop="name" :show-overflow-tooltip="true" width="150" />
<el-table-column label="角色标识" prop="code" :show-overflow-tooltip="true" width="150" />
<el-table-column label="角色类型" prop="type" width="80">
<template v-slot="scope">
<template slot-scope="scope">
<dict-tag :type="DICT_TYPE.SYSTEM_ROLE_TYPE" :value="scope.row.type"/>
</template>
</el-table-column>
<el-table-column label="显示顺序" prop="sort" width="100" />
<el-table-column label="状态" align="center" width="100">
<template v-slot="scope">
<el-switch v-model="scope.row.status" :active-value="0" :inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch>
<template slot-scope="scope">
<el-switch v-model="scope.row.status" :active-value="0" :inactive-value="1" @change="handleStatusChange(scope.row)"/>
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template v-slot="scope">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template v-slot="scope">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
v-hasPermi="['system:role:update']">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-circle-check" @click="handleMenu(scope.row)"