Commit 62051b13 authored by liwenhong's avatar liwenhong

Merge branch 'feature/activity' into test

# Conflicts:
#	package-lock.json
#	server/config.js
#	server/router.js
#	server/utils/request.js
#	src/App.vue
#	src/pages/Goods/Detail/index.vue
#	src/pages/Groupmeal/Distrib/index.vue
#	src/router/index.js
parents 65168916 98ee2c46
...@@ -2866,9 +2866,13 @@ ...@@ -2866,9 +2866,13 @@
"resolved": "https://registry.nlark.com/@vue/cli-plugin-vuex/download/@vue/cli-plugin-vuex-4.5.13.tgz", "resolved": "https://registry.nlark.com/@vue/cli-plugin-vuex/download/@vue/cli-plugin-vuex-4.5.13.tgz",
"integrity": "sha1-mGRti8HmnPbGpsui/tPqzgNWw2A=", "integrity": "sha1-mGRti8HmnPbGpsui/tPqzgNWw2A=",
"dev": true, "dev": true,
<<<<<<< HEAD
"peerDependencies": { "peerDependencies": {
"@vue/cli-service": "^3.0.0 || ^4.0.0-0" "@vue/cli-service": "^3.0.0 || ^4.0.0-0"
} }
=======
"requires": {}
>>>>>>> feature/activity
}, },
"node_modules/@vue/cli-service": { "node_modules/@vue/cli-service": {
"version": "4.5.13", "version": "4.5.13",
...@@ -3404,6 +3408,7 @@ ...@@ -3404,6 +3408,7 @@
"resolved": "https://registry.npm.taobao.org/@vue/preload-webpack-plugin/download/@vue/preload-webpack-plugin-1.1.2.tgz?cache=0&sync_timestamp=1613215133431&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40vue%2Fpreload-webpack-plugin%2Fdownload%2F%40vue%2Fpreload-webpack-plugin-1.1.2.tgz", "resolved": "https://registry.npm.taobao.org/@vue/preload-webpack-plugin/download/@vue/preload-webpack-plugin-1.1.2.tgz?cache=0&sync_timestamp=1613215133431&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40vue%2Fpreload-webpack-plugin%2Fdownload%2F%40vue%2Fpreload-webpack-plugin-1.1.2.tgz",
"integrity": "sha1-zrkktOyzucQ4ccekKaAvhCPmIas=", "integrity": "sha1-zrkktOyzucQ4ccekKaAvhCPmIas=",
"dev": true, "dev": true,
<<<<<<< HEAD
"engines": { "engines": {
"node": ">=6.0.0" "node": ">=6.0.0"
}, },
...@@ -3411,6 +3416,9 @@ ...@@ -3411,6 +3416,9 @@
"html-webpack-plugin": ">=2.26.0", "html-webpack-plugin": ">=2.26.0",
"webpack": ">=4.0.0" "webpack": ">=4.0.0"
} }
=======
"requires": {}
>>>>>>> feature/activity
}, },
"node_modules/@vue/reactivity": { "node_modules/@vue/reactivity": {
"version": "3.0.11", "version": "3.0.11",
...@@ -3449,9 +3457,13 @@ ...@@ -3449,9 +3457,13 @@
"resolved": "https://registry.nlark.com/@vue/test-utils/download/@vue/test-utils-2.0.0-rc.6.tgz", "resolved": "https://registry.nlark.com/@vue/test-utils/download/@vue/test-utils-2.0.0-rc.6.tgz",
"integrity": "sha1-0KrCTSBFDTeeGD9wVCwIImcLh4M=", "integrity": "sha1-0KrCTSBFDTeeGD9wVCwIImcLh4M=",
"dev": true, "dev": true,
<<<<<<< HEAD
"peerDependencies": { "peerDependencies": {
"vue": "^3.0.1" "vue": "^3.0.1"
} }
=======
"requires": {}
>>>>>>> feature/activity
}, },
"node_modules/@vue/web-component-wrapper": { "node_modules/@vue/web-component-wrapper": {
"version": "1.3.0", "version": "1.3.0",
...@@ -3696,9 +3708,13 @@ ...@@ -3696,9 +3708,13 @@
"resolved": "https://registry.npm.taobao.org/acorn-jsx/download/acorn-jsx-5.3.1.tgz", "resolved": "https://registry.npm.taobao.org/acorn-jsx/download/acorn-jsx-5.3.1.tgz",
"integrity": "sha1-/IZh4Rt6wVOcR9v+oucrOvNNJns=", "integrity": "sha1-/IZh4Rt6wVOcR9v+oucrOvNNJns=",
"dev": true, "dev": true,
<<<<<<< HEAD
"peerDependencies": { "peerDependencies": {
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
} }
=======
"requires": {}
>>>>>>> feature/activity
}, },
"node_modules/acorn-walk": { "node_modules/acorn-walk": {
"version": "6.2.0", "version": "6.2.0",
...@@ -3750,18 +3766,26 @@ ...@@ -3750,18 +3766,26 @@
"resolved": "https://registry.npm.taobao.org/ajv-errors/download/ajv-errors-1.0.1.tgz", "resolved": "https://registry.npm.taobao.org/ajv-errors/download/ajv-errors-1.0.1.tgz",
"integrity": "sha1-81mGrOuRr63sQQL72FAUlQzvpk0=", "integrity": "sha1-81mGrOuRr63sQQL72FAUlQzvpk0=",
"dev": true, "dev": true,
<<<<<<< HEAD
"peerDependencies": { "peerDependencies": {
"ajv": ">=5.0.0" "ajv": ">=5.0.0"
} }
=======
"requires": {}
>>>>>>> feature/activity
}, },
"node_modules/ajv-keywords": { "node_modules/ajv-keywords": {
"version": "3.5.2", "version": "3.5.2",
"resolved": "https://registry.npm.taobao.org/ajv-keywords/download/ajv-keywords-3.5.2.tgz?cache=0&sync_timestamp=1616882351228&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fajv-keywords%2Fdownload%2Fajv-keywords-3.5.2.tgz", "resolved": "https://registry.npm.taobao.org/ajv-keywords/download/ajv-keywords-3.5.2.tgz?cache=0&sync_timestamp=1616882351228&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fajv-keywords%2Fdownload%2Fajv-keywords-3.5.2.tgz",
"integrity": "sha1-MfKdpatuANHC0yms97WSlhTVAU0=", "integrity": "sha1-MfKdpatuANHC0yms97WSlhTVAU0=",
"dev": true, "dev": true,
<<<<<<< HEAD
"peerDependencies": { "peerDependencies": {
"ajv": "^6.9.1" "ajv": "^6.9.1"
} }
=======
"requires": {}
>>>>>>> feature/activity
}, },
"node_modules/alphanum-sort": { "node_modules/alphanum-sort": {
"version": "1.0.2", "version": "1.0.2",
...@@ -4296,9 +4320,13 @@ ...@@ -4296,9 +4320,13 @@
"resolved": "https://registry.npm.taobao.org/babel-core/download/babel-core-7.0.0-bridge.0.tgz", "resolved": "https://registry.npm.taobao.org/babel-core/download/babel-core-7.0.0-bridge.0.tgz",
"integrity": "sha1-laSS3dkPm06aSh2hTrM1uHtjTs4=", "integrity": "sha1-laSS3dkPm06aSh2hTrM1uHtjTs4=",
"dev": true, "dev": true,
<<<<<<< HEAD
"peerDependencies": { "peerDependencies": {
"@babel/core": "^7.0.0-0" "@babel/core": "^7.0.0-0"
} }
=======
"requires": {}
>>>>>>> feature/activity
}, },
"node_modules/babel-eslint": { "node_modules/babel-eslint": {
"version": "10.1.0", "version": "10.1.0",
...@@ -7298,10 +7326,17 @@ ...@@ -7298,10 +7326,17 @@
"integrity": "sha1-LnG/CxGRU9u0zE6I2epaz7UNwFw=", "integrity": "sha1-LnG/CxGRU9u0zE6I2epaz7UNwFw=",
"dev": true "dev": true
}, },
<<<<<<< HEAD
"node_modules/dayjs": { "node_modules/dayjs": {
"version": "1.10.5", "version": "1.10.5",
"resolved": "https://registry.nlark.com/dayjs/download/dayjs-1.10.5.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fdayjs%2Fdownload%2Fdayjs-1.10.5.tgz", "resolved": "https://registry.nlark.com/dayjs/download/dayjs-1.10.5.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fdayjs%2Fdownload%2Fdayjs-1.10.5.tgz",
"integrity": "sha1-VgDfRUj8JFOz8WPrsqu+llzPuYY=" "integrity": "sha1-VgDfRUj8JFOz8WPrsqu+llzPuYY="
=======
"dayjs": {
"version": "1.10.6",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.6.tgz",
"integrity": "sha512-AztC/IOW4L1Q41A86phW5Thhcrco3xuAA+YX/BLpLWWjRcTj5TOt/QImBLmCKlrF7u7k47arTnOyL6GnbG8Hvw=="
>>>>>>> feature/activity
}, },
"node_modules/deasync": { "node_modules/deasync": {
"version": "0.1.21", "version": "0.1.21",
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
"dependencies": { "dependencies": {
"axios": "^0.21.1", "axios": "^0.21.1",
"core-js": "^3.6.5", "core-js": "^3.6.5",
"dayjs": "^1.10.6",
"element-plus": "^1.0.2-beta.44", "element-plus": "^1.0.2-beta.44",
"form-data": "^4.0.0", "form-data": "^4.0.0",
"json-bigint": "^1.0.0", "json-bigint": "^1.0.0",
......
...@@ -21,4 +21,5 @@ module.exports = { ...@@ -21,4 +21,5 @@ module.exports = {
GOODS_URI: API_INTERNAL_URI[env], GOODS_URI: API_INTERNAL_URI[env],
WITHDRAWAL_URI: API_INTERNAL_URI[env], WITHDRAWAL_URI: API_INTERNAL_URI[env],
GROUPMEAL_URI: API_INTERNAL_URI[env], GROUPMEAL_URI: API_INTERNAL_URI[env],
ACTIVITY_URI: API_INTERNAL_URI[env]
}; };
const ACTIVITY_URI = require("../config.js").ACTIVITY_URI;
const req = require("../utils/request").httpReq;
// 获取商家列表
exports.getBusinessList = async ctx => {
const url = `${ACTIVITY_URI}/goods/background/ota_list`;
const opts = {
url,
method: "GET"
};
ctx.body = await req(ctx, opts);
};
// 添加商品
exports.addGoods = async ctx => {
const url = `${ACTIVITY_URI}/goods/background/add_goods`;
const opts = {
url,
method: "POST",
json: true,
body: ctx.request.body
};
ctx.body = await req(ctx, opts);
};
// 商品库列表
exports.pindanGoods = async ctx => {
const url = `${ACTIVITY_URI}/goods/background/pindan_goods`;
const opts = {
url,
method: "GET"
};
ctx.body = await req(ctx, opts);
};
// 查看商品详情
exports.markGoodsInfo = async ctx => {
const url = `${ACTIVITY_URI}/goods/background/marketing_goods_info`;
const opts = {
url,
method: "GET"
};
ctx.body = await req(ctx, opts);
};
// 编辑商品
exports.editGoods = async ctx => {
const url = `${ACTIVITY_URI}/goods/background/edit_goods`;
const opts = {
url,
method: "POST",
json: true,
body: ctx.request.body
};
ctx.body = await req(ctx, opts);
};
// 获取活动过列表
exports.getActivityList = async ctx => {
const url = `${ACTIVITY_URI}/marketing/background/marketing_list`;
const opts = {
url,
method: "GET"
};
ctx.body = await req(ctx, opts);
};
// 修改商品
exports.editGoodsDetail = async ctx => {
const url = `${ACTIVITY_URI}/goods/background/edit_goods`;
const opts = {
url,
method: "POST",
json: true,
body: ctx.request.body
};
ctx.body = await req(ctx, opts);
};
// 添加营销活动
exports.addMarketing = async ctx => {
const url = `${ACTIVITY_URI}/marketing/background/add_marketing`;
const opts = {
url,
method: "POST",
json: true,
body: ctx.request.body
};
ctx.body = await req(ctx, opts);
};
// 编辑营销活动
exports.updateMarketing = async ctx => {
const url = `${ACTIVITY_URI}/marketing/background/update_marketing`;
const opts = {
url,
method: "POST",
json: true,
body: ctx.request.body
};
ctx.body = await req(ctx, opts);
};
// 营销活动详情
exports.marketingInfo = async ctx => {
const url = `${ACTIVITY_URI}/marketing/background/marketing_info`;
const opts = {
url,
method: "POST",
json: true,
body: ctx.request.body
};
ctx.body = await req(ctx, opts);
};
// 关闭/开启 活动
exports.updateActivity = async ctx => {
const url = `${ACTIVITY_URI}/marketing/background/update_marketing`;
const opts = {
url,
method: "POST",
json: true,
body: ctx.request.body
};
ctx.body = await req(ctx, opts);
};
// 查看活动订单
exports.checkActivityDetail = async ctx => {
const url = `${ACTIVITY_URI}/marketing/background/marketing_info`;
const opts = {
url,
method: "POST",
json: true,
body: ctx.request.body
};
ctx.body = await req(ctx, opts);
};
// 查看活动订单
exports.checkActivityDetailInfo = async ctx => {
const url = `${ACTIVITY_URI}/order/background/pindan_marketing_info_data_statistics`;
const opts = {
url,
method: "GET",
json: true,
body: ctx.request.body
};
ctx.body = await req(ctx, opts);
};
// 获取自提点列表
exports.getPlaceList = async ctx => {
const url = `${ACTIVITY_URI}/marketing/background/take_place_list`;
const opts = {
url,
method: "GET"
};
ctx.body = await req(ctx, opts);
};
// 添加自提点
exports.addPlace = async ctx => {
const url = `${ACTIVITY_URI}/marketing/background/add_take_place`;
const opts = {
url,
method: "POST",
json: true,
body: ctx.request.body
};
ctx.body = await req(ctx, opts);
};
//删除自提点
exports.deletePlace = async ctx => {
const url = `${ACTIVITY_URI}/marketing/background/delete_take_place`;
const opts = {
url,
method: "POST",
json: true,
body: ctx.request.body
};
ctx.body = await req(ctx, opts);
};
...@@ -8,6 +8,7 @@ const life = require('./controllers/life-no'); ...@@ -8,6 +8,7 @@ const life = require('./controllers/life-no');
const goods = require('./controllers/goods'); const goods = require('./controllers/goods');
const withdrawal = require('./controllers/withdrawal'); const withdrawal = require('./controllers/withdrawal');
const groupmeal = require('./controllers/groupmeal'); const groupmeal = require('./controllers/groupmeal');
const activity = require('./controllers/activity');
const router = Router(); const router = Router();
const API_VERSION = "/api/v1"; const API_VERSION = "/api/v1";
...@@ -87,5 +88,25 @@ router.post(`${API_VERSION}/get_withdrawal_black_list`, withdrawal.getBlackList) ...@@ -87,5 +88,25 @@ router.post(`${API_VERSION}/get_withdrawal_black_list`, withdrawal.getBlackList)
router.post(`${API_VERSION}/get_withdraw_audit`, withdrawal.getWithdrawAudit) router.post(`${API_VERSION}/get_withdraw_audit`, withdrawal.getWithdrawAudit)
router.post(`${API_VERSION}/get_freezing_fund`, withdrawal.getFreezingFund) router.post(`${API_VERSION}/get_freezing_fund`, withdrawal.getFreezingFund)
router.get(`${API_VERSION}/get_apply_detail`, withdrawal.getApplyDetail) router.get(`${API_VERSION}/get_apply_detail`, withdrawal.getApplyDetail)
// 后台运营管理
router.get(`${API_VERSION}/marketing/background/marketing_list`, activity.getActivityList)
router.get(`${API_VERSION}/order/background/pindan_marketing_info_data_statistics`, activity.checkActivityDetailInfo)
router.post(`${API_VERSION}/goods/background/edit_goods`, activity.editGoodsDetail)
router.post(`${API_VERSION}/marketing/background/update_marketing`, activity.updateActivity)
router.post(`${API_VERSION}/marketing/background/marketing_info`, activity.checkActivityDetail)
//
router.get(`${API_VERSION}/marketing/background/take_place_list`, activity.getPlaceList)
router.post(`${API_VERSION}/marketing/background/add_take_place`, activity.addPlace)
router.post(`${API_VERSION}/marketing/background/delete_take_place`, activity.deletePlace)
router.get(`${API_VERSION}/goods/background/ota_list`, activity.getBusinessList);
router.post(`${API_VERSION}/goods/background/add_goods`, activity.addGoods);
router.get(`${API_VERSION}/goods/background/pindan_goods`, activity.pindanGoods);
router.get(`${API_VERSION}/goods/background/marketing_goods_info`, activity.markGoodsInfo);
router.post(`${API_VERSION}/goods/background/edit_goods`, activity.editGoods);
router.post(`${API_VERSION}/marketing/background/add_marketing`, activity.addMarketing);
router.post(`${API_VERSION}/marketing/background/marketing_info`, activity.marketingInfo);
router.post(`${API_VERSION}/marketing/background/update_marketing`, activity.updateMarketing);
module.exports = router; module.exports = router;
<template> <template>
<div> <div class="app-wrapper">
<router-view v-slot="{ Component }"> <router-view v-slot="{ Component }">
<keep-alive v-if="$route.meta.keepAlive"> <keep-alive v-if="$route.meta.keepAlive">
<component :is="Component"> </component> <component :is="Component"> </component>
...@@ -28,8 +28,13 @@ export default { ...@@ -28,8 +28,13 @@ export default {
} else { } else {
redirectToLogin(); redirectToLogin();
} }
}, }
}; };
</script> </script>
<style lang="less" src="./global.less"></style> <style lang="less" src="./global.less"></style>
<style lang="less" scoped>
.app-wrapper {
height: 100%;
}
</style>
...@@ -14,7 +14,6 @@ import { redirectToLogin } from "./utils/util"; ...@@ -14,7 +14,6 @@ import { redirectToLogin } from "./utils/util";
// 处理路由权限 // 处理路由权限
router.beforeResolve(async (to, from, next) => { router.beforeResolve(async (to, from, next) => {
if (!to.meta.requireAuth) { if (!to.meta.requireAuth) {
next(); next();
return true; return true;
...@@ -22,9 +21,9 @@ router.beforeResolve(async (to, from, next) => { ...@@ -22,9 +21,9 @@ router.beforeResolve(async (to, from, next) => {
if (!store.state.permissions) { if (!store.state.permissions) {
const { status, user } = await fetchCurrentUser(); const { status, user } = await fetchCurrentUser();
if (status === 'success') { if (status === "success") {
store.commit('updateUserInfo', user); store.commit("updateUserInfo", user);
await store.dispatch('updateUserPermission', { email: user.email }) await store.dispatch("updateUserPermission", { email: user.email });
} else { } else {
redirectToLogin(); redirectToLogin();
return false; return false;
...@@ -32,11 +31,11 @@ router.beforeResolve(async (to, from, next) => { ...@@ -32,11 +31,11 @@ router.beforeResolve(async (to, from, next) => {
} }
if (!checkPathAuth(to.path)) { if (!checkPathAuth(to.path)) {
router.push({name: 'Forbidden'}) router.push({ name: "Forbidden" });
} else { } else {
next() next();
} }
}) });
createApp(App) createApp(App)
.use(router) .use(router)
......
<template>
<div
class="wrapper"
v-loading="pageLoading"
element-loading-text="拼命加载中"
element-loading-spinner="el-icon-loading"
element-loading-background="rgba(0, 0, 0, 0.8)"
>
<div class="activityInfo-wrapper">
<el-card class="activityInfo">
<div class="infoItem">
<p class="infoItemText">{{ detailInfo.order_count }}</p>
<p>订单数量</p>
</div>
<div class="infoItem">
<p class="infoItemText">{{ detailInfo.sold_goods_count }}</p>
<p>已售商品数量</p>
</div>
<div class="infoItem">
<p class="infoItemText">{{ detailInfo.pay_amount_count }}</p>
<p>支付金额</p>
</div>
<div class="infoItem">
<p class="infoItemText">{{ detailInfo.discount_amount_count }}</p>
<p>优惠金额</p>
</div>
<div class="infoItem">
<p class="infoItemText">{{ detailInfo.refund_count }}</p>
<p>退款</p>
</div>
<div class="infoItem">
<p class="infoItemText">{{ detailInfo.real_income_count }}</p>
<p>实际收入</p>
</div>
</el-card>
</div>
<div class="activityDetail">
<section class="content">
<el-card class="activityGoods box-card">
<div class="my-header">
<h3>{{ marketingInfo.marketing_name }}</h3>
<p class="endTime">{{ showTimer }}</p>
</div>
<p class="title">拼单商品</p>
<div class="images-wrapper">
<div
class="image-block"
v-for="picItem in goodsList"
:key="picItem.audit_status"
>
<el-image
class="activityImage"
style="width: 100px; height: 100px"
:src="picItem.desc_pic_url_list[0]"
fit="cover"
></el-image>
<span class="goodsPrice">{{ `¥${picItem.price}` }}</span>
</div>
</div>
</el-card>
<el-card class="activityIntroduce box-card">
<p class="introduceText">
{{ marketingInfo.pindan_desc }}
</p>
<el-image
v-for="(picItem, index) in marketingInfo.pindan_pic_url"
:key="index"
class="activityImage"
style="width: 100%; height: 400px"
:src="picItem"
fit="contain"
></el-image>
</el-card>
<el-card class="activities box-card">
<div
v-for="goodsItem in goodsList"
:key="goodsItem.goods_sku_id"
class="activityItem"
>
<el-image
class="activityImage"
style="width: 100px; height: 100px"
:src="goodsItem.desc_pic_url_list[0]"
fit="fit"
></el-image>
<div class="itemIntroduce">
<p>{{ goodsItem.desc }}</p>
<p class="price">
<span class="nowPrice">{{ `¥${goodsItem.price}` }}</span>
<span class="originPrice">{{
`¥${goodsItem.original_price} `
}}</span>
</p>
</div>
</div>
</el-card>
</section>
</div>
</div>
</template>
<script>
import ActivityService from "@/service/Activity/index";
import { ElMessage } from "element-plus";
import dayJs from "dayjs";
export default {
components: {},
props: {},
data() {
return {
pageLoading: false,
goodsList: [],
marketingInfo: {},
endTime: "",
showTimer: "",
detailInfo: {}
};
},
watch: {},
computed: {},
methods: {
async checkActivityDetail() {
try {
this.pageLoading = true;
let dataArr = await Promise.all([
ActivityService.checkActivityDetail({
marketing_id: this.$route.query.marketing_id,
marketing_type: this.$route.query.marketing_type
}),
ActivityService.checkActivityDetailInfo({
marketing_id: this.$route.query.marketing_id
})
]);
// let data = await ActivityService.checkActivityDetail({
// marketing_id: this.$route.query.marketing_id,
// marketing_type: this.$route.query.marketing_type
// });
this.pageLoading = false;
this.goodsList = dataArr[0].result.goods_list;
this.marketingInfo = dataArr[0].result.marketing_info;
this.endTime = dataArr[0].result.marketing_info.end_time;
this.detailInfo = dataArr[1].result;
} catch {
this.pageLoading = false;
ElMessage.error("加载失败");
}
},
// 时间差转时分秒
getTimeout(timeCount) {
if (timeCount > 0) {
var days = parseInt(timeCount / (1000 * 60 * 60 * 24));
var hours = parseInt(
(timeCount % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)
);
var minutes = parseInt((timeCount % (1000 * 60 * 60)) / (1000 * 60));
var seconds = parseInt((timeCount % (1000 * 60)) / 1000);
this.showTimer =
"距结束:" +
days +
" 天 " +
hours +
" 小时 " +
minutes +
" 分钟 " +
seconds +
" 秒 ";
} else {
this.showTimer = "已结束";
}
},
myTimer() {
let dateNow = dayJs();
this.timer = setInterval(() => {
dateNow = dayJs().subtract(1, "minute");
let myTime = dayJs(this.endTime).diff(dateNow); // 时间差
this.getTimeout(myTime);
if (this.myTime <= 0) {
clearInterval(this.timer);
}
}, 1000);
}
},
async created() {
await this.checkActivityDetail();
this.myTimer();
},
beforeUnmount() {
clearInterval(this.timer);
}
};
</script>
<style lang="less" scoped>
.wrapper {
height: 100%;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: center;
padding: 45px 10px 0;
.activityInfo {
width: 500px;
/deep/ .el-card__body {
width: 100%;
display: flex;
flex-wrap: wrap;
}
.infoItem {
width: 33%;
text-align: center;
margin-bottom: 20px;
.infoItemText {
font-weight: bolder;
}
// display: flex;
// align-items: center;
// justify-content: center;
}
}
.activityDetail {
width: 500px;
.content {
.my-header {
.endTime {
margin: 5px 0;
font-size: 15px;
color: red;
}
}
.box-card {
margin: 10px 0;
}
.activityGoods {
.images-wrapper {
display: flex;
flex-wrap: wrap;
.image-block {
margin: 0 5px 0 0px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.goodsPrice {
color: red;
font-size: 18px;
}
}
.image-block:nth-child(4n + 0) {
margin-right: 0;
}
}
.activityImage {
margin: 10px 10px 0 0;
}
}
.activityIntroduce {
padding: 5px 0;
.introduceText {
margin-bottom: 20px;
}
}
.activities {
.activityItem {
display: flex;
margin: 15px 0;
.itemIntroduce {
display: flex;
flex-direction: column;
justify-content: space-around;
margin-left: 10px;
> p {
width: 200px;
}
.price {
.nowPrice {
color: red;
padding-right: 10px;
}
.originPrice {
text-decoration: line-through;
}
}
}
}
}
}
}
}
</style>
.header {
width: 100%;
height: 100%;
padding: 0 30px;
}
\ No newline at end of file
<template>
<div
class="manage-wrapper"
v-loading="tableLoading"
element-loading-text="拼命加载中"
element-loading-spinner="el-icon-loading"
element-loading-background="rgba(0, 0, 0, 0.8)"
>
<el-form
ref="form"
:model="activity"
inline
label-width="80px"
class="form-wrapper"
>
<!-- 表单控件 -->
<div class="formitem-wrapper">
<el-form-item label="活动名称">
<el-input v-model="activity.activityName"></el-input>
</el-form-item>
<el-form-item label="活动状态">
<el-select v-model="activity.online_status">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</el-form-item>
<el-form-item style="margin-left: 50px">
<el-button type="primary" @click="getActivityList">搜索</el-button>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="goReleaseProduc"
>发布拼单</el-button
>
</el-form-item>
</div>
<!-- 列表 -->
<div class="table-wrapper">
<el-table :data="tableActivityList" border style="width: 100%">
<el-table-column
align="center"
prop="activiteId"
label="活动ID"
width="width"
>
</el-table-column>
<el-table-column
align="center"
prop="activiteHead"
label="活动标题"
width="width"
>
<template #default="scope">
<div @click="handleHeadline(scope.row)" class="activityTitle">
<div>
{{ scope.row.activiteHead }}
</div>
<div class="activityPrice">
{{
scope.row.minPrice === scope.row.maxPrice
? ` ¥ ${scope.row.minPrice}`
: ` ¥ ${scope.row.minPrice}~¥${scope.row.maxPrice} `
}}
</div>
</div>
</template>
</el-table-column>
<el-table-column
align="center"
prop="activiteStatus"
label="活动状态"
width="width"
>
</el-table-column>
<el-table-column
align="center"
prop="orderNumber"
label="订单数量"
width="width"
>
</el-table-column>
<el-table-column align="center" prop="scope" label="操作" width="250">
<template #default="scope">
<div class="button-one">
<el-button
type="primary"
size="small"
@click="handleModify(scope.row)"
>修改</el-button
>
<el-popconfirm
title="确定要结束本次拼单吗?"
@confirm="updateActivity"
>
<template #reference>
<el-button
v-show="scope.row.status === 1"
type="primary"
size="small"
@click="handleEnd(scope.row)"
>结束</el-button
>
</template>
</el-popconfirm>
<el-popconfirm
title="确定要开启本次拼单吗?"
@confirm="updateActivity"
>
<template #reference>
<el-button
v-show="scope.row.status === 2 || scope.row.status === 3"
type="primary"
size="small"
@click="handleStart(scope.row)"
>开始</el-button
>
</template>
</el-popconfirm>
</div>
<el-button
class="checkButton"
type="primary"
size="small"
@click="handleLook(scope.row)"
>查看订单</el-button
>
</template>
</el-table-column>
</el-table>
</div>
<!-- 分页 -->
<div class="pagination-wrapper">
<el-pagination
background
layout="prev, pager, next"
:total="pageCount"
:page-size="10"
@current-change="handleCurrentChange"
>
</el-pagination>
</div>
</el-form>
</div>
</template>
<script>
import { ElMessage } from "element-plus";
import ActivityService from "@/service/Activity/index";
import dayJs from "dayjs";
export default {
name: "Manage",
data() {
return {
activity: {
activityName: "",
online_status: ""
},
pageCount: 0, // 总条数
currentPage: 1, //当前页码
pageSize: 10, // 每页条数
storeQuery: {}, // 存储开始 结束 参数
tableActivityList: [],
tableLoading: false,
options: [
{ value: "", label: "全部" },
{ value: "1", label: "未开始" },
{ value: "2", label: "进行中" },
{ value: "3", label: "已结束" }
]
};
},
methods: {
/* API */
// 获取商品列表
async getActivityList() {
let params = {
marketing_name: this.activity.activityName,
activity_status: this.activity.online_status, //1 未开始,2进行中,3已结束 空值 全部
marketing_type: 4, //1分销 2团购 3秒杀 4团餐 默认传4
// marketing_id: "",
page: this.currentPage,
page_size: this.pageSize
};
try {
this.tableLoading = true;
let data = await ActivityService.getActivityList(params);
this.filterTableActiveList(data.result);
this.pageCount = data.count;
this.tableLoading = false;
} catch {
this.tableLoading = false;
ElMessage.error("加载失败");
}
},
/* API */
// 结束 开始
async updateActivity() {
try {
this.tableLoading = true;
let data = await ActivityService.updateActivity(this.storeQuery);
if (data.code === 0) {
await this.getActivityList();
} else {
this.tableLoading = false;
ElMessage.error(data.reason);
}
} catch {
this.tableLoading = false;
}
},
/* API */
// 修改
/* API */
// 查看订单
// 数据转换成tableData格式
filterTableActiveList(tableData) {
this.tableActivityList = tableData.map(item => {
let activityStatusText = "";
let dateNow = dayJs();
if (dateNow.diff(dayJs(item.start_time)) < 0) {
// 开始时间大于当前时间 return 未开始
activityStatusText = "未开始";
} else if (dayJs(item.end_time).diff(dayJs(item.start_time)) > 0) {
// 结束时间大于开始时间 return 进行中
activityStatusText = "进行中";
} else if (dateNow.diff(dayJs(item.end_time)) > 0) {
// 当前时间大于结束时间 return 已结束
activityStatusText = "已结束";
}
return {
activiteId: item.marketing_id,
activiteHead: item.marketing_name,
activiteStatus: activityStatusText,
status: item.online_status,
minPrice: item.min_price,
maxPrice: item.max_price,
marketing_type: 4
};
});
},
// 更改页数
handleCurrentChange(val) {
this.currentPage = val;
this.getActivityList();
},
// 点击活动标题
async handleHeadline(val) {
console.log(val);
this.$router.push({
name: "ActivityDetail",
query: {
marketing_id: val.activiteId,
marketing_type: val.marketing_type
}
});
},
// 发布拼单
goReleaseProduc() {
this.$router.push("/op/activity/releaseProduc");
},
// 修改
handleModify(val) {
this.$router.push({
path: "/op/activity/releaseProduc",
query: {
marketing_id: val.activiteId,
marketing_type: val.marketing_type
}
});
},
// 结束
handleEnd(val) {
this.storeQuery = {
marketing_id: val.activiteId,
online_status: 2 // 1 启用 2 关闭
};
},
// 开始
handleStart(val) {
this.storeQuery = {
marketing_id: val.activiteId,
online_status: 1 // 1 启用 2 关闭
};
},
// 查看详情
handleLook(row) {
this.$router.push({
path: "/op/groupmeal/orderManagement",
query: {
marketing_id: row.activiteId,
marketing_type: row.marketing_type
}
});
}
},
created() {
this.getActivityList();
}
};
</script>
<style lang="less" src="./index.less" scope></style>
<style lang="less" scoped>
.manage-wrapper {
height: 100%;
}
.header {
height: 100%;
}
.form-wrapper {
display: flex;
flex-direction: column;
justify-content: space-between;
height: 100%;
.el-card__body {
height: 100%;
}
.formitem-wrapper {
height: 100px;
display: flex;
align-items: flex-end;
}
.table-wrapper {
flex: 1;
overflow-y: scroll;
}
.pagination-wrapper {
width: 100%;
height: 100px;
bottom: 20px;
display: flex;
justify-content: center;
align-items: center;
}
}
.checkButton {
margin-top: 5px;
}
.activityTitle {
cursor: pointer;
}
.activityPrice {
color: red;
}
</style>
This diff is collapsed.
<template>
<div class="infoEditing">
<el-form ref="infoEditForm" :model="infoEditForm" label-width="80px">
<el-form-item label="标题:">
<el-input v-model="infoEditForm.title" maxlength="30"></el-input>
</el-form-item>
<el-form-item label="介绍:">
<el-input
type="textarea"
v-model="infoEditForm.desc"
maxlength="1000"
rows="4"
></el-input>
</el-form-item>
<el-form-item label="图片:">
<el-upload
:data="{ type: 1 }"
:action="uploadUrl"
:on-preview="previewImage"
:on-success="handleDetailSuccess"
:before-remove="removeDetailFiles"
:file-list="infoEditForm.picUrlList"
auto-upload
ref="picUpload"
:limit="9"
list-type="picture-card"
multiple
>
<template #default>
<i class="el-icon-plus"></i>
</template>
</el-upload>
</el-form-item>
</el-form>
<!-- 展示缩略图 -->
<el-dialog width="40%" v-model="isShowPopver">
<el-image :src="popoverImage" fit="fill" style="width: 100%"></el-image>
</el-dialog>
</div>
</template>
<script>
import { GOODS_URI } from "../../../../../server/config";
export default {
props: {
editInfo: {
type: Object,
required: () => {}
}
},
data() {
return {
infoEditForm: {
title: "", // 标题
desc: "", // 介绍
picUploadList: [], // 上传详情图片列表
picUrlList: [] // 图片回显列表
},
propData: {},
isShowPopver: false, // 是否展示图片框
uploadUrl: `${GOODS_URI}/ksy/ks3apiunencrypt/ks3api_upload` // 金山云上传地址
};
},
methods: {
// 展示商品大图
previewImage(file) {
this.popoverImage = file.url;
this.isShowPopver = true;
},
// 图片上传成功时
handleDetailSuccess(res) {
this.infoEditForm.picUploadList.push(res.result.image_id);
},
// 图片删除后
removeDetailFiles(file, fileList) {
for (let i = 0; i < fileList.length; i++) {
if (fileList[i].uid == file.uid) {
this.infoEditForm.picUploadList.splice(i, 1);
}
}
},
// 获取营销活动详情
marketingInfoMet() {
let marketingId = this.$route.query.marketing_id;
if (marketingId == undefined) {
return;
}
this.propData = JSON.parse(localStorage.getItem("propData"));
this.infoEditForm.title = this.propData.marketing_name;
this.infoEditForm.desc = this.propData.pindan_desc;
for (var i in this.propData.pindan_pic_url) {
this.infoEditForm.picUrlList.push({
url: this.propData.pindan_pic_url[i]
});
}
}
},
created() {
this.marketingInfoMet();
}
};
</script>
<style scoped>
.infoEditing {
width: 64%;
margin: 0 auto;
}
</style>
<template>
<div id="map" class="mapContainer">
<!-- map -->
<div class="mapWrapper">
<div class="search">
<el-form-item label-position="left">
<el-button @click="handleSearch">搜索</el-button>
<el-input
class="dialog-input"
v-model="searchKey"
placeholder="请输入关键字"
autocomplete="off"
></el-input>
</el-form-item>
<div id="js-result" v-show="searchKey" class="result"></div>
</div>
<div id="js-container" class="myMap">
正在加载数据 ...
</div>
</div>
<!-- info -->
<div class="mapInfo">
<!-- <div class="search" v-if="placeSearch">
<input type="text" placeholder="请输入关键字" v-model="searchKey" />
<button type="button" @click="handleSearch">搜索</button>
<div id="js-result" v-show="searchKey" class="result"></div>
</div> -->
<h3 class="title">拖拽选址</h3>
<ul class="info">
<li><span>经度:</span>{{ dragData.lng }}</li>
<li><span>纬度:</span>{{ dragData.lat }}</li>
<li><span>地址:</span>{{ dragData.address }}</li>
</ul>
</div>
</div>
</template>
<script>
import remoteLoad from "@/utils/remoteLoad.js";
export default {
name: "app",
data() {
return {
MapCityName: "北京",
searchKey: "",
dragData: {
lng: null,
lat: null,
address: null,
nearestJunction: null,
nearestRoad: null,
nearestPOI: null
}
};
},
methods: {
// 搜索
handleSearch() {
if (this.searchKey) {
this.placeSearch.search(this.searchKey);
}
},
dragMap(data) {
this.dragData = {
lng: data.position.lng,
lat: data.position.lat,
address: data.address,
province: data.regeocode.addressComponent.province,
city: data.regeocode.addressComponent.city,
area: data.regeocode.addressComponent.district
};
},
// 初始化地图
initMap() {
let that = this;
// 加载PositionPicker,loadUI的路径参数为模块名中 'ui/' 之后的部分
let AMapUI = (this.AMapUI = window.AMapUI);
let AMap = (this.AMap = window.AMap);
AMapUI.loadUI(["misc/PositionPicker"], PositionPicker => {
let mapConfig = {
zoom: 16
// cityName: this.MapCityName
};
if (this.lat && this.lng) {
mapConfig.center = [this.lng, this.lat];
}
let map = new AMap.Map("js-container", mapConfig);
// 加载地图搜索插件
AMap.service("AMap.PlaceSearch", () => {
this.placeSearch = new AMap.PlaceSearch({
pageSize: 5,
pageIndex: 1,
citylimit: true,
// city: this.MapCityName,
map: map,
panel: "js-result"
});
});
// 启用工具条
AMap.plugin(["AMap.ToolBar"], function() {
map.addControl(
new AMap.ToolBar({
position: "RB"
})
);
});
// 地图地图定位
AMap.plugin("AMap.Geolocation", function() {
var geolocation = new AMap.Geolocation({
// 是否使用高精度定位,默认:true
enableHighAccuracy: true,
// 设置定位超时时间,默认:无穷大
timeout: 10000,
// 定位按钮的停靠位置的偏移量,默认:Pixel(10, 20)
buttonOffset: new AMap.Pixel(10, 20),
// 定位成功后调整地图视野范围使定位位置及精度范围视野内可见,默认:false
zoomToAccuracy: true,
// 定位按钮的排放位置, RB表示右下
buttonPosition: "RB"
});
map.addControl(geolocation);
geolocation.getCurrentPosition();
AMap.event.addListener(geolocation, "complete", onComplete);
AMap.event.addListener(geolocation, "error", onError);
function onComplete(data) {
console.log(data);
// data是具体的定位信息
}
function onError(data) {
console.log(data);
// 定位出错
}
});
// 创建地图拖拽
let positionPicker = new PositionPicker({
mode: "dragMap", // 设定为拖拽地图模式,可选'dragMap'、'dragMarker',默认为'dragMap'
map: map // 依赖地图对象
});
// 拖拽完成发送自定义 drag 事件
positionPicker.on("success", positionResult => {
// 过滤掉初始化地图后的第一次默认拖放
if (!this.dragStatus) {
this.dragStatus = true;
} else {
this.dragMap(positionResult);
that.$emit("getMapInfo", this.dragData);
}
});
// 启动拖放
positionPicker.start();
});
}
},
async created() {
// 已载入高德地图API,则直接初始化地图
if (window.AMap && window.AMapUI) {
this.initMap();
// 未载入高德地图API,则先载入API再初始化
} else {
await remoteLoad(
`http://webapi.amap.com/maps?v=1.3&key=bb057625545d8cf77df1379e7aaae0b5`
);
await remoteLoad("http://webapi.amap.com/ui/1.0/main.js");
this.initMap();
}
}
};
</script>
<style lang="less" scoped>
.mapContainer {
height: 100%;
width: 100%;
display: flex;
flex-direction: row;
.mapWrapper {
position: relative;
width: 80%;
height: 100%;
.search {
position: absolute;
top: 10px;
left: 20px;
z-index: 100000;
.dialog-input {
width: 250px;
}
}
.myMap {
height: 100%;
height: 500px;
}
}
.mapInfo {
width: 20%;
padding-left: 20px;
display: flex;
flex-direction: column;
justify-content: start;
align-items: flex-start;
.info {
text-align: left;
}
}
}
.m-map .search {
position: absolute;
top: 10px;
left: 10px;
width: 285px;
z-index: 1;
}
.m-map .search input {
width: 180px;
border: 1px solid #ccc;
line-height: 20px;
padding: 5px;
outline: none;
}
// .g-wraper {
// width: 1000px;
// margin: 0 auto;
// color: #666;
// font-size: 16px;
// line-height: 30px;
// }
// .m-part {
// margin-bottom: 30px;
// }
// .m-part::after {
// content: "";
// display: block;
// clear: both;
// }
// .m-part .title {
// font-size: 30px;
// line-height: 60px;
// margin-bottom: 10px;
// color: #333;
// }
// .m-part .mapbox {
// width: 600px;
// height: 400px;
// margin-bottom: 20px;
// float: left;
// }
// .m-part .info {
// margin: 0;
// padding: 0;
// list-style: none;
// line-height: 30px;
// margin-left: 620px;
// }
// .m-part .info span {
// display: block;
// color: #999;
// }
// .m-part ol {
// line-height: 40px;
// margin-left: 0;
// padding-left: 0;
// }
// .m-part pre {
// padding: 10px 20px;
// line-height: 30px;
// border-radius: 3px;
// box-shadow: 0 0 15px rgba(0, 0, 0, 0.5);
// }
// .m-footer {
// background: #eee;
// line-height: 60px;
// text-align: center;
// color: #999;
// font-size: 12px;
// }
// .m-footer a {
// margin: 0 5px;
// color: #999;
// text-decoration: none;
// }
</style>
This diff is collapsed.
<template>
<div class="releaseProduc">
<h4 class="headTitle">发布活动</h4>
<el-steps
class="steps"
:active="active"
finish-status="success"
space="30%"
:align-center="true"
>
<el-step title="信息编辑"></el-step>
<el-step title="添加商品"></el-step>
<el-step title="拼单设置"></el-step>
</el-steps>
<div class="content">
<infoEditing
ref="infoEdit"
v-show="active === 1"
:editInfo="infoEditArr"
/>
<addProduc
ref="addProduc"
v-show="active === 2"
:editInfo="infoEditArr"
:addProduc="addProducArr"
/>
<spellOrderSet
ref="spellOrderSet"
v-show="active === 3"
:spellOrderSetArr="spellOrderSetArr"
:startTime1="startTime"
:endTime1="endTime"
@getTakeTakePlaceListFromChild="getTakeTakePlaceListFromChild"
/>
</div>
<div class="stepsBtn">
<el-button @click="prev" v-show="active >= 2" style="margin-right: 20px"
>上一步</el-button
>
<el-button @click="next" v-show="active < 3" style="margin-right: 20px"
>下一步</el-button
>
<el-button @click="cancel" v-show="active == 1">取消</el-button>
<el-button @click="confirmRelease" v-show="active == 3" type="primary"
>确认发布</el-button
>
</div>
</div>
</template>
<script>
import store from "../../../store/index";
import { ElMessage } from "element-plus";
import infoEditing from "./components/infoEditing.vue";
import addProduc from "./components/addProduc.vue";
import spellOrderSet from "./components/spellOrderSet.vue";
import {
addMarketing,
marketingInfo,
updateMarketing
} from "../../../service/Activity/index";
export default {
components: {
infoEditing,
addProduc,
spellOrderSet
},
data() {
return {
active: 1, // 步骤条状态
infoEditArr: [], // 信息编辑数据
addProducArr: [], // 添加商品
goodsSkuIDArr: [], // 接收goods_sku_id
spellOrderSetArr: [],
startDate: "", // 开始时间
endDate: "", // 结束时间
takePlaceIDArr: []
};
},
methods: {
// 上一步
prev() {
this.active--;
},
// 下一步
next() {
if (this.active === 1) {
if (this.$refs.infoEdit.infoEditForm.title == "") {
ElMessage.error("请填写商品标题");
return;
}
this.infoEditArr.title = this.$refs.infoEdit.infoEditForm.title;
this.active = 2;
} else if (this.active === 2) {
if (this.$refs.addProduc.comTableData.length == 0) {
ElMessage.error("请至少选择一个商品");
return;
}
this.addProducArr = this.$refs.addProduc.comTableData;
this.active = 3;
} else {
console.log();
}
// this.active++;
},
// 获取营销活动详情
async marketingInfoMet() {
let marketingId = this.$route.query.marketing_id;
if (marketingId == undefined) {
return;
}
let params = {
marketing_id: marketingId,
marketing_type: "4"
};
const res = await marketingInfo(params);
this.infoEditArr = res.result.marketing_info;
this.addProducArr = res.result.goods_list;
this.spellOrderSetArr = res.result.take_place;
this.startTime = res.result.marketing_info.start_time;
this.endTime = res.result.marketing_info.end_time;
localStorage.setItem("propData", JSON.stringify(this.infoEditArr));
},
// 取消
cancel() {
this.$router.go(-1);
},
// 确认发布
async confirmRelease() {
for (var i in this.addProducArr) {
this.goodsSkuIDArr.push(this.addProducArr[i].goods_sku_id);
}
this.startDate = this.$refs.spellOrderSet.startDate;
this.endDate = this.$refs.spellOrderSet.endDate;
let params = {
marketing_id:
this.$route.query.marketing_id == undefined
? ""
: this.$route.query.marketing_id,
goods_sku_id: this.goodsSkuIDArr.join(","),
marketing_name: this.$refs.infoEdit.infoEditForm.title,
marketing_type: "4",
op_cur_user: store.state.userInfo.email,
start_time: this.startDate,
end_time: this.endDate,
pindan_pic: this.$refs.infoEdit.infoEditForm.picUploadList.join(","),
pindan_desc: this.$refs.infoEdit.infoEditForm.desc,
take_place_ids: this.takePlaceIDArr
};
if (this.$route.query.marketing_id == undefined) {
const res = await addMarketing(params);
if (res.code === 0) {
ElMessage.success({
message: "添加成功",
type: "success"
});
this.$router.push({ path: "/op/activity/manage" });
} else {
ElMessage.error(res.reason);
}
} else {
const res = await updateMarketing(params);
if (res.code === 0) {
ElMessage.success({
message: "修改成功",
type: "success"
});
this.$router.push({ path: "/op/activity/manage" });
} else {
ElMessage.error(res.reason);
}
}
},
getTakeTakePlaceListFromChild(val) {
this.takePlaceIDArr = val;
}
},
created() {
this.marketingInfoMet();
}
};
</script>
<style scope>
.releaseProduc {
padding: 30px;
box-sizing: border-box;
}
.headTitle {
width: 75%;
font-size: 18px;
margin: 0 auto 40px auto;
}
.steps {
display: flex;
justify-content: center;
margin-bottom: 50px;
}
.steps /deep/ .el-step__icon {
width: 50px;
height: 50px;
}
.steps /deep/ .el-step.is-horizontal .el-step__line {
top: 25px;
}
.stepsBtn {
margin: 20px auto;
}
.stepsBtn {
width: 64%;
text-align: center;
margin-top: 50px;
}
</style>
...@@ -381,6 +381,14 @@ ...@@ -381,6 +381,14 @@
></el-input> ></el-input>
<span v-else>{{ goodsObj.original_price }}</span> <span v-else>{{ goodsObj.original_price }}</span>
</el-form-item> </el-form-item>
<el-form-item label="结算价">
<el-input
v-if="$route.params.operation === 'EDIT'"
v-model="goodsObj.clear_price"
@change="perPrice"
></el-input>
<span v-else>{{ goodsObj.clear_price }}</span>
</el-form-item>
<h4 style="margin:20px 0">库存信息</h4> <h4 style="margin:20px 0">库存信息</h4>
<el-form-item label="剩余库存量:"> <el-form-item label="剩余库存量:">
<span>{{ goodsObj.inventory_rest }}</span> <span>{{ goodsObj.inventory_rest }}</span>
...@@ -1167,21 +1175,12 @@ export default { ...@@ -1167,21 +1175,12 @@ export default {
}, },
// 更改原价 // 更改原价
perPrice () { perPrice (val) {
if (!this.goodsObj.original_price || this.goodsObj.original_price == 0) { if (val.length === 0) val = 0;
this.$nextTick(() => { const parseOriginalPrice = Number(val).toFixed(2);
this.goodsObj.original_price = ""; val = Number(parseOriginalPrice);
}) if (typeof val === "number" &&isNaN(val)) {
} val = 0;
const parseOriginalPrice = Number(this.goodsObj.original_price).toFixed(
2
);
this.goodsObj.original_price = Number(parseOriginalPrice);
if (
typeof this.goodsObj.original_price === "number" &&
isNaN(this.goodsObj.original_price)
) {
this.goodsObj.original_price = "";
return this.$message.error("原价价格必为数字"); return this.$message.error("原价价格必为数字");
} }
}, },
...@@ -1300,6 +1299,10 @@ export default { ...@@ -1300,6 +1299,10 @@ export default {
} }
console.log(query); console.log(query);
// 是否该商品关联的分销活动满足售价-分销总金额>=结算价
// if (query.price - d >= query.clear_price) {
// return this.$message.error("请至少选择一个门店");
// }
const res = await editGoods(query); const res = await editGoods(query);
if (res.code !== 0) { if (res.code !== 0) {
......
...@@ -200,6 +200,17 @@ ...@@ -200,6 +200,17 @@
></el-input> ></el-input>
<div style="margin: 20px 0"></div> <div style="margin: 20px 0"></div>
</el-form-item> </el-form-item>
<el-form-item
prop="commission_mode"
label="金额计算方式:"
>
<el-radio-group
v-model="countType"
>
<el-radio :label="2">按金额</el-radio>
<el-radio :label="1">按比例</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="上线佣金:" prop="first_commission_value"> <el-form-item label="上线佣金:" prop="first_commission_value">
<el-input <el-input
v-model="ruleForm.first_commission_value" v-model="ruleForm.first_commission_value"
...@@ -207,7 +218,7 @@ ...@@ -207,7 +218,7 @@
@input="changeValue($event, 'first_commission_value')" @input="changeValue($event, 'first_commission_value')"
:disabled="shopStart !== 0" :disabled="shopStart !== 0"
> >
<template #append>%</template> <template #append>{{countType == 1? '%' : '¥'}}</template>
</el-input> </el-input>
</el-form-item> </el-form-item>
<el-form-item label="分享者佣金: " prop="second_commission_value"> <el-form-item label="分享者佣金: " prop="second_commission_value">
...@@ -217,7 +228,7 @@ ...@@ -217,7 +228,7 @@
@input="changeValue($event, 'second_commission_value')" @input="changeValue($event, 'second_commission_value')"
:disabled="shopStart !== 0" :disabled="shopStart !== 0"
> >
<template #append>%</template> <template #append>{{countType == 1? '%' : '¥'}}</template>
</el-input> </el-input>
</el-form-item> </el-form-item>
<el-form-item label="活动生效时间:"> <el-form-item label="活动生效时间:">
...@@ -358,10 +369,11 @@ export default { ...@@ -358,10 +369,11 @@ export default {
data() { data() {
var commission = (rule, value, callback) => { var commission = (rule, value, callback) => {
if ( if (
this.ruleForm.first_commission_value + this.countType == 1 &&
(this.ruleForm.first_commission_value +
this.ruleForm.second_commission_value > this.ruleForm.second_commission_value >
50 || 50 ||
value > 50 value > 50 )
) { ) {
callback(new Error("上线佣金与分享者佣金之和不可大于50%")); callback(new Error("上线佣金与分享者佣金之和不可大于50%"));
} else { } else {
...@@ -438,6 +450,7 @@ export default { ...@@ -438,6 +450,7 @@ export default {
marketing_id: "", marketing_id: "",
marketing_info: {}, marketing_info: {},
disabled: false, disabled: false,
countType: 2
}; };
}, },
methods: { methods: {
......
...@@ -368,11 +368,9 @@ export default { ...@@ -368,11 +368,9 @@ export default {
const { selectActivity, multipleSelection } = this; const { selectActivity, multipleSelection } = this;
const uids = multipleSelection.map((item) => item.deliverer_id); const uids = multipleSelection.map((item) => item.deliverer_id);
if (!selectActivity) return ElMessage("请选择活动姓名"); if (!selectActivity) return ElMessage("请选择活动姓名");
// if (!uids.length) return this.$message.info("请至少选择一名骑手");
try { try {
const {code, reason} = await getSaveDeliverer({ code: selectActivity, uids: uids.join(",") }); await getSaveDeliverer({ code: selectActivity, uids: uids.join(",") });
if(code !== 0) return this.$message.error(reason || (this.isEdit ? "修改配送员失败":"分配配送员失败")) ElMessage("分配配送员成功");
ElMessage(this.isEdit ? "修改配送员成功":"分配配送员成功");
this.dialogFormAssign = false; this.dialogFormAssign = false;
this.isEdit = false; this.isEdit = false;
this.getList(); this.getList();
......
/**
* 活动管理
*/
const activityRouters = [
{
path: "/op/activity",
redirect: "/op/activity/manage"
},
{
path: "/op/activity/manage",
name: "ManageList",
component: () =>
import(/* webpackChunkName: "activity" */ "@/pages/Activity/Manage")
},
// 发布拼单
{
path: "/op/activity/releaseProduc",
name: "releaseProduc",
component: () =>
import(
/* webpackChunkName: "activity" */ "@/pages/Activity/releaseProduc"
)
},
// 标题详情
{
path: "/op/activity/activityDetail",
name: "ActivityDetail",
component: () =>
import(
/* webpackChunkName: "activity" */ "@/pages/Activity/ActivityDetail"
)
},
{
path: "/op/activity/releaseProduc/spellOrderSet",
name: "spellOrderSet",
component: () =>
import(
/* webpackChunkName: "activity" */ "@/pages/Activity/releaseProduc/components/spellOrderSet"
)
}
];
export default activityRouters;
...@@ -12,6 +12,8 @@ import RoleDetail from "../pages/Role/role-detail.vue"; ...@@ -12,6 +12,8 @@ import RoleDetail from "../pages/Role/role-detail.vue";
import goodsRouter from "./Goods/index"; import goodsRouter from "./Goods/index";
import withdrawalRoutes from "./Withdrawal/index"; import withdrawalRoutes from "./Withdrawal/index";
import groupmealRouters from "./Groupmeal/index"; import groupmealRouters from "./Groupmeal/index";
import activityRouters from "./Activity/index";
const routes = [ const routes = [
{ {
path: "/op/enterprise", path: "/op/enterprise",
...@@ -99,7 +101,9 @@ const routes = [ ...@@ -99,7 +101,9 @@ const routes = [
// 钱包审核 // 钱包审核
...withdrawalRoutes, ...withdrawalRoutes,
// 团餐运营 // 团餐运营
...groupmealRouters ...groupmealRouters,
// 活动管理路由
...activityRouters
]; ];
console.log(routes); console.log(routes);
......
import axios from "@/utils/request";
// 获取商家列表
export async function getBusinessList(params) {
const res = await axios.get("/api/v1/goods/background/ota_list", {
params
});
return res;
}
// 添加商品
export async function addGoods(params) {
const res = await axios.post("/api/v1/goods/background/add_goods", params);
return res;
}
// 商品库列表
export async function pindanGoods(params) {
const res = await axios.get("/api/v1/goods/background/pindan_goods", {
params
});
return res;
}
// 查看商品详情
export async function markGoodsInfo(params) {
const res = await axios.get("/api/v1/goods/background/marketing_goods_info", {
params
});
return res;
}
// 编辑商品详情
export async function editGoods(params) {
const res = await axios.post("/api/v1/goods/background/edit_goods", params);
return res;
}
// 添加营销活动
export async function addMarketing(params) {
const res = await axios.post(
"/api/v1/marketing/background/add_marketing",
params
);
return res;
}
// 编辑营销活动
export async function updateMarketing(params) {
const res = await axios.post(
"/api/v1/marketing/background/update_marketing",
params
);
return res;
}
// 营销活动详情
export async function marketingInfo(params) {
const res = await axios.post(
"/api/v1/marketing/background/marketing_info",
params
);
return res;
}
class ActivityService {
// 获取活动列表
static async getActivityList(params) {
const res = await axios.get("/api/v1/marketing/background/marketing_list", {
params
});
return res;
}
// 修改商品
static async editGoodsDetail(query) {
const res = await axios.post("/api/v1/goods/background/edit_goods", {
...query
});
return res;
}
// 关闭/开启 活动
static async updateActivity(query) {
const res = await axios.post(
"/api/v1/marketing/background/update_marketing",
{
...query
}
);
return res;
}
// 查看活动订单
static async checkActivityDetail(query) {
const res = await axios.post(
"/api/v1/marketing/background/marketing_info",
{
...query
}
);
return res;
}
// 查看活动订单-- 具体信息(新添加)
static async checkActivityDetailInfo(params) {
const res = await axios.get(
"/api/v1/order/background/pindan_marketing_info_data_statistics",
{
params
}
);
return res;
}
// 获取自提点列表
static async getPlaceList(params) {
const res = await axios.get(
"/api/v1/marketing/background/take_place_list",
{
params
}
);
return res;
}
// 添加自提点
static async addPlace(query) {
const res = await axios.post(
"/api/v1/marketing/background/add_take_place",
{
...query
}
);
return res;
}
//删除自提点
static async deletePlace(query) {
const res = await axios.post(
"/api/v1/marketing/background/delete_take_place",
{
...query
}
);
return res;
}
}
export default ActivityService;
export default function remoteLoad(url, hasCallback) {
return createScript(url);
/**
* 创建script
* @param url
* @returns {Promise}
*/
function createScript(url) {
let scriptElement = document.createElement("script");
document.body.appendChild(scriptElement);
let promise = new Promise((resolve, reject) => {
scriptElement.addEventListener(
"load",
e => {
removeScript(scriptElement);
if (!hasCallback) {
resolve(e);
}
},
false
);
scriptElement.addEventListener(
"error",
e => {
removeScript(scriptElement);
reject(e);
},
false
);
if (hasCallback) {
window.____callback____ = function() {
resolve();
window.____callback____ = null;
};
}
});
if (hasCallback) {
url += "&callback=____callback____";
}
scriptElement.src = url;
return promise;
}
/**
* 移除script标签
* @param scriptElement script dom
*/
function removeScript(scriptElement) {
document.body.removeChild(scriptElement);
}
}
import axios from "axios"; import axios from "axios";
import store from "@/store" import store from "@/store";
import { v1 as uuidv1 } from 'uuid'; import { v1 as uuidv1 } from "uuid";
// import jsonBig from 'json-bigint' // import jsonBig from 'json-bigint'
// import { ElMessage } from "element-plus"; // import { ElMessage } from "element-plus";
...@@ -32,17 +32,16 @@ export const defaultConfig = { ...@@ -32,17 +32,16 @@ export const defaultConfig = {
*/ */
const getDefaultParams = () => { const getDefaultParams = () => {
return { return {
'op_cur_user': store.state.userInfo && store.state.userInfo.email, op_cur_user: store.state.userInfo && store.state.userInfo.email,
'reqid': uuidv1().replace(/-/g, '') reqid: uuidv1().replace(/-/g, "")
};
}
}; };
const getDefaultHeaders = (config) => { const getDefaultHeaders = config => {
const { method } = config; const { method } = config;
if (method.toLowerCase() === 'post') { if (method.toLowerCase() === "post") {
return { return {
"Content-Type": "application/json" "Content-Type": "application/json"
} };
} }
}; };
...@@ -56,7 +55,7 @@ const instance = axios.create(defaultConfig); ...@@ -56,7 +55,7 @@ const instance = axios.create(defaultConfig);
* axios instance interceptors * axios instance interceptors
*/ */
instance.interceptors.request.use( instance.interceptors.request.use(
function (config) { function(config) {
// network error // network error
if (navigator.onLine !== undefined && navigator.onLine === false) { if (navigator.onLine !== undefined && navigator.onLine === false) {
return Promise.reject({ message: "网络未链接", code: -1 }); return Promise.reject({ message: "网络未链接", code: -1 });
...@@ -65,7 +64,7 @@ instance.interceptors.request.use( ...@@ -65,7 +64,7 @@ instance.interceptors.request.use(
/** /**
* merge headers * merge headers
*/ */
config.headers = { ...getDefaultHeaders(config), ...config.headers } config.headers = { ...getDefaultHeaders(config), ...config.headers };
/** /**
* merge params * merge params
...@@ -74,7 +73,7 @@ instance.interceptors.request.use( ...@@ -74,7 +73,7 @@ instance.interceptors.request.use(
return config; return config;
}, },
function (error) { function(error) {
// handle error // handle error
return Promise.reject(error); return Promise.reject(error);
} }
...@@ -84,7 +83,7 @@ instance.interceptors.request.use( ...@@ -84,7 +83,7 @@ instance.interceptors.request.use(
* axios response instance * axios response instance
*/ */
instance.interceptors.response.use( instance.interceptors.response.use(
function (response) { function(response) {
const { data = {} } = response; const { data = {} } = response;
// const code = data.code ?? -1; // const code = data.code ?? -1;
// if (code !== 0) { // if (code !== 0) {
...@@ -106,8 +105,7 @@ instance.interceptors.response.use( ...@@ -106,8 +105,7 @@ instance.interceptors.response.use(
// return data; // return data;
// } // }
return data; return data;
}
},
// function (error) { // function (error) {
// if (!(error.code && error.code === -1)) error.message = "接口请求错误"; // if (!(error.code && error.code === -1)) error.message = "接口请求错误";
// showErrorMessage(error.message); // showErrorMessage(error.message);
......
const path = require('path'); const path = require("path");
const isDev = process.env.NODE_ENV === 'development'; const isDev = process.env.NODE_ENV === "development";
module.exports = { module.exports = {
outputDir: isDev outputDir: isDev ? "./dist" : path.resolve("./public/dist/"),
? './dist' publicPath: isDev ? "/" : "/dist",
: path.resolve('./public/dist/'),
publicPath: isDev ? '/' : '/dist',
configureWebpack: { configureWebpack: {
devServer: { devServer: {
proxy: 'http://localhost:8055', proxy: "http://127.0.0.1:8055", //http://localhost:8055
hot: true, hot: true,
disableHostCheck: true, disableHostCheck: true
}, }
}, },
chainWebpack: config => { chainWebpack: config => {
// 默认不开启 prefetch // 默认不开启 c
config.plugins.delete('prefetch'); config.plugins.delete("prefetch");
// 默认不开启 preload // 默认不开启 preload
config.plugins.delete('preload'); config.plugins.delete("preload");
// 修改页面 title // 修改页面 title
config.plugin('html').tap(args => { config.plugin("html").tap(args => {
args[0].title = '运营管理系统'; args[0].title = "运营管理系统";
return args; return args;
}); });
}, }
}; };
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment