This commit is contained in:
pikachu
2021-06-19 14:51:45 +08:00
150 changed files with 6654 additions and 2947 deletions

View File

@@ -5,6 +5,7 @@
</template>
<script>
import {v4 as uuidv4} from 'uuid';
import {getCategoryTree} from '@/api/goods.js'
export default {
updated() {
@@ -15,7 +16,14 @@ export default {
}
})
}
}
},
mounted() {
let uuid = this.getStore('uuid');
if (!uuid) {
uuid = uuidv4();
this.setStore('uuid', uuid);
}
},
};
</script>

View File

@@ -1,4 +1,4 @@
import {commonUrl, getRequest} from '@/libs/axios';
import {commonUrl, getRequest, getRequestWithNoToken, postRequestWithNoToken} from '@/libs/axios';
// 通过id获取子地区
export const getChildRegion = (id) => {
@@ -6,6 +6,16 @@ export const getChildRegion = (id) => {
};
// 点地图获取地址信息
export const getRegion = (parpams) => {
return getRequest(`${commonUrl}/common/region/region`, parpams);
export const getRegion = (params) => {
return getRequest(`${commonUrl}/common/region/region`, params);
};
// 获取拼图验证
export const getVerifyImg = (verificationEnums) => {
return getRequestWithNoToken(`${commonUrl}/common/slider/${verificationEnums}`);
};
// 拼图验证
export const postVerifyImg = (params) => {
return postRequestWithNoToken(`${commonUrl}/common/slider/${params.verificationEnums}`, params);
};

View File

@@ -86,4 +86,9 @@ export const getMemberFeedbackDetail = (id) => {
return getRequest(`/feedback/${id}`);
};
//管理员获取发送详情列表
export const getMemberMessage = (params) => {
return getRequest(`/message/member`, params);
};

View File

@@ -1,174 +1,231 @@
// 统一请求路径前缀在libs/axios.js中修改
import { getRequest, postRequest, putRequest, deleteRequest } from '@/libs/axios';
import {
getRequest,
postRequest,
putRequest,
deleteRequest
} from "@/libs/axios";
// 获取限时抢购申请列表
export const getPromotionSeckill = (params) => {
export const getPromotionSeckill = params => {
return getRequest(`/promotion/seckill/apply`, params);
};
return getRequest(`/promotion/seckill/apply`, params)
}
// 是否推荐直播间
export const whetherStar = params => {
return putRequest(`/broadcast/studio/recommend/${params.id}`,params);
};
// 添加优惠券活动
export const addCouponActivity = params => {
return postRequest(`/promotion/couponActivity/addCouponActivity`, params);
};
// 获取店铺直播间列表
export const getLiveList = params => {
return getRequest("/broadcast/studio", params);
};
// 获取直播间详情
export const getLiveInfo = studioId => {
return getRequest(`/broadcast/studio/studioInfo/${studioId}`);
};
// 获取当前进行中的促销活动商品
export const getPromotionGoods = (promotionId,params) => {
return getRequest(`/promotion/${promotionId}/goods`, params)
}
export const getPromotionGoods = (promotionId, params) => {
return getRequest(`/promotion/${promotionId}/goods`, params);
};
// 获取当前进行中的促销活动
export const getAllPromotion = (params) => {
return getRequest('/promotion/current', params)
}
export const getAllPromotion = params => {
return getRequest("/promotion/current", params);
};
// 获取拼团数据
export const getPintuanList = (params) => {
return getRequest('/promotion/pintuan', params)
}
export const getPintuanList = params => {
return getRequest("/promotion/pintuan", params);
};
// 获取拼团详情
export const getPintuanDetail = (id) => {
return getRequest(`/promotion/pintuan/${id}`)
}
export const getPintuanDetail = id => {
return getRequest(`/promotion/pintuan/${id}`);
};
// 获取拼团商品数据
export const getPintuanGoodsList = (params) => {
return getRequest(`/promotion/pintuan/goods/${params.pintuanId}`,params)
}
export const getPintuanGoodsList = params => {
return getRequest(`/promotion/pintuan/goods/${params.pintuanId}`, params);
};
// 关闭拼团活动
export const closePintuan = (pintuanId) => {
return putRequest(`/promotion/pintuan/close/${pintuanId}`)
}
export const closePintuan = pintuanId => {
return putRequest(`/promotion/pintuan/close/${pintuanId}`);
};
// 保存平台优惠券
export const savePlatformCoupon = (params) => {
return postRequest('/promotion/coupon', params,{'Content-type': 'application/json'})
}
export const savePlatformCoupon = params => {
return postRequest("/promotion/coupon", params, {
"Content-type": "application/json"
});
};
// 修改平台优惠券
export const editPlatformCoupon = (params) => {
return putRequest('/promotion/coupon', params,{'Content-type': 'application/json'})
}
export const editPlatformCoupon = params => {
return putRequest("/promotion/coupon", params, {
"Content-type": "application/json"
});
};
// 获取平台优惠券
export const getPlatformCouponList = (params) => {
return getRequest('/promotion/coupon', params)
}
export const getPlatformCouponList = params => {
return getRequest("/promotion/coupon", params);
};
// 作废优惠券
export const deletePlatformCoupon = (ids) => {
return deleteRequest(`/promotion/coupon/${ids}`)
}
export const deletePlatformCoupon = ids => {
return deleteRequest(`/promotion/coupon/${ids}`);
};
// 更新优惠券状态
export const updatePlatformCouponStatus = ( params) => {
return putRequest(`/promotion/coupon/status`, params)
}
export const updatePlatformCouponStatus = params => {
return putRequest(`/promotion/coupon/status`, params);
};
// 获取单个优惠券
export const getPlatformCoupon = (id) => {
return getRequest(`/promotion/coupon/${id}`)
}
export const getPlatformCoupon = id => {
return getRequest(`/promotion/coupon/${id}`);
};
// 获取优惠券领取详情
export const getMemberReceiveCouponList = (id) => {
return getRequest(`/promotion/coupon/member/${id}`)
}
export const getMemberReceiveCouponList = id => {
return getRequest(`/promotion/coupon/member/${id}`);
};
// 作废会员优惠券
export const deleteMemberReceiveCoupon = (id) => {
return putRequest(`/promotion/coupon/member/cancellation/${id}`)
}
export const deleteMemberReceiveCoupon = id => {
return putRequest(`/promotion/coupon/member/cancellation/${id}`);
};
// 保存平台优惠券
export const saveActivityCoupon = params => {
return postRequest("/promotion/couponActivity", params, {
"Content-type": "application/json"
});
};
// 获取活动优惠券列表
export const getActivityCouponList = params => {
return getRequest("/promotion/couponActivity/activityCoupons", params);
};
// 获取平台优惠券活动
export const getCouponActivityList = params => {
return getRequest("/promotion/couponActivity", params);
};
// 作废优惠券
export const closeActivity = id => {
return deleteRequest(`/promotion/couponActivity/${id}`);
};
// 更新优惠券活动
export const updateCouponActivity = params => {
return putRequest(`/promotion/couponActivity/status`, params);
};
// 获取单个优惠券活动
export const getCouponActivity = id => {
return getRequest(`/promotion/couponActivity/${id}`);
};
// 获取限时抢购数据
export const getSeckillList = (params) => {
return getRequest('/promotion/seckill', params)
}
export const getSeckillList = params => {
return getRequest("/promotion/seckill", params);
};
// 获取限时抢购审核列表
export const seckillGoodsList = (params) => {
return getRequest('/promotion/seckill/apply', params)
}
export const seckillGoodsList = params => {
return getRequest("/promotion/seckill/apply", params);
};
// 获取限时抢购详情数据
export const seckillDetail = (id, params) => {
return getRequest(`/promotion/seckill/${id}`, params)
}
return getRequest(`/promotion/seckill/${id}`, params);
};
// 删除限时抢购
export const delSeckill = (id) => {
return deleteRequest(`/promotion/seckill/${id}`)
}
export const delSeckill = id => {
return deleteRequest(`/promotion/seckill/${id}`);
};
// 保存限时抢购
export const saveSeckill = (params) => {
return postRequest('/promotion/seckill', params)
}
export const saveSeckill = params => {
return postRequest("/promotion/seckill", params);
};
// 修改限时抢购
export const updateSeckill = (params) => {
return putRequest('/promotion/seckill', params)
}
export const updateSeckill = params => {
return putRequest("/promotion/seckill", params);
};
// 关闭限时抢购
export const closeSeckill = (id) => {
return putRequest(`/promotion/seckill/close/${id}`)
}
export const closeSeckill = id => {
return putRequest(`/promotion/seckill/close/${id}`);
};
// 审核限时抢购
export const auditApplySeckill = (params) => {
return putRequest(`/promotion/seckill/apply/audit/${params.ids}`, params)
}
export const auditApplySeckill = params => {
return putRequest(`/promotion/seckill/apply/audit/${params.ids}`, params);
};
// 满优惠列表
export const getFullDiscountList = (params) => {
return getRequest(`/promotion/fullDiscount`,params)
}
export const getFullDiscountList = params => {
return getRequest(`/promotion/fullDiscount`, params);
};
// 满优惠列表
export const getFullDiscountById = (id) => {
return getRequest(`/promotion/fullDiscount/${id}`)
}
export const getFullDiscountById = id => {
return getRequest(`/promotion/fullDiscount/${id}`);
};
// 积分商品列表
export const getPointsGoodsList = (params) => {
return getRequest(`/promotion/pointsGoods`,params)
}
export const getPointsGoodsList = params => {
return getRequest(`/promotion/pointsGoods`, params);
};
// 积分商品详情
export const getPointsGoodsById = (id) => {
return getRequest(`/promotion/pointsGoods/${id}`)
}
export const getPointsGoodsById = id => {
return getRequest(`/promotion/pointsGoods/${id}`);
};
// 添加积分商品
export const addPointsGoods = (params) => {
return postRequest(`/promotion/pointsGoods`,params, {'Content-type': 'application/json'})
}
export const addPointsGoods = params => {
return postRequest(`/promotion/pointsGoods`, params, {
"Content-type": "application/json"
});
};
// 修改积分商品
export const updatePointsGoods = (params) => {
return putRequest(`/promotion/pointsGoods`,params, {'Content-type': 'application/json'})
}
export const updatePointsGoods = params => {
return putRequest(`/promotion/pointsGoods`, params, {
"Content-type": "application/json"
});
};
// 修改积分商品状态
export const editPointsGoodsStatus = (id, params) => {
return putRequest(`/promotion/pointsGoods/${id}`,params)
}
return putRequest(`/promotion/pointsGoods/${id}`, params);
};
// 删除积分商品
export const deletePointsGoodsStatus = (id) => {
return deleteRequest(`/promotion/pointsGoods/${id}`)
}
export const deletePointsGoodsStatus = id => {
return deleteRequest(`/promotion/pointsGoods/${id}`);
};
// 积分商品分类列表
export const getPointsGoodsCategoryList = (params) => {
return getRequest(`/promotion/pointsGoodsCategory`,params)
}
export const getPointsGoodsCategoryList = params => {
return getRequest(`/promotion/pointsGoodsCategory`, params);
};
// 积分商品分类详情
export const getPointsGoodsCategoryById = (id) => {
return getRequest(`/promotion/pointsGoodsCategory/${id}`)
}
export const getPointsGoodsCategoryById = id => {
return getRequest(`/promotion/pointsGoodsCategory/${id}`);
};
// 添加积分商品分类
export const addPointsGoodsCategory = (params) => {
return postRequest(`/promotion/pointsGoodsCategory`, params)
}
export const addPointsGoodsCategory = params => {
return postRequest(`/promotion/pointsGoodsCategory`, params);
};
// 更新积分商品分类
export const updatePointsGoodsCategory = (params) => {
return putRequest(`/promotion/pointsGoodsCategory`, params)
}
export const updatePointsGoodsCategory = params => {
return putRequest(`/promotion/pointsGoodsCategory`, params);
};
// 删除积分商品分类
export const deletePointsGoodsCategoryById = (id) => {
return deleteRequest(`/promotion/pointsGoodsCategory/${id}`)
}
export const deletePointsGoodsCategoryById = id => {
return deleteRequest(`/promotion/pointsGoodsCategory/${id}`);
};

View File

@@ -24,6 +24,8 @@ service.interceptors.request.use(
...config.params
}
}
const uuid = getStore('uuid');
config.headers['uuid'] = uuid;
return config;
},
err => {

View File

@@ -5,7 +5,7 @@ export const loginRouter = {
path: "/login",
name: "login",
meta: {
title: "登录 - lili "
title: "登录 - lili运营后台"
},
component: () => import("@/views/login.vue")
};
@@ -243,6 +243,43 @@ export const otherRouter = {
name: "platform-coupon-info",
component: () => import("@/views/promotion/coupon/couponInfo.vue")
},
{
path: "coupon-activity/add",
title: "添加优惠券活动",
name: "add-coupon-activity",
component: () => import("@/views/promotion/couponActivity/couponPublish.vue")
},
{
path: "coupon-activity/edit",
title: "编辑平台优惠券活动",
name: "edit-coupon-activity",
component: () => import("@/views/promotion/couponActivity/couponPublish.vue")
},
{
path: "promotion/coupon-activity-info",
title: "券活动详情",
name: "coupon-activity-info",
component: () => import("@/views/promotion/couponActivity/couponInfo.vue")
},
{
path: "promotion/member-receive-coupon",
title: "领取详情",
name: "member-coupon-activity",
component: () =>
import("@/views/promotion/coupon/memberReceiveCoupon.vue")
},
{
path: "promotion/platform-coupon-info",
title: "详情",
name: "platform-coupon-activity",
component: () => import("@/views/promotion/coupon/couponInfo.vue")
},
{
path: "promotion/add-coupon-specify",
title: "精准发劵",
name: "add-coupon-specify",
component: () => import("@/views/promotion/coupon/couponSpecify.vue")
},
{
path: "promotion/manager-pintuan",
title: "平台拼团",
@@ -296,6 +333,12 @@ export const otherRouter = {
title: "短信签名",
name: "add-sms-sign",
component: () => import("@/views/sys/message/smsSign.vue")
},
{
path: "liveDetail",
title: "查看直播",
name: "liveDetail",
component: () => import("@/views/promotion/live/liveDetail.vue")
}
]
};

View File

@@ -18,6 +18,72 @@ export function unitPrice(val, unit, location) {
let timer, flag;
/**
* 节流原理:在一定时间内,只能触发一次
*
* @param {Function} func 要执行的回调函数
* @param {Number} wait 延时的时间
* @param {Boolean} immediate 是否立即执行
* @return null
*/
export function throttle(func, wait = 500, immediate = true) {
if (immediate) {
if (!flag) {
flag = true;
// 如果是立即执行则在wait毫秒内开始时执行
typeof func === 'function' && func();
timer = setTimeout(() => {
flag = false;
}, wait);
}
} else {
if (!flag) {
flag = true
// 如果是非立即执行则在wait毫秒内的结束处执行
timer = setTimeout(() => {
flag = false
typeof func === 'function' && func();
}, wait);
}
}
};
let timeout = null;
/**
* 防抖原理一定时间内只有最后一次操作再过wait毫秒后才执行函数
*
* @param {Function} func 要执行的回调函数
* @param {Number} wait 延时的时间
* @param {Boolean} immediate 是否立即执行
* @return null
*/
export function debounce(func, wait = 500, immediate = false) {
// 清除定时器
if (timeout !== null) clearTimeout(timeout);
// 立即执行,此类情况一般用不到
if (immediate) {
var callNow = !timeout;
timeout = setTimeout(function() {
timeout = null;
}, wait);
if (callNow) typeof func === 'function' && func();
} else {
// 设置定时器当最后一次操作后timeout不会再被清除所以在延时wait毫秒后执行func回调方法
timeout = setTimeout(function() {
typeof func === 'function' && func();
}, wait);
}
}
/**
* 货币格式化
* @param price
@@ -172,4 +238,4 @@ export function formatLinkType (item) {
break;
}
return url;
}
}

View File

@@ -10,67 +10,77 @@
<span slot="close">关闭</span>
</i-switch>
</FormItem>
<FormItem label="分销关系绑定天数" prop="distributionDay">
<InputNumber :min="1" style="width:100px;" v-model="form.distributionDay" @on-change="handleSubmit"></InputNumber>
</FormItem>
<FormItem label="分销结算天数" prop="cashDay">
<InputNumber :min="1" style="width:100px;" v-model="form.cashDay" @on-change="handleSubmit "></InputNumber>
</FormItem>
</Form>
</div>
</template>
<script>
import { setSetting, getSetting } from "@/api/index";
import {setSetting, getSetting} from "@/api/index";
export default {
name: "distributionSetting",
components: {},
data() {
return {
loading: true, // 表单加载状态
form: { // 添加或编辑表单对象初始化数据
isOpen: ""
},
// 表单验证规则
formValidate: {},
submitLoading: false, // 添加或编辑提交状态
selectList: [], // 多选数据
selectCount: 0, // 多选计数
data: [], // 表单数据
total: 0 // 表单数据总数
};
},
methods: {
init() {
this.getDataList();
export default {
name: "distributionSetting",
components: {},
data() {
return {
loading: true, // 表单加载状态
form: {
// 添加或编辑表单对象初始化数据
isOpen: "",
distributionDay: "", //分销关系绑定天数
cashDay: "", //分销结算天数
},
getDataList() {
this.loading = true;
// 带多条件搜索参数获取表单数据 请自行修改接口
getSetting("DISTRIBUTION_SETTING").then(res => {
this.loading = false;
if (res.success) {
this.form = res.result;
}
});
// 表单验证规则
formValidate: {},
submitLoading: false, // 添加或编辑提交状态
selectList: [], // 多选数据
selectCount: 0, // 多选计数
data: [], // 表单数据
total: 0, // 表单数据总数
};
},
methods: {
init() {
this.getDataList();
},
getDataList() {
this.loading = true;
// 带多条件搜索参数获取表单数据 请自行修改接口
getSetting("DISTRIBUTION_SETTING").then((res) => {
this.loading = false;
},
handleSubmit() {
this.$refs.form.validate(valid => {
if (valid) {
setSetting("DISTRIBUTION_SETTING", this.form).then(res => {
if (res.success) {
this.$Message.success("操作成功");
this.getDataList();
}
});
}
})
}
if (res.success) {
this.form = res.result;
}
});
this.loading = false;
},
mounted() {
this.init();
}
};
handleSubmit() {
this.$refs.form.validate((valid) => {
if (valid) {
// 防抖处理一下
this.$options.filters.debounce(this.submit(), 1500);
}
});
},
submit() {
setSetting("DISTRIBUTION_SETTING", this.form).then((res) => {
if (res.success) {
this.$Message.success("操作成功");
this.getDataList();
}
});
},
},
mounted() {
this.init();
},
};
</script>
<style lang="scss" scoped>
</style>

View File

@@ -211,10 +211,8 @@
import { homeStatistics, hotGoods, hotShops, getNoticePage } from "@/api/index";
import show from "./show.vue";
import * as API_Goods from "@/api/goods";
import { Chart } from "@antv/g2";
import * as API_Member from "@/api/member";
import Cookies from "js-cookie";
export default {
name: "home",
components: {
@@ -502,11 +500,13 @@ export default {
let data = this.chartList;
data.forEach((item) => {
item.title = "历史在线人数";
item.date = item.date.substring(5)
});
this.historyMemberChart.data(data);
console.error(data)
this.historyMemberChart.tooltip({
showCrosshairs: true,
shared: true,

View File

@@ -0,0 +1,246 @@
<template>
<div class="wrapper">
<div class="wap-content">
<div class="query-wrapper">
<div class="query-item">
<div>搜索范围</div>
<Input placeholder="商品名称" @on-clear="goodsData=[]; goodsParams.goodsName=''; goodsParams.pageNumber = 1; getQueryGoodsList()" @on-enter="()=>{goodsData=[];goodsParams.pageNumber =1; getQueryGoodsList();}" icon="ios-search" clearable
style="width: 150px" v-model="goodsParams.goodsName" />
</div>
<div class="query-item">
<Cascader v-model="category" placeholder="请选择商品分类" style="width: 250px" :data="skuList"></Cascader>
</div>
<div class="query-item">
<Button type="primary" @click="goodsData=[]; getQueryGoodsList();" icon="ios-search">搜索</Button>
</div>
</div>
<div style="positon:retavle;">
<Scroll class="wap-content-list" :on-reach-bottom="handleReachBottom" :distance-to-edge="[3,3]">
<div class="wap-content-item" :class="{ active: item.selected }" @click="checkedGoods(item, index)" v-for="(item, index) in goodsData" :key="index">
<div>
<img :src="item.thumbnail" alt="" />
</div>
<div class="wap-content-desc">
<div class="wap-content-desc-title">{{ item.goodsName }}</div>
<div class="wap-sku">{{ item.goodsUnit }}</div>
<div class="wap-content-desc-bottom">
<div>¥{{ item.price | unitPrice }}</div>
</div>
</div>
</div>
<Spin size="large" fix v-if="loading"></Spin>
<div v-if="empty" class="empty">暂无商品信息</div>
</Scroll>
</div>
</div>
</div>
</template>
<script>
import * as API_Goods from "@/api/goods";
export default {
data() {
return {
type: "multiple", //单选或者多选 single multiple
skuList: [], // 商品sku列表
total: "", // 商品总数
goodsParams: { // 商品请求参数
pageNumber: 1,
pageSize: 18,
order: "desc",
goodsName: "",
sn: "",
categoryPath: "",
marketEnable: "UPPER",
isAuth: "PASS",
},
category: [], // 分类
goodsData: [], // 商品数据
empty: false, // 空数据
loading: false, // 加载状态
};
},
props: {
selectedWay: {
type: Array,
default: new Array()
}
},
watch: {
category(val) {
this.goodsParams.categoryPath = val[0];
},
selectedWay: {
handler() {
this.$emit("selected", this.selectedWay);
},
deep: true,
immediate: true
},
"goodsParams.categoryPath": {
handler: function () {
this.goodsData = [];
(this.goodsParams.pageNumber = 0), this.getQueryGoodsList();
},
deep: true,
},
},
mounted() {
this.init();
},
methods: {
handleReachBottom() {
setTimeout(() => {
if (
this.goodsParams.pageNumber * this.goodsParams.pageSize <=
this.total
) {
this.goodsParams.pageNumber++;
this.getQueryGoodsList();
}
}, 1500);
},
getQueryGoodsList() {
API_Goods.getGoodsSkuData(this.goodsParams).then((res) => {
this.initGoods(res);
});
},
initGoods(res) {
if (res.result.records.length !=0) {
res.result.records.forEach((item) => {
item.selected = false;
item.___type = "goods"; //设置为goods让pc wap知道标识
this.selectedWay.forEach(e => {
if (e.id === item.id) {
item.selected = true
}
})
});
/**
* 解决数据请求中,滚动栏会一直上下跳动
*/
this.total = res.result.total;
this.goodsData.push(...res.result.records);
} else {
this.empty = true;
}
},
// 查询商品
init() {
API_Goods.getGoodsSkuData(this.goodsParams).then((res) => {
// 商品
this.initGoods(res);
});
if (localStorage.getItem('category')) {
this.deepGroup(JSON.parse(localStorage.getItem('category')))
} else {
setTimeout(() => {
this.deepGroup(JSON.parse(localStorage.getItem('category')))
},3000)
}
},
deepGroup(val) {
val.forEach((item) => {
let childWay = []; //第二级
// 第二层
if (item.children) {
item.children.forEach((child) => {
// // 第三层
if (child.children) {
child.children.forEach((grandson, index, arr) => {
arr[index] = {
value: grandson.id,
label: grandson.name,
children: "",
};
});
}
let children = {
value: child.id,
label: child.name,
children: child.children,
};
childWay.push(children);
});
}
// 第一层
let way = {
value: item.id,
label: item.name,
children: childWay,
};
this.skuList.push(way);
});
},
/**
* 点击商品
*/
checkedGoods(val, index) {
// 如果单选的话
if (this.type != "multiple") {
this.goodsData.forEach((item) => {
item.selected = false;
});
this.selectedWay = [];
val.selected = true;
this.selectedWay.push(val);
return false;
}
if (val.selected == false) {
val.selected = true;
this.selectedWay.push(val);
} else {
val.selected = false;
for (let i = 0; i<this.selectedWay.length; i++ ) {
if (this.selectedWay[i].id===val.id) {
this.selectedWay.splice(i,1)
break;
}
}
}
},
},
};
</script>
<style scoped lang="scss">
@import "./style.scss";
.wap-content {
width: 100%;
}
.empty {
text-align: center;
padding: 8px 0;
width: 100%;
}
.wap-content {
flex: 1;
padding: 0;
}
.wap-content-list {
position: relative;
}
.wap-content-item {
width: 210px;
margin: 10px 7px;
padding: 6px 0;
}
// .wap-content-item{
// }
.active {
background: url("../../assets/selected.png") no-repeat;
background-position: right;
background-size: 10%;
}
</style>

View File

@@ -1,7 +1,7 @@
<template>
<Modal :styles="{ top: '120px' }" width="1160" @on-cancel="clickClose" @on-ok="clickOK" v-model="flag" :mask-closable="false" scrollable>
<template v-if="flag">
<goodsDialog @selected="(val) => {goodsData = val;}"
<goodsDialog @selected="(val) => {goodsData = val;}"
v-if="goodsFlag" ref="goodsDialog" :selectedWay='goodsData'/>
<linkDialog @selectedLink="
(val) => {
@@ -14,10 +14,12 @@
<script>
import goodsDialog from "./goods-dialog";
import linkDialog from "./link-dialog";
import couponDialog from "./coupon-dialog";
export default {
components: {
goodsDialog,
linkDialog,
couponDialog,
},
data() {
return {
@@ -60,7 +62,7 @@ export default {
} else {
this.goodsFlag = false;
}
},
close() {
this.flag = false;

View File

@@ -1,254 +0,0 @@
<template>
<div class="floor-list">
<div class="list">
<div class="template-saved" v-for="item in templateList" :key="item.id">
<div class="template-title">
<span>{{ item.name }}</span>
<span :class="{ 'theme-color': item.pageShow == 'OPEN' }">{{
item.pageShow == "OPEN" ? "已发布" : "未发布"
}}</span>
</div>
<div class="template-content">
<!-- <img :src="item.img || require(`@/assets/img-error.png`)" alt=""> -->
<div class="cover">
<Button icon="md-color-palette" @click="decorate(item.id)"
>装修</Button
>
<Button icon="md-pricetags" @click="Template(item)">编辑</Button>
<Button
icon="md-send"
v-if="item.pageShow == 'CLOSE'"
@click="releaseTemplate(item.id)"
>发布</Button
>
<Button
icon="md-trash"
v-if="item.pageShow == 'CLOSE'"
@click="delTemplate(item.id)"
>删除</Button
>
</div>
</div>
</div>
<div class="new-template" @click="createTemp">
<Icon type="md-add" />
<div>新建模板</div>
</div>
</div>
<Modal
v-model="showModal"
title="模板设置"
draggable
width="600"
:z-index="100"
:loading="loading"
mask-closable="false"
@on-ok="newTemplate"
@on-cancel="showModal = false"
>
<Form ref="form" :model="formData" :rules="rules" :label-width="80">
<FormItem label="模板名称" prop="name">
<Input v-model="formData.name" placeholder="请输入模板名称" />
</FormItem>
</Form>
</Modal>
</div>
</template>
<script>
import * as API_floor from "@/api/other.js";
export default {
name: "floorList",
data() {
return {
showModal: false,
templateList: [],
formData: {
status: false,
name: "",
},
rules: {
name: [{ required: true, message: "请输入模板名称", trigger: "blur" }],
},
loading: true,
};
},
mounted() {
let height = window.innerHeight - 150;
document.querySelector(".floor-list").style.height = height + "px";
this.getTemplateList();
},
methods: {
newTemplate() {
// 添加,编辑模板
this.$refs.form.validate((valid) => {
if (valid) {
const data = this.formData;
data.status ? (data.pageShow = "OPEN") : (data.pageShow = "CLOSE");
delete data.status;
(data.pageType = "INDEX"), (data.pageClientType = "PC");
if (data.id) {
API_floor.updateHome(data.id, data).then((res) => {
this.$Message.success("编辑模板成功");
this.showModal = false;
this.getTemplateList();
});
} else {
API_floor.setHomeSetup(data).then((res) => {
this.$Message.success("新建模板成功");
this.showModal = false;
this.getTemplateList();
});
}
} else {
this.loading = false;
}
});
},
createTemp() {
// 新建表单
this.$refs.form.resetFields();
this.showModal = true;
},
Template(item) {
// 编辑表单
item.pageShow == "OPEN" ? (item.status = true) : (item.status = false);
this.formData = item;
this.showModal = true;
},
decorate(id) {
// 装修
this.$router.push({ name: "renovation", query: { id: id } });
},
getTemplateList() {
//模板列表
let params = {
pageNumber: 1,
pageSize: 999,
pageType: "INDEX",
pageClientType: "PC",
};
API_floor.getHomeList(params).then((res) => {
if (res.success) {
this.templateList = res.result.records;
}
});
},
releaseTemplate(id) {
//发布模板
API_floor.releasePageHome(id).then((res) => {
if (res.success) {
this.$Message.success("发布模板成功");
this.getTemplateList();
}
});
},
delTemplate(id) {
this.$Modal.confirm({
title: "提示",
content: "<p>确定删除该模板吗?</p>",
onOk: () => {
API_floor.removePageHome(id).then((res) => {
if (res.success) {
this.$Message.success("删除模板成功");
this.getTemplateList();
}
});
},
onCancel: () => {},
});
},
},
computed: {},
};
</script>
<style lang="scss" scoped>
.floor-list {
background-color: #fff;
width: 100%;
}
.list {
width: 100%;
height: 100%;
padding: 10px;
display: flex;
flex-wrap: wrap;
> div {
width: 260px;
height: 450px;
margin: 10px 15px;
border: 1px solid #eee;
border-radius: 5px;
}
.new-template {
cursor: pointer;
display: flex;
align-items: center;
flex-direction: column;
justify-content: center;
border: 2px dashed $theme_color;
color: $theme_color;
background: #f88c7138;
.ivu-icon {
font-size: 30px;
margin-bottom: 10px;
}
}
.template-saved {
overflow: hidden;
.template-title {
padding: 10px;
background: #eee;
display: flex;
justify-content: space-between;
.theme-color {
color: $theme_color;
}
}
}
.template-content {
height: 407px;
width: 100%;
position: relative;
background: #ddd;
&:hover {
.cover {
visibility: visible;
}
}
img {
width: 100%;
height: 100%;
}
.cover {
visibility: hidden;
width: 100%;
height: 407px;
background: rgba(0, 0, 0, 0.3);
position: absolute;
top: 0;
left: 0;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.ivu-btn {
margin-bottom: 10px;
background: transparent;
color: #fff;
border-color: #fff;
&:hover {
background-color: $theme_color;
}
}
}
}
}
</style>

View File

@@ -8,7 +8,7 @@
<div class="full-shadow" v-if="type == 'full'">
<img :src="advertising[0].img" alt="" />
</div>
</div>
</div>
</div>
@@ -16,7 +16,7 @@
<div class="decorate">
<div class="decorate-title">全屏广告</div>
<div class="decorate-list">
<div
@@ -79,11 +79,11 @@
</div>
</template>
<script>
import { btnWay } from "./btn.js";
export default {
data() {
return {
btnWay, // 按钮类型
type: "full", // 是否全屏
//全屏广告
@@ -100,21 +100,16 @@ export default {
},
methods: {},
mounted() {
console.log(this.btnWay);
},
methods: {
// 点击链接
clickLink(item) {
this.$refs.liliDialog.open('link')
},
// 关闭
closeDecorate(index) {
this.$nextTick(() => {
this.btnWay.splice(index, 1);
});
},
//点击图片解析成base64
changeFile(item, index) {
const file = document.getElementById("files" + index).files[0];
@@ -177,4 +172,4 @@ export default {
height: 30px;
}
}
</style>
</style>

View File

@@ -76,7 +76,7 @@
</div>
</template>
<script>
import { btnWay } from "./btn.js";
export default {
data() {
return {
@@ -95,7 +95,7 @@ export default {
},
methods: {},
mounted() {
console.log(this.btnWay);
},
methods: {
// 点击链接
@@ -103,12 +103,7 @@ export default {
this.$refs.liliDialog.open('link')
},
// 关闭
closeDecorate(index) {
this.$nextTick(() => {
this.btnWay.splice(index, 1);
});
},
//点击图片解析成base64
changeFile(item, index) {
const file = document.getElementById("files" + index).files[0];
@@ -171,4 +166,4 @@ export default {
height: 30px;
}
}
</style>
</style>

View File

@@ -1,21 +0,0 @@
/**
* btnWay 设置悬浮按钮功能
*/
export const btnWay = [
{
img: require('@/assets/icon.png'),
title: "",
size:"80*80"
},
{
img: require('@/assets/icon.png'),
title: "",
size:"80*80"
},
{
img: require('@/assets/icon.png'),
title: "",
size:"80*80"
},
];

View File

@@ -1,147 +0,0 @@
<template>
<div class="model-view">
<div class="model-view-content">
<div class="content">
<div class="wap-title">首页</div>
<div class="draggable">
<div class="position">
<div class="btn-item">
<img
src="https://shopro-1253949872.file.myqcloud.com/uploads/20200704/f6b9c9d20d21df541ac52e9548486e1a.png"
alt=""
/>
</div>
<div class="btn-item" v-for="(item, index) in btnWay" :key="index">
<img :src="item.img" alt="" />
</div>
</div>
</div>
</div>
</div>
<div class="model-config">
<div class="decorate">
<div class="decorate-title">悬浮按钮</div>
<div class="decorate-list">
<div
class="decorate-item"
v-for="(item, index) in btnWay"
:key="index"
>
<div class="decorate-item-title">
<div>图标{{ index + 1 }}</div>
<Icon
@click="closeDecorate(index)"
size="20"
color="#e1251b"
type="md-close-circle"
/>
</div>
<div class="decorate-item-box">
<!-- 选择照片 -->
<div class="decorate-view">
<div class="decorate-view-title">选择图标</div>
<div>
<img class="show-image" :src="item.img" alt />
<input
type="file"
class="hidden-input"
@change="changeFile(item, index)"
ref="files"
:id="'files' + index"
/>
<div class="tips">
建议尺寸
<span>{{ item.size }}</span>
</div>
</div>
<div class="selectBtn">
<Button
size="small"
@click="handleClickFile(item, index)"
ghost
type="primary"
>选择照片</Button
>
</div>
</div>
</div>
</div>
</div>
<Button type="primary" @click="addDecorate()" ghost>添加</Button>
</div>
</div>
</div>
</template>
<script>
import { btnWay } from "./btn.js";
export default {
data() {
return {
btnWay, // 按钮类型
};
},
methods: {},
mounted() {
console.log(this.btnWay);
},
methods: {
//添加设置
addDecorate() {
let way = {
img: "https://picsum.photos/id/264/200/200",
title: "标题",
size: this.btnWay[0].size,
};
this.btnWay.push(way);
},
// 关闭
closeDecorate(index) {
this.$nextTick(() => {
this.btnWay.splice(index, 1);
});
},
//点击图片解析成base64
changeFile(item, index) {
const file = document.getElementById("files" + index).files[0];
if (file == void 0) return false;
const reader = new FileReader();
reader.readAsDataURL(file);
this.$nextTick((res) => {
reader.onload = (e) => {
item.img = e.target.result;
};
});
},
// 点击选择照片
handleClickFile(item, index) {
document.getElementById("files" + index).click();
// console.log(let files = files)
},
},
};
</script>
<style scoped lang="scss">
@import "./style.scss";
@import "./decorate.scss";
.draggable {
position: relative;
}
.position {
position: absolute;
right: 30px;
bottom: 50px;
display: flex;
flex-direction: column-reverse;
}
.btn-item {
> img {
margin: 4px 0;
border-radius: 50%;
width: 30px;
height: 30px;
}
}
</style>

View File

@@ -1,5 +1,5 @@
import index from './index.vue' //首页
import btn from './btn.vue' //按钮
import advertising from './advertising.vue' //全屏活动
import alertAdvertising from './alertAdvertising.vue' //弹窗活动
@@ -7,7 +7,7 @@ import alertAdvertising from './alertAdvertising.vue' //弹窗活动
const templates = {
index,
btn,
advertising,
alertAdvertising
}

View File

@@ -3,35 +3,22 @@
<div class="model-title">
<div>店铺装修</div>
<div class="btns">
<Button
@click="clickBtn(item)"
size="small"
v-for="(item, index) in way"
:key="index"
:type="item.selected ? 'primary' : ''"
>
<Button @click="clickBtn(item)" size="small" v-for="(item, index) in way" :key="index" :type="item.selected ? 'primary' : ''">
{{ item.title }}
</Button>
</div>
<div class="model-title-view-btn">
<Poptip placement="bottom" width="100">
<!-- TODO 后期会补全 目前版本暂无 -->
<!-- <Poptip placement="bottom" width="100">
<Button size="default" @click="creatQrCode">预览模板</Button>
<div slot="content" class="default-view-content">
<div>临时预览</div>
<div ref="qrCodeUrl"></div>
</div>
</Poptip>
<Button size="default" type="primary" @click="handleSpinShow"
>保存模板</Button
>
</Poptip> -->
<Button size="default" type="primary" @click="handleSpinShow">保存模板</Button>
<Modal
title="保存中"
v-model="saveDialog"
:closable="true"
:mask-closable="false"
:footer-hide="true"
>
<Modal title="保存中" v-model="saveDialog" :closable="true" :mask-closable="false" :footer-hide="true">
<div v-if="progress">
<div class="model-item">
模板名称 <Input style="width: 200px" v-model="submitWay.name" />
@@ -61,17 +48,14 @@ export default {
progress: true, // 展示进度
num: 20, // 提交进度
saveDialog: false, // 加载状态
way: [ // 装修tab栏切换
way: [
// 装修tab栏切换
{
title: "首页",
name: "index",
selected: true,
},
{
title: "悬浮按钮",
name: "btn",
selected: false,
},
{
title: "全屏广告",
name: "advertising",
@@ -84,7 +68,8 @@ export default {
},
],
qrcode: "", // 二维码
submitWay: { // 表单信息
submitWay: {
// 表单信息
pageShow: this.$route.query.type || false,
name: this.$route.query.name || "模板名称",
pageClientType: "H5",
@@ -128,11 +113,13 @@ export default {
// 更新
update() {
this.progress = false;
this.progress = false;
API_Other.updateHome(this.$route.query.id, {
pageData: JSON.stringify(this.$store.state.styleStore),
name: this.submitWay.name,
pageShow: this.submitWay.pageShow,
pageType: "INDEX",
pageClientType: "H5",
})
.then((res) => {
this.num = 50;
@@ -175,7 +162,7 @@ export default {
this.goback();
}, 1000);
} else {
this.progress = true;
this.progress = true;
this.saveDialog = false;
this.$Message.error("保存失败,请稍后重试");
}

View File

@@ -1,6 +1,6 @@
.image-mode {
max-width: 100%;
height: auto;
width: 100%;
height: 100%;
display: block;
padding: 1px;
}

View File

@@ -1,11 +1,11 @@
<template>
<div class="layout">
<img class="image-mode" :src="res.list[0].img" alt="">
<img class="image-mode" :src="res.list[1].img" alt="">
<img class="image-mode" :src="res.list[2].img" alt="">
<img class="image-mode" :src="res.list[3].img" alt="">
<img class="image-mode" :src="res.list[4].img" alt="">
<img class="image-mode" :src="res.list[0].img" alt="">
<img class="image-mode" :src="res.list[1].img" alt="">
<img class="image-mode" :src="res.list[2].img" alt="">
<img class="image-mode" :src="res.list[3].img" alt="">
<img class="image-mode" :src="res.list[4].img" alt="">
</div>
</template>
@@ -13,21 +13,18 @@
export default {
title: "五列单行图片模块",
props: ["res"],
mounted() {
console.log(this.res);
}
};
</script>
<style lang="scss" scoped>
@import "./tpl.scss";
.layout {
background: #e8e8e8;
display: flex;
align-items: center;
justify-content: center;
background-size: cover;
}
img{
img {
width: 67px;
}
</style>
</style>

View File

@@ -12,21 +12,22 @@
export default {
title: "四列单行图片模块",
props: ["res"],
mounted() {
console.log(this.res);
}
};
</script>
<style lang="scss" scoped>
@import "./tpl.scss";
.layout {
height: 84px;
// background: #e8e8e8;
// height: 84px;
display: flex;
padding: 0 8px;
align-items: center;
justify-content: center;
background-size: cover;
}
img{
width: 84px;
}
</style>
</style>

View File

@@ -11,14 +11,12 @@
export default {
title: "三列单行图片模块",
props: ["res"],
mounted() {
console.log(this.res);
}
};
</script>
<style lang="scss" scoped>
@import "./tpl.scss";
.layout {
background: #e8e8e8;
height: 110px;
display: flex;
align-items: center;
@@ -28,4 +26,4 @@ export default {
img{
width: 111px;
}
</style>
</style>

View File

@@ -20,7 +20,7 @@ export default {
title: "左一右二",
props: ["res"],
mounted() {
console.log(this.res);
}
};
</script>
@@ -34,4 +34,4 @@ export default {
background-size: cover;
}
</style>
</style>

View File

@@ -10,7 +10,7 @@
</div>
</div>
<div class="view-height-150">
<img class="image-mode" :src="res.list[2].img" />
<img class="image-mode" style="height:150px;" :src="res.list[2].img" />
</div>
</div>
</template>
@@ -21,18 +21,22 @@ export default {
props: ["res"],
mounted() {
console.log(this.res);
}
},
};
</script>
<style lang="scss" scoped>
@import "./tpl.scss";
.layout {
height: 167px;
height: 150px;
display: flex;
align-items: center;
justify-content: center;
background-size: cover;
}
</style>
.view-height-75 {
.image-mode {
height: 75px;
}
}
</style>

View File

@@ -22,6 +22,8 @@
</Row>
</Row>
<!-- 拼图验证码 -->
<verify ref="verify" class="verify-con" verifyType="LOGIN" @change="verifyChange"></verify>
<div v-if="socialLogining">
<RectLoading />
</div>
@@ -41,6 +43,7 @@ import LangSwitch from "@/views/main-components/lang-switch";
import RectLoading from "@/views/my-components/lili/rect-loading";
import CountDownButton from "@/views/my-components/lili/count-down-button";
import util from "@/libs/util.js";
import verify from "@/views/my-components/verify";
export default {
components: {
@@ -49,17 +52,20 @@ export default {
LangSwitch,
Header,
Footer,
verify,
},
data() {
return {
loading: false, // 加载状态
form: { // 表单数据
form: {
// 表单数据
username: "",
password: "",
mobile: "",
code: "",
},
rules: { // 验证规则
rules: {
// 验证规则
username: [
{
required: true,
@@ -80,6 +86,7 @@ export default {
methods: {
mounted() {},
afterLogin(res) {
// 登录成功后处理
let accessToken = res.result.accessToken;
let refreshToken = res.result.refreshToken;
this.setStore("accessToken", accessToken);
@@ -101,22 +108,34 @@ export default {
});
},
submitLogin() {
// 登录操作
this.$refs.usernameLoginForm.validate((valid) => {
if (valid) {
this.loading = true;
login({
username: this.form.username,
password: this.md5(this.form.password),
}).then((res) => {
if (res && res.success) {
this.afterLogin(res);
} else {
this.loading = false;
}
});
this.$refs.verify.show = true;
}
});
},
verifyChange(con) {
// 拼图验证码回显
if (!con.status) return;
this.loading = true;
login({
username: this.form.username,
password: this.md5(this.form.password),
})
.then((res) => {
if (res && res.success) {
this.afterLogin(res);
} else {
this.loading = false;
}
})
.catch(() => {
this.loading = false;
});
this.$refs.verify.show = false;
},
},
};
</script>
@@ -140,7 +159,12 @@ export default {
position: relative;
zoom: 1;
}
.verify-con {
position: absolute;
top: 90px;
z-index: 10;
left: 20px;
}
.form {
padding-top: 1vh;
@@ -179,5 +203,4 @@ export default {
.flex {
justify-content: center;
}
</style>

View File

@@ -2,7 +2,6 @@
<div>
<Row class="header">
<img src="../../assets/logo.png" class="logo" width="220px">
<!-- <div class="description">{{ $t('LILISHOP-ADMIN') }}</div> -->
</Row>
</div>
</template>
@@ -15,13 +14,13 @@ export default {
<style lang="scss" scoped>
.header {
margin-bottom: 6vh;
text-align: center;
display: flex;
justify-content: center !important;
}
.logo {
transform: scale(2);
width: 440px;
height: 158px;
}
</style>

View File

@@ -55,6 +55,7 @@ export default {
},
methods: {
changeMenu(name) { //二级路由点击
console.log(name)
this.$router.push({
name: name
});

View File

@@ -21,11 +21,11 @@
<Button @click="addMember" type="primary">添加会员</Button>
</Row>
<Table :loading="loading" border :columns="columns" :data="data" ref="table" sortable="custom" @on-sort-change="changeSort" @on-selection-change="changeSelect">
</Table>
<Table :loading="loading" border :columns="columns" :data="data" ref="table" sortable="custom" @on-sort-change="changeSort" @on-selection-change="changeSelect">
</Table>
<Row type="flex" justify="end" class="page">
<Page :current="searchForm.pageNumber" :total="total" :page-size="searchForm.pageSize" @on-change="changePage" @on-page-size-change="changePageSize" :page-size-opts="[10, 20, 50]"
size="small" show-total show-elevator show-sizer></Page>
<Page :current="searchForm.pageNumber" :total="total" :page-size="searchForm.pageSize" @on-change="changePage" @on-page-size-change="changePageSize" :page-size-opts="[10, 20, 50]" size="small"
show-total show-elevator show-sizer></Page>
</Row>
</Card>
@@ -137,12 +137,14 @@ export default {
loading: true, // 表单加载状态
addFlag: false, // modal显隐控制
updateRegion: false, // 地区
addMemberForm: { // 添加用户表单
addMemberForm: {
// 添加用户表单
mobile: "",
username: "",
password: "",
},
searchForm: { // 请求参数
searchForm: {
// 请求参数
pageNumber: 1,
pageSize: 10,
order: "desc",
@@ -152,7 +154,8 @@ export default {
},
picModelFlag: false, // 选择图片
formValidate: {}, // 表单数据
addRule: { // 验证规则
addRule: {
// 验证规则
mobile: [
{ required: true, message: "请输入手机号码" },
{
@@ -229,6 +232,7 @@ export default {
{
props: {
size: "small",
type: params.row.___selected ? "primary" : "",
},
style: {
marginRight: "5px",
@@ -236,11 +240,11 @@ export default {
},
on: {
click: () => {
this.callback(params.row);
this.callback(params.row, params.index);
},
},
},
"选择"
params.row.___selected ? "已选择" : "选择"
),
h(
@@ -251,7 +255,8 @@ export default {
size: "small",
},
style: {
marginRight: "5px", display: this.selectedMember ? "none" : "block",
marginRight: "5px",
display: this.selectedMember ? "none" : "block",
},
on: {
click: () => {
@@ -270,7 +275,8 @@ export default {
ghost: true,
},
style: {
marginRight: "5px", display: this.selectedMember ? "none" : "block",
marginRight: "5px",
display: this.selectedMember ? "none" : "block",
},
on: {
click: () => {
@@ -306,18 +312,75 @@ export default {
],
data: [], // 表单数据
total: 0, // 表单数据总数
selectMember: [], //保存选中的用户
};
},
props: {
// 是否为选中模式
selectedMember: {
type: Boolean,
default: false,
},
// 已选择用户数据
selectedList: {
type: null,
default: "",
},
},
watch: {
selectedList: {
handler(val) {
this.$set(this, "selectMember", JSON.parse(JSON.stringify(val)));
this.init(this.data);
// 将父级数据与当前组件数据进行匹配
},
deep: true,
immediate: true,
},
},
methods: {
// 回调给父级
callback(val) {
callback(val, index) {
this.$set(val, "___selected", !val.___selected);
console.log(val.___selected);
let findUser = this.selectMember.find((item) => {
return item.id == val.id;
});
// 如果没有则添加
if (!findUser) {
this.selectMember.push(val);
} else {
// 有重复数据就删除
this.selectMember.map((item, index) => {
if (item.id == findUser.id) {
this.selectMember.splice(index, 1);
}
});
}
this.$emit("callback", val);
},
init() {
this.getData();
// 初始化信息
init(data) {
data.forEach((item) => {
if (this.selectMember.length != 0) {
this.selectMember.forEach((member) => {
if (member.id == item.id) {
this.$set(item, "___selected", true);
}
});
} else {
this.$set(item, "___selected", false);
}
});
this.data = data;
},
changePage(v) {
this.searchForm.pageNumber = v;
// 此处如果是父子级传值的时候需要做一下处理
//selectedMember
this.getData();
},
changePageSize(v) {
@@ -373,12 +436,13 @@ export default {
}
});
},
//查询会员列表
getData() {
API_Member.getMemberListData(this.searchForm).then((res) => {
if (res.result.records) {
this.loading = false;
this.data = res.result.records;
this.init(res.result.records);
this.total = res.result.total;
}
});
@@ -467,7 +531,7 @@ export default {
},
},
mounted() {
this.init();
this.getData();
},
};
</script>
@@ -476,7 +540,7 @@ export default {
/deep/ .ivu-table-wrapper {
width: 100%;
}
/deep/ .ivu-card{
/deep/ .ivu-card {
width: 100%;
}
.face {

View File

@@ -0,0 +1,346 @@
<template>
<div class="sku-choose">
<Button @click="showDrawer=true" :icon="icon">{{ text }}</Button>
<span @click="clearSelectData" class="clear">清空已选</span>
<Collapse simple class="collapse">
<Panel name="1">
已选择
<span class="select-count">{{ selectObj.length }}</span>
<p slot="content">
<Tag
v-for="(item, i) in selectObj"
:key="i"
:name="item.id"
color="default"
closable
@on-close="handleCancelObj"
>{{ createName(item) }}
</Tag>
</p>
</Panel>
</Collapse>
<Drawer title="选择活动优惠券" closable v-model="showDrawer" :width="width" draggable>
<Table
:loading="showLoading"
border
:columns="tableColumns"
:data="tableData"
:height="height"
ref="tableData"
></Table>
<Row type="flex" justify="end" style="margin: 10px 0;">
<Page
:current="searchForm.pageNumber"
:total="tableTotal"
:page-size="searchForm.pageSize"
@on-change="changeDataPage"
@on-page-size-change="changeDataPageSize"
:page-size-opts="[10,20,50]"
size="small"
show-total
show-elevator
show-sizer
></Page>
</Row>
<div class="my-drawer-footer">
已选择
<span class="select-count">{{ selectObj.length }}</span>
<Button @click="clearSelectData" style="margin-left:10px">清空已选</Button>
<Button @click="showDrawer=false" type="primary" style="margin-left:10px">关闭</Button>
</div>
</Drawer>
</div>
</template>
<script>
import {
getPlatformCouponList
} from "@/api/promotion";
export default {
name: "userChoose",
props: {
text: {
type: String,
default: "选择SKU"
},
icon: {
type: String,
default: "md-basket"
},
initData: {
type: Array,
default: []
},
createName: {
type: Function,
default: function (item) {
return item.goodsName
}
}
},
mounted() {
this.selectObj = this.initData
console.log(JSON.stringify(this.initData))
},
data() {
return {
//默认值后续计算
height: 500,
width: 500,
//加载状态
showLoading: true,
//展示抽屉
showDrawer: false,
selectObj: [], // 选择数据
searchForm: { // 请求参数
getType: "ACTIVITY",// 活动优惠券
pageNumber: 1, // 当前页数
pageSize: 10, // 页面大小
sort: "createTime", // 默认排序字段
order: "desc", // 默认排序方式
},
tableColumns: [ // 表头
{
type: "index",
width: 60,
align: "center"
},
{
title: "商品名称",
key: "goodsName",
minWidth: 140
},
{
title: "规格",
key: "specName",
minWidth: 140,
},
{
title: "图片",
key: "thumbnail",
width: 80,
align: "center",
render: (h, params) => {
return h("Avatar", {
props: {
src: params.row.face
}
});
}
},
{
title: "状态",
key: "status",
align: "center",
width: 120,
render: (h, params) => {
if (params.row.delFlag == 0) {
return h("div", [
h("Badge", {
props: {
status: "success",
text: "正常"
}
})
]);
} else if (params.row.delFlag == -1) {
return h("div", [
h("Badge", {
props: {
status: "error",
text: "禁用"
}
})
]);
}
}
},
{
title: "创建时间",
key: "createTime",
sortable: true,
sortType: "desc",
width: 170
},
{
title: "操作",
key: "action",
width: 130,
align: "center",
fixed: "right",
render: (h, params) => {
let select;
this.selectObj.forEach(item => {
if (item.id === params.row.id) {
select = params.row
}
});
if (select) {
return h("div", [
h(
"Button",
{
props: {
type: "info",
size: "small"
},
on: {
click: () => {
this.chooseCancel(params.row);
}
}
},
"取消选择"
)
]);
} else {
return h("div", [
h(
"Button",
{
props: {
type: "info",
size: "small"
},
on: {
click: () => {
this.chooseObj(params.row);
}
}
},
"选择"
)
]);
}
}
}
],
tableData: [], // 表格数据
tableTotal: 0 // 总数
};
},
methods: {
changeDataPage(v) {
this.searchForm.pageNumber = v;
this.searchData();
},
changeDataPageSize(v) {
this.searchForm.pageSize = v;
this.searchData();
},
searchData() {
this.showLoading = true;
getPlatformCouponList(this.searchForm).then(res => {
this.showLoading = false;
if (res.success) {
this.tableData = res.result.records;
this.tableTotal = res.result.total;
}
});
},
handleSearchData() {
this.searchForm.pageNumber = 1;
this.searchForm.pageSize = 10;
this.searchData();
},
handleResetObj() {
this.$refs.searchForm.resetFields();
this.searchForm.pageNumber = 1;
this.searchForm.pageSize = 9;
this.searchForm.departmentId = "";
// 重新加载数据
this.searchData();
},
setData(v) {
this.selectObj = v;
this.$emit("on-change", this.selectObj);
},
chooseCancel(v) {
let _index;
this.selectObj.forEach((e, index) => {
if (v.id == e.id) {
_index = index;
}
});
if (_index || _index == 0) {
this.selectObj.splice(_index, 1);
this.$emit("on-change", this.selectObj);
}
},
chooseObj(v) {
// 去重
let that = this;
let flag = true;
this.selectObj.forEach(e => {
if (v.id == e.id) {
flag = false;
}
});
if (flag) {
this.selectObj.push(v);
this.$emit("on-change", this.selectObj);
}
},
clearSelectData() {
this.selectObj = [];
this.$emit("on-change", this.selectObj);
},
handleCancelObj(e, id) {
// 删除所选用户
let newArray = [];
this.selectObj.forEach(e => {
if (id != e.id) {
newArray.push(e);
}
});
this.selectObj = newArray;
this.$emit("on-change", this.selectObj);
}
},
created() {
// 计算高度
this.height = Number(document.documentElement.clientHeight - 230);
this.width = Number(document.documentElement.clientWidth / 2) > 900 ? 900 : Number(document.documentElement.clientWidth / 2)
this.searchData();
}
};
</script>
<style lang="scss" scoped>
.sku-choose {
.clear {
font-size: 12px;
margin-left: 15px;
color: #40a9ff;
cursor: pointer;
}
.collapse {
font-size: 12px;
margin-top: 15px;
}
.select-count {
font-weight: 600;
color: #40a9ff;
}
}
.my-drawer-footer {
z-index: 10;
width: 100%;
position: absolute;
bottom: 0;
left: 0;
border-top: 1px solid #e8e8e8;
padding: 10px 16px;
text-align: right;
background: #fff;
}
</style>

View File

@@ -15,20 +15,8 @@
</div>
</div>
<Modal
title="编辑html代码"
v-model="showHTMLModal"
:mask-closable="false"
:width="900"
:fullscreen="full"
>
<Input
v-if="!full"
v-model="dataEdit"
:rows="15"
type="textarea"
style="max-height:60vh;overflow:auto;"
/>
<Modal title="编辑html代码" v-model="showHTMLModal" :mask-closable="false" :width="900" :fullscreen="full">
<Input v-if="!full" v-model="dataEdit" :rows="15" type="textarea" style="max-height:60vh;overflow:auto;" />
<Input v-if="full" v-model="dataEdit" :rows="32" type="textarea" />
<div slot="footer">
<Button @click="full=!full" icon="md-expand">全屏开/</Button>
@@ -56,21 +44,21 @@ export default {
props: {
id: {
type: String,
default: "editor"
default: "editor",
},
value: String,
base64: {
type: Boolean,
default: false
default: false,
},
showExpand: {
type: Boolean,
default: true
default: true,
},
openXss: {
type: Boolean,
default: false
}
default: false,
},
},
data() {
return {
@@ -79,16 +67,17 @@ export default {
dataEdit: "", // 编辑数据
showHTMLModal: false, // 显示html
full: false, // html全屏开关
fullscreenModal: false // 显示全屏预览
fullscreenModal: false, // 显示全屏预览
};
},
methods: {
initEditor() {
let that = this;
// 详见wangeditor3官网文档 https://www.kancloud.cn/wangfupeng/wangeditor3/332599
editor = new E(`#${this.id}`);
// 编辑内容绑定数据
editor.config.onchange = html => {
editor.config.onchange = (html) => {
if (this.openXss) {
this.data = xss(html);
} else {
@@ -108,30 +97,30 @@ export default {
editor.config.uploadImgServer = uploadFile;
// lili如要header中传入token鉴权
editor.config.uploadImgHeaders = {
accessToken: that.getStore("accessToken")
accessToken: that.getStore("accessToken"),
};
editor.config.uploadFileName = "file";
editor.config.uploadImgHooks = {
before: function(xhr, editor, files) {
before: function (xhr, editor, files) {
// 图片上传之前触发
},
success: function(xhr, editor, result) {
success: function (xhr, editor, result) {
// 图片上传并返回结果,图片插入成功之后触发
},
fail: function(xhr, editor, result) {
fail: function (xhr, editor, result) {
// 图片上传并返回结果,但图片插入错误时触发
that.$Message.error("上传图片失败");
},
error: function(xhr, editor) {
error: function (xhr, editor) {
// 图片上传出错时触发
that.$Message.error("上传图片出错");
},
timeout: function(xhr, editor) {
timeout: function (xhr, editor) {
// 图片上传超时时触发
that.$Message.error("上传图片超时");
},
// 如果服务器端返回的不是 {errno:0, data: [...]} 这种格式,可使用该配置
customInsert: function(insertImg, result, editor) {
customInsert: function (insertImg, result, editor) {
if (result.success == true) {
let url = result.result;
insertImg(url);
@@ -139,10 +128,11 @@ export default {
} else {
that.$Message.error(result.message);
}
}
},
};
}
editor.config.customAlert = function(info) {
editor.config.customAlert = function (info) {
// info 是需要提示的内容
// that.$Message.info(info);
};
@@ -156,8 +146,8 @@ export default {
// type -> 'emoji' / 'image'
type: "image",
// content -> 数组
content: sina
}
content: sina,
},
];
editor.create();
if (this.value) {
@@ -187,7 +177,7 @@ export default {
editor.txt.html(this.data);
this.$emit("input", this.data);
this.$emit("on-change", this.data);
}
},
});
},
setData(value) {
@@ -200,22 +190,21 @@ export default {
this.$emit("input", this.data);
this.$emit("on-change", this.data);
}
}
},
},
watch: {
value(val) {
this.setData(val);
}
},
},
mounted() {
this.initEditor();
}
},
};
</script>
<style lang="scss" scoped>
.e-menu {
z-index: 101;
position: absolute;
cursor: pointer;

View File

@@ -0,0 +1,14 @@
### 滑动拼图验证
### 在页面中引入 .vue文件
#### 参数
#### 在组件上添加v-if来判断组件显隐
#### verifyType 验证格式[ 'LOGIN' ,'REGISTER' ]
#### @change方法 获取回调,参数为对象 {status:false,distance:100} status 为回调状态distance为移动距离
#### <Verify class="verify-content" verifyType='LOGIN' @change="verifyChange"></Verify>

View File

@@ -0,0 +1,185 @@
<template>
<div class="verify-content" v-if="show" @mousemove="mouseMove" @mouseup="mouseUp">
<div class="imgBox" :style="{width:data.originalWidth+'px',height:data.originalHeight + 'px'}">
<img :src="data.backImage" style="width:100%;height:100%" alt="">
<img class="slider" :src="data.slidingImage" :style="{left:distance+'px',top:data.randomY+'px'}" :width="data.sliderWidth" :height="data.sliderHeight" alt="">
<Icon type="md-refresh" class="refresh" @click="refresh" />
</div>
<div class="handle" :style="{width:data.originalWidth+'px'}">
<span class="bgcolor" :style="{width:distance + 'px',background:bgColor}"></span>
<span class="swiper" :style="{left:distance + 'px'}" @mousedown="mouseDown">
<Icon type="md-arrow-round-forward" />
</span>
<span class="text">{{verifyText}}</span>
</div>
</div>
</template>
<script>
import { getVerifyImg, postVerifyImg } from './verify.js';
export default {
props: {
verifyType: {
defalut: 'LOGIN',
type: String
}
},
data () {
return {
show: false, // 验证码显隐
type: 'LOGIN', // 请求类型
data: { // 验证码数据
backImage: '',
slidingImage: '',
originalHeight: 150,
originalWidth: 300,
sliderWidth: 60,
sliderHeight: 60
},
distance: 0, // 拼图移动距离
flag: false, // 判断滑块是否按下
downX: 0, // 鼠标按下位置
bgColor: 'aqua', // 滑动背景颜色
verifyText: '拖动滑块解锁' // 文字提示
};
},
methods: {
mouseDown (e) {
this.downX = e.clientX;
this.flag = true;
},
mouseMove (e) {
if (this.flag) {
let offset = e.clientX - this.downX;
if (offset > this.data.originalWidth - 43) {
this.distance = this.data.originalWidth - 43;
} else if (offset < 0) {
this.distance = 0;
} else {
this.distance = offset;
}
}
},
mouseUp () {
if (!this.flag) return false;
this.flag = false;
let params = {
verificationEnums: this.type,
xPos: this.distance
};
postVerifyImg(params).then(res => {
if (res.result) {
this.bgColor = 'green';
this.verifyText = '解锁成功';
this.$emit('change', { status: true, distance: this.distance });
} else {
this.bgColor = 'red';
this.verifyText = '解锁失败';
let that = this;
setTimeout(() => {
that.refresh();
}, 1000);
this.$emit('change', { status: false, distance: this.distance });
}
});
},
refresh () {
this.flag = false;
this.downX = 0;
this.distance = 0;
this.bgColor = 'aqua';
this.verifyText = '拖动滑块解锁';
this.getImg();
},
getImg () {
getVerifyImg(this.type).then(res => {
this.data = res.result;
});
}
},
created () {
this.getImg();
},
watch: {
verifyType: {
immediate: true,
handler: function (v) {
this.type = v;
this.refresh();
}
},
show (v) {
if (v) this.refresh();
}
}
};
</script>
<style lang="scss" scoped>
.verify-content{
padding: 10px;
background: #fff;
border: 1px solid #eee;
border-radius: 5px;
box-shadow: 1px 1px 3px #999;
}
.imgBox {
width: 300px;
height: 150px;
position: relative;
overflow: hidden;
.slider {
position: absolute;
cursor: pointer;
}
.refresh {
position: absolute;
right: 5px;
top: 5px;
font-size: 20px;
color: #fff;
cursor: pointer;
}
}
.handle {
border: 1px solid rgb(134, 134, 134);
margin-top: 5px;
height: 42px;
background: #ddd;
position: relative;
.bgcolor {
position: absolute;
top: 0;
left: 0;
width: 40px;
height: 40px;
opacity: 0.5;
background: aqua;
}
.swiper {
position: absolute;
width: 40px;
height: 40px;
background-color: #fff;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
.ivu-icon {
font-size: 20px;
}
}
.text {
display: inline-block;
width: inherit;
text-align: center;
line-height: 42px;
font-size: 14px;
user-select: none;
}
}
</style>

View File

@@ -0,0 +1,13 @@
import {commonUrl, getRequestWithNoToken, postRequestWithNoToken} from '@/libs/axios';
// 获取拼图验证
export const getVerifyImg = (verificationEnums) => {
return getRequestWithNoToken(`${commonUrl}/common/slider/${verificationEnums}`);
};
// 拼图验证
export const postVerifyImg = (params) => {
return postRequestWithNoToken(`${commonUrl}/common/slider/${params.verificationEnums}`, params);
};

View File

@@ -1,16 +1,27 @@
<template>
<div class="search">
<Card>
<Row @keydown.enter.native="handleSearch">
<Form ref="searchForm" :model="searchForm" inline :label-width="70" class="search-form">
<Form-item label="订单号" prop="orderSn">
<Input type="text" v-model="searchForm.orderSn" placeholder="请输入订单号" clearable style="width: 200px" />
<Input type="text" v-model="searchForm.orderSn" placeholder="请输入订单号" clearable style="width: 160px" />
</Form-item>
<Form-item label="会员名称" prop="buyerName">
<Input type="text" v-model="searchForm.buyerName" placeholder="请输入会员名称" clearable style="width: 200px" />
<Input type="text" v-model="searchForm.buyerName" placeholder="请输入会员名称" clearable style="width: 160px" />
</Form-item>
<Form-item label="订单类型" prop="orderType">
<Select v-model="searchForm.orderType" placeholder="请选择" clearable style="width: 160px">
<Option value="NORMAL">普通订单</Option>
<Option value="PINTUAN">拼团订单</Option>
<Option value="GIFT">赠品订单</Option>
<Option value="VIRTUAL">核验订单</Option>
</Select>
</Form-item>
<Form-item label="订单状态" prop="orderStatus">
<Select v-model="searchForm.orderStatus" placeholder="请选择" clearable style="width: 200px">
<Select v-model="searchForm.orderStatus" placeholder="请选择" clearable style="width: 160px">
<Option value="UNPAID">未付款</Option>
<Option value="PAID">已付款</Option>
<Option value="UNDELIVERED">待发货</Option>
@@ -20,29 +31,91 @@
<Option value="CANCELLED">已取消</Option>
</Select>
</Form-item>
<Form-item label="下单时间">
<DatePicker v-model="selectDate" type="datetimerange" format="yyyy-MM-dd" clearable @on-change="selectDateRange" placeholder="选择起始时间" style="width: 200px"></DatePicker>
<DatePicker v-model="selectDate" type="datetimerange" format="yyyy-MM-dd" clearable @on-change="selectDateRange" placeholder="选择起始时间" style="width: 160px"></DatePicker>
</Form-item>
<Button @click="handleSearch" type="primary" icon="ios-search" class="search-btn">搜索</Button>
</Form>
</Row>
<div>
<download-excel class="export-excel-wrapper" :data="data" :fields="fields" name="商品订单.xls">
<Button type="primary" class="export">
导出Excel
</Button>
</download-excel>
</div>
<Table :loading="loading" border :columns="columns" :data="data" ref="table" sortable="custom" @on-sort-change="changeSort" @on-selection-change="changeSelect"></Table>
<Row type="flex" justify="end" class="page">
<Page :current="searchForm.pageNumber" :total="total" :page-size="searchForm.pageSize" @on-change="changePage" @on-page-size-change="changePageSize" :page-size-opts="[10, 20, 50]"
size="small" show-total show-elevator show-sizer></Page>
<Page :current="searchForm.pageNumber" :total="total" :page-size="searchForm.pageSize" @on-change="changePage" @on-page-size-change="changePageSize" :page-size-opts="[10, 20, 50]" size="small"
show-total show-elevator show-sizer></Page>
</Row>
</Card>
</div>
</template>
<script>
import * as API_Order from "@/api/order";
import JsonExcel from "vue-json-excel";
export default {
name: "orderList",
components: {},
components: {
"download-excel": JsonExcel,
},
data() {
return {
// 表格的表头以及内容
fields: {
订单编号: "sn",
下单时间: "createTime",
客户名称: "memberName",
客户账号: "",
收货人: "",
收货人手机号: "",
收货人地址: "",
支付方式: {
field: "clientType",
callback: (value) => {
if (value == "H5") {
return "移动端";
} else if (value == "PC") {
return "PC端";
} else if (value == "WECHAT_MP") {
return "小程序端";
} else if (value == "APP") {
return "移动应用端";
} else {
return value;
}
},
},
配送方式: "",
配送费用: "",
订单商品金额: "",
订单优惠金额: "",
订单应付金额: "",
商品SKU编号: "",
商品数量: "groupNum",
买家备注: "",
订单状态: "",
付款状态: {
field: "payStatus",
callback: (value) => {
return value == "UNPAID"
? "未付款"
: value == "PAID"
? "已付款"
: "";
},
},
发货状态: "",
发票类型: "",
发票抬头: "",
店铺: "storeName",
},
loading: true, // 表单加载状态
searchForm: {
// 搜索框初始化对象
@@ -65,42 +138,56 @@ export default {
{
title: "订单号",
key: "sn",
minWidth: 230,
minWidth: 240,
tooltip: true,
},
{
title: "下单时间",
key: "createTime",
width: 200,
},
{
title: "订单来源",
key: "clientType",
width: 95,
width: 120,
render: (h, params) => {
if (params.row.clientType == "H5") {
return h("div",{},"移动端");
}else if(params.row.clientType == "PC") {
return h("div",{},"PC端");
}else if(params.row.clientType == "WECHAT_MP") {
return h("div",{},"小程序端");
}else if(params.row.clientType == "APP") {
return h("div",{},"移动应用端");
return h("div", {}, "移动端");
} else if (params.row.clientType == "PC") {
return h("div", {}, "PC端");
} else if (params.row.clientType == "WECHAT_MP") {
return h("div", {}, "小程序端");
} else if (params.row.clientType == "APP") {
return h("div", {}, "移动应用端");
} else {
return h("div", {}, params.row.clientType);
}
else{
return h("div",{},params.row.clientType);
},
},
{
title: "订单类型",
key: "orderType",
width: 120,
render: (h, params) => {
if (params.row.orderType == "NORMAL") {
return h("div", [h("span", {}, "普通订单")]);
} else if (params.row.orderType == "PINTUAN") {
return h("div", [h("span", {}, "拼团订单")]);
} else if (params.row.orderType == "GIFT") {
return h("div", [h("span", {}, "赠品订单")]);
} else if (params.row.orderType == "VIRTUAL") {
return h("div", [h("tag", {}, "核验订单")]);
}
},
},
{
title: "买家名称",
key: "memberName",
width: 130,
minWidth: 130,
tooltip: true,
},
{
title: "订单金额",
key: "flowPrice",
minWidth: 120,
minWidth: 100,
tooltip: true,
render: (h, params) => {
return h(
"div",
@@ -112,7 +199,7 @@ export default {
{
title: "订单状态",
key: "orderStatus",
width: 95,
minWidth: 100,
render: (h, params) => {
if (params.row.orderStatus == "UNPAID") {
return h("div", [h("span", {}, "未付款")]);
@@ -131,12 +218,19 @@ export default {
}
},
},
{
title: "下单时间",
key: "createTime",
width: 170,
sortable: true,
sortType: "desc",
},
{
title: "操作",
key: "action",
align: "center",
width: 180,
width: 100,
render: (h, params) => {
return h("div", [
h(
@@ -280,4 +374,11 @@ export default {
<style lang="scss" scoped>
// 建议引入通用样式 可删除下面样式代码
@import "@/styles/table-common.scss";
.export {
margin: 10px 20px 10px 0;
}
.export-excel-wrapper {
display: inline;
}
</style>

View File

@@ -57,7 +57,7 @@
<Input type="number" v-model="form.sort" clearable style="width: 10%" />
</FormItem>
<FormItem class="form-item-view-el" label="文章内容" prop="content">
<editor v-model="form.content"></editor>
<editor openXss v-model="form.content"></editor>
</FormItem>
<FormItem label="是否展示" prop="openStatus">
<i-switch size="large" v-model="form.openStatus" :true-value="open" :false-value="close">
@@ -72,7 +72,7 @@
</div>
</Modal>
</template>
</Card>
</Col>
@@ -123,7 +123,7 @@ export default {
searchTreeValue: "", // 切换
form: {
// 添加或编辑表单对象初始化数据
openStatus:false,
openStatus: false,
title: "",
categoryId: "",
sort: 1,
@@ -380,7 +380,6 @@ export default {
//为了在是否展示一列展示开关 需要改一下数据类型,最终提交再次更改
this.data = [];
if (res.result.records.length > 0) {
this.data = res.result.records;
}
}
@@ -390,7 +389,6 @@ export default {
},
handleSubmit() {
this.$refs.form.validate((valid) => {
if (valid) {
this.submitLoading = true;
@@ -403,7 +401,6 @@ export default {
this.$Message.success("操作成功");
this.getDataList();
this.modalVisible = false;
}
});
} else {
@@ -414,8 +411,6 @@ export default {
this.$Message.success("操作成功");
this.getDataList();
this.modalVisible = false;
}
});
}
@@ -440,10 +435,25 @@ export default {
this.form.categoryId = res.result.categoryId;
this.treeValue = data.articleCategoryName;
this.form.id = data.id;
this.form.content = res.result.content;
this.form.content = htmlEscape(res.result.content);
this.form.title = res.result.title;
this.form.sort = res.result.sort;
this.form.openStatus = res.result.openStatus
this.form.openStatus = res.result.openStatus;
}
});
},
htmlEscape(text) {
return text.replace(/[<>"&]/g, function (match, pos, originalText) {
switch (match) {
case "<":
return "&lt;";
case ">":
return "&gt;";
case "&":
return "&amp;";
case '"':
return "&quot;";
}
});
},

View File

@@ -4,21 +4,10 @@
<Row>
<Form ref="searchForm" :model="searchForm" inline :label-width="70" class="search-form">
<Form-item label="活动名称" prop="couponName">
<Input
type="text"
v-model="searchForm.couponName"
placeholder="请输入活动名称"
clearable
style="width: 200px"
/>
<Input type="text" v-model="searchForm.couponName" placeholder="请输入活动名称" clearable style="width: 200px" />
</Form-item>
<Form-item label="活动状态" prop="promotionStatus">
<Select
v-model="searchForm.promotionStatus"
placeholder="请选择"
clearable
style="width: 200px"
>
<Select v-model="searchForm.promotionStatus" placeholder="请选择" clearable style="width: 200px">
<Option value="NEW">未开始</Option>
<Option value="START">已开始/上架</Option>
<Option value="END">已结束/下架</Option>
@@ -26,66 +15,27 @@
</Select>
</Form-item>
<Form-item label="活动时间">
<DatePicker
v-model="selectDate"
type="daterange"
clearable
placeholder="选择起始时间"
style="width: 200px"
></DatePicker>
<DatePicker v-model="selectDate" type="daterange" clearable placeholder="选择起始时间" style="width: 200px"></DatePicker>
</Form-item>
<Button @click="handleSearch" type="primary" icon="ios-search" class="search-btn">搜索</Button>
</Form>
</Row>
<Row class="operation padding-row">
<Button @click="add" type="primary">添加</Button>
<Button @click="add" type="primary">添加优惠券</Button>
<Button @click="delAll">批量下架</Button>
<!-- <Button @click="upAll" >批量上架</Button> -->
</Row>
<Table
:loading="loading"
border
:columns="columns"
:data="data"
ref="table"
sortable="custom"
@on-sort-change="changeSort"
@on-selection-change="changeSelect"
>
<template slot-scope="{ row }" slot="action">
<Button
v-if="row.promotionStatus === 'NEW' || row.promotionStatus === 'CLOSE'"
type="primary"
size="small"
style="margin-right: 10px"
@click="edit(row)"
>编辑
</Button
>
<Button
v-if="row.promotionStatus === 'START' || row.promotionStatus === 'NEW'"
type="error"
size="small"
style="margin-right: 10px"
@click="remove(row)"
>下架
</Button
>
<Table :loading="loading" border :columns="columns" :data="data" ref="table" sortable="custom" @on-sort-change="changeSort" @on-select-cancel="cancelSelect" @on-selection-change="changeSelect">
<template slot-scope="{ row,index }" slot="action">
<Button v-if="!checked && row.promotionStatus === 'NEW' || row.promotionStatus === 'CLOSE'" type="primary" size="small" style="margin-right: 10px" @click="edit(row)">编辑
</Button>
<Button v-if="!checked && row.promotionStatus === 'START' || row.promotionStatus === 'NEW'" type="error" size="small" style="margin-right: 10px" @click="remove(row)">下架
</Button>
</template>
</Table>
<Row type="flex" justify="end" class="page">
<Page
:current="searchForm.pageNumber + 1"
:total="total"
:page-size="searchForm.pageSize"
@on-change="changePage"
@on-page-size-change="changePageSize"
:page-size-opts="[10, 20, 50]"
size="small"
show-total
show-elevator
show-sizer
></Page>
<Page :current="searchForm.pageNumber" :total="total" :page-size="searchForm.pageSize" @on-change="changePage" @on-page-size-change="changePageSize" :page-size-opts="[10, 20, 50]" size="small"
show-total show-elevator show-sizer></Page>
</Row>
</Card>
</div>
@@ -94,13 +44,13 @@
<script>
import {
getPlatformCouponList,
deletePlatformCoupon,
updatePlatformCouponStatus,
} from "@/api/promotion";
export default {
name: "coupon",
components: {},
data() {
return {
loading: true, // 表单加载状态
@@ -109,10 +59,11 @@ export default {
modalTitle: "", // 添加或编辑标题
searchForm: {
// 搜索框初始化对象
pageNumber: 0, // 当前页数
pageNumber: 1, // 当前页数
pageSize: 10, // 页面大小
sort: "startTime", // 默认排序字段
order: "desc", // 默认排序方式
getType: "", // 默认排序方式
},
form: {
// 添加或编辑表单对象初始化数据
@@ -121,7 +72,7 @@ export default {
// 表单验证规则
formValidate: {
promotionName: [
{required: true, message: "不能为空", trigger: "blur"},
{ required: true, message: "不能为空", trigger: "blur" },
],
},
submitLoading: false, // 添加或编辑提交状态
@@ -138,15 +89,16 @@ export default {
{
title: "活动名称",
key: "promotionName",
width: 120,
minWidth: 100,
fixed: "left",
},
{
title: "优惠券名称",
key: "couponName",
width: 120,
tooltip: true
}, {
minWidth: 100,
tooltip: true,
},
{
title: "面额/折扣",
key: "price",
width: 120,
@@ -165,11 +117,14 @@ export default {
{
title: "领取数量/总数量",
key: "publishNum",
width: 150,
render: (h, params) => {
return h(
"div", params.row.receivedNum + "/" + params.row.publishNum)
"div",
params.row.receivedNum + "/" + params.row.publishNum
);
},
minWidth:130,
minWidth: 130,
},
{
title: "优惠券类型",
@@ -205,21 +160,28 @@ export default {
},
{
title: "活动时间",
render: (h, params) => {
return h("div", {
domProps:
{innerHTML: params.row.startTime + "<br/>" + params.row.endTime}
});
if (params.row.getType === "ACTIVITY") {
return h("div", "长期有效");
} else {
return h("div", {
domProps: {
innerHTML:
params.row.startTime + "<br/>" + params.row.endTime,
},
});
}
},
minWidth:150,
},
{
title: "状态",
width: 100,
key: "promotionStatus",
fixed: "right",
render: (h, params) => {
let text = "未知",
color = "";
color = "red";
if (params.row.promotionStatus == "NEW") {
text = "未开始";
color = "default";
@@ -245,20 +207,38 @@ export default {
),
]);
},
minWidth:70,
minWidth: 70,
},
{
title: "操作",
slot: "action",
align: "center",
fixed: "right",
minWidth: 140
maxWidth: 140,
},
],
data: [], // 表单数据
total: 0, // 表单数据总数
selectCoupon: [], //本级选中的优惠券
};
},
props: {
// 是否为选中模式
checked: {
type: Boolean,
default: false,
},
//优惠券类型 查询参数
getType: {
type: String,
default: "",
},
//已选择优惠券
selectedList: {
type: Array,
default: [],
},
},
watch: {
$route(to, from) {
if (to.fullPath == "/promotion/manager-coupon") {
@@ -267,23 +247,38 @@ export default {
},
},
methods: {
// 选中优惠券 父级传值
selectedList: {
handler(val) {
// 判断是否是父级回调给自己已选择优惠券
if (val.length != 0) {
this.selectCoupon = val;
}
},
deep: true,
immediate: true,
},
check() {
// this.selectCoupon.push(this.selectList)
this.$emit("selected", this.selectCoupon);
},
init() {
this.getDataList();
},
add() {
this.$router.push({name: "add-platform-coupon"});
this.$router.push({ name: "add-platform-coupon" });
},
/** 跳转至领取详情页面 */
receiveInfo(v) {
this.$router.push({name: "member-receive-coupon", query: {id: v.id}});
this.$router.push({ name: "member-receive-coupon", query: { id: v.id } });
},
info(v) {
this.$router.push({name: "platform-coupon-info", query: {id: v.id}});
this.$router.push({ name: "platform-coupon-info", query: { id: v.id } });
},
changePage(v) {
this.searchForm.pageNumber = v - 1;
this.searchForm.pageNumber = v;
this.getDataList();
this.clearSelectAll();
// this.clearSelectAll();
},
changePageSize(v) {
this.searchForm.pageSize = v;
@@ -305,7 +300,35 @@ export default {
clearSelectAll() {
this.$refs.table.selectAll(false);
},
/**
* 取消已选择的数据
*/
cancelSelect(selection, row) {
console.log(row)
let findCoupon = this.selectCoupon.find((item) => {
return item.id == row.id;
});
// 如果没有则添加
if (!findCoupon) {
this.selectCoupon.push(row);
} else {
// 有重复数据就删除
this.selectCoupon.map((item, index) => {
if (item.id == findCoupon.id) {
this.selectCoupon.splice(index, 1);
}
});
}
},
/**
* 选择优惠券
*/
changeSelect(e) {
if (this.checked && e.length != 0) {
this.selectCoupon.push(...e);
this.check();
}
this.selectList = e;
this.selectCount = e.length;
},
@@ -322,6 +345,18 @@ export default {
getPlatformCouponList(this.searchForm).then((res) => {
this.loading = false;
if (res.success) {
res.result.records.forEach((item) => {
if (this.selectCoupon.length != 0) {
this.selectCoupon.forEach((child) => {
if (item.id == child.id) {
item.___selected = true;
item._checked = true;
}
});
}
item.___selected = false;
});
this.data = res.result.records;
this.total = res.result.total;
}
@@ -363,7 +398,7 @@ export default {
});
},
edit(v) {
this.$router.push({name: "edit-platform-coupon", query: {id: v.id}});
this.$router.push({ name: "edit-platform-coupon", query: { id: v.id } });
},
remove(v) {
this.$Modal.confirm({
@@ -373,7 +408,10 @@ export default {
loading: true,
onOk: () => {
// 删除
updatePlatformCouponStatus({couponIds: v.id, promotionStatus: "CLOSE"})
updatePlatformCouponStatus({
couponIds: v.id,
promotionStatus: "CLOSE",
})
.then((res) => {
this.$Modal.remove();
if (res.success) {
@@ -449,6 +487,10 @@ export default {
},
},
mounted() {
//如果作为组件方式,传入了类型值,则搜索参数附加类型
if (this.getType) {
this.searchForm.getType = this.getType;
}
this.init();
},
};

View File

@@ -6,10 +6,10 @@
<h4>基本信息</h4>
<div class="form-item-view">
<FormItem label="活动名称" prop="promotionName">
<Input type="text" v-model="form.promotionName" placeholder="活动名称" clearable style="width: 260px" />
<Input type="text" v-model="form.promotionName" placeholder="活动名称" clearable style="width: 260px"/>
</FormItem>
<FormItem label="优惠券名称" prop="couponName">
<Input type="text" v-model="form.couponName" placeholder="优惠券名称" clearable style="width: 260px" />
<Input type="text" v-model="form.couponName" placeholder="优惠券名称" clearable style="width: 260px"/>
</FormItem>
<FormItem label="优惠券类型" prop="couponType">
<Select v-model="form.couponType" style="width: 260px">
@@ -18,11 +18,11 @@
</Select>
</FormItem>
<FormItem label="折扣" prop="couponDiscount" v-if="form.couponType == 'DISCOUNT'">
<Input type="number" v-model="form.couponDiscount" placeholder="折扣" clearable style="width: 260px" />
<Input type="number" v-model="form.couponDiscount" placeholder="折扣" clearable style="width: 260px"/>
<span class="describe">请输入0-10之间数字可以输入一位小数</span>
</FormItem>
<FormItem label="面额" prop="price" v-if="form.couponType == 'PRICE'">
<Input type="text" v-model="form.price" placeholder="面额" clearable style="width: 260px" />
<Input type="text" v-model="form.price" placeholder="面额" clearable style="width: 260px"/>
</FormItem>
<FormItem label="活动类型" prop="getType">
<Select v-model="form.getType" style="width: 260px">
@@ -33,33 +33,49 @@
<FormItem label="店铺承担比例" prop="storeCommission">
<Input v-model="form.storeCommission" placeholder="店铺承担比例" style="width: 260px">
<span slot="append">%</span>
<span slot="append">%</span>
</Input>
<span class="describe">店铺承担比例输入0-100之间数值</span>
</FormItem>
<FormItem label="发放数量" prop="publishNum">
<Input v-model="form.publishNum" placeholder="发放数量" style="width: 260px" />
<FormItem label="发放数量" prop="publishNum" v-if="form.getType==='FREE'">
<Input v-model="form.publishNum" placeholder="发放数量" style="width: 260px"/>
</FormItem>
<FormItem label="领取数量限制" prop="couponLimitNum" v-if="form.getType==='FREE'">
<Input v-model="form.couponLimitNum" placeholder="领取限制" clearable style="width: 260px"/>
</FormItem>
<FormItem label="范围描述" prop="description">
<Input v-model="form.description" type="textarea" :rows="4" maxlength="50" show-word-limit clearable
style="width: 260px"/>
</FormItem>
</div>
<h4>使用限制</h4>
<div class="form-item-view">
<FormItem label="消费门槛" prop="consumeThreshold">
<Input type="text" v-model="form.consumeThreshold" placeholder="消费门槛" clearable style="width: 260px" />
</FormItem>
<FormItem label="领取限制" prop="couponLimitNum">
<Input v-model="form.couponLimitNum" placeholder="领取限制" clearable style="width: 260px" />
<Input type="text" v-model="form.consumeThreshold" placeholder="消费门槛" clearable style="width: 260px"/>
</FormItem>
<FormItem label="有效期" prop="rangeTime">
<DatePicker
type="datetimerange"
v-model="form.rangeTime"
format="yyyy-MM-dd HH:mm:ss"
placeholder="请选择"
:options="options"
style="width: 260px"
>
</DatePicker>
<div v-if="form.getType == 'ACTIVITY'">
<RadioGroup v-model="rangeTimeType">
<Radio :label="1">
起止时间
</Radio>
<Radio :label="0">固定时间</Radio>
</RadioGroup>
</div>
<div v-if="rangeTimeType == 1">
<DatePicker type="datetimerange" v-model="form.rangeTime" format="yyyy-MM-dd HH:mm:ss" placeholder="请选择"
:options="options" style="width: 260px">
</DatePicker>
</div>
<div class="effectiveDays" v-if="rangeTimeType == 0">
领取当天开始
<InputNumber v-model="form.effectiveDays" :min="1" style="width:100px;" :max="365"/>
天内有效(1-365间的整数)
</div>
</FormItem>
<FormItem label="使用范围" prop="scopeType">
<RadioGroup type="button" button-style="solid" v-model="form.scopeType">
<Radio label="ALL">全品类</Radio>
@@ -75,20 +91,17 @@
</div>
<Table border :columns="columns" :data="form.promotionGoodsList" @on-selection-change="changeSelect">
<template slot-scope="{ row }" slot="QRCode">
<img :src="row.QRCode || '../../../assets/lili.png'" width="50px" height="50px" alt="" />
<img :src="row.QRCode || '../../../assets/lili.png'" width="50px" height="50px" alt=""/>
</template>
</Table>
</FormItem>
<FormItem v-if="form.scopeType == 'PORTION_GOODS_CATEGORY'">
<Cascader @on-change="getGoodsCategory" :data="goodsCategoryList" style="width:300px;" v-model="form.scopeIdGoods"></Cascader>
<Cascader @on-change="getGoodsCategory" :data="goodsCategoryList" style="width:300px;"
v-model="form.scopeIdGoods"></Cascader>
</FormItem>
<FormItem label="范围描述" prop="description">
<Input v-model="form.description" type="textarea" :rows="4" maxlength="50" show-word-limit clearable style="width: 260px" />
</FormItem>
<div>
<Button type="text" @click="closeCurrentPage">返回</Button>
<Button type="primary" :loading="submitLoading" @click="handleSubmit">提交</Button>
@@ -107,8 +120,8 @@ import {
getPlatformCoupon,
editPlatformCoupon,
} from "@/api/promotion";
import { getCategoryTree } from "@/api/goods";
import { regular } from "@/utils";
import {getCategoryTree} from "@/api/goods";
import {regular} from "@/utils";
import skuSelect from "@/views/lili-dialog";
export default {
@@ -116,6 +129,16 @@ export default {
components: {
skuSelect,
},
watch: {
"form.getType": {
handler(val) {
if (val == "FREE") {
this.rangeTimeType = 1;
}
},
deep: true,
},
},
data() {
const checkPrice = (rule, value, callback) => {
if (!value && value !== 0) {
@@ -140,12 +163,13 @@ export default {
}
};
return {
rangeTimeType: 1,
modalType: 0, // 是否编辑
form: {
/** 店铺承担比例 */
storeCommission: 0,
/** 发行数量 */
publishNum: 1,
publishNum: 0,
/** 运费承担者 */
scopeType: "ALL",
/** 限领数量 */
@@ -154,9 +178,11 @@ export default {
couponType: "PRICE",
/** 优惠券名称 */
couponName: "",
promotionName: "",
getType: "FREE",
promotionGoodsList: [],
scopeIdGoods: [],
rangeDayType: "",
},
id: this.$route.query.id, // 优惠券id
submitLoading: false, // 添加或编辑提交状态
@@ -169,38 +195,37 @@ export default {
value: "id",
}, // 级联选择器配置项
formRule: {
promotionName: [{ required: true, message: "活动名称不能为空" }],
couponName: [{ required: true, message: "优惠券名称不能为空" }],
couponLimitNum: [{ required: true, message: "领取限制不能为空" }],
promotionName: [{required: true, message: "活动名称不能为空"}],
couponName: [{required: true, message: "优惠券名称不能为空"}],
price: [
{ required: true, message: "请输入面额" },
{ validator: checkPrice },
{required: true, message: "请输入面额"},
{validator: checkPrice},
],
rangeTime: [{ required: true, message: "请选择优惠券有效期" }],
rangeTime: [{required: true, message: "请选择优惠券有效期"}],
consumeThreshold: [
{ required: true, message: "请输入消费门槛" },
{ validator: checkWeight },
{required: true, message: "请输入消费门槛"},
{validator: checkWeight},
],
couponDiscount: [
{ required: true, message: "请输入折扣" },
{required: true, message: "请输入折扣"},
{
pattern: regular.discount,
message: "请输入0-10的数字,可有一位小数",
},
],
storeCommission: [
{ required: true, message: "请输入店铺承担比例" },
{ pattern: regular.rate, message: "请输入0-100的正整数" },
{required: true, message: "请输入店铺承担比例"},
{pattern: regular.rate, message: "请输入0-100的正整数"},
],
publishNum: [
{ required: true, message: "请输入发放数量" },
{ pattern: regular.integer, message: "请输入正整数" },
{required: true, message: "请输入发放数量"},
{pattern: regular.integer, message: "请输入正整数"},
],
couponLimitNum: [
{ required: true, message: "请输入领取限制" },
{ pattern: regular.integer, message: "请输入正整数" },
{required: true, message: "领取限制不能为空"},
{pattern: regular.integer, message: "请输入正整数"},
],
description: [{ required: true, message: "请输入范围描述" }],
description: [{required: true, message: "请输入范围描述"}],
},
columns: [
{
@@ -277,6 +302,7 @@ export default {
if (!data.promotionGoodsList) data.promotionGoodsList = [];
if (data.scopeType == "PORTION_GOODS_CATEGORY") {
let prevCascader = data.scopeId.split(",");
// console.log(prevCascader);
function next(params, prev) {
for (let i = 0; i < params.length; i++) {
@@ -301,6 +327,7 @@ export default {
}
}
}
next(this.goodsCategoryList, []);
data.scopeIdGoods = prevCascader;
}
@@ -314,13 +341,24 @@ export default {
this.$refs.form.validate((valid) => {
if (valid) {
const params = JSON.parse(JSON.stringify(this.form));
params.startTime = this.$options.filters.unixToDate(
this.form.rangeTime[0] / 1000
);
params.endTime = this.$options.filters.unixToDate(
this.form.rangeTime[1] / 1000
);
delete params.rangeTime
// 判断当前活动类型
params.getType != "ACTIVITY" ? delete params.effectiveDays : "";
//判断当前时间类型
if (this.rangeTimeType == 1) {
params.rangeDayType = "FIXEDTIME";
params.startTime = this.$options.filters.unixToDate(
this.form.rangeTime[0] / 1000
);
params.endTime = this.$options.filters.unixToDate(
this.form.rangeTime[1] / 1000
);
delete params.effectiveDays;
} else {
params.rangeDayType = "DYNAMICTIME";
delete params.rangeTime;
}
let scopeId = [];
if (
@@ -328,7 +366,7 @@ export default {
(!params.promotionGoodsList ||
params.promotionGoodsList.length == 0)
) {
this.$Modal.warning({ title: "提示", content: "请选择指定商品" });
this.$Modal.warning({title: "提示", content: "请选择指定商品"});
return;
}
@@ -336,7 +374,7 @@ export default {
params.scopeType == "PORTION_GOODS_CATEGORY" &&
(!params.scopeIdGoods || params.scopeIdGoods.length == 0)
) {
this.$Modal.warning({ title: "提示", content: "请选择商品分类" });
this.$Modal.warning({title: "提示", content: "请选择商品分类"});
return;
}
@@ -392,12 +430,13 @@ export default {
);
this.$router.go(-1);
},
openSkuList() { // 显示商品选择器
openSkuList() {
// 显示商品选择器
this.$refs.skuSelect.open("goods");
let data = JSON.parse(JSON.stringify(this.form.promotionGoodsList))
data.forEach(e => {
e.id = e.skuId
})
let data = JSON.parse(JSON.stringify(this.form.promotionGoodsList));
data.forEach((e) => {
e.id = e.skuId;
});
this.$refs.skuSelect.goodsData = data;
},
changeSelect(e) {
@@ -434,15 +473,15 @@ export default {
// 回显已选商品
let list = [];
item.forEach((e) => {
list.push({
goodsName: e.goodsName,
price: e.price,
originalPrice: e.price,
quantity: e.quantity,
storeId: e.storeId,
storeName: e.storeName,
skuId: e.id,
});
list.push({
goodsName: e.goodsName,
price: e.price,
originalPrice: e.price,
quantity: e.quantity,
storeId: e.storeId,
storeName: e.storeName,
skuId: e.id,
});
});
this.form.promotionGoodsList = list;
},
@@ -480,7 +519,7 @@ export default {
}
});
}
return { value: item.id, label: item.name, children: item.children };
return {value: item.id, label: item.name, children: item.children};
});
},
filterCategory(list) {
@@ -522,10 +561,20 @@ h4 {
line-height: 40px;
text-align: left;
}
.describe {
font-size: 12px;
margin-left: 10px;
color: #999;
}
.effectiveDays {
font-size: 12px;
color: #999;
> * {
margin: 0 4px;
}
}
</style>

View File

@@ -0,0 +1,172 @@
<template>
<div>
<Card>
<Form ref="form" :model="form" :label-width="120">
<div class="base-info-item">
<h4>优惠券将在指定发放时间发放到用户账号中</h4>
<div class="form-item-view">
<FormItem label="活动名称" prop="promotionName">
<Input type="text" v-model="form.promotionName" placeholder="活动名称" clearable style="width: 260px" />
</FormItem>
<FormItem label="目标客户" prop="vipType">
<RadioGroup v-model="vipType">
<Radio :label="0">全平台客户</Radio>
<Radio :label="1">指定客户</Radio>
</RadioGroup>
<Button type="primary" v-if="vipType==1" icon="ios-add" @click="addVip" ghost>添加客户</Button>
</FormItem>
<FormItem label="发放时间" prop="couponDiscount">
<DatePicker type="datetime" v-model="form.rangeTime" format="yyyy-MM-dd HH:mm:ss" placeholder="请选择" :options="options" style="width: 260px">
</DatePicker>
</FormItem>
<FormItem label="选择优惠券" prop="couponType">
<Button type="primary" icon="ios-add" @click="checkCoupon=!checkCoupon" ghost>选择优惠券</Button>
<Table class="table" :columns="couponColumns" :data="couponData"></Table>
</FormItem>
</div>
<div style="margin-left:100px">
<Button type="text" @click="closeCurrentPage">返回</Button>
<Button type="primary" :loading="submitLoading" @click="handleSubmit">提交</Button>
</div>
</div>
</Form>
<Modal width="1200" v-model="checkCoupon">
<couponList checked @selected="callbackSelectCoupon" />
</Modal>
<Modal width="1200" v-model="checkUserList">
<userList @selected="callbackSelectUser" ref="memberLayout" />
</Modal>
</Card>
</div>
</template>
<script>
import { addCouponActivity } from "@/api/promotion";
import couponList from "./coupon";
import userList from "@/views/member/list/index";
// import userList from ''
export default {
components: {
couponList,
userList,
},
data() {
return {
// 选择优惠券
checkCoupon: false,
// 选择用户
checkUserList: false,
// 优惠券表格title
couponColumns: [
{
title: "优惠券名称",
key: "name",
},
{
title: "有效期",
key: "age",
},
{
title: "优惠券数量",
key: "address",
},
{
title: "操作",
key: "action",
},
],
// datpicker时间设置
options: {
disabledDate(date) {
return date && date.valueOf() < Date.now() - 86400000;
},
},
//
vipType: 0, //客户会员类型 0全平台客户 1指定客户
form: {},
formRule: {},
id: this.$route.query.id, // 优惠券id
callbackCoupon: [],
};
},
mounted() {},
methods: {
// 添加指定用户
addVip() {
this.checkUserList = true;
this.$nextTick(() => {
this.$refs.memberLayout.selectedMember = true;
});
},
// 返回已选择的用户
callbackSelectUser(val){
console.log(val)
},
// 返回已选择的优惠券
callbackSelectCoupon(val) {
if (val.___selected) {
this.callbackCoupon.forEach((item, index) => {
if (item.id == val.id) this.callbackCoupon.splice(index, 1);
});
} else {
this.callbackCoupon.push(val);
}
},
// 关闭当前页面
closeCurrentPage() {
this.$store.commit("removeTag", "add-coupon-specify");
localStorage.pageOpenedList = JSON.stringify(
this.$store.state.app.pageOpenedList
);
this.$router.go(-1);
},
async handleSubmit() {
let res = await addCouponActivity();
},
},
};
</script>
<style lang="scss" scpoed>
.table {
width: 800px;
margin: 20px 0;
}
h4 {
margin-bottom: 10px;
padding: 0 10px;
border: 1px solid #ddd;
background-color: #f8f8f8;
font-weight: bold;
color: #333;
font-size: 14px;
line-height: 40px;
text-align: left;
}
.form-item-view {
margin: 20px 0;
}
.describe {
font-size: 12px;
margin-left: 10px;
color: #999;
}
.effectiveDays {
font-size: 12px;
color: #999;
> * {
margin: 0 4px;
}
}
</style>

View File

@@ -1,30 +1,30 @@
<template>
<div class="search">
<Card>
<Table
:loading="loading"
border
:columns="columns"
:data="data"
ref="table"
sortable="custom"
@on-sort-change="changeSort"
@on-selection-change="changeSelect"
>
<template slot-scope="{ row }" slot="rangeTime">
<div>{{ row.startTime }} ~ {{ row.endTime }}</div>
</template>
<template slot-scope="{ row }" slot="action">
<Button
type="error"
ghost
size="small"
:disabled="row.memberCouponStatus != 'NEW'"
@click="remove(row)"
>作废</Button
>
</template>
</Table>
<Table
:loading="loading"
border
:columns="columns"
:data="data"
ref="table"
sortable="custom"
@on-sort-change="changeSort"
@on-selection-change="changeSelect"
>
<template slot-scope="{ row }" slot="rangeTime">
<div>{{ row.startTime }} ~ {{ row.endTime }}</div>
</template>
<template slot-scope="{ row }" slot="action">
<Button
type="error"
ghost
size="small"
:disabled="row.memberCouponStatus != 'NEW'"
@click="remove(row)"
>作废</Button
>
</template>
</Table>
<Row type="flex" justify="end" class="page">
<Page
:current="searchForm.pageNumber"

View File

@@ -0,0 +1,241 @@
<template>
<div class="search">
<Card>
<Row class="operation padding-row">
<Button @click="add" type="primary">添加活动</Button>
</Row>
<Table :loading="loading" border :columns="columns" :data="data" ref="table" sortable="custom">
<template slot-scope="{ row,index }" slot="action">
<Button type="primary"
size="small" style="margin-right: 10px" @click="info(row)">查看
</Button>
<Button v-if="!checked && row.promotionStatus === 'START' || row.promotionStatus === 'NEW'" type="error"
size="small" style="margin-right: 10px" @click="remove(row)">停止
</Button>
</template>
</Table>
<Row type="flex" justify="end" class="page">
<Page :current="searchForm.pageNumber + 1" :total="total" :page-size="searchForm.pageSize"
@on-change="changePage" @on-page-size-change="changePageSize" :page-size-opts="[10, 20, 50]"
size="small" show-total show-elevator show-sizer></Page>
</Row>
</Card>
</div>
</template>
<script>
import {
getCouponActivityList,
closeActivity,
} from "@/api/promotion";
export default {
name: "couponActivity",
components: {},
data() {
return {
loading: true, // 表单加载状态
modalType: 0, // 添加或编辑标识
modalVisible: false, // 添加或编辑显示
modalTitle: "", // 添加或编辑标题
searchForm: {
// 搜索框初始化对象
pageNumber: 0, // 当前页数
pageSize: 10, // 页面大小
sort: "startTime", // 默认排序字段
order: "desc", // 默认排序方式
},
form: {
// 添加或编辑表单对象初始化数据
promotionName: "",
},
// 表单验证规则
formValidate: {
promotionName: [
{required: true, message: "不能为空", trigger: "blur"},
],
},
submitLoading: false, // 添加或编辑提交状态
selectList: [], // 多选数据
selectCount: 0, // 多选计数
columns: [
// 表头
{
title: "活动名称",
key: "promotionName",
minWidth: 120,
},
{
title: "活动类型",
key: "couponActivityType",
minWidth: 120,
render: (h, params) => {
if (params.row.couponActivityType === 'REGISTERED') {
return h("div", ["注册赠券"]);
} else {
return h("div", ["精确发券"]);
}
},
},
{
title: "优惠券类型",
key: "activityScope",
minWidth: 120,
render: (h, params) => {
let text = "未知";
if (params.row.activityScope === "DESIGNATED") {
text = "指定会员";
} else {
text = "全部会员";
}
return h("div", [text]);
},
},
{
title: "活动时间",
minWidth: 150,
render: (h, params) => {
return h("div", {
domProps: {
innerHTML: params.row.startTime + "<br/>" + params.row.endTime,
},
});
},
},
{
title: "状态",
minWidth: 80,
key: "promotionStatus",
fixed: "right",
render: (h, params) => {
let text = "未知",
color = "red";
if (params.row.promotionStatus == "NEW") {
text = "未开始";
color = "default";
} else if (params.row.promotionStatus == "START") {
text = "已开始";
color = "green";
} else if (params.row.promotionStatus == "END") {
text = "已结束";
color = "red";
} else if (params.row.promotionStatus == "CLOSE") {
text = "已关闭";
color = "red";
}
return h("div", [
h(
"Tag",
{
props: {
color: color,
},
},
text
),
]);
},
},
{
title: "操作",
slot: "action",
align: "center",
fixed: "right",
minWidth: 100,
},
],
data: [], // 表单数据
total: 0, // 表单数据总数
};
},
props: {
// 是否为选中模式
checked: {
type: Boolean,
default: false,
},
},
methods: {
//获取数据 初始化
init() {
this.getDataList();
},
//增加券活动
add() {
this.$router.push({name: "add-coupon-activity"});
},
//查看详情
info(v) {
this.$router.push({name: "coupon-activity-info", query: {id: v.id}});
},
//跳转页面
changePage(v) {
this.searchForm.pageNumber = v - 1;
this.getDataList();
},
//修改分页
changePageSize(v) {
this.searchForm.pageSize = v;
this.getDataList();
},
//搜索活动
handleSearch() {
this.searchForm.pageNumber = 0;
this.searchForm.pageSize = 10;
this.getDataList();
},
//数据获取
getDataList() {
this.loading = true;
if (this.selectDate && this.selectDate[0] && this.selectDate[1]) {
this.searchForm.startTime = this.selectDate[0].getTime();
this.searchForm.endTime = this.selectDate[1].getTime();
} else {
this.searchForm.startTime = null;
this.searchForm.endTime = null;
}
// 带多条件搜索参数获取表单数据 请自行修改接口
getCouponActivityList(this.searchForm).then((res) => {
this.loading = false;
if (res.success) {
this.data = res.result.records;
this.total = res.result.total;
}
});
this.loading = false;
},
//跳转编辑
edit(v) {
this.$router.push({name: "edit-platform-coupon", query: {id: v.id}});
},
//下架活动
remove(v) {
this.$Modal.confirm({
title: "确认下架",
// 记得确认修改此处
content: "确认要下架此优惠券活动么?下架活动只能重新创建",
loading: true,
onOk: () => {
// 删除
closeActivity(v.id).then((res) => {
if (res.success) {
this.$Message.success("优惠券活动已作废");
this.getDataList();
}
}).catch(() => {
this.$Modal;
});
},
});
},
},
mounted() {
this.init();
},
};
</script>
<style lang="scss">
@import "@/styles/table-common.scss";
</style>

View File

@@ -0,0 +1,129 @@
<template>
<div>
<div class="content-goods-publish">
<Form ref="form" :model="form" :label-width="130">
<div class="base-info-item">
<h4>优惠券活动详情</h4>
<div class="form-item-view">
<FormItem label="活动名称">
<span>{{ couponActivity.promotionName }}</span>
</FormItem>
<FormItem label="活动类型">
<span v-if="couponActivity.couponActivityType === 'REGISTERED'" >新人发券</span>
<spin v-else>精确发券</spin>
</FormItem>
<FormItem label="活动范围" v-if="couponActivity.couponActivityType === 'SPECIFY'" >
<span v-if="couponActivity.activityScope === 'ALL'" >全部会员</span>
<spin v-else>指定会员</spin>
</FormItem>
<FormItem label="活动时间">
<span>{{ couponActivity.startTime }}{{ couponActivity.endTime }}</span>
</FormItem>
<FormItem label="活动状态">
<span v-if="couponActivity.promotionStatus==='NEW'">新建</span>
<span v-if="couponActivity.promotionStatus==='START'">已开始</span>
<span v-if="couponActivity.promotionStatus==='END'">已结束</span>
<span v-if="couponActivity.promotionStatus==='CLOSE'">已废弃</span>
</FormItem>
</div>
<h4>优惠券列表</h4>
<Table :columns="couponColumn" :data="couponData" ref="table">
</Table>
<h4 v-if="couponActivity.activityScopeInfo && memberData.length>0">会员列表列表</h4>
<Table :columns="memberColumn" :data="memberData">
</Table>
</div>
</Form>
</div>
<div class="footer">
<Button type="primary" @click="back">返回活动列表</Button>
</div>
</div>
</template>
<script>
import {getCouponActivity} from "@/api/promotion";
export default {
name: "couponActivityInfo",
data() {
return {
id: this.$route.query.id,//表单id
couponActivity: "",//券活动
couponColumn: [
{
title: "优惠券名称",
key: 'couponName'
},
{
title: "优惠券金额",
key: 'price',
render: (h, params) => {
let text = "未知";
if (params.row.couponType === "DISCOUNT") {
text = params.row.price + "折";
} else if (params.row.couponType === "PRICE") {
text = "¥" + params.row.price;
}
return h("div", [text]);
},
},
{
title: "优惠券类型",
key: 'couponType',
render: (h, params) => {
let text = "未知";
if (params.row.couponType == "DISCOUNT") {
text = "打折";
} else if (params.row.couponType == "PRICE") {
text = "减免现金";
}
return h("div", [text]);
},
},
{
title: "赠送数量",
key: "num",
}
],
couponData: [],
memberColumn: [
{
title: "会员id",
key: "id",
},
{
title: "昵称",
key: "nickName",
},
],
memberData: [],
};
},
mounted() {
this.getCouponActivity();
},
methods: {
//获取优惠券活动
getCouponActivity() {
getCouponActivity(this.id).then((res) => {
this.couponActivity = res.result;
this.couponData = this.couponActivity.couponActivityItems;
this.memberData = JSON.parse(this.couponActivity.activityScopeInfo);
});
},
back() {
this.$store.commit("removeTag", "coupon-activity");
this.$router.go(-1);
},
},
};
</script>
<style lang="scss" scoped>
@import "couponPublish.scss";
</style>

View File

@@ -0,0 +1,253 @@
/*选择商品品类*/
.content-goods-publish {
padding: 15px;
margin: 0 auto;
text-align: center;
border: 1px solid #ddd;
background: none repeat 0 0 #fff;
height: 100%;
margin-bottom: 20px;
/*商品品类*/
.goods-category {
text-align: left;
padding: 10px;
background: #fafafa;
border: 1px solid #e6e6e6;
ul {
padding: 8px 4px 8px 8px;
list-style: none;
width: 300px;
background: none repeat 0 0 #fff;
border: 1px solid #e6e6e6;
display: inline-block;
letter-spacing: normal;
margin-right: 15px;
vertical-align: top;
word-spacing: normal;
li {
line-height: 20px;
padding: 5px;
cursor: pointer;
color: #333;
font-size: 12px;
display: flex;
flex-wrap: nowrap;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
}
}
/** 当前品类被选中的样式 */
.activeClass {
background-color: #d9edf7;
border: 1px solid #bce8f1;
color: #3a87ad;
}
/*!*当前选择的商品品类文字*!*/
.current-goods-category {
text-align: left;
padding: 10px;
width: 100%;
border: 1px solid #fbeed5;
color: #c09853;
background-color: #fcf8e3;
margin: 10px auto;
padding: 8px 35px 8px 14px;
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
font-size: 12px;
font-weight: bold;
}
}
/*编辑基本信息*/
.el-form {
padding-bottom: 80px;
.el-form-item {
width: 100%;
color: gray;
text-align: left;
}
}
div.base-info-item {
h4 {
margin-bottom: 10px;
padding: 0 10px;
border: 1px solid #ddd;
background-color: #f8f8f8;
font-weight: bold;
color: #333;
font-size: 14px;
line-height: 40px;
text-align: left;
}
.form-item-view {
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: space-between;
padding-left: 80px;
.shop-category-text {
font-size: 12px;
}
}
.item-goods-properts-row {
display: flex;
flex-direction: row;
word-break: break-all;
white-space: normal;
width: 300px;
height: 100px;
}
.item-goods-properts {
display: flex;
flex-direction: row;
margin-bottom: 10px;
}
.form-item {
display: flex;
align-items: center;
}
.el-form-item {
width: 30%;
min-width: 300px;
}
.goods-name-width {
width: 50%;
min-width: 300px;
}
.el-form-item__content {
margin-left: 120px;
text-align: left;
}
p.goods-group-manager {
padding-left: 7.5%;
text-align: left;
color: #999;
font-size: 13px;
}
/*teatarea*/
/deep/ .el-textarea {
width: 150%;
}
.seo-text {
width: 150%;
}
}
/*折叠面板*/
.el-collapse-item {
/deep/ .el-collapse-item__header {
text-align: left;
background-color: #f8f8f8;
padding: 0 10px;
font-weight: bold;
color: #333;
font-size: 14px;
}
.el-form-item {
margin-left: 5%;
width: 25%;
}
/deep/ .el-form-item__content {
margin-left: 120px;
text-align: left;
}
p.goods-group-manager {
padding-left: 12%;
text-align: left;
color: #999;
}
/deep/ .el-collapse-item__content {
padding: 10px 0;
text-align: left;
}
}
/*商品描述*/
.goods-intro {
line-height: 40;
}
/** 底部步骤 */
.footer {
width: 88.7%;
padding: 10px;
background-color: #ffc;
position: fixed;
bottom: 0px;
left: 10%;
text-align: center;
z-index: 9999;
}
/*图片上传组件第一张图设置封面*/
.goods-images {
/deep/ li.el-upload-list__item:first-child {
position: relative;
}
/deep/ li.el-upload-list__item:first-child:after {
content: "";
color: #fff;
font-weight: bold;
font-size: 12px;
position: absolute;
left: -15px;
top: -6px;
width: 40px;
height: 24px;
padding-top: 6px;
background: #13ce66;
text-align: center;
-webkit-transform: rotate(-45deg);
transform: rotate(-45deg);
-webkit-box-shadow: 0 0 1pc 1px rgba(0, 0, 0, 0.2);
box-shadow: 0 0 1pc 1px rgba(0, 0, 0, 0.2);
}
}
.el-form-item__label {
word-break: break-all;
}
.step-view {
width: 33%;
height: 40px;
font-size: 19px;
text-align: center;
display: flex;
background-color: #fff;
justify-content: center;
align-items: center;
}
.page {
margin-top: 2vh;
margin-bottom: 5vh;
}

View File

@@ -0,0 +1,365 @@
<template>
<div>
<Card>
<Form ref="form" :model="form" :label-width="120" :rules="formRule">
<div class="base-info-item">
<h4>活动信息</h4>
<div class="form-item-view">
<FormItem label="活动名称" prop="promotionName">
<Input type="text" v-model="form.promotionName" placeholder="活动名称" clearable style="width: 260px"/>
</FormItem>
<FormItem label="活动时间">
<DatePicker type="datetimerange" :options="options" v-model="rangeTime" format="yyyy-MM-dd HH:mm:ss"
placeholder="请选择" style="width: 260px">
</DatePicker>
</FormItem>
<FormItem label="优惠券活动类型" prop="couponActivityType">
<RadioGroup type="button" button-style="solid" v-model="form.couponActivityType">
<Radio label="REGISTERED">新人发券</Radio>
<Radio label="SPECIFY">精确发券</Radio>
</RadioGroup>
</FormItem>
<FormItem label="活动范围" prop="activityScope" v-if="form.couponActivityType==='SPECIFY'">
<RadioGroup type="button" button-style="solid" v-model="form.activityScope">
<Radio label="ALL">全部会员</Radio>
<Radio label="DESIGNATED">指定会员</Radio>
</RadioGroup>
</FormItem>
<FormItem label="选择会员" prop="scopeType"
v-if="form.couponActivityType==='SPECIFY' && form.activityScope==='DESIGNATED'">
<Button type="primary" icon="ios-add" @click="addVip" ghost>选择会员</Button>
<div style="margin-top:24px;" v-if="form.activityScope == 'DESIGNATED'">
<Table border :columns="userColumns" :data="this.selectedMember">
</Table>
</div>
</FormItem>
</div>
<h4>配置优惠券</h4>
<div class="form-item-view">
<FormItem label="选择优惠券" prop="scopeType">
<Button type="primary" :loading="submitLoading" @click="showSelector">选择优惠券</Button>
</FormItem>
<FormItem label="赠送配置" prop="scopeType">
<Table border :columns="columns" :data="this.selectCouponList">
<template slot="sendNum" slot-scope="scope">
<Input type="text" v-model="form.couponActivityItems[scope.index].num" placeholder="赠送数量"/>
<Input type="text" v-model="form.couponActivityItems[scope.index].couponId" v-show="false"/>
</template>
</Table>
</FormItem>
<div>
<Button type="text" @click="closeCurrentPage">返回</Button>
<Button type="primary" :loading="submitLoading" @click="handleSubmit">提交</Button>
</div>
</div>
</div>
</Form>
</Card>
<Modal @on-ok="()=>{this.showCouponSelect = false}" @on-cancel="()=>{this.showCouponSelect = false}"
v-model="showCouponSelect" width="80%">
<couponTemplate :checked="true" :selectedList="selectCouponList" getType="ACTIVITY" @selected="selectedCoupon"/>
</Modal>
<Modal width="1200" v-model="checkUserList">
<userList v-if="checkUserList" @callback="callbackSelectUser" :selectedList="selectedMember" ref="memberLayout"/>
</Modal>
</div>
</template>
<script>
import couponTemplate from "@/views/promotion/coupon/coupon";
import userList from "@/views/member/list/index";
import {saveActivityCoupon, updateCouponActivity} from "@/api/promotion";
export default {
name: "addCouponActivity",
components: {
couponTemplate,
userList,
},
data() {
return {
options: {
disabledDate(date) {
return date && date.valueOf() < Date.now() - 86400000;
},
},
showCouponSelect: false, //显示优惠券选择框
rangeTime: "", //时间区间
checkUserList: false, //会员选择器
selectedMember: [], //选择的会员
form: {
promotionName: "", //活动名称
activityScope: "ALL", //活动范围 ,默认全体发券
couponActivityType: "REGISTERED", //触发活动方式 默认新人赠券
startTime: "", //开始时间
endTime: "", //结束时间
memberDTOS: [], //指定会员范围
couponActivityItems: [],//优惠券列表
},
submitLoading: false, // 添加或编辑提交状态
selectCouponList: [], //选择的优惠券列表
formRule: {
promotionName: [{required: true, message: "活动名称不能为空"}],
rangeTime: [{required: true, message: "请选择活动有效期"}],
description: [{required: true, message: "请输入范围描述"}],
},
// 用户表格
userColumns: [
{
title: "用户名称",
key: "nickName",
minWidth: 120,
},
{
title: "手机号",
key: "mobile",
render: (h, params) => {
return h("div", params.row.mobile || "暂未填写");
},
},
{
title: "最后登录时间",
key: "lastLoginDate",
},
{
title: "操作",
key: "action",
minWidth: 50,
align: "center",
render: (h, params) => {
return h(
"Button",
{
props: {
size: "small",
type: "error",
ghost: true,
},
on: {
click: () => {
this.delUser(params.index);
},
},
},
"删除"
);
},
},
],
//优惠券表格
columns: [
{
title: "优惠券名称",
key: "couponName",
minWidth: 120,
},
{
title: "品类描述",
key: "scopeType",
width: 100,
render: (h, params) => {
let text = "未知";
if (params.row.scopeType == "ALL") {
text = "全品类";
} else if (params.row.scopeType == "PORTION_GOODS_CATEGORY") {
text = "商品分类";
} else if (params.row.scopeType == "PORTION_SHOP_CATEGORY") {
text = "店铺分类";
} else if (params.row.scopeType == "PORTION_GOODS") {
text = "指定商品";
}
return h("div", [text]);
},
},
{
title: "面额/折扣",
key: "couponName",
minWidth: 120,
render: (h, params) => {
if (params.row.price) {
return h(
"div",
this.$options.filters.unitPrice(params.row.price, "")
);
} else {
return h("div", params.row.couponDiscount + "");
}
},
},
{
title: "赠送数量",
type: "template",
slot: "sendNum",
minWidth: 120,
},
{
title: "操作",
key: "action",
minWidth: 50,
align: "center",
render: (h, params) => {
return h(
"Button",
{
props: {
size: "small",
type: "error",
ghost: true,
},
on: {
click: () => {
this.delCoupon(params.index);
},
},
},
"删除"
);
},
},
],
};
},
methods: {
// 返回已选择的用户
callbackSelectUser(val) {
// 每次将返回的数据回调判断
let findUser = this.selectedMember.find((item) => {
return item.id === val.id;
});
// 如果没有则添加
if (!findUser) {
this.selectedMember.push(val);
} else {
// 有重复数据就删除
this.selectedMember.map((item, index) => {
if (item.id === findUser.id) {
this.selectedMember.splice(index, 1);
}
});
}
this.reSelectMember();
},
// 删除选择的会员
delUser(index) {
this.selectedMember.splice(index, 1);
this.reSelectMember();
},
//更新选择的会员
reSelectMember() {
this.form.memberDTOS = this.selectedMember.map((item) => {
return {
nickName: item.nickName,
id: item.id
}
});
},
/**
* 返回优惠券*/
selectedCoupon(val) {
this.selectCouponList = val;
this.reSelectCoupon();
},
// 删除选择的优惠券
delCoupon(index) {
this.selectCouponList.splice(index, 1);
this.reSelectCoupon();
},
reSelectCoupon() {
//清空原有数据
this.form.couponActivityItems = this.selectCouponList.map((item) => {
return {
num: 0,
couponId: item.id,
}
});
console.log(this.form.couponActivityItems)
},
// 添加指定用户
addVip() {
this.checkUserList = true;
this.$nextTick(() => {
this.$refs.memberLayout.selectedMember = true;
});
},
//显示优惠券选择框
showSelector() {
this.showCouponSelect = true;
},
/** 保存平台优惠券 */
handleSubmit() {
this.form.startTime = this.$options.filters.unixToDate(
this.rangeTime[0] / 1000
);
this.form.endTime = this.$options.filters.unixToDate(
this.rangeTime[1] / 1000
);
this.$refs.form.validate((valid) => {
if (valid) {
const params = JSON.parse(JSON.stringify(this.form));
console.log(params);
this.submitLoading = true;
// 添加 避免编辑后传入id等数据 记得删除
delete params.id;
saveActivityCoupon(params).then((res) => {
this.submitLoading = false;
if (res.success) {
this.$Message.success("优惠券活动创建成功");
this.closeCurrentPage();
}
});
}
});
},
// 关闭当前页面
closeCurrentPage() {
this.$store.commit("removeTag", "add-platform-coupon");
localStorage.pageOpenedList = JSON.stringify(
this.$store.state.app.pageOpenedList
);
this.$router.go(-1);
},
},
};
</script>
<style lang="scss" scpoed>
h4 {
margin-bottom: 10px;
padding: 0 10px;
border: 1px solid #ddd;
background-color: #f8f8f8;
font-weight: bold;
color: #333;
font-size: 14px;
line-height: 40px;
text-align: left;
}
.describe {
font-size: 12px;
margin-left: 10px;
color: #999;
}
.effectiveDays {
font-size: 12px;
color: #999;
> * {
margin: 0 4px;
}
}
</style>

View File

@@ -0,0 +1,249 @@
<template>
<div>
<Card>
<Tabs v-model="searchForm.status">
<!-- 标签栏 -->
<TabPane v-for="(item,index) in tabs" :key="index" :name="item.status" :label="item.title">
</TabPane>
</Tabs>
<Table :columns="liveColumns" :data="liveData"></Table>
<Row type="flex" style="margin:20px;" justify="end" class="page">
<Page :current="searchForm.pageNumber" :total="total" :page-size="searchForm.pageSize" @on-change="changePageNumber" @on-page-size-change="changePageSize" :page-size-opts="[10, 20, 50]"
size="small" show-total show-elevator show-sizer></Page>
</Row>
</Card>
</div>
</template>
<script>
import { getLiveList, whetherStar } from "@/api/promotion.js";
export default {
data() {
return {
// 查询数据的总数
total: "",
// 查询的form
searchForm: {
pageSize: 10,
pageNumber: 1,
status: "NEW",
},
// 直播tab选项栏
tabs: [
{
title: "直播中",
status: "START",
},
{
title: "未开始",
status: "NEW",
},
{
title: "已结束",
status: "END",
},
],
liveColumns: [
{
title: "直播标题",
key: "name",
},
{
title: "主播昵称",
key: "anchorName",
},
{
title: "直播开始时间",
key: "createTime",
render: (h, params) => {
return h(
"span",
this.$options.filters.unixToDate(params.row.startTime)
);
},
},
{
title: "直播结束时间",
key: "endTime",
render: (h, params) => {
return h(
"span",
this.$options.filters.unixToDate(params.row.endTime)
);
},
},
{
title: "是否推荐",
align: "center",
render: (h, params) => {
return h("div", [
h(
"i-switch",
{
// 数据库0 enabled,1 disabled
props: {
type: "primary",
size: "large",
value: params.row.recommend == true,
},
on: {
"on-change": () => {
this.star(params.row, params.index);
},
},
},
[
h("span", {
slot: "open",
domProps: {
innerHTML: "是",
},
}),
h("span", {
slot: "close",
domProps: {
innerHTML: "否",
},
}),
]
),
]);
},
},
{
title: "直播状态",
render: (h, params) => {
return h(
"span",
params.row.status == "NEW"
? "未开始"
: params.row.status == "START"
? "直播中"
: "已结束"
);
},
},
{
title: "操作",
key: "action",
render: (h, params) => {
return h(
"div",
{
style: {
display: "flex",
},
},
[
h(
"Button",
{
props: {
type: "error",
size: "small",
},
style: {
marginRight: "5px",
},
on: {
click: () => {
this.getLiveDetail(params.row);
},
},
},
"查看"
),
]
);
},
},
], //table中显示的title
liveData: [], //table中显示的直播数据
};
},
watch: {
"searchForm.status": {
handler() {
this.liveData = [];
this.getStoreLives();
},
deep: true,
},
},
mounted() {
this.getStoreLives();
},
methods: {
/**
* 是否推荐
*/
async star(val, index) {
let switched;
if (this.liveData[index].recommend) {
this.$set(this.liveData[index], "recommend", false);
switched = false;
} else {
this.$set(this.liveData[index], "recommend", true);
switched = true;
}
await whetherStar({ id: val.id, recommend: switched });
this.getStoreLives();
},
/**
* 页面数据大小分页回调
*/
changePageSize(val) {
this.searchForm.pageSize = val;
this.getStoreLives();
},
/**
* 分页回调
*/
changePageNumber(val) {
this.searchForm.pageNumber = val;
this.getStoreLives();
},
/**
* 获取店铺直播间列表
*/
async getStoreLives() {
let result = await getLiveList(this.searchForm);
if (result.success) {
this.liveData = result.result.records;
this.total = result.result.total;
}
},
/**
* 获取直播间详情
*/
getLiveDetail(val) {
this.$router.push({
path: "/liveDetail",
query: { ...val, liveStatus: this.searchForm.status },
});
},
},
};
</script>
<style lang="scss" scoped>
@import "@/styles/table-common.scss";
.btns {
margin-bottom: 10px;
margin-top: 10px;
}
.page {
margin-top: 20px;
}
</style>

View File

@@ -0,0 +1,300 @@
<template>
<div>
<Card>
<Form :model="liveForm" ref="liveForm" :rules="liveRulesForm" :label-width="120">
<FormItem label="直播标题" prop="name">
<Input disabled v-model="liveForm.name" style="width:460px"></Input>
<div class="tips">直播间名字最短3个汉字最长17个汉字1个汉字相当于2个字符</div>
</FormItem>
<FormItem label="主播昵称" prop="anchorName">
<Input disabled v-model="liveForm.anchorName" style="width:360px"></Input>
<div class="tips">主播昵称最短2个汉字最长15个汉字1个汉字相当于2个字符</div>
</FormItem>
<FormItem label="直播时间" prop="startTime">
<DatePicker disabled format="yyyy-MM-dd HH:mm" type="datetimerange" v-model="times" @on-change="handleChangeTime" :options="optionsTime" placeholder="直播计划开始时间-直播计划结束时间" style="width: 300px">
</DatePicker>
<div class="tips">直播开播时间需要在当前时间的10分钟后 并且 开始时间不能在 6 个月后</div>
</FormItem>
<FormItem label="主播微信号" prop="anchorWechat">
<Input disabled v-model="liveForm.anchorWechat" style="width:360px" placeholder="主播微信号"></Input>
<div class="tips">主播微信号如果未实名认证需要先前往小程序直播小程序进行<a target="_black" href="https://res.wx.qq.com/op_res/9rSix1dhHfK4rR049JL0PHJ7TpOvkuZ3mE0z7Ou_Etvjf-w1J_jVX0rZqeStLfwh">实名验证</a></div>
</FormItem>
<!-- 分享卡片 -->
<FormItem label="分享卡片封面" prop="feedsImg">
<div class="upload-list" v-if="liveForm.feedsImg">
<template>
<img :src="liveForm.feedsImg">
<div class="upload-list-cover">
<Icon type="ios-eye-outline" @click.native="handleView(liveForm.feedsImg)"></Icon>
</div>
</template>
</div>
<Upload v-if="liveForm.feedsImg.length ==0" ref="upload" :show-upload-list="false" :on-success="handleFeedsImgSuccess" :default-file-list="defaultImgList" :format="['jpg','jpeg','png']"
:on-format-error="handleFormatError" :max-size="1024" :on-exceeded-size="handleMaxSize" type="drag" :action="action" :headers="accessToken" style="display: inline-block;width:58px;">
<div style="width: 58px;height:58px;line-height: 58px;">
<Icon type="ios-camera" size="20"></Icon>
</div>
</Upload>
<div class="tips">
直播间分享图图片规则建议像素800*640大小不超过1M
</div>
</FormItem>
<!-- 直播间背景墙 -->
<FormItem label="直播间背景墙" prop="coverImg">
<div class="upload-list" v-if="liveForm.coverImg">
<template>
<img :src="liveForm.coverImg">
<div class="upload-list-cover">
<Icon type="ios-eye-outline" @click.native="handleView(liveForm.coverImg)"></Icon>
</div>
</template>
</div>
<Upload v-if="liveForm.coverImg.length ==0" ref="upload" :show-upload-list="false" :on-success="handleCoverImgSuccess" :default-file-list="defaultImgList" :format="['jpg','jpeg','png']"
:on-format-error="handleFormatError" :max-size="2048" :on-exceeded-size="handleMaxSize" type="drag" :action="action" :headers="accessToken" style="display: inline-block;width:58px;">
<div style="width: 58px;height:58px;line-height: 58px;">
<Icon type="ios-camera" size="20"></Icon>
</div>
</Upload>
<div class="tips"> 直播间背景图图片规则建议像素1080*1920大小不超过2M</div>
</FormItem>
<!-- 直播间背景墙 -->
<FormItem label="直播间分享图" prop="shareImg">
<div class="upload-list" v-if="liveForm.shareImg">
<template>
<img :src="liveForm.shareImg">
<div class="upload-list-cover">
<Icon type="ios-eye-outline" @click.native="handleView(liveForm.shareImg)"></Icon>
</div>
</template>
</div>
<Upload v-if="liveForm.shareImg.length ==0" ref="upload" :show-upload-list="false" :on-success="handleShareImgSuccess" :default-file-list="defaultImgList" :format="['jpg','jpeg','png']"
:on-format-error="handleFormatError" :max-size="2048" :on-exceeded-size="handleMaxSize" type="drag" :action="action" :headers="accessToken" style="display: inline-block;width:58px;">
<div style="width: 58px;height:58px;line-height: 58px;">
<Icon type="ios-camera" size="20"></Icon>
</div>
</Upload>
<div class="tips"> 直播间分享图图片规则建议像素800*640大小不超过1M</div>
</FormItem>
<FormItem label="商品" v-if="$route.query.id">
<Table class="goods-table" :columns="liveColumns" :data="liveData">
<template slot-scope="{ row,index }" slot="goodsName">
<div class="flex-goods">
<Badge v-if="index == 0 || index ==1" color="volcano"></Badge>
<img class="thumbnail" :src="row.thumbnail || row.goodsImage">
{{ row.goodsName || row.name }}
</div>
</template>
<template slot-scope="{ row }" class="price" slot="price">
<div>
<div v-if="row.priceType == 1">{{row.price | unitPrice('')}}</div>
<div v-if="row.priceType == 2">{{row.price | unitPrice('')}}{{row.price2 | unitPrice('')}}</div>
<div v-if="row.priceType == 3">{{row.price | unitPrice('¥')}}<span class="original-price">{{row.price2 | unitPrice('')}}</span></div>
</div>
</template>
<template slot-scope="{ row }" slot="quantity">
<div>{{row.quantity}}</div>
</template>
</Table>
<div class="tips">
直播间商品中前两个商品将自动被选为封面伴随直播间在直播列表中显示
</div>
</FormItem>
<FormItem>
<Button type="primary" @click="createLives()">保存</Button>
</FormItem>
</Form>
</Card>
<!-- 浏览图片 -->
<Modal title="查看图片" v-model="imageVisible">
<img :src="imageSrc" v-if="imageVisible" style="width: 100%">
</Modal>
</div>
</template>
<script>
import { getLiveInfo } from "@/api/promotion";
export default {
data() {
return {
imageVisible: false, //查看图片的dailog
imageSrc: "", //查看图片的路径
liveForm: {
name: "", //直播标题
anchorName: "", //主播昵称
anchorWechat: "", //主播微信号
feedsImg: "", //分享卡片封面
coverImg: "", //直播间背景墙
shareImg: "", //分享图
startTime: "",
},
times: [], //接收直播时间数据
// 直播商品表格表头
liveColumns: [
{
title: "商品",
slot: "goodsName",
},
{
title: "价格",
slot: "price",
},
{
title: "库存",
slot: "quantity",
width: 100,
},
{
title: "操作",
slot: "action",
width: 250,
},
],
liveData: [], //直播商品集合
commodityList: "", //商品集合
};
},
mounted() {
/**
* 如果query.id有值说明是查看详情
* liveStatus 可以判断当前直播状态 从而区分数据 是否是未开始、已开启、已关闭、
*/
if (this.$route.query.id) {
// 获取直播间详情
this.getLiveDetail();
}
this.accessToken = {
accessToken: this.getStore("accessToken"),
};
},
methods: {
/**
* 上传图片查看图片
*/
handleView(src) {
this.imageVisible = true;
this.imageSrc = src;
},
/**
* 获取直播间详情
*/
async getLiveDetail() {
let result = await getLiveInfo(this.$route.query.id);
// 将数据回调到liveform里面
if (result.success) {
let data = result.result;
for (let key in data) {
this.liveForm[key] = data[key];
}
// 将选择的商品回调给表格
this.liveData = data.commodityList;
this.commodityList = data.commodityList;
// 将时间格式化
this.$set(
this.times,
[0],
this.$options.filters.unixToDate(data.startTime, "yyyy-MM-dd hh:mm")
);
this.$set(
this.times,
[1],
this.$options.filters.unixToDate(data.endTime, "yyyy-MM-dd hh:mm")
);
this.liveStatus = data.status;
}
},
},
};
</script>
<style lang="scss" scoped>
.action {
display: flex;
/deep/ .ivu-btn {
margin: 0 5px !important;
}
}
.original-price {
margin-left: 10px;
color: #999;
text-decoration: line-through;
}
.thumbnail {
width: 50px;
height: 50px;
border-radius: 0.4em;
}
.flex-goods {
margin: 10px;
display: flex;
align-items: center;
> img {
margin-right: 10px;
}
}
.tips {
color: #999;
font-size: 12px;
}
.goods-table {
width: 1000px;
margin: 10px 0;
}
.upload-list {
display: inline-block;
width: 60px;
height: 60px;
text-align: center;
line-height: 60px;
border: 1px solid transparent;
border-radius: 4px;
overflow: hidden;
background: #fff;
position: relative;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
margin-right: 4px;
}
.upload-list img {
width: 100%;
height: 100%;
}
.upload-list-cover {
display: none;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background: rgba(0, 0, 0, 0.6);
}
.upload-list:hover .upload-list-cover {
display: block;
}
.upload-list-cover i {
color: #fff;
font-size: 20px;
cursor: pointer;
margin: 0 2px;
}
</style>

View File

@@ -2,29 +2,12 @@
<div class="seckill">
<Card>
<Row>
<Form
ref="searchForm"
:model="searchForm"
inline
:label-width="70"
class="search-form"
>
<Form ref="searchForm" :model="searchForm" inline :label-width="70" class="search-form">
<Form-item label="活动名称" prop="promotionName">
<Input
type="text"
v-model="searchForm.promotionName"
placeholder="请输入活动名称"
clearable
style="width: 200px"
/>
<Input type="text" v-model="searchForm.promotionName" placeholder="请输入活动名称" clearable style="width: 200px" />
</Form-item>
<Form-item label="活动状态" prop="promotionStatus">
<Select
v-model="searchForm.promotionStatus"
placeholder="请选择"
clearable
style="width: 200px"
>
<Select v-model="searchForm.promotionStatus" placeholder="请选择" clearable style="width: 200px">
<Option value="NEW">未开始</Option>
<Option value="START">已开始/上架</Option>
<Option value="END">已结束/下架</Option>
@@ -32,22 +15,10 @@
</Select>
</Form-item>
<Form-item label="活动时间">
<DatePicker
v-model="selectDate"
type="daterange"
clearable
placeholder="选择起始时间"
style="width: 200px"
></DatePicker>
<DatePicker v-model="selectDate" type="daterange" clearable placeholder="选择起始时间" style="width: 200px"></DatePicker>
</Form-item>
<Button
@click="handleSearch"
type="primary"
icon="ios-search"
class="search-btn"
>搜索</Button
>
<Button @click="handleSearch" type="primary" icon="ios-search" class="search-btn">搜索</Button>
</Form>
</Row>
<Row class="operation padding-row">
@@ -131,19 +102,25 @@
<script>
import { getSeckillList, delSeckill, closeSeckill } from "@/api/promotion";
import setupSeckill from "@/views/promotion/seckill/setupSeckill";
export default {
name: "seckill",
components: {
setupSeckill,
},
data() {
return {
loading: true, // 表单加载状态
searchForm: {
// 搜索框初始化对象
pageNumber: 0, // 当前页数
pageNumber: 1, // 当前页数
pageSize: 10, // 页面大小
sort: "startTime",
order: "desc", // 默认排序方式
},
columns: [ // 表单
setupFlag: false, //默认不请求设置
columns: [
// 表单
{
title: "活动名称",
key: "promotionName",
@@ -225,14 +202,27 @@ export default {
};
},
methods: {
clickTabPane(name) {
if (name == "setup") {
this.setupFlag = true;
} else {
this.setupFlag = false;
}
},
// 初始化信息
init() {
this.getDataList();
},
// 点击分页
changePage(v) {
this.searchForm.pageNumber = v - 1;
this.searchForm.pageNumber = v;
this.getDataList();
this.clearSelectAll();
},
// 设置每页大小
changePageSize(v) {
this.searchForm.pageSize = v;
this.getDataList();
@@ -285,6 +275,7 @@ export default {
},
});
},
// 获取数据集合
getDataList() {
this.loading = true;
if (this.selectDate && this.selectDate[0] && this.selectDate[1]) {

View File

@@ -0,0 +1,151 @@
<template>
<div>
<Form :model="form" :label-width="120">
<FormItem label="每日场次设置">
<Row :gutter="16" class="row">
<Col class="time-item" @click.native="handleClickTime(item,index)" v-for="(item,index) in this.times" :key="index" span="3">
<div class="time" :class="{'active':item.check}">{{item.time}}:00</div>
</Col>
</Row>
</FormItem>
<FormItem label="秒杀规则">
<Input type="textarea" :autosize="{minRows: 4,}" v-model="form.seckillRule" placeholder="申请规则" clearable style="width: 360px; margin-left:10px" />
</FormItem>
<FormItem>
<div class="foot-btn">
<Button @click="closeCurrentPage" style="margin-right: 5px">返回</Button>
<Button type="primary" :loading="submitLoading" @click="handleSubmit">提交</Button>
</div>
</FormItem>
</Form>
<!-- 选择时间 -->
</div>
</template>
<script>
import { getSetting, setSetting } from "@/api/index";
export default {
data() {
return {
submitLoading: false,
selectedTime: [],
times: [], //时间集合 1-24点
form: {
seckillRule: "",
},
};
},
mounted() {
/**
* 初始化
*/
this.init();
},
methods: {
/**
* 关闭当前页面
*/
closeCurrentPage() {
this.$store.commit("removeTag", "manager-seckill-add");
localStorage.pageOpenedList = JSON.stringify(
this.$store.state.app.pageOpenedList
);
this.$router.go(-1);
},
/**
* 提交秒杀信息
*/
async handleSubmit() {
let hours = this.times
.filter((item) => {
return item.check;
})
.map((item) => {
return item.time;
})
.join(",");
let result = await setSetting("SECKILL_SETTING", {
seckillRule: this.form.seckillRule,
hours,
});
if (result.success) {
this.$Message.success("设置成功!");
this.init();
}
},
/**
* 初始化当前信息
*/
async init() {
let result = await getSetting("SECKILL_SETTING");
if (result.success) {
this.form.seckillRule = result.result.seckillRule;
this.times=[]
for (let i = 0; i < 24; i++) {
// 将数据拆出
if (result.result.hours) {
let way = result.result.hours.split(",");
way.forEach((hours) => {
if (hours == i) {
this.times.push({
time: i,
check: true,
});
}
});
if (!this.times[i]) {
this.times.push({
time: i,
check: false,
});
}
}
}
}
},
/**
* 选中时间
*/
handleClickTime(val, index) {
val.check = !val.check;
},
},
};
</script>
<style scoped lang="scss">
.row {
width: 50%;
}
.foot-btn {
margin-left: 10px;
}
.time-list {
display: flex;
flex-wrap: wrap;
}
.active {
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.12), 0 0 6px rgba(0, 0, 0, 0.04);
color: #fff;
background: $theme_color !important;
}
.time {
width: 100%;
cursor: pointer;
transition: 0.35s;
border-radius: 0.8em;
justify-content: center;
align-items: center;
display: flex;
background: #f3f5f7;
height: 100%;
}
.time-item {
height: 50px;
margin: 8px 0;
font-size: 15px;
}
</style>

View File

@@ -224,7 +224,6 @@ import memberLayout from "@/views/member/list/index";
import ossManage from "@/views/sys/oss-manage/ossManage";
import { getCategoryTree } from "@/api/goods";
import { shopDetail, shopAdd, shopEdit, getShopByMemberId } from "@/api/shops";
import * as filters from "@/utils/filters";
import uploadPicInput from "@/views/my-components/lili/upload-pic-input";
import region from "@/views/lili-components/region";
import liliMap from "@/views/my-components/map/index";

View File

@@ -66,7 +66,8 @@ export default {
uvs: 0, // 访客数
pvs: 0, // 浏览量
dateList: [ // 选择项
dateList: [
// 选择项
{
title: "今天",
selected: false,
@@ -90,7 +91,8 @@ export default {
],
orderChart: "", // 初始化图表
params: { // 请求参数
params: {
// 请求参数
searchType: "LAST_SEVEN",
year: "",
month: "",
@@ -117,6 +119,8 @@ export default {
watch: {
params: {
handler(val) {
this.uvs = 0;
this.pvs = 0;
this.init();
},
deep: true,

View File

@@ -347,6 +347,7 @@ export default {
this.form.versionUpdateDate / 1000
);
this.form.versionUpdateDate = versionUpdateDate;
this.form.updateTime = versionUpdateDate;
if (this.modalType == 0) {
// 添加 避免编辑后传入id等数据 记得删除

View File

@@ -70,7 +70,7 @@
size="16"
style="margin-right: 5px"
></Icon>
<span>菜单</span>
<span>菜单</span>
</div>
<div v-show="form.level == 1 || form.level == 2">
<Icon
@@ -168,7 +168,7 @@
size="16"
style="margin-right: 5px"
></Icon>
<span>菜单</span>
<span>菜单</span>
</div>
<div v-show="formAdd.level != 0">
<Icon
@@ -271,13 +271,11 @@ export default {
path: "",
frontRoute: "",
parentId: "",
buttonType: "",
sortOrder: 0,
level: 0,
showAlways: true,
},
formAdd: { // 添加表单
buttonType: "",
},
formValidate: { // 验证规则
title: [{required: true, message: "名称不能为空", trigger: "blur"}],
@@ -542,7 +540,7 @@ export default {
return;
}
this.parentTitle = this.form.title;
this.modalTitle = "添加子节点(可拖动)";
this.modalTitle = "添加子节点";
this.showParent = true;
if (this.form.level == 2) {
this.$Modal.warning({
@@ -557,7 +555,6 @@ export default {
parentId: this.form.id,
level: Number(this.form.level) + 1,
sortOrder: 0,
buttonType: "",
status: 0,
showAlways: true,
};
@@ -568,7 +565,7 @@ export default {
this.menuModalVisible = true;
},
addRootMenu() {
this.modalTitle = "添加顶菜单(可拖动)";
this.modalTitle = "添加顶菜单";
this.showParent = false;
this.formAdd = {
level: 0,

View File

@@ -35,16 +35,18 @@
<Row class="operation" style="margin-top: 20px">
<Button @click="sendMessage" type="primary">发送消息</Button>
</Row>
<Table
:loading="loading"
border
:columns="messageColumns"
:data="messageData"
ref="table"
sortable="custom"
@on-sort-change="messageChangeSort"
@on-selection-change="messageChangeSelect"
></Table>
<Row>
<Table
:loading="loading"
border
:columns="messageColumns"
:data="messageData"
ref="table"
sortable="custom"
@on-sort-change="messageChangeSort"
@on-selection-change="messageChangeSelect"
></Table>
</Row>
<Row type="flex" justify="end" class="page">
<Page
:current="searchMessageForm.pageNumber"
@@ -62,16 +64,18 @@
</TabPane>
<TabPane label="通知类站内信" name="SETTING">
<Table
:loading="loading"
border
:columns="noticeColumns"
:data="noticeData"
ref="table"
sortable="custom"
@on-sort-change="changeSort"
@on-selection-change="changeSelect"
></Table>
<Row>
<Table
:loading="loading"
border
:columns="noticeColumns"
:data="noticeData"
ref="table"
sortable="custom"
@on-sort-change="changeSort"
@on-selection-change="changeSelect"
></Table>
</Row>
<Row type="flex" justify="end" class="page">
<Page
:current="searchForm.pageNumber"
@@ -106,21 +110,22 @@
</div>
<div class="send-setting">
<div class="left-show">
<div v-for="(item, index) in form.variables" >
#{<span>{{item}}</span>}
</div>
<div v-for="(item, index) in form.variables">
#{<span>{{item}}</span>}
</div>
</div>
<div class="send-form">
<Form ref="form" :model="form" :label-width="100" :rules="formValidate">
<FormItem label="通知节点" prop="noticeNode">
<Input v-model="form.noticeNode" clearable type="text" style="width: 90%" maxlength="20" disabled />
<Input v-model="form.noticeNode" clearable type="text" style="width: 90%" maxlength="20" disabled/>
</FormItem>
<FormItem label="消息标题" prop="noticeTitle">
<Input v-model="form.noticeTitle" clearable type="text" style="width: 90%" maxlength="20"/>
</FormItem>
<FormItem label="消息内容" prop="noticeContent">
<Input v-model="form.noticeContent" clearable type="textarea" style="width: 90%" maxlength="50" :autosize="{maxRows:4,minRows: 4}" show-word-limit />
<Input v-model="form.noticeContent" clearable type="textarea" style="width: 90%" maxlength="50"
:autosize="{maxRows:4,minRows: 4}" show-word-limit/>
</FormItem>
</Form>
</div>
@@ -137,24 +142,34 @@
:title="messageModalTitle"
v-model="messageModalVisible"
:mask-closable="false"
:width="500"
:width="800"
>
<Form ref="messageSendForm" :model="messageSendForm" :label-width="100" :rules="messageFormValidate">
<FormItem label="消息标题" prop="title">
<Input v-model="messageSendForm.title" maxlength="15" clearable style="width: 90%"/>
<Input v-model="messageSendForm.title" maxlength="15" clearable style="width: 70%"/>
</FormItem>
<FormItem label="消息内容" prop="content">
<Input
v-model="messageSendForm.content"
:rows="4"
type="textarea"
style="max-height:60vh;overflow:auto;width: 90%"
style="max-height:60vh;overflow:auto;width: 70%"
/>
</FormItem>
<FormItem label="发送对象">
<RadioGroup type="button" button-style="solid" v-model="messageSendForm.messageClient"
@on-change="selectObject">
<Radio label="member">会员</Radio>
<Radio label="store">商家</Radio>
</RadioGroup>
</FormItem>
<FormItem label="发送范围">
<RadioGroup type="button" button-style="solid" v-model="messageSendForm.messageRange" @on-change="selectShop">
<Radio label="ALL">全站</Radio>
<Radio label="APPOINT">指定商家</Radio>
<Radio v-if="messageSendForm.messageClient == 'store'" label="APPOINT">指定商家</Radio>
<Radio v-if="messageSendForm.messageClient == 'member'" label="MEMBER">指定会员</Radio>
</RadioGroup>
</FormItem>
<FormItem label="指定商家" v-if="shopShow">
@@ -165,6 +180,17 @@
</Option>
</Select>
</FormItem>
<FormItem label="选择会员" prop="scopeType"
v-if="memberShow">
<Button type="primary" icon="ios-add" @click="addVip" ghost>选择会员</Button>
<div style="margin-top:24px;" v-if="messageSendForm.messageClient == 'member'">
<Table border :columns="userColumns" :data="this.selectedMember">
</Table>
</div>
</FormItem>
<Modal width="1200" v-model="checkUserList">
<userList v-if="checkUserList" @callback="callbackSelectUser" :selectedList="selectedMember" ref="memberLayout"/>
</Modal>
</Form>
<div slot="footer">
<Button type="text" @click="messageModalVisible = false">取消</Button>
@@ -180,7 +206,7 @@
:title="modalTitle"
v-model="messageDetailModalVisible"
:mask-closable="false"
:width="700"
:width="800"
>
<Form ref="messageSendForm" :model="messageSendForm" :label-width="100" :rules="messageFormValidate">
<FormItem label="消息标题" prop="title">
@@ -195,30 +221,64 @@
style="max-height:60vh;overflow:auto;width: 50%"
/>
</FormItem>
<FormItem label="发送对象">
<RadioGroup type="button" button-style="solid" v-model="messageSendForm.messageClient">
<Radio disabled label="member">会员</Radio>
<Radio disabled label="store">商家</Radio>
</RadioGroup>
</FormItem>
<FormItem label="发送范围">
<RadioGroup type="button" button-style="solid" v-model="messageSendForm.messageRange">
<Radio disabled label="ALL">全站</Radio>
<Radio disabled label="APPOINT">指定商家</Radio>
<Radio disabled label="APPOINT">指定商家</Radio>
</RadioGroup>
</FormItem>
<FormItem label="指定商家">
<Table
:loading="loading"
border
:columns="messageDetailColumns"
:data="shopMessageData"
ref="table"
sortable="custom"
@on-sort-change="messageChangeSort"
@on-selection-change="messageChangeSelect"
></Table>
<FormItem label="指定商家" v-if="messageSendForm.messageClient == 'store'">
<Row>
<Table
:loading="loading"
border
:columns="messageDetailColumns"
:data="shopMessageData"
ref="table"
sortable="custom"
@on-sort-change="shopMessageChangeSort"
></Table>
</Row>
<Row type="flex" justify="end" class="page">
<Page
:current="searchShopMessageForm.pageNumber"
:total="shopMessageDataTotal"
:page-size="searchShopMessageForm.pageSize"
@on-change="messageChangePage"
@on-page-size-change="messageChangePageSize"
@on-change="shopMessageChangePage"
@on-page-size-change="shopMessageChangePageSize"
:page-size-opts="[10, 20, 50]"
size="small"
show-total
show-elevator
show-sizer
></Page>
</Row>
</FormItem>
<FormItem label="指定会员" v-if="messageSendForm.messageClient == 'member'">
<Row>
<Table
:loading="loading"
border
:columns="memberMessageDetailColumns"
:data="memberMessageData"
ref="table"
sortable="custom"
@on-sort-change="memberMessageChangeSort"
></Table>
</Row>
<Row type="flex" justify="end" class="page">
<Page
:current="searchMemberMessageForm.pageNumber"
:total="memberMessageDataTotal"
:page-size="searchMemberMessageForm.pageSize"
@on-change="memberMessageChangePage"
@on-page-size-change="memberMessageChangePageSize"
:page-size-opts="[10, 20, 50]"
size="small"
show-total
@@ -239,14 +299,18 @@
import * as API_Setting from "@/api/setting.js";
import * as API_Other from "@/api/other.js";
import * as API_Shop from "@/api/shops.js";
import userList from "@/views/member/list/index";
export default {
name: "bill",
components: {},
components: {
userList
},
data() {
return {
openSearch: true, // 显示搜索
checkUserList: false, //会员选择器
selectedMember: [], //选择的会员
openTip: true, // 显示提示
loading: true, // 表单加载状态
modalVisible: false, // 添加或编辑显示
@@ -255,6 +319,7 @@
messageModalTitle: "", // 发送站内信标题
messageDetailModalVisible: false, // 添加或编辑显示
shopShow: false, //指定商家是否出现
memberShow: false, //指定会员是否出现
shopList: [],//店铺列表
searchForm: {
// 搜索框初始化对象
@@ -283,6 +348,12 @@
pageNumber: 1, // 当前页数
pageSize: 10, // 页面大小
},
//发送给会员的消息
searchMemberMessageForm: {
// 搜索框初始化对象
pageNumber: 1, // 当前页数
pageSize: 10, // 页面大小
},
form: {
noticeNode: "",
noticeTitle: ""
@@ -290,6 +361,7 @@
//消息发送表单
messageSendForm: {
messageRange: "ALL",
messageClient: "member",
userIds: [],
userNames: [],
},
@@ -413,6 +485,45 @@
}
},
],
// 用户表格
userColumns: [
{
title: "用户名称",
key: "nickName",
minWidth: 120,
},
{
title: "手机号",
key: "mobile",
render: (h, params) => {
return h("div", params.row.mobile || "暂未填写");
},
},
{
title: "操作",
key: "action",
minWidth: 50,
align: "center",
render: (h, params) => {
return h(
"Button",
{
props: {
size: "small",
type: "error",
ghost: true,
},
on: {
click: () => {
this.delUser(params.index);
},
},
},
"删除"
);
},
},
],
noticeData: [], // 表单数据
noticeDataTotal: 0, // 表单数据总数
messageColumns: [
@@ -427,7 +538,22 @@
minWidth: 350,
tooltip: true
},
{
title: "发送对象",
key: "messageClient",
width: 100,
render: (h, params) => {
if (params.row.messageClient == "member") {
return h('div', [
h('span', {}, '会员'),
]);
} else if (params.row.messageClient == "store") {
return h('div', [
h('span', {}, '商家'),
]);
}
}
},
{
title: "发送类型",
key: "messageRange",
@@ -499,7 +625,7 @@
}
},
],
messageData: [], // 表单数据
messageData: [], // 表单数据
messageDataTotal: 0, // 表单数据总数
messageDetailColumns: [
{
@@ -518,17 +644,47 @@
key: "status",
render: (h, params) => {
if (params.row.status == "ALREADY_READY") {
return h( "Badge", {props: { status: "success",text: "已读" } })
return h("Badge", {props: {status: "success", text: "已读"}})
} else if (params.row.status == "UN_READY") {
return h( "Badge", {props: { status: "processing",text: "未读" } })
}else{
return h( "Badge", {props: { status: "processing",text: "回收站" } })
return h("Badge", {props: {status: "processing", text: "未读"}})
} else {
return h("Badge", {props: {status: "processing", text: "回收站"}})
}
}
},
],
shopMessageData: [], // 发送给店铺的消息数据
shopMessageDataTotal: 0, // 发送给店铺的消息数据总数
memberMessageDetailColumns: [
{
title: "会员ID",
key: "memberId",
maxWidth: 300,
sortable: false,
},
{
title: "会员名称",
key: "memberName",
sortable: false,
},
{
title: "是否已读",
key: "status",
maxWidth: 120,
render: (h, params) => {
if (params.row.status == "ALREADY_READY") {
return h("Badge", {props: {status: "success", text: "已读"}})
} else if (params.row.status == "UN_READY") {
return h("Badge", {props: {status: "processing", text: "未读"}})
} else {
return h("Badge", {props: {status: "processing", text: "回收站"}})
}
}
},
],
memberMessageData: [], // 发送给店铺的消息数据
memberMessageDataTotal: 0, // 发送给店铺的消息数据总数
};
},
methods: {
@@ -536,6 +692,41 @@
this.getMessage();
},
// 返回已选择的用户
callbackSelectUser(val) {
// 每次将返回的数据回调判断
let findUser = this.selectedMember.find((item) => {
return item.id === val.id;
});
// 如果没有则添加
if (!findUser) {
this.selectedMember.push(val);
} else {
// 有重复数据就删除
this.selectedMember.map((item, index) => {
if (item.id === findUser.id) {
this.selectedMember.splice(index, 1);
}
});
}
this.reSelectMember();
},
// 删除选择的会员
delUser(index) {
this.selectedMember.splice(index, 1);
this.reSelectMember();
},
//更新选择的会员
reSelectMember() {
this.form.memberDTOS = this.selectedMember.map((item) => {
return {
nickName: item.nickName,
id: item.id
}
});
},
//获取全部商家
getShopList() {
this.loading = true;
@@ -548,6 +739,13 @@
this.loading = false;
},
// 添加指定用户
addVip() {
this.checkUserList = true;
this.$nextTick(() => {
this.$refs.memberLayout.selectedMember = true;
});
},
paneChange(v) {
if (v == "SETTING") {
this.getNoticeMessage()
@@ -582,6 +780,42 @@
this.getMessage();
this.clearSelectAll();
},
//会员消息每页条数发生变化
memberMessageChangePageSize(v) {
this.searchMemberMessageForm.pageSize = v;
this.messageDetail();
},
//会员消息页数变化
memberMessageChangePage(v) {
this.searchMemberMessageForm.pageNumber = v;
this.messageDetail();
this.clearSelectAll();
},
//会员消息
memberMessageChangeSort(e) {
this.searchMemberMessageForm.sort = e.key;
this.searchMemberMessageForm.order = e.order;
this.messageDetail()
},
//店铺消息每页条数发生变化
shopMessageChangePageSize(v) {
this.searchShopMessageForm.pageSize = v;
this.messageDetail();
},
//店铺消息页数变化
shopMessageChangePage(v) {
this.searchShopMessageForm.pageNumber = v;
this.messageDetail();
this.clearSelectAll();
},
//店铺消息
shopMessageChangeSort(e) {
this.searchShopMessageForm.sort = e.key;
this.searchShopMessageForm.order = e.order;
this.messageDetail()
},
//消息
messageChangeSort(e) {
this.searchMessageForm.sort = e.key;
@@ -622,7 +856,7 @@
})
},
//删除站内信
delete(id){
delete(id) {
console.warn(id)
this.$Modal.confirm({
title: "确认删除",
@@ -647,9 +881,11 @@
this.messageModalVisible = true
this.messageModalTitle = "发送站内信"
this.shopShow = false
this.memberShow = false
this.messageSendForm =
{
messageRange: "ALL",
messageClient: "member",
content: "",
title: "",
userIds: [],
@@ -658,6 +894,11 @@
},
//管理员发送站内信提交
sendMessageSubmit() {
console.warn(this.selectedMember)
if(this.messageSendForm.messageClient == 'member' && this.messageSendForm.messageRange == 'MEMBER'){
}
if (this.messageSendForm.userIds.length <= 0 && this.messageSendForm.messageRange == "APPOINT") {
this.$Message.error("请选择发送对象");
return
@@ -677,14 +918,26 @@
})
},
//发送对象选择
selectObject(v) {
this.messageSendForm.messageRange = "ALL"
this.shopShow = false
this.memberShow =false
},
//弹出选择商家的框
selectShop(v) {
if (v == "APPOINT") {
this.getShopList()
this.shopShow = true
this.memberShow = false
}
if (v == "ALL") {
this.shopShow = false
this.memberShow = false
}
if (v == "MEMBER") {
this.shopShow = false
this.memberShow = true
}
},
//获取管理员发送列表
@@ -715,9 +968,9 @@
handleSubmit() {
this.$refs.form.validate((valid) => {
if (valid) {
let params ={
noticeContent:this.form.noticeContent,
noticeTitle:this.form.noticeTitle
let params = {
noticeContent: this.form.noticeContent,
noticeTitle: this.form.noticeTitle
}
API_Setting.editNoticeMessage(this.form.id, params).then((res) => {
this.submitLoading = false;
@@ -731,19 +984,38 @@
});
},
//消息详情
detail(v) {
this.searchShopMessageForm.messageId = v.id
API_Other.getShopMessage(this.searchShopMessageForm).then((res) => {
if (res.success) {
this.messageDetailModalVisible = true;
this.modalTitle = "消息详情"
this.messageSendForm = v
this.shopMessageData = res.result.records;
this.shopMessageDataTotal = res.result.total;
}
});
messageDetail() {
if (this.messageSendForm.messageClient == 'member') {
API_Other.getMemberMessage(this.searchMemberMessageForm).then((res) => {
if (res.success) {
this.memberMessageData = res.result.records;
this.memberMessageDataTotal = res.result.total;
}
});
} else {
console.warn(this.searchShopMessageForm)
API_Other.getShopMessage(this.searchShopMessageForm).then((res) => {
if (res.success) {
this.shopMessageData = res.result.records;
this.shopMessageDataTotal = res.result.total;
}
});
}
},
//消息详情弹出框
detail(v) {
console.warn(this.searchShopMessageForm)
this.messageSendForm = v
if (this.messageSendForm.messageClient == 'member') {
this.searchMemberMessageForm.messageId = v.id
} else {
this.searchShopMessageForm.messageId = v.id
}
this.messageDetail();
this.messageDetailModalVisible = true;
this.modalTitle = "消息详情"
},
edit(v) {
API_Setting.getNoticeMessageDetail(v.id).then((res) => {
if (res.success) {
@@ -755,7 +1027,7 @@
},
//禁用站内信模板
disable(v) {
API_Setting.updateMessageStatus(v.id,"CLOSE").then((res) => {
API_Setting.updateMessageStatus(v.id, "CLOSE").then((res) => {
if (res.success) {
this.$Message.success("禁用成功");
this.getNoticeMessage();
@@ -764,7 +1036,7 @@
},
//启用站内信模板
enable(v) {
API_Setting.updateMessageStatus(v.id,"OPEN").then((res) => {
API_Setting.updateMessageStatus(v.id, "OPEN").then((res) => {
if (res.success) {
this.$Message.success("启用成功");
this.getNoticeMessage();

View File

@@ -116,7 +116,7 @@
<Scroll :on-reach-bottom="memberSearchEdge">
<div dis-hover v-for="(item, index) in members" :key="index" class="scroll-card">
<Button class="btns" :class="{'active':item.___selected}" @click="moveMember(index,item)" style="width: 100%;text-align: left">
<Button class="btns" :class="{'active':item.____selected}" @click="moveMember(index,item)" style="width: 100%;text-align: left">
<span v-if="item.mobile" class="mobile">
{{item.mobile}}
</span>
@@ -501,8 +501,8 @@ export default {
this.members.forEach((item,index)=>{
if(item.___selected && item.mobile == val.mobile){
item.___selected = false
if(item.____selected && item.mobile == val.mobile){
item.____selected = false
}
})
@@ -543,7 +543,7 @@ export default {
this.$Message.error("当前用户暂无手机号绑定");
return false;
}
item.___selected = true;
item.____selected = true;
if (this.alreadyCheck.length == 0) {
this.alreadyCheck.push(item.mobile);
this.alreadyCheckShow.push(item);
@@ -581,7 +581,7 @@ export default {
this.loading = false;
if (res.success) {
res.result.records.forEach((item) => {
item.___selected = false;
item.____selected = false;
this.members.push(item);
});