first commit

This commit is contained in:
wtq
2025-11-12 09:47:04 +08:00
commit f759c3a7c3
1182 changed files with 447658 additions and 0 deletions

113
src/components/Index.vue Normal file
View File

@@ -0,0 +1,113 @@
<template>
<div class="body">
<el-container>
<el-header class="index-header">
<TopBar></TopBar>
</el-header>
<el-container>
<el-aside :class="{'index-aside': true, 'index-aside-fold': fold}">
<el-button size="mini" class="fold" @click="handleFold">{{fold ? '' : ''}}</el-button>
<LeftBar v-if="userInfo"></LeftBar>
</el-aside>
<el-main class="index-main">
<el-scrollbar
wrap-class="content-scroll-area"
:native="false"
>
<transition name="fade">
<router-view v-if="$store.state.isRouterAlive"></router-view>
</transition>
</el-scrollbar>
</el-main>
</el-container>
</el-container>
</div>
</template>
<script>
import LeftBar from './menu/leftbarnew.vue'
import TopBar from './menu/topbar.vue'
import { mapGetters } from 'vuex'
export default {
name: 'Index',
components: {
LeftBar,
TopBar
},
data() {
return {
// isRouterAlive: true
fold: false
}
},
computed: {
...mapGetters({
userInfo: 'userInfo'
})
},
methods: {
// reload () {
// this.isRouterAlive = false
// this.$nextTick(() => (this.isRouterAlive = true))
// }
handleFold() {
this.fold = !this.fold
}
},
}
</script>
<style lang="scss">
.body {
background: #f5f5f5;
.el-header,
.el-main,
.el-aside {
padding: 0;
}
.el-header {
box-shadow: 0 1px 3px rgba(#ccc, 0.5);
}
.el-container {
// height: calc(100vh - 61px);
padding: 0;
margin: 0;
}
.index-header {
margin-bottom: 2px;
}
.index-aside {
width: 231px !important; // 50
height: calc(100vh - 63px);
position: relative;
transition: all 0.3s;
overflow: hidden;
}
.index-aside-fold {
width: 42px !important;
}
.index-main {
height: calc(100vh - 63px);
overflow: hidden;
}
.content-scroll-area {
max-height: calc(100vh - 63px);
}
.fold {
position: absolute;
right: 0;
top: 14px;
z-index: 1;
border-radius: 0;
border: 1px solid #e6e6e6;
border-right: none;
border-top-left-radius: 100px;
border-bottom-left-radius: 100px;
color: #ccc;
}
}
</style>

View File

@@ -0,0 +1,447 @@
<template>
<div class="afsOrder-detail baselayout">
<!-- order.storeName -->
<h2 style="color:#409EFF;">
售后单详情-{{afsOrderStatus || ''}}
<div class="status-155" v-if="afsOrder.status === 155">
<el-button :disabled="(afsOrder.flag & 3) !== 0" size="mini" type="danger" @click="handleAgreeOrRefuse(3, afsOrder)">驳回{{(afsOrder.flag & 3) === 3 ? '(已操作)' : ''}}</el-button>
<el-button :disabled="(afsOrder.flag & 3) !== 0" size="mini" type="primary" @click="handleAgreeOrRefuse(1, afsOrder)">退款{{(afsOrder.flag & 3) === 1 ? '(已操作)' : ''}}</el-button>
</div>
<div v-if="afsOrder.status === 165">
<el-button :disabled="(afsOrder.flag & 4) !== 0" size="mini" type="primary" @click="handleReceiveGoods(afsOrder)">收到退货{{(afsOrder.flag & 4) === 4 ? '(已操作)' : ''}}</el-button>
</div>
</h2>
<div class="wrapper">
<div class="wrapper-left">
<div class="top">
<!-- 门店名称 -->
<div @click="goStore" class="link" style="width: 48%">{{order.storeName}}({{order.deliveryType === 'self' ? order.jxStoreID : afsOrder.jxStoreID}})</div>
<!-- 售后单号 -->
<div style="width: 48%">售后单号: <b>{{afsOrder.afsOrderID}}</b></div>
<!-- 订单号 -->
<div style="width: 48%">
<router-link class="link" :to="'/ordermanager/' + afsOrder.vendorOrderID" target="_blank">
订单号: <b>{{afsOrder.vendorOrderID}}({{vendorName}})</b>
</router-link>
</div>
<!-- 售后方式 -->
<div style="width: 48%">售后方式: <b>{{afsAppealTypeName}}</b></div>
</div>
<div class="top">
<div style="width: 28%">售后状态: <b>{{afsOrderStatus}}</b></div>
<div style="width: 68%">售后描述: <b>{{afsOrder.reasonDesc}}</b></div>
</div>
<div class="img-wrapper">
<div>图片描述: </div>
<div class="img">
<img @click="showImg(url)" v-for="(url, index) in imgList" :src="url" :key="index">
</div>
</div>
<h4>客户信息</h4>
<div class="top">
<!-- 申请时间 -->
<div style="width: 98%;">申请时间<b v-if="afsOrder.afsCreatedAt">{{afsOrder.afsCreatedAt | timeToLLL}}</b></div>
<!-- 申请人 -->
<div style="width: 34%">申请人: <b>{{ order.deliveryType === 'self' ? '' : order.consigneeName}}</b></div>
<!-- 联系方式 -->
<div style="width: 62%;">临时号:<b>{{order.deliveryType === 'self' ? '' : order.consigneeMobile}}</b> &emsp;&emsp;真实号:<b>{{ order.deliveryType === 'self' ? '' : order.consigneeMobile2 || '暂无'}}</b></div>
<div style="width: 98%;">地址: {{ order.deliveryType === 'self' ? '' : order.consigneeAddress}}</div>
<div style="width: 98%;">备注: {{ comment }}</div>
</div>
<h4 v-if="order.deliveryType !== 'self'">快递信息</h4>
<!-- <div class="devider"></div> -->
<div class="top" v-if="order.deliveryType !== 'self'">
<!-- 快递信息 -->
<!-- 物流 -->
<div style="width: 30%">物流:<b>{{$store.state.serverInfo.vendorName[order.waybillVendorID] || '自送'}}</b></div>
<div style="width: 66%">运单号: <b>{{order.vendorWaybillID}}</b></div>
<div style="width: 30%">配送员: <b>{{order.courierName}}</b></div>
<div style="width: 66%">电话: <b>{{order.courierMobile}}</b></div>
</div>
<h4>商品信息</h4>
<!-- 商品信息 -->
<div class="goods-info">
<div class="left">
<div class="title">该单商品( <b>{{order.skuCount}}</b> <b>{{order.goodsCount}}</b> )</div>
<div class="price">
京西:<b>{{(order.shopPrice / 100).toFixed(2)}}</b>&nbsp;
售卖:<b>{{(order.salePrice / 100).toFixed(2)}}</b>&nbsp;
<!-- 平台:<b>{{(order.vendorPrice / 100).toFixed(2)}}</b>&nbsp; -->
实付:<b>{{(order.actualPayPrice / 100).toFixed(2)}}</b>&nbsp;
订单优惠:<b>{{(order.discountMoney / 100).toFixed(2)}}</b>&nbsp;
配送费:<b>{{(order.desiredFee / 100).toFixed(2)}}</b>&nbsp;
</div>
<div class="price">
门店收益:<b>{{computedStoreEarning}}</b>&nbsp;
平台结算(含补贴):<b>{{(order.totalShopMoney / 100).toFixed(2)}}</b>&nbsp;
</div>
<div class="price">
平台补贴:<b>{{(order.pmSubsidyMoney / 100).toFixed(2)}}</b>&nbsp;
预计收益:<b>{{computedJxEarning}}</b>&nbsp;
</div>
<!-- skulist -->
<div class="sku-list" v-loading="!orderSkus">
<div v-for="(item, index) in orderSkus" :key="index" class="sku-item">
<div class="left">
<img :src="item.image.split('?')[0] + '?imageView2/1/w/60/h/60'" class="cpt" @click="imgPreview(item.image.split('?')[0])">
</div>
<div class="center">
<div>(skuID: {{item.skuID}}) {{item.skuName}}</div>
<div style="margin-top: 5px;">
<span>京西:{{(item.shopPrice / 100).toFixed(2)}}</span>
<span style="margin-left: 10px;">售卖:{{(item.salePrice / 100).toFixed(2)}}</span>
<!-- <span style="margin-left: 10px;">平台:{{(item.vendorPrice / 100).toFixed(2)}}</span> -->
</div>
<div v-if="!isNewPriceDisplay && (order.payPercentage > 50 && isGY)">
<span>活动结算:{{item.storeSubID ? (item.earningPrice / 100).toFixed(2) : 0}}</span>
<span>结算:{{(item.earningPrice / 100).toFixed(2)}}</span>
</div>
</div>
<div class="right">
<span>X{{item.count}}</span>
<el-button icon="el-icon-search" type="text" @click="goStoreSku(item.skuID)"></el-button>
</div>
</div>
</div>
</div>
<div class="right">
<div class="title">售后商品</div>
<!-- <div class="price">退换商品金额: <b>{{(afsOrder.skuUserMoney / 100).toFixed(2)}}</b></div> -->
<!-- skulist -->
<div class="sku-list" v-loading="!orderSkus">
<div v-for="(item, index) in afsOrderSkus" :key="index" class="sku-item">
<div class="left">
<img class="cpt" @click="imgPreview(item.image.split('?')[0])" :src="item.image.split('?')[0] + '?imageView2/1/w/60/h/60'">
</div>
<div class="center">
<div>(skuID: {{item.skuID}}) {{item.name}}</div>
<div style="margin-top: 5px;">
<span>{{item.shopPrice / 100}}</span>
</div>
</div>
<div class="right">
<span>X{{item.count}}</span>
<el-button icon="el-icon-search" type="text" @click="goStoreSku(item.skuID)"></el-button>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="wrapper-right">
<div class="table-wrapper">
<OrderStatus :orderStatus="orderStatus"></OrderStatus>
</div>
</div>
</div>
</div>
</template>
<script>
/* eslint-disable */
import api from '@/utils/api'
import {
getOrderSkus,
apiGetOrder,
apiGetAfsOrders
} from '@/apis/controls/order'
import {showLoad, hideLoad} from '@/tools/loading'
import moment from 'moment'
moment.locale('zh-cn')
import OrderStatus from './cmp/cmp-order-status'
import {getOneStore} from '@/apis/controls/shop.js'
import imgPreview from '@/tools/imgPreview.js'
import {mapGetters} from 'vuex'
import {isGY} from '@/utils/api'
/* eslint-disable */
export default {
name: 'AfsOrderDetail',
components: {
OrderStatus
},
data () {
return {
afsOrderID: '',
order: {},
afsOrder: {},
orderSkus: [],
afsOrderSkus: [],
storeInfo: {},
orderStatus: []
}
},
computed: {
...mapGetters({
isNewPriceDisplay: 'isNewPriceDisplay'
}),
isGY: () => isGY,
// 售后类型
afsAppealTypeName () {
let serverInfo = this.$store.getters.serverInfo || {}
return serverInfo.afsAppealTypeName ? serverInfo.afsAppealTypeName[this.afsOrder.appealType] : ''
},
// 售后状态
afsOrderStatus () {
let serverInfo = this.$store.getters.serverInfo || {}
let orderStatus = serverInfo.orderStatus || {}
return orderStatus[this.afsOrder.status] || ''
},
imgList () {
return this.afsOrder.reasonImgList ? this.afsOrder.reasonImgList.split(',') : []
},
vendorName () {
let serverInfo = this.$store.getters.serverInfo || {}
return serverInfo.vendorName[this.afsOrder.vendorID] || ''
},
computedStoreEarning () {
const storeInfo = this.storeInfo
const order = this.order
if (storeInfo) {
if (!this.isNewPriceDisplay) {
if (!(storeInfo.payPercentage >= 50 && storeInfo.payPercentage <= 100)) {
// 小于50
return ((order.totalShopMoney - order.desiredFee) * (100 - storeInfo.payPercentage / 2) / 100 / 100).toFixed(2)
} else {
// 大于等于50
return (order.earningPrice / 100).toFixed(2)
}
} else {
return (order.shopPrice / 100).toFixed(2)
}
} else {
return '--'
}
},
computedJxEarning () {
const storeInfo = this.storeInfo
const order = this.order
if (storeInfo) {
if (!this.isNewPriceDisplay) {
if (!(storeInfo.payPercentage >= 50 && storeInfo.payPercentage <= 100)) {
// 小于50
// 预计收益=平台结算*门店结算比例/200
return (order.totalShopMoney * storeInfo.payPercentage / 200 / 100).toFixed(2)
} else {
// 大于50
// 预计收益=平台结算-配送费-预计收益(-远距离配送费-京西已加小费 - order.distanceFreightMoney - order.waybillTipMoney)
return ((order.totalShopMoney - order.desiredFee - order.earningPrice) / 100).toFixed(2)
}
} else {
return ((order.totalShopMoney - order.desiredFee - order.shopPrice - order.distanceFreightMoney) / 100).toFixed(2)
}
} else {
return '--'
}
},
comment(){
if(this.order.buyerComment === '支付方式:扫码枪' || this.order.buyerComment === '支付方式cashPay') return ''
return this.order.buyerComment
}
},
async created () {
const afsOrderID = this.$route.params.id
this.afsOrderID = afsOrderID
try {
// 获取售后单信息
await this.getAfsOrder()
// 获取售后单商品信息
await this.getAfsOrderSkus()
// 获取订单信息
await this.getOrder()
// 订单商品信息
await this.getOrderSkus()
// 获取订单序列
await this.getOrderStatus()
// 获取门店信息
let {stores} = await getOneStore(this.order.jxStoreID ? this.order.jxStoreID : this.order.storeID, true)
this.storeInfo = stores[0]
} catch (e) {
this.$message({
message: '请求出错,请刷新重试',
type: 'error',
center: true
})
} finally {
hideLoad()
}
},
methods: {
// 获取订单信息
async getOrder () {
let res = await apiGetOrder({vendorOrderID:this.afsOrder.vendorOrderID})
if(res.data) this.order = res.data[0]
},
// 获取售后单信息
async getAfsOrder () {
let { data } = await apiGetAfsOrders({ afsOrderID:this.afsOrderID})
this.afsOrder = data[0]
},
// 订单商品信息
async getOrderSkus () {
let data = await getOrderSkus(this.afsOrder.vendorOrderID,this.afsOrder.vendorID)
this.orderSkus = data
},
// 获取售后单商品信息
async getAfsOrderSkus () {
let data = await api(`v2/order/GetAfsOrderSkuInfo?afsOrderID=${this.afsOrderID}&vendorID=${this.afsOrder.vendorID}`)
this.afsOrderSkus = data
},
// 获取门店信息
async getStoreInfo () {
let {data} = await api(`v2/store/GetStores?storeID=${this.afsOrder.jxStoreID}`)
this.storeInfo = data
},
// 获取售后单序列
async getOrderStatus () {
let data = await api(`v2/order/GetOrderStatusList?vendorOrderID=${this.afsOrder.vendorOrderID}&vendorID=${this.afsOrder.vendorID}&orderType=3`)
// 过滤 orderType === 2 运单
// this.orderStatus =this.afsOrder.vendorID !== 16?data.filter(item => item.vendorOrderID === this.afsOrder.afsOrderID) : data // .filter(item => item.orderType !== 2)
this.orderStatus = data.filter(item => item.vendorOrderID === this.afsOrder.afsOrderID) // .filter(item => item.orderType !== 2)
// let arr = data.map(item => `${item.vendorOrderID},${item.orderType}`)
// this.statusList = Array.from(new Set(arr))
},
// 跳转到门店
goStore () {
// this.$router.push('/455555')
let routeData = this.$router.resolve({
name: 'JxStoreManager',
query: {storeID: this.order.jxStoreID ? this.order.jxStoreID : this.order.storeID}
})
window.open(routeData.href, '_blank')
},
// 显示大图
showImg (url) {
this.$msgbox({
title: '',
message: `<div style="padding: 0 20px;"><img class="big-img" src="${url}" width="100%"></div>`,
dangerouslyUseHTMLString: true,
showCancelButton: false,
showConfirmButton: false,
showCancel: true
})
},
// 退款或驳回
async handleAgreeOrRefuse (type, afsOrder) {
if (type === 1) {
// 退款处理
try {
await this.$confirm('是否进行退款处理', '提示', {type: 'warning'})
// 确定
this.apiDealAfs(type, '同意退款', afsOrder)
} catch (e) {
// 取消
}
} else if (type === 3) {
try {
let res = await this.$prompt('请输入驳回理由', '提示', {
inputValidator: (str) => {
if (!str || !str.trim()) return false
return true
},
inputErrorMessage: '理由不能为空'
})
let {value} = res // 理由
// 确定
this.apiDealAfs(type, value, afsOrder)
} catch (e) {
// 取消
}
}
},
// 处理售后订单
async apiDealAfs (type, reason, afsOrder) {
try {
showLoad()
let form = new FormData()
form.append('afsOrderID', afsOrder.afsOrderID)
form.append('vendorID', afsOrder.vendorID)
form.append('approveType', type)
form.append('reason', reason)
if(type === 1 && this.afsOrder.vendorID === 3){
form.append('vendorOrderID', this.afsOrder.vendorOrderID)
form.append('refundSkuList', JSON.stringify(this.afsOrderSkus))
// // 饿百退款处理
// await api('v2/order/PartRefundOrder', {
// method: 'PUT',
// data: form
// })
}
// else {
// await api('v2/order/AgreeOrRefuseRefund', {
// method: 'PUT',
// data: form
// })
// }
await api('v2/order/AgreeOrRefuseRefund', {
method: 'PUT',
data: form
})
// 成功
this.$message({
message: '操作成功',
type: 'success',
center: true
})
afsOrder.flag = type === 1 ? 1 : 3
afsOrder.refuseReason = reason
} catch (e) {
// 失败
this.$message({
message: e,
type: 'error',
center: true
})
} finally {
hideLoad()
}
},
// 收到退货
async handleReceiveGoods (afsOrder) {
try {
await this.$confirm('是否确认收到退货', '提醒')
this.apiReceiveGoods(afsOrder)
} catch (e) {
console.log(e)
}
},
imgPreview (src) {
imgPreview(src)
},
// 收到退款api
async apiReceiveGoods (afsOrder) {
try {
showLoad()
let form = new FormData()
form.append('afsOrderID', afsOrder.afsOrderID)
form.append('vendorID', afsOrder.vendorID)
await api('v2/order/ConfirmReceivedReturnGoods', {
method: 'PUT',
data: form
})
afsOrder.flag = 4
} catch (e) {
this.$message({
message: e,
type: 'error',
center: true
})
} finally {
hideLoad()
}
},
// 跳转到门店商品
goStoreSku (skuID) {
let routeData = this.$router.resolve({
name: 'StoreGoodsManager',
query: {storeID: this.order.jxStoreID, skuID}
})
window.open(routeData.href, '_blank')
}
}
}
</script>
<style lang="sass" scoped>
@import './afs-order-manager';
</style>

View File

@@ -0,0 +1,193 @@
// 售后单管理
.afsOrder-manager {
overflow-x: auto;
min-height: calc(100vh - 130px);
min-width: auto !important;
.scroll-box {
height: calc(100vh - 310px);
@media screen and (max-width: 1830px) {
// height: calc(100vh - 310px);
}
}
.max-width {
width: 1300px;
overflow-x: auto;
// overflow: auto;
}
.page {
text-align: center;
margin-top: 10px;
}
.afs-order-table {
td {
padding: 5px 0;
}
}
.afs-order-id {
display: flex;
align-items: center;
line-height: 1.3;
div:nth-of-type(1) {
margin-right: 10px;
// border-right: 1px solid #ccc;
}
}
.afs-order-id-detail {
a {
cursor: pointer;
text-decoration: none;
color: #606266;
&:hover {
color: #409EFF;
text-decoration: underline;
}
}
}
.focusColor {
color: #E6A23C;
}
.operate-wall {
button {
cursor: pointer;
padding: 5px 0;
}
}
}
// 售后单详情
$width: 1400px;
.afsOrder-detail {
overflow: auto;
min-height: calc(100vh - 130px);
min-width: $width;
h2 {
display: flex;
align-items: center;
div {
margin-left: 40px;
}
}
.wrapper {
min-width: $width;
display: flex;
// background: orange;
.wrapper-left {
width: 800px;
box-sizing: border-box;
// overflow: auto;
}
.wrapper-right {
// flex: 1;
// max-width: $width - 800px;
// height: 300px;
width: 100%;
box-sizing: border-box;
padding: 0 10px;
min-width: 230px;
// width: 600px;
// background: red;
.table-wrapper {
width: 95%;
}
}
}
.top {
display: flex;
flex-flow: row wrap;
justify-content: space-between;
color: #303133;
align-items: center;
div {
// width: 23%;
margin-bottom: 20px;
margin-right: 2%
}
}
.link {
cursor: pointer;
text-decoration: none;
color: #303133;
&:hover {
color: rgba(#409EFF, 1);
text-decoration: underline;
}
}
h4 {
// margin-bottom: 0;
color: rgba(#409EFF, 1);
border-bottom: 1px solid rgba(#409EFF, .5);
}
.img-wrapper {
color: #303133;
display: flex;
align-items: center;
.img {
margin-left: 40px;
}
img {
width: 80px;
height: 80px;
border-radius: 10px;
margin: 0 20px;
cursor: pointer;
transition: all .3s;
&:hover {
box-shadow: 0 0 10px #409EFF;
}
}
}
.goods-info {
display: flex;
.left, .right {
width: 390px;
padding: 10px 10px 10px 0;
}
.price {
font-size: 14px;
b {
color: #F56C6C;
font-weight: bold;
}
}
}
.sku-list {
margin-top: 10px;
min-height: 50px;
.sku-item {
display: flex;
align-items: center;
// padding: 5px 0;
border-radius: 5px;
.left, .center, .right {
margin: 0 5px;
// border: 1px solid #ccc;
}
.left {
// flex: 1;
font-size: 0;
width: 60px;
img {
border-radius: 5px;
border: 1px solid #DCDFE6;
width: 60px;
height: 60px;
}
}
.center {
flex: 5;
font-size: 14px;
}
.right {
flex: 1;
// line-height: 50px;
font-size: 12px;
}
&:nth-of-type(odd) {
background: #f4f1f1;
}
}
.sku-item + .sku-item {
// border-top: 1px solid #efefef;
}
}
}

View File

@@ -0,0 +1,528 @@
<template>
<div class="afsOrder-manager baselayout">
<div class="max-width">
<el-form :model="query" size="mini" :inline="true" ref="form" style="" :rules="rules" label-width="90px">
<!-- 关键字 -->
<el-form-item label="" label-width="0">
<el-input clearable @keypress.enter.native="submitForm" v-model.trim="query.keyword" placeholder="请输入售后单关键字"
style="width: 180px;">
<i slot="prefix" class="el-icon-search"></i>
</el-input>
</el-form-item>
<!-- 关键字 -->
<!-- skuIDs -->
<el-form-item label="" label-width="">
<el-input clearable @keypress.enter.native="submitForm" v-model.trim="skuIDs" placeholder="skuIDs空格分隔"
@input="changeSkuIDs" style="width: 180px;">
<!-- <i slot="prefix" class="el-icon-search"></i> -->
</el-input>
</el-form-item>
<!-- skuIDs -->
<!-- 厂商 -->
<el-form-item label="平台:" label-width="50px">
<el-select v-model="query.vendorIDs" placeholder="请选择" style="width: 100px;" @change="vendorChange">
<el-option :key="-1" label="不限" :value="-1"></el-option>
<el-option v-for="item in ConVendorName" :key="item.vendorID" :label="item.name"
:value="item.vendorID"></el-option>
</el-select>
</el-form-item>
<!-- 厂商 -->
<!-- 包含门店 -->
<el-form-item>
<el-button type="success" style="width: 110px;"
@click="storePickShow = true">门店选择({{ query.storeIDs.length }})</el-button>
</el-form-item>
<!-- 包含门店 -->
<!-- <br> -->
<!-- 开始时间 -->
<el-form-item label="日期范围:" label-width="75px">
<el-date-picker style="width: 260px;" v-model="query.dateRange" type="daterange" align="left" unlink-panels
:clearable="false" :default-value="Date.now() - 3600 * 1000 * 24 * 30" value-format="yyyy-MM-dd"
range-separator="" start-placeholder="开始日期" end-placeholder="结束日期">
</el-date-picker>
</el-form-item>
<!-- 结束时间 -->
<!-- 售后处理方式 -->
<el-form-item label="售后方式:" label-width="75px">
<el-checkbox-group v-model="query.appealTypes" :min="1">
<el-checkbox-button v-for="(val, key) in afsAppealTypeName" :label="Number(key)"
:key="key">{{ val }}</el-checkbox-button>
</el-checkbox-group>
</el-form-item>
<!-- 售后处理方式 -->
<!-- 状态 -->
<el-form-item label="状态:" label-width="50px">
<el-checkbox-group v-model="query.statuss" :min="1">
<el-checkbox-button v-for="(val, key) in afsOrderStatus" :label="Number(key)"
:key="key">{{ val }}</el-checkbox-button>
</el-checkbox-group>
</el-form-item>
<!-- 状态 -->
<!-- 检索按钮 -->
<el-form-item>
<el-button type="success" style="width: 100px;" @click="submitForm">查询</el-button>
<el-button type="success" size="mini" @click="exportExcel">导出excel</el-button>
</el-form-item>
<!-- 检索按钮 -->
</el-form>
</div>
<!-- 表格 -->
<div class="scroll-box">
<el-table class="afs-order-table" :data="afsOrderList" tooltip-effect="dark" style="min-width: 1300px; width: 100%;"
empty-text="暂无数据请检查检索条件是否正确" height="100%" stripe>
<!-- 创建时间 -->
<el-table-column label="创建时间" align="center" width="150px">
<template slot-scope="scope">
<div>{{ scope.row.afsCreatedAt | timeToLLL }}</div>
</template>
</el-table-column>
<!-- 创建时间 -->
<!-- 门店ID -->
<el-table-column label="门店ID" align="center" width="140px" min-width="">
<template slot-scope="scope">
<div>{{ scope.row.jxStoreID }}</div>
</template>
</el-table-column>
<!-- 门店ID -->
<!-- 门店名 -->
<el-table-column label="门店名" align="center" width="140px" min-width="">
<template slot-scope="scope">
<div>{{ scope.row.storeName }}</div>
</template>
</el-table-column>
<!-- 门店名 -->
<!-- 售后单号订单号 -->
<el-table-column label="售后单号/订单号" align="left" header-align="center" min-width="">
<template slot-scope="scope">
<div class="afs-order-id">
<div>({{ dealVendorName(scope.row.vendorID) }})</div>
<div class="afs-order-id-detail">
<router-link :to="'/afsordermanager/' + scope.row.afsOrderID" target="_blank">
售后单号: {{ scope.row.afsOrderID }}
</router-link>
<br>
<router-link :to="'/ordermanager/' + scope.row.vendorOrderID" target="_blank">
订单号: {{ scope.row.vendorOrderID }}
</router-link>
</div>
</div>
</template>
</el-table-column>
<!-- 售后单号 -->
<!-- 状态 -->
<el-table-column label="售后状态" align="center" width="120px" min-width="">
<template slot-scope="scope">
<div :class="{ 'focusColor': scope.row.status === 155 || scope.row.status === 165 }"
v-if="scope.row.status !== 190">{{ dealStatus(scope.row.status) }}</div>
<div v-if="scope.row.status === 190">
<el-tooltip :content="'理由: ' + scope.row.refuseReason" placement="top">
<span
:class="{ 'focusColor': scope.row.status === 155 || scope.row.status === 165 }">{{ dealStatus(scope.row.status) }}</span>
</el-tooltip>
</div>
<div v-if="scope.row.flag !== 0">
<span v-if="(scope.row.flag & 3) === 1">(已退款)</span>
<el-tooltip :content="'理由: ' + scope.row.refuseReason" placement="top">
<span v-if="(scope.row.flag & 3) === 3">(已驳回)</span>
</el-tooltip>
<span v-if="(scope.row.flag & 4) === 4">(已处理)</span>
</div>
</template>
</el-table-column>
<!-- 状态 -->
<!-- 售后方式 -->
<el-table-column label="售后方式" align="center" width="120px" min-width="">
<template slot-scope="scope">
<div>{{ dealAppealType(scope.row.appealType) }}</div>
</template>
</el-table-column>
<!-- 售后方式 -->
<!-- 售后原因 -->
<el-table-column label="售后原因" align="left" min-width="">
<template slot-scope="scope">
<div style="line-height: 1.2">{{ scope.row.reasonDesc }}</div>
</template>
</el-table-column>
<!-- 售后原因 -->
<!-- 操作 -->
<el-table-column label="操作" align="center" width="" min-width="">
<template slot-scope="scope">
<div class="operate-wall">
<div class="status-155">
<el-button type="text" :disabled="!(scope.row.status === 155 && (scope.row.flag & 3) === 0)"
@click="handleAgreeOrRefuse(1, scope.row)">退款{{ (scope.row.flag & 3) === 1 ? '(已操作)' : '' }}</el-button>
<el-button type="text" :disabled="!(scope.row.status === 155 && (scope.row.flag & 3) === 0)"
@click="handleAgreeOrRefuse(3, scope.row)">驳回{{ (scope.row.flag & 3) === 3 ? '(已操作)' : '' }}</el-button>
<el-button type="text" :disabled="!(scope.row.status === 155 && (scope.row.flag & 4) === 0)"
@click="handleAgreeOrRefuse(4, scope.row)">退货转退款{{ (scope.row.flag & 4) === 4 ? '(已操作)' :
'' }}</el-button>
</div>
<el-button type="text" :disabled="!(scope.row.status === 165 && (scope.row.flag & 4) === 0)"
@click="handleReceiveGoods(scope.row)">收到退货{{ (scope.row.flag & 4) === 4 ? '(已操作)' : '' }}</el-button>
</div>
</template>
</el-table-column>
</el-table>
</div>
<!-- 表格 -->
<!-- 分页 -->
<!-- <div class="page">
<el-pagination @size-change="sizeChange" @current-change="handleCurrentChange" :page-sizes="[15, 30, 50]"
:page-size.sync="query.pageSize" layout="total, sizes, prev, pager, next" :current-page="page"
:total="totalCount">
</el-pagination>
</div> -->
<!-- 分页 -->
<el-dialog title="门店筛选" :visible.sync="storePickShow" custom-class="store-pick" width="800px" :show-close="false">
<div style="text-align: right;">
<el-button size="mini" type="danger" @click="storePickShow = false"> </el-button>
<el-button size="mini" type="primary" @click="confirmStorePick"> </el-button>
</div>
<!-- 平台多选 -->
<div style="display: flex;margin: 20px 0;">
<span style="font-size: 14px; color: #666;line-height: 1.4;">门店平台限制</span>
<el-checkbox-group v-model="vendorIDs" @change="vendorIDsChange" style="">
<el-checkbox v-for="item in ConVendorName" :key="item.vendorID"
:label="item.vendorID">{{ item.name }}</el-checkbox>
</el-checkbox-group>
</div>
<StoresPick ref="treeStorePick" @updateStoreIDs="updateStoreIDs" :vendorIDs="vendorIDs"></StoresPick>
</el-dialog>
</div>
</template>
<script>
import StoresPick from "@/components/cmp/storePick/index.vue";
import { showLoad, hideLoad } from '@/tools/loading'
import { json2Excel } from '@/tools/excel.js'
import api from '@/utils/api'
import { apiGetAfsOrders,queryBarCodeRefundStatus } from '@/apis/controls/order'
import moment from 'moment'
moment.locale('zh-cn')
export default {
name: 'AfsOrderManager',
components: {
StoresPick
},
data() {
return {
query: {
keyword: '', // 关键字
afsOrderID: '', // 售后单号
vendorOrderID: '', // 订单号
vendorIDs: -1, // 厂商
appealTypes: [1, 2, 3], // 售后处理方式
storeIDs: [], // 门店列表
skuIDs: [],
statuss: [155, 160, 165, 167, 180, 190], // 状态
fromTime: '', // 开始时间
toTime: '', // 结束时间
dateRange: [],
offset: 0,
pageSize: 50
},
page: 1, // 页码,
// 校验规则
rules: {},
totalCount: 0,
afsOrderList: [], // 售后单列表
skuIDs: '',
storePickShow: false,
vendorIDs: []
}
},
computed: {
// 售后类型
afsAppealTypeName() {
return this.$store.getters.serverInfo.afsAppealTypeName || {}
},
// 售后状态
afsOrderStatus() {
let { orderStatus } = this.$store.getters.serverInfo || {}
let json = {}
for (let attr in orderStatus) {
if (attr <= 190 && attr >= 155) {
json[attr] = orderStatus[attr] || ''
}
}
return json
}
},
async created() {
let now = moment(new Date().getTime()).format('YYYY-MM-DD')
let old = moment(new Date().getTime() - 3600 * 1000 * 24 * 7).format('YYYY-MM-DD')
this.query.dateRange[0] = old // '2018-07-18' // old
this.query.dateRange[1] = now // '2018-07-19' // now
this.submitForm()
// 扫码订单刷新售后信息
let res = await queryBarCodeRefundStatus(this.query.afsOrderID)
console.log('刷新订单后的信息_lakala',res)
},
methods: {
// api
async getAfsOrder(type) {
try {
showLoad()
let { totalCount, data } = await apiGetAfsOrders({ ...this.mapQuery(type) })
this.totalCount = totalCount
// this.afsOrderList = data
return data || []
} catch (err) {
this.$message({
message: err,
type: 'error',
center: true
})
} finally {
hideLoad()
}
},
// 过滤数据
mapQuery(type) {
// 过滤数据
// const routeStatus = this.$route.query.status ? Number(this.$route.query.status) : null
// this.query.statuss = routeStatus ? [routeStatus] : this.query.statuss
// this.query.vendorIDs = routeStatus ? 1 : this.query.vendorIDs
let json = JSON.parse(JSON.stringify(this.query))
json.fromTime = json.dateRange[0] + ' 00:00:00'
json.toTime = json.dateRange[1] + ' 23:59:59'
delete json.dateRange
if (json.vendorIDs === -1) {
json.vendorIDs = JSON.stringify([])
} else {
json.vendorIDs = JSON.stringify([json.vendorIDs])
}
// 分页
if (type === 'all') {
json.pageSize = -1
json.offset = 0
} else {
json.offset = (this.page - 1) * json.pageSize
}
for (let attr in json) {
if (typeof json[attr] === 'object') json[attr] = JSON.stringify(json[attr])
if (!json[attr]) {
delete json[attr]
}
}
return json
},
// 查询订单
async submitForm() {
this.afsOrderList = await this.getAfsOrder()
},
// 厂商修改
vendorChange(e) {
},
vendorIDsChange(arr) {
this.vendorIDs = arr
},
confirmStorePick() {
this.storePickShow = false
this.submitForm()
},
updateStoreIDs(storeIDs) {
this.query.storeIDs = storeIDs
},
// 更新门店
updateStore(arr) {
this.query.storeIDs = arr
},
// 每页个数改变
sizeChange() {
this.$nextTick(async () => {
this.afsOrderList = await this.getAfsOrder()
})
},
// 点击页码
async handleCurrentChange(val) {
this.page = val
this.query.offset = (val - 1) * this.query.pageSize
this.afsOrderList = await this.getAfsOrder()
document.querySelector('.el-table__body-wrapper').scrollTop = 0
},
// 处理vendorName
dealVendorName(vendorID) {
// return this.ConVendorName[vendorID] ? this.ConVendorName[vendorID].nick : '未知'
return this.ConVendorName ? this.ConVendorName.find(item => item.vendorID === vendorID).nick : '未知'
},
// 处理售后状态
dealStatus(status) {
let serverInfo = this.$store.getters.serverInfo || {}
return serverInfo.orderStatus ? serverInfo.orderStatus[status] : ''
},
// 处理 售后方式
dealAppealType(appealType) {
let serverInfo = this.$store.getters.serverInfo || {}
return serverInfo.afsAppealTypeName ? serverInfo.afsAppealTypeName[appealType] : ''
},
// 退款或驳回
async handleAgreeOrRefuse(type, afsOrder) {
if (type === 1) {
// 退款处理
try {
await this.$confirm('是否进行退款处理', '提示', { type: 'warning' })
// 确定
this.apiDealAfs(type, '同意退款', afsOrder)
} catch (e) {
// 取消
console.log(e)
}
} else if (type === 3) {
try {
let res = await this.$prompt('请输入驳回理由', '提示', {
inputValidator: (str) => {
if (!str || !str.trim()) return false
return true
},
inputErrorMessage: '理由不能为空'
})
let { value } = res // 理由
// 确定
this.apiDealAfs(type, value, afsOrder)
} catch (e) {
// 取消
console.log(e)
}
} else if (type === 4) {
try {
await this.$confirm('是否进行退货转退款处理', '提示', { type: 'warning' })
this.apiDealAfs(type, '退货转退款', afsOrder)
} catch (e) {
// 取消
console.log(e)
}
}
},
// 处理售后订单
async apiDealAfs(type, reason, afsOrder) {
try {
showLoad()
let form = new FormData()
form.append('vendorID', afsOrder.vendorID)
form.append('reason', reason)
if (afsOrder.vendorID === 3 && type !== 4) {
form.append('vendorOrderID', afsOrder.vendorOrderID)
let flag = type === 1 ? true : false
form.append('acceptIt', flag)
// await api('v2/order/AgreeOrRefuseCancel', {
// method: 'PUT',
// header: {
// 'content-type': 'application/x-www-form-urlencoded'
// },
// data: form
// })
} else {
form.append('afsOrderID', afsOrder.afsOrderID)
form.append('approveType', type)
}
await api('v2/order/AgreeOrRefuseRefund', {
method: 'PUT',
data: form
})
// 成功
this.$message({
message: '操作成功',
type: 'success',
center: true
})
afsOrder.flag = type === 1 ? 1 : 3
afsOrder.refuseReason = reason
} catch (e) {
// 失败
this.$message({
message: e,
type: 'error',
center: true
})
} finally {
hideLoad()
}
},
// 收到退货
async handleReceiveGoods(afsOrder) {
try {
await this.$confirm('是否确认收到退货', '提醒')
this.apiReceiveGoods(afsOrder)
} catch (e) {
console.log(e)
}
},
// 收到退款api
async apiReceiveGoods(afsOrder) {
try {
showLoad()
let form = new FormData()
form.append('afsOrderID', afsOrder.afsOrderID)
form.append('vendorID', afsOrder.vendorID)
await api('v2/order/ConfirmReceivedReturnGoods', {
method: 'PUT',
data: form
})
afsOrder.flag = 4
} catch (e) {
this.$message({
message: e,
type: 'error',
center: true
})
} finally {
hideLoad()
}
},
// skuIDs修改
changeSkuIDs(val) {
if (val) {
this.query.skuIDs = Array.from(new Set(val.split(/\s/).map(item => +item).filter(item => item)))
} else {
this.query.skuIDs = []
}
},
// 导出excel
async exportExcel() {
const vendorMap = ['京东', '美团', '', '饿百']
try {
let res = await this.getAfsOrder('all')
let keys = Object.keys(res[0])
let jsonKey = {}
keys.forEach(item => {
jsonKey[item] = ''
})
let excelData = res.map(item => {
let json = {}
for (let attr in jsonKey) {
if (attr === 'vendorOrderID') {
json['订单号'] = item[attr] || ''
} else if (attr === 'vendorID') {
json['平台'] = vendorMap[item[attr]]
} else if (attr === 'skuUserMoney') {
json['退款金额'] = item[attr] || ''
} else if (attr === 'vendorOrderID2') {
json['订单号2(饿百)'] = item[attr] || ''
} else {
json[attr] = (item[attr] === 0 || item[attr] === '0') ? 0 : item[attr] || ''
}
}
return json
})
let fileName = `售后单导出${+new Date()}`
json2Excel(excelData, fileName)
} catch (e) {
console.error(e)
this.$alert(e, '错误')
} finally {
hideLoad()
}
}
}
}
</script>
<style lang="sass">
@import './afs-order-manager';
</style>

View File

@@ -0,0 +1,197 @@
<template>
<el-table class="order-status-table" :data="orderStatus" style="width: 100%;" max-height="600" :span-method="objectSpanMethod" border>
<el-table-column
fixed
label="时间"
align="center"
width="80px">
<template slot-scope="scope">
<div style="font-weight: bold;font-size: 12px; color: #303133; line-height: 1.5;">
<!-- {{scope.row.statusTime | timeToLLL}} -->
<div>{{scope.row.statusTime | timeTol}}</div>
<div>{{scope.row.statusTime | timeToLLLL}}</div>
</div>
</template>
</el-table-column>
<!-- :render-header="renderHeader" -->
<el-table-column
v-for="(item, index) in statusList"
:key="index"
min-width="190px"
:label="JSON.stringify(item)"
>
<template slot="header" slot-scope="scope">
<div style="display:flex;justify-content: space-between;">
<div style="user-select: text;" class="table-title" :class="{'color-blue': statusList[0].vendorOrderID === JSON.parse(scope.column.label).vendorOrderID}">
({{dealOrderType(JSON.parse(scope.column.label).orderType)}}){{dealVendorID(JSON.parse(scope.column.label).vendorName)}}
<br>
{{JSON.parse(scope.column.label).vendorOrderID}}
</div>
<!-- v-show="statusList[0].vendorOrderID === JSON.parse(scope.column.label).vendorOrderID" -->
<div >
<el-button type="primary" size="mini" @click="cancelWaybill(item)">取消运单</el-button>
</div>
</div>
</template>
<template slot-scope="scope" v-if="scope.row.vendorOrderID == item.vendorOrderID && scope.row.orderType == item.orderType">
<div class="table-body">
<!-- {{scope.row.vendorOrderID}} -->
<!-- {{scope.row.orderType}} -->
<!-- 状态 -->
<span>{{switchWaybillStatus(scope.row)}}</span>
<br>
<!-- 备注 -->
<span>{{switchWaybillRemark(scope.row)}}</span>
</div>
</template>
</el-table-column>
</el-table>
</template>
<script>
import { cancelWaybillsApi } from "@/apis/order.js";
import { showLoad, hideLoad } from "@/tools/loading.js";
const orderTypeArr = ['', '订单', '运单', '售后单']
export default {
name: 'CMPOrderStatus',
props: ['orderStatus', 'fee'],
data () {
return {}
},
computed: {
statusList () {
if (this.orderStatus) {
let arr = this.orderStatus.map(item => `${item.vendorOrderID},${item.orderType},${item.vendorID}`)
arr = Array.from(new Set(arr))
let arr2 = arr.map(item => {
let tem = item.split(',')
return {
vendorOrderID: tem[0],
orderType: tem[1],
vendorName: tem[2]
}
})
return arr2
} else {
return []
}
}
},
methods: {
cancelWaybill(item) {
cancelWaybillsApi(
item.vendorOrderID,
Number(item.vendorName),
'',
'',
(e) => {
this.$message({
message: "取消三方运单成功",
type: "success",
center: true,
});
}
)
hideLoad()
},
// 处理订单类型
dealOrderType (str) {
return orderTypeArr[str]
},
// 处理vendorID
dealVendorID (vendorID) {
const serverInfo = this.$store.state.serverInfo
return serverInfo.vendorName[vendorID]
},
// 状态
switchWaybillStatus (item) {
const serverInfo = this.$store.state.serverInfo
let str = ''
switch (item.orderType) {
case 1:
str = '(订单)' + serverInfo.orderStatus[item.status]
break
case 2:
str = '(运单)' + serverInfo.waybillStatus[item.status]
break
case 3:
str = '(售后单)' + serverInfo.orderStatus[item.status]
break
default:
str = '(未知)'
}
return str + `,${item.vendorStatus}`
},
// 备注
switchWaybillRemark (item) {
if (item && item.remark) {
// 如果是召唤骑手,后面跟上召唤骑手的费用
// const remark = this.fee ?
// item.remark + ', ¥' + this.fee / 100 :
// item.remark;
// 前端不添加配送费用显示,后端加
const remark = item.remark
return '备注: ' + remark
} else {
return ''
}
},
// 合并行
objectSpanMethod ({ row, column, rowIndex, columnIndex }) {
if (this.orderStatus.length === 0) return false
let arr = this.orderStatus
let contactDot = 0
let spanArr = []
arr.forEach((item, index) => {
if (index === 0) {
spanArr.push(1)
} else {
if (item.statusTime === arr[index - 1].statusTime) {
spanArr[contactDot] += 1
spanArr.push(0)
} else {
contactDot = index
spanArr.push(1)
}
}
})
if (columnIndex === 0) {
if (spanArr[rowIndex]) {
return {
rowspan: spanArr[rowIndex],
colspan: 1
}
} else {
return {
rowspan: 0,
colspan: 0
}
}
}
}
}
}
</script>
<style lang="scss">
.order-status-table {
.table-title {
line-height: 1 !important;
// margin: 0;
// padding: 0;
padding: 0 !important;
}
.color-blue {
color: #409EFF;
}
.table-body {
font-size: 12px;
line-height: 1.2;
}
td {
padding: 10px 0;
}
}
</style>

View File

@@ -0,0 +1,94 @@
<template>
<el-table
:data="tableData"
:span-method="objectSpanMethod"
border
style="width: 100%; margin-top: 20px">
<el-table-column
prop="id"
label="ID"
width="180">
</el-table-column>
<el-table-column
prop="name"
label="姓名">
</el-table-column>
<el-table-column
prop="age"
label="age">
</el-table-column>
</el-table>
</template>
<script>
export default {
data(){
return {
tableData: [
{id: "1",name:"小米", age: 18},
{id: "1",name:"小名", age: 18},
{id: "3",name:"小红", age: 18},
{id: "3",name:"小棒", age: 18},
{id: "2",name:"小李", age: 18},
{id: "2",name:"小李", age: 18}
],
spanArr: []
}
},
mounted(){
let contactDot = 0;
this.tableData.forEach( (item,index) => {
if(index===0){
this.spanArr.push(1)
}else{
if(item.id === this.tableData[index-1].id){
this.spanArr[contactDot] += 1;
this.spanArr.push(0)
}else{
contactDot = index
this.spanArr.push(1)
}
}
})
},
methods:{
objectSpanMethod({row, column, rowIndex, columnIndex}){
if(columnIndex ===0){
if(this.spanArr[rowIndex]){
return {
rowspan:this.spanArr[rowIndex],
colspan:1
}
}else{
return {
rowspan: 0,
colspan: 0
}
}
}
}
}
}
</script>
<style lang="scss">
.order-status-table {
.table-title {
line-height: 1 !important;
// margin: 0;
// padding: 0;
padding: 0 !important;
color: #409EFF;
}
.table-body {
font-size: 12px;
line-height: 1.2;
}
td {
padding: 10px 0;
}
.hover-row {
// background: none !important;
}
}
</style>

View File

@@ -0,0 +1,386 @@
<template>
<div class="amap">
<div class="amap-wrapper">
<!-- 经纬度窗体 -->
<div class="latlng-info">经度lng:{{clickLng}} 纬度lat:{{clickLat}}</div>
<!-- 经纬度窗体 -->
<!-- 搜索框 -->
<el-amap-search-box
class="search-box"
:search-option="searchOption"
:on-search-result="onSearchResult"
></el-amap-search-box>
<!-- <div>{{center}}</div> -->
<el-amap :zoom="zoom" :center="center" :events="events" class="amap-demo">
<el-amap-info-window
:position="currentWindow.position"
:offset="[10,-10]"
:autoMove="false"
:visible="currentWindow.visible"
>
<div class="currentWindow-content">加载中</div>
</el-amap-info-window>
<!-- <el-amap-marker v-for="(marker, index) in markers" :position="marker.position" :vid="index" :content="marker.content"></el-amap-marker> -->
<!-- <el-amap-marker v-for="(marker, index) in markers" :position="marker.position" :vid="index" :content="`<div style='background:#a2b5ba;'><div>`" :key="index"></el-amap-marker> -->
<!-- #7c8bca #6c79d1-> #a2b5ba -->
<div v-for="(circle,index) in circles" :key="index" class="test">
<el-amap-circle
v-if="(circle.deliveryRangeType === 3 && showScope && showScope2) && circle.drawCircle"
:center="circle.center"
:extData="circle"
:radius="circle.deliveryRange2"
:fill-opacity="circle.fillOpacity"
:strokeColor="circle.strokeColor"
:zIndex="circle.zIndex"
:fillColor="circle.fillColor"
></el-amap-circle>
<el-amap-polygon
v-if="circle.deliveryRangeType === 2 && showScope && showScope2"
:path="circle.deliveryRange2"
:extData="circle"
:center="circle.center"
:fill-opacity="circle.fillOpacity"
:strokeColor="circle.strokeColor"
:zIndex="circle.zIndex"
:fillColor="circle.fillColor"
></el-amap-polygon>
<el-amap-text
:text="circle.name"
:offset="circle.offset"
:position="circle.center"
:clickable="circle.clickable"
></el-amap-text>
<el-amap-marker :extData="circle" :position="circle.center" :events="circle.events"></el-amap-marker>
</div>
<div v-if="searchMarker.position.length >= 2">
<el-amap-marker :position="searchMarker.position" :content="searchMarker.content"></el-amap-marker>
<div v-for="(item, i) in distanceList" :key="i+'distance'">
<el-amap-circle
:center="searchMarker.position"
:radius="i * 1000 + 1000"
:zIndex="item.zIndex - 1"
:fill-opacity="0"
:strokeColor="'#007acc'"
:strokeWeight="1"
:strokeStyle="'dashed'"
:fillColor="'#ffffff'"
></el-amap-circle>
<el-amap-text
:text="item.title"
:offset="item.offset"
:position="item.center"
:zIndex="item.zIndex"
></el-amap-text>
</div>
</div>
</el-amap>
</div>
</div>
</template>
<script>
import { setInterval, clearInterval, setTimeout, clearTimeout } from "timers";
import { mapGetters } from "vuex";
export default {
props: ["storeData", "placeID", "mapCenter"],
data() {
return {
searchMarker: {
position: [],
content: "",
},
distanceList: [],
searchOption: {
city: "",
citylimit: true,
},
showScope: true,
showScope2: true,
zoom: 12,
center: [],
events: {
moveend: (e) => console.log(e),
rightclick: (e) => {
this.rightClick(e);
},
},
circles: [],
currentWindow: {
position: [-74.0059731, 40.7143528], // 初始渲染,但是要让人看不到
visible: true,
content: [],
},
timer: "",
timer2: "",
clickLat: "",
clickLng: "",
};
},
computed: {
...mapGetters({
cms: "cms",
}),
},
created: function () {
this.getCirles(this.storeData, this.mapCenter);
},
mounted: function () {},
methods: {
// 地址编辑辅助线偏移
moveDistanceList: function () {
let distanceList = [];
for (let i = 1; i <= 5; i++) {
let distance = {
center: [
this.center[0],
this.center[1] + 0.000009405717451407729 * i * -1000,
],
title: i + "km",
offset: [0, 0],
zIndex: 99,
};
distanceList.push(distance);
}
this.distanceList = distanceList;
},
// 通过地图输入框选择地址
onSearchResult(pois) {
let center = [];
center.push(pois[0].lng);
center.push(pois[0].lat);
this.center = center;
this.searchMarker = {
position: center,
content: '<div class="searchMarker"></div>',
};
// 地址编辑辅助线偏移
this.moveDistanceList();
},
// 正常营业的店铺以黑色显示,异常店铺显示红色
getColor: function () {
this.timer2 = setInterval(() => {
let storeHtmls = document.querySelectorAll(
".amap-wrapper .amap-overlay-text-container"
);
let count = 0;
Array.from(storeHtmls).forEach((html) => {
count++;
this.circles.forEach((item) => {
if (html.innerText === item.name) {
// html.style.color = item.status === 1 ? '#67c23a' : item.status === -1 ? '#dddddd' : item.status === 0 ? '#F56C6C' : ''
html.className = `amap-overlay-text-container openStatus${item.status}`;
}
});
if (count === this.circles.length) {
clearInterval(this.timer2);
this.timer2 = "";
}
});
}, 1000 / 60);
},
getCirles: function (storeData, mapCenter) {
this.center = mapCenter;
let timer = setInterval(() => {
if (document.querySelectorAll(".currentWindow-content")[0]) {
clearInterval(timer);
}
}, 1000 / 60);
if (storeData !== null && storeData.length > 0) {
this.searchOption.city =
this.placeID === "" ? "" : storeData[0].cityName;
storeData.forEach((store) => {
// 隔日达+666666不画圈
store.drawCircle = true;
const storeMap = store.StoreMaps
? store.StoreMaps.find((item) => item.vendorID === 9)
: null;
if ((storeMap && storeMap.isOrder) || store.id === 666666)
store.drawCircle = false;
store.center = [store.lng, store.lat];
store.fillColor = "#4EB331";
store.strokeColor = "#49a72e";
store.zIndex = 10;
store.fillOpacity = 0.5;
store.offset = [0, -45];
store.clickable = false;
store.deliveryRange2 = store.deliveryRange;
if (store.deliveryRangeType === 2) {
if (typeof store.deliveryRange2 === "string") {
store.deliveryRange2 = store.deliveryRange2.split(";");
}
if (
store.deliveryRange2 !== undefined &&
store.deliveryRange2.length > 0
) {
for (let i = 0; i < store.deliveryRange2.length; i++) {
if (store.deliveryRange2[i] === "") {
store.deliveryRange2.splice(i, 1);
i--;
}
}
store.deliveryRange2.forEach((item, index) => {
if (typeof item === "string") {
store.deliveryRange2[index] = item.split(",");
}
});
} else {
store.deliveryRange2 = [];
}
}
store.events = {
mouseover: (e) => this.mouseover(e),
mouseout: (e) => this.mouseout(e),
dblclick: (e) => this.dblclick(e),
};
});
this.zoom = 12;
if (storeData.length > 300) {
this.zoom = 11;
}
if (storeData.length > 400) {
this.zoom = 10;
}
if (storeData.length > 500) {
this.zoom = 9;
}
if (storeData.length > 600) {
this.zoom = 8;
}
if (storeData.length > 700) {
this.zoom = 7;
}
if (storeData.length > 800) {
this.zoom = 6;
}
if (storeData.length > 900) {
this.zoom = 5;
}
if (storeData.length > 1000) {
this.zoom = 4;
}
this.circles = storeData;
} else {
this.circles = [];
}
this.$nextTick(() => {
this.getColor();
});
},
dblclick: function (e) {
this.$emit("modifyStore", e.target.Ce.extData, "修改");
},
mouseover: function (e) {
this.showScope = false;
this.currentWindow.content = [];
this.currentWindow.visible = false;
this.circles.forEach((item, index) => {
if (item.id === e.target.Ce.extData.id) {
let child = item;
child.zIndex = 11;
child.fillOpacity = 0.9;
child.fillColor = "#49a72e";
this.circles[index] = child;
this.currentWindow.content.push(`京西编号: ${child.id}`);
this.currentWindow.content.push(`门店名称: ${child.name}`);
this.currentWindow.content.push(`店长电话: ${child.tel1}`);
this.currentWindow.content.push(`所在城市: ${child.cityName}`);
this.currentWindow.content.push(`店铺地址: ${child.address}`);
// let status = child.status === 1 ? '营业中' : child.status === 0 ? '休息' : '禁用'
this.currentWindow.content.push(
`门店状态: ${this.cms.storeStatus[child.status]}`
);
let time = `${this.timeToXX(item["openTime1"])}-${this.timeToXX(
item["closeTime1"]
)}`;
this.currentWindow.content.push(`营业时间: ${time}`);
this.currentWindow.position = child.center;
let currentWindowContent = "";
for (let content of this.currentWindow.content) {
currentWindowContent += `<p>${content}</p>`;
}
this.timer = setTimeout(() => {
this.currentWindow.visible = true;
if (document.querySelectorAll(".currentWindow-content")[0]) {
document.querySelectorAll(
".currentWindow-content"
)[0].innerHTML = currentWindowContent;
}
}, 1000);
}
});
this.showScope = true;
},
// 730 -> 7:30 时间转换
timeToXX(str) {
if (str.toString().length < 4) {
str = "0" + str;
} else {
str = "" + str;
}
return str.substring(0, 2) + ":" + str.substring(2, str.length);
},
mouseout: function (e) {
if (this.timer) {
clearTimeout(this.timer);
this.timer = "";
}
this.currentWindow.content = [];
this.currentWindow.visible = false;
this.showScope = false;
this.circles.forEach((item, index) => {
if (item.id === e.target.Ce.extData.id) {
this.circles[index].zIndex = 10;
this.circles[index].fillOpacity = 0.5;
this.circles[index].fillColor = "#4EB331";
}
});
this.showScope = true;
},
rightClick({ lnglat }) {
const { lng, lat } = lnglat;
// 经度lng
// 纬度lat
// this.$message({
// message: `经度lng:${lng} 纬度lat:${lat}`,
// type: 'success'
// })
// this.$alert(`经度lng:${lng} 纬度lat:${lat}`, '右键经纬度信息')
this.clickLat = lat;
this.clickLng = lng;
},
},
};
</script>
<style lang="scss">
.amap {
.amap-wrapper {
width: 100%;
height: 700px;
position: relative;
.search-box {
position: absolute;
top: 40px;
left: 40px;
}
.latlng-info {
position: absolute;
right: 0;
top: 0;
background: white;
z-index: 100;
padding: 10px 20px;
font-size: 12px;
}
.amap-overlay-text-container {
font-size: 12px;
}
}
.searchMarker {
background: url(../../assets/img/searchMarkerImg.png) center center
no-repeat;
background-size: cover;
width: 40px;
height: 40px;
z-index: 999;
}
}
</style>

View File

@@ -0,0 +1,905 @@
<template>
<div class="heat-amap baselayout" id="container"></div>
</template>
<script>
import { setTimeout } from 'timers';
export default {
data () {
return {
}
},
created: function () {
var _this = this
let jsonp = document.createElement('script')
jsonp.src = 'https://webapi.amap.com/maps?v=1.4.4&key=269b3df895addf63a4575dbb9b81e655'
jsonp.onload = function () {
setTimeout(() => {
_this.getData()
}, 500)
}
document.body.appendChild(jsonp)
},
methods: {
// 获取数据
getData () {
var map = new AMap.Map('container', {
resizeEnable: true,
center: [116.418261, 39.921984],
zoom: 6
})
if (!isSupportCanvas()) {
alert('热力图仅对支持canvas的浏览器适用,您所使用的浏览器不能使用热力图功能,请换个浏览器试试~')
}
var heatmap
map.plugin(['AMap.Heatmap'], function () {
// 初始化heatmap对象
heatmap = new AMap.Heatmap(map, {
radius: 25, // 给定半径
opacity: [0, 0.8]
})
// 设置数据集:该数据为北京部分“公园”数据
let heatmapData = [
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.287444,
lat: 39.810742,
count: 12
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.287444,
lat: 39.810742,
count: 12
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.287444,
lat: 39.810742,
count: 12
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.287444,
lat: 39.810742,
count: 12
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.287444,
lat: 39.810742,
count: 12
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.287444,
lat: 39.810742,
count: 12
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.287444,
lat: 39.810742,
count: 12
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.287444,
lat: 39.810742,
count: 12
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.287444,
lat: 39.810742,
count: 12
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.287444,
lat: 39.810742,
count: 12
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.287444,
lat: 39.810742,
count: 12
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.287444,
lat: 39.810742,
count: 12
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.191031,
lat: 39.988585,
count: 10
},
{
lng: 116.389275,
lat: 39.925818,
count: 11
},
{
lng: 116.287444,
lat: 39.810742,
count: 12
}
]
heatmap.setDataSet({
data: heatmapData,
max: 100
})
})
// 判断浏览区是否支持canvas
function isSupportCanvas () {
var elem = document.createElement('canvas')
return !!(elem.getContext && elem.getContext('2d'))
}
}
}
}
</script>
<style lang="scss">
</style>

View File

@@ -0,0 +1,804 @@
<template>
<div class="bad-review-manager baselayout">
<el-form
:model="searchForm"
size="mini"
:inline="true"
ref="searchForm"
style=""
:rules="rules"
label-width="100px">
<!-- 关键字 -->
<el-form-item label="" label-width="0">
<el-input clearable @keypress.enter.native="getBadReviewList" v-model="searchForm.keyword" placeholder="请输入关键字" style="width: 180px;">
<i slot="prefix" class="el-icon-search"></i>
</el-input>
</el-form-item>
<!-- 关键字 -->
<!-- 门店检索 -->
<el-form-item>
<el-button type="success" style="width: 110px;" @click="openStorePick">门店选择({{searchForm.storeIDs.length}})</el-button>
</el-form-item>
<!-- 差评状态0-未解决/1-全部 -->
<el-form-item label="评价状态:" label-width="80px">
<el-checkbox-group v-model="searchForm.type" :min="1">
<el-checkbox-button :label="0">差评</el-checkbox-button>
<el-checkbox-button :label="2">好评</el-checkbox-button>
</el-checkbox-group>
</el-form-item>
<!-- 差评状态 -->
<!-- 日期范围 -->
<el-form-item label="日期范围:" label-width="80px">
<el-date-picker
style="width: 260px;"
v-model="searchForm.dateRange"
type="daterange"
align="left"
unlink-panels
:clearable="false"
value-format="yyyy-MM-dd"
range-separator=""
start-placeholder="开始日期"
end-placeholder="结束日期"
:picker-options="pickerOptions">
</el-date-picker>
</el-form-item>
<!-- 订单平台 -->
<el-form-item label="订单平台">
<el-select v-model="searchForm.orderFlag" clearable placeholder="请选择订单平台">
<el-option :label="'京东'" :value="0" :key="0"></el-option>
<el-option :label="'美团'" :value="1" :key="1"></el-option>
<el-option :label="'饿了么'" :value="2" :key="2"></el-option>
</el-select>
</el-form-item>
<!-- 负责人电话 -->
<el-form-item label="负责人电话">
<el-input placeholder="请输入负责人电话" v-model.number="searchForm.operatorPhone"></el-input>
</el-form-item>
<el-form-item>
<el-button
size="mini"
type="primary"
@click="getBadReviewList('1')"
style="width: 120px;">
查询
</el-button>
<el-button
size="mini"
type="primary"
@click="refshOrderDia = true"
style="width: 120px;">
刷新订单号
<i class="el-icon-question el-icon--right"></i>
</el-button>
<el-button
size="mini"
type="success"
@click="getBadReviewListTOExcel"
style="width: 120px;">
导出excel
</el-button>
</el-form-item>
</el-form>
<!-- 表格 -->
<el-table
ref="multipleTable"
:data="badReviewList"
tooltip-effect="dark"
style="width: 100%;"
empty-text="暂无数据请检查检索条件是否正确"
height="calc(100vh - 270px)"
stripe>
<!-- 城市 -->
<el-table-column
label="城市"
align="center"
width="76">
<template slot-scope="scope">
<div>{{scope.row.cityName}}</div>
</template>
</el-table-column>
<!-- 城市 -->
<!-- 店铺名称 -->
<el-table-column
label="店铺名称"
align="center"
width="104">
<template slot-scope="scope">
<div>{{scope.row.storeName}}</div>
</template>
</el-table-column>
<!-- 店铺名称 -->
<!-- 店铺ID -->
<el-table-column
label="店铺ID"
align="center"
width="75">
<template slot-scope="scope">
<div>{{scope.row.jxstoreid}}</div>
</template>
</el-table-column>
<!-- 店铺ID -->
<!-- 订单号 -->
<el-table-column
label="订单号"
align="center"
width="200">
<template slot-scope="scope">
<div style="cursor: pointer" @click="goOrder(scope.row)">{{Number(scope.row.order_flag) | switchVendoID}} {{scope.row.order_flag === '1' ?scope.row.vendor_order_id?scope.row.vendor_order_id:scope.row.order_id:scope.row.order_id}}</div>
</template>
</el-table-column>
<!-- 订单号 -->
<!-- 用户手机 -->
<el-table-column
label="用户手机"
align="center"
width="140">
<template slot-scope="scope">
<div>{{scope.row.userPhone}}</div>
</template>
</el-table-column>
<!-- 用户手机 -->
<!-- 创建时间 -->
<el-table-column
label="创建时间"
align="center"
width="140">
<template slot-scope="scope">
<div>{{scope.row.createTime | timeToLLL}}</div>
</template>
</el-table-column>
<!-- 创建时间 -->
<!-- 更新时间 -->
<el-table-column
label="更新时间"
align="center"
width="140">
<template slot-scope="scope">
<div v-if="scope.row.updateTime === ''">{{scope.row.updateTime}}</div>
<div v-else>{{scope.row.updateTime | timeToLLL}}</div>
</template>
</el-table-column>
<!-- 更新时间 -->
<!-- 初始星级 -->
<el-table-column
label="初始星级"
align="center"
width="65">
<template slot-scope="scope">
<div>{{scope.row.score4}}</div>
</template>
</el-table-column>
<!-- 初始星级 -->
<!-- 更改星级 -->
<el-table-column
label="更改星级"
align="center"
width="65">
<template slot-scope="scope">
<div>{{scope.row.updatedScore > 0 ? scope.row.updatedScore : ''}}</div>
</template>
</el-table-column>
<!-- 更改星级 -->
<!-- 当前状态 -->
<el-table-column
label="当前状态"
align="center"
width="65">
<template slot-scope="scope">
<div>{{scope.row.status === 0 ? '未解决' : '已解决'}}</div>
</template>
</el-table-column>
<!-- 当前状态 -->
<!-- 用户评价 -->
<el-table-column
label="用户评价"
align="center"
min-width="280">
<template slot-scope="scope">
<div style="text-align: left;">{{scope.row.score4Content}}</div>
</template>
</el-table-column>
<!-- 用户评价 -->
<!-- 评价标签 -->
<el-table-column
label="评价标签"
align="center"
min-width="180">
<template slot-scope="scope">
<div v-if="scope.row.venderTags !==''">
<div v-for="tag in JSON.parse(scope.row.venderTags)" :key="tag" style="display: inline-block;padding: 0 3px;">
{{tag}}
</div>
</div>
</template>
</el-table-column>
<!-- 评价标签 -->
<!-- 负责人 -->
<el-table-column
label="负责人:"
align="center">
<template slot-scope="scope">
<div>{{scope.row.userName}}</div>
</template>
</el-table-column>
<!-- 负责人 -->
<!-- 负责人电话 -->
<el-table-column
label="负责人电话:"
align="center">
<template slot-scope="scope">
<div >{{scope.row.operatorPhone}}</div>
</template>
</el-table-column>
<!-- 负责人电话 -->
</el-table>
<!-- 表格 -->
<!-- 分页 -->
<div class="page">
<el-pagination
@size-change="sizeChange"
@current-change="handleCurrentChange"
:page-sizes="[15, 30, 50]"
:page-size.sync="size"
layout="total, sizes, prev, pager, next"
:current-page="page"
:total="totalCount">
</el-pagination>
</div>
<!-- 分页 -->
<el-dialog
title="门店筛选"
:visible.sync="storePickShow"
custom-class="store-pick"
width="800px"
:show-close="false"
>
<div style="text-align: right;">
<el-button size="mini" type="danger" @click="storePickShow = false"> </el-button>
<el-button size="mini" type="primary" @click="confirmStorePick"> </el-button>
</div>
<!-- 平台多选 -->
<div style="display: flex;margin: 20px 0;">
<span style="font-size: 14px; color: #666;line-height: 1.4;">门店平台限制</span>
<el-checkbox-group v-model="vendorIDs" @change="vendorIDsChange" style="">
<el-checkbox v-for="item in ConVendorName" :key="item.vendorID" :label="item.vendorID">{{item.name}}</el-checkbox>
</el-checkbox-group>
</div>
<StoresPick
ref="treeStorePick"
@updateStoreIDs="updateStoreIDs"
:vendorIDs="vendorIDs"
></StoresPick>
</el-dialog>
<!-- 刷新订单号 -->
<el-dialog
title="刷新订单号"
:visible.sync="refshOrderDia"
custom-class="store-pick"
:show-close="false"
width="1200px"
>
<div style="padding: 10px">
<div style="width:1112px;margin:0 auto;">
<el-tag type="danger" style="margin-bottom: 20px;">注意请确认以下信息是否正确</el-tag>
<el-carousel indicator-position="outside" :interval="4000" height="436px">
<el-carousel-item v-for="(item,index) in optionsList" :key="index">
<img :src="item + '?imageView2/1/w/1112/h/436'" alt="略缩图" />
</el-carousel-item>
</el-carousel>
</div>
<el-form label-width="100px" style="margin:0 auto;width:400px;margin-top: 20px;padding: 10px">
<el-form-item label="平台账号" prop="vendorOrgCode">
<el-select
filterable
v-model="vendorOrgCode"
>
<el-option
v-for="(item, index) in MtVendorArr"
:label="item.name + '(' + item.key + ')'"
:value="item.key"
:key="index"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="账号id">
<el-select
filterable
v-model="account"
>
<el-option
v-for="(item, index) in accountArr"
:label="item.key"
:value="item.key"
:key="index"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="日期范围">
<el-date-picker
style="width: 260px;"
v-model="venDateRage"
type="daterange"
align="left"
unlink-panels
:clearable="false"
value-format="yyyy-MM-dd"
range-separator=""
start-placeholder="开始日期"
end-placeholder="结束日期"
:picker-options="pickerOptions">
</el-date-picker>
</el-form-item>
<div style="text-align: center;margin-top:20px">
<el-button size="mini" type="danger" @click="refshOrderDia = false"> </el-button>
<el-button size="mini" type="primary" @click="refshOrderSure"> </el-button>
</div>
</el-form>
</div>
</el-dialog>
</div>
</template>
<script>
import {arr2excel} from '@/tools/excel2'
import {hideLoad} from '@/tools/loading.js'
import $ajax from 'axios'
import moment from 'moment'
import StoresPick from "@/components/cmp/storePick/index.vue";
import {formatDate} from '@/utils/index.js'
import {getStores} from '@/apis/controls/shop.js'
import { mapGetters } from 'vuex'
import api from '@/utils/api.js'
import {apiGetOrderID4Comment} from '@/apis/controls/order.js'
moment.locale('zh-cn')
export default {
components: {
StoresPick
},
data () {
return {
optionsList:[
'https://image.jxc4.com/image/8f5fc94783d92d7ad87bb769ad676d81.png',
'https://image.jxc4.com/image/215522691b97fac374955d2b1e317f21.png',
'https://image.jxc4.com/image/ccca2aa775ce96861ace3e2836613264.png',
'https://image.jxc4.com/image/45695344d44d458e5b07122ce7b3daab.png'
],
html:[],
cityData: [],
badReviewList: [
// {
// id: 7827,
// createdAt: '0001-01-01T00:00:00Z',
// order_id: '904016419000021',
// jxstoreid: '100118',
// userPhone: '13036684705,8339',
// status: 0,
// createTime: '2019-02-16 12:35:50',
// maxModifyTime: 72,
// score4: 1,
// score4Content: '两个梨24元坑啊。',
// venderTags: '["价格贵","缺斤少两"]',
// updateTime: '',
// updatedScore: 0,
// updatedScoreContent: '',
// updatedVenderTags: '',
// order_flag: '0'
// }
],
totalCount: 0,
getStoreLoading: false, // 检索门店时控制加载
options: [], // 存储门店选项的变量
options2: [], // 存储门店选项的变量
page: 1,
size: 30,
searchForm: { // 搜索参数
keyword: '',
placeCode: '', // 城市
storeIDs: [], // 门店列表
type: [0, 2], // 初始拉取状态
dateRange: [], // fromDate toDate
orderFlag:'', // 订单平台'[]'
operatorPhone:'', // 负责人电话
},
vendorOrgCode:'5873',
account:'jxcaishi_cookie',
accountArr:[],
venDateRage:[],
refshOrderDia:false,
rules: {
jxStoreId: [
{ required: true, message: '请先选择门店', trigger: 'change' }
]
},
// 时间选择
pickerOptions: {
disabledDate (time) {
return time.getTime() > Date.now()
},
shortcuts: [
{
text: '1天内',
onClick (picker) {
const end = new Date()
const start = new Date()
start.setTime(start.getTime() - 3600 * 1000 * 24 * 1)
picker.$emit('pick', [start, end])
}
},
{
text: '3天内',
onClick (picker) {
const end = new Date()
const start = new Date()
start.setTime(start.getTime() - 3600 * 1000 * 24 * 3)
picker.$emit('pick', [start, end])
}
},
{
text: '7天内',
onClick (picker) {
const end = new Date()
const start = new Date()
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)
picker.$emit('pick', [start, end])
}
},
{
text: '15天内',
onClick (picker) {
const end = new Date()
const start = new Date()
start.setTime(start.getTime() - 3600 * 1000 * 24 * 15)
picker.$emit('pick', [start, end])
}
},
{
text: '30天内',
onClick (picker) {
const end = new Date()
const start = new Date()
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
picker.$emit('pick', [start, end])
}
}
]
},
storePickShow: false,
vendorIDs: []
}
},
async created () {
this.getDefaultData()
try {
// 获取城市数据
let cityData = (await ($ajax.get('v2/cms/GetPlaces?level=2'))).data
if (cityData.code !== '0') {
this.$message({
message: '[获取城市列表失败] ' + cityData.desc,
type: 'warning',
center: true
})
} else {
this.cityData = JSON.parse(cityData.data)
}
} catch (err) {
this.$message({
message: err,
type: 'error',
center: true
})
}
hideLoad() // 关闭加载
this.getBadReviewList('1')
let config = await api('v2/cms/QueryConfigs',{
params:{
type:'Cookie'
}
})
this.accountArr = config
},
computed:{
...mapGetters({
MtVendorArr: 'MtVendorArr',
})
},
methods: {
// 每页个数改变
sizeChange () {
this.$nextTick(() => {
// 如果存在当前页码在最后一页然后选取较大每页个数显示会出现获取不到数据因为this.page没有变化拉取起始位超出了this.totalCount
if (this.totalCount + this.size <= this.page * this.size) {
this.page = Math.ceil(this.totalCount / this.size)
}
this.getBadReviewList()
})
},
// 点击页码
handleCurrentChange (val) {
this.page = val
this.getBadReviewList()
},
// 初始进入页面,时间默认七天内
getDefaultData: function () {
// 设置日期范围 7天
// this.searchForm.dateRange
let now = new Date().getTime()
let old = now - 3600 * 1000 * 24 * 7
now = moment(now).format('YYYY-MM-DD')
old = moment(old).format('YYYY-MM-DD')
this.searchForm.dateRange[0] = old // '2018-07-18' // old
this.searchForm.dateRange[1] = now // '2018-07-19' // now
this.venDateRage[0] = old
this.venDateRage[1] = moment(new Date().getTime() - 3600 * 1000 * 24 * 1).format('YYYY-MM-DD')
},
async getBadList (json, fn) {
let arr = []
for (let attr in json) {
arr.push(`${attr}=${json[attr]}`)
}
let str = arr.join('&')
try {
// 获取城市数据
let data = (await ($ajax.get(`v2/store/TmpGetJxBadComments?${str}`))).data
if (data.code === '0') {
fn && fn(data)
} else {
this.$message({
message: data.desc,
type: 'error',
center: true
})
}
} catch (err) {
this.$message({
message: err,
type: 'error',
center: true
})
}
hideLoad() // 关闭加载
},
async refshOrderSure(){
let res = await apiGetOrderID4Comment({
userName:this.account,
appOrgCode:this.vendorOrgCode,
fromTime:this.venDateRage[0],
toTime:this.venDateRage[1]
})
if(res === null || res === 'null') this.$toast('刷新成功','success')
else {
this.$message({
message: `刷新失败,${res}`,
type: 'error',
center: true
})
}
this.refshOrderDia = false
},
getBadReviewList: function (type) {
this.$refs.searchForm.validate(valid => {
if (valid) {
// 使用let storeIDs = this.searchForm.storeIDs 会导致对storeIDs进行编辑一样会编辑this.searchForm.storeIDs
let storeIDs = JSON.parse(JSON.stringify(this.searchForm.storeIDs))
if (storeIDs.length === 0 && this.searchForm.placeCode !== '') {
this.options2.forEach(store => {
storeIDs.push(store.id)
})
}
let data = {
storeIDs: JSON.stringify(storeIDs),
type: this.searchForm.type.length === 2 ? 1 : this.searchForm.type[0],
fromTime: this.searchForm.dateRange[0] + ' 00:00:00',
toTime: this.searchForm.dateRange[1] + ' 23:59:59',
orderFlag:this.searchForm.orderFlag + '',
operatorPhone:this.searchForm.operatorPhone + '',
offset: type === '1' ? 1 * this.size - this.size : this.page * this.size - this.size,
pageSize: this.size,
keyword: this.searchForm.keyword
}
this.getBadList(data, res => {
let data2 = JSON.parse(res.data)
if (data2.list === null) {
this.$message({
message: '没有符合当前条件的数据',
type: 'info',
center: true
})
}
this.totalCount = data2.total
this.badReviewList = data2.list
this.page = type === '1' ? 1 : this.page
if (document.querySelector('.el-table__body-wrapper')) {
document.querySelector('.el-table__body-wrapper').scrollTop = 0
}
})
}
})
},
// 时间戳转日期YYYY-MM-DD
fmtDate: function (obj) {
let date = new Date(obj)
// let time = Moment(date).format('YYYY-MM-DD HH:mm:ss')
// return time
let y = 1900 + date.getYear()
let m = '0' + (date.getMonth() + 1)
let d = '0' + date.getDate()
// let h = '0' + date.getHours()
// let min = '0' + date.getMinutes()
// let s = '0' + date.getSeconds()
return y + '-' + m.substring(m.length - 2, m.length) + '-' + d.substring(d.length - 2, d.length)
// + ' ' + h.substring(d.length - 2, d.length) + ':' + min.substring(d.length - 2, d.length) + ':' + s.substring(d.length - 2, d.length)
},
getBadReviewListTOExcel: async function () {
this.$refs.searchForm.validate(async valid => {
if (valid) {
// 使用let storeIDs = this.searchForm.storeIDs 会导致对storeIDs进行编辑一样会编辑this.searchForm.storeIDs
let storeIDs = JSON.parse(JSON.stringify(this.searchForm.storeIDs))
if (storeIDs.length === 0 && this.searchForm.placeCode !== '') {
this.options2.forEach(store => {
storeIDs.push(store.id)
})
}
let data = {
storeIDs: JSON.stringify(storeIDs),
type: this.searchForm.type.length === 2 ? 1 : this.searchForm.type[0],
fromTime: this.searchForm.dateRange[0] + ' 00:00:00',
toTime: this.searchForm.dateRange[1] + ' 23:59:59',
offset: 0,
pageSize: -1
}
const excelData = []
excelData.push([
'id',
'createdAt',
'order_id',
'jxstoreid',
'userPhone',
'status',
'maxModifyTime',
'order_flag',
'createTime',
'score4',
'score4Content',
'venderTags',
'updateTime',
'updatedScore',
'updatedScoreContent',
'updatedVenderTags',
'storeName',
'cityName',
'vendorOrderID2',
'创建时间',
'修改截止时间',
'订单号',
'平台',
'城市',
'门店ID',
'门店名称',
'平台负责人',
'平台负责人电话',
'用户手机',
'初始星级',
'更改星级',
'当前状态',
'用户评价',
'评价标签'
])
const vendorArr = ['京东', '美团', '饿了么', '饿百']
let {stores} = await getStores({pageSize: -1, statuss: JSON.stringify([-1, 0, 1]), briefLevel: 1}, false)
this.getBadList(data, res => {
let list = JSON.parse(res.data).list
// // 文件名称
// let fileName = '差评列表'
// json2Excel(excelData, fileName)
list.forEach(item => {
const findStore = stores.find(store => +item.jxstoreid === store.id)
excelData.push([
item.id,
item.createdAt,
item.order_id,
item.jxstoreid,
item.userPhone,
item.status,
item.maxModifyTime,
item.order_flag,
item.createTime,
item.score4,
item.score4Content,
item.venderTags,
item.updateTime,
item.updatedScore,
item.updatedScoreContent,
item.updatedVenderTags,
item.storeName,
item.cityName,
item.vendorOrderID2,
formatDate(new Date(item.createdAt), 'YYYY-MM-DD hh:mm:ss'),
item.maxModifyTime ? formatDate(+new Date(item.createdAt) + 1000 * 60 * 60 * item.maxModifyTime, 'YYYY-MM-DD hh:mm:ss') : '',
item.order_id,
vendorArr[item.order_flag],
item.cityName,
item.jxstoreid,
item.storeName,
findStore ? findStore.marketManName : '',
findStore ? findStore.marketManPhone : '',
item.userPhone,
item.score4,
item.updatedScore,
item.status ? '已解决' : '未解决',
item.score4Content,
item.venderTags
])
})
let fileName = moment(new Date()).format('YYYY.MM.DD-HH:mm') + '差评.xlsx'
arr2excel(excelData, fileName)
hideLoad()
})
}
})
},
// 跳转到订单页面
goOrder (row) {
let orderID = row.order_flag==='1'?row.vendor_order_id?row.vendor_order_id:row.order_id:row.order_id
let routeData = this.$router.resolve({
name: 'OrderManager',
query: {orderID}
})
window.open(routeData.href, '_blank')
},
openStorePick () {
this.storePickShow = true
},
confirmStorePick () {
this.storePickShow = false
// this.submitForm()
},
updateStoreIDs (storeIDs) {
this.searchForm.storeIDs = storeIDs
},
vendorIDsChange (arr) {
this.vendorIDs = arr
}
}
}
</script>
<style lang="scss">
.bad-review-manager{
.el-form.el-form--inline{
width: 1100px;
}
.el-table{
min-height: 150px;
.cell{
padding: 0 3px;
}
}
.page {
text-align: center;
margin-top: 10px;
}
}
.el-carousel__item h3 {
color: #475669;
font-size: 14px;
opacity: 0.75;
// line-height: 150px;
margin: 0;
}
.el-carousel__item:nth-child(2n) {
background-color: #99a9bf;
}
.el-carousel__item:nth-child(2n+1) {
background-color: #d3dce6;
}
</style>

View File

@@ -0,0 +1,132 @@
<template>
<el-cascader
:placeholder="placeholder"
:filterable="filterable"
:clearable="clearable"
:options="optionsValue"
:separator="separator"
:props="propsCmp"
:value="valueSwicth"
@focus="getClass"
@change="change"
:style="{
'width': width + 'px'
}"
>
</el-cascader>
</template>
<script>
import { mapGetters } from "vuex";
export default{
props:{
value:{
type:String,
default:''
},
type:{
type:String,
default:''
},
placeholder:{
type:String,
default:'试试搜索:蔬菜'
},
filterable:{
type:Boolean,
default:true
},
clearable:{
type:Boolean,
default:true
},
options:{
type:Array,
default:() => []
},
propsCmp:{
type:Object,
default:() => {
return {
value: "vendorCategoryID",
label: "name"
}
}
},
width:{
type:Number,
default:300
},
separator:{
type:String,
default:'>'
}
},
computed:{
...mapGetters({
jDCategoryData:"jDCategoryData",
jGCategoryData:"jGCategoryData",
mTCategoryData:"mTCategoryData",
dYCategoryData:"dYCategoryData",
eBCategoryData:"eBCategoryData",
}),
optionsValue(){
return this.type ? this.optionsType(this.type)[this.optionsType(this.type).length -1] || [] : this.options
},
valueSwicth(){
let cateAll = this.optionsType(this.type)
if(cateAll.length) return this.switchCat(cateAll,this.value)
else []
}
},
watch:{
},
methods:{
getClass(){
if(this.type) this.$emit('getClass',this.type)
},
// 类型
optionsType(type){
let arr = []
switch(type) {
case 'JD':
arr = this.jDCategoryData
break
case 'JG':
arr = this.jGCategoryData
break
case 'MT':
arr = this.mTCategoryData
break
case 'DD':
arr = this.dYCategoryData
break
case 'EB':
arr = this.eBCategoryData
break
default:
arr = this.options || []
}
return arr
},
// 分类转换
switchCat(arr,id){
return arr.reduce((prev, cur) =>{
let parent = cur.filter(item => +item.vendorCategoryID === +prev[0])[0]
if(parent && parent.parentID) prev.unshift(parent.parentID)
return prev
},[id])
},
// 选中的节点发生变化时
change(e){
this.$emit('input',e.length > 0 ? e[e.length-1] : '')
this.$emit('onChange',this.type,e)
}
}
}
</script>
<style>
</style>

View File

@@ -0,0 +1,59 @@
.sku-list {
margin-top: 20px;
min-height: 50px;
.sku-item {
display: flex;
align-items: center;
padding: 5px 0;
border-radius: 5px;
.left,
.center,
.right {
margin: 0 2px;
// border: 1px solid #ccc;
}
.left {
// flex: 1;
flex-shrink: 0;
font-size: 0;
width: 80px;
img {
border-radius: 5px;
border: 1px solid #dcdfe6;
width: 60px;
height: 60px;
}
}
.center {
width: 100%;
font-size: 14px;
}
.locationCode{
font-size: 14px;
width: 204px;
// margin-right: 10px;
// border: 1px solid #eee;
border: 1px solid #b1b1b1;
padding:5px;
padding-left: 24px;
border-radius: 20px;
font-size: 13px;
}
.count {
width: 140px;
flex-shrink: 0;
font-size: 12px;
}
&:nth-of-type(odd) {
background: #f4f1f1;
}
}
}

View File

@@ -0,0 +1,185 @@
<template>
<div class="sku-list" v-loading="!orderSkus">
<div style="margin-bottom: 10px;" v-show="isShowPartGoods">
<el-tag type="info" >
<!-- <sapn style="margin-right: 10px;">选中的商品:</sapn> -->
<span style="margin-right: 5px;">选择金额{{ (partShopPrice / 100).toFixed(2) }}</span>
<span>实际收益{{ (partActPrice / 100).toFixed(2) }}</span>
</el-tag>
<el-button type="danger" size="mini" @click="delSelectPartSku">批量删除商品</el-button>
</div>
<div
v-for="(item, index) in orderSkusNew"
:key="index"
class="sku-item"
>
<el-checkbox v-if="withoutAuth && (orderInfo.brandID == 1 || orderInfo.brandID == 38)" :disabled="index === 0 || !item.skuID" style="margin:0 5px;" @change="handleCheckedCitiesChange($event,index)"></el-checkbox>
<div class="left">
<img
class="cpt"
v-if="item.image"
@click="imgPreview(item.image.split('?')[0])"
:src="item.image.split('?')[0] + '?imageView2/1/w/60/h/60'"
/>
</div>
<div class="center">
<div>(skuID: {{ item.skuID }}) {{ item.skuName }}</div>
<div style="margin-top: 5px">
<span>京西: {{ (item.shopPrice / 100).toFixed(2) }}</span>
<span style="margin-left: 10px">售卖: {{ (item.salePrice / 100).toFixed(2) }}</span>
<span style="margin-left: 10px" v-if="item.actPrice">活动价: {{ (item.actPrice / 100).toFixed(2) }}</span>
<!-- <span style="margin-left: 10px;">平台: {{(item.vendorPrice / 100).toFixed(2)}}</span> -->
<span style="margin-left: 10px">活动ID:{{ item.storeSubID }}</span>
<!-- !isNewPriceDisplay && (order.orderPayPercentage > 50 && isGY) 最初的结算判断 现在修改为 (order.orderPayPercentage > 50) 只有果园显示 现在菜市也显示(2021 3.8 14:53 小苏说的 ) by 万世雄 -->
<span v-if=" order.orderPayPercentage > 50 && item.earningPrice !== item.shopPrice">
<span style="margin-left: 10px">活动结算: {{ item.storeSubID ? (item.earningPrice / 100).toFixed(2) : 0}}</span>
<span style="margin-left: 10px">结算: {{ (item.earningPrice / 100).toFixed(2) }}</span>
</span>
<!-- <span style="margin-left: 10px">利润:<span :style="{'color':(item.salePrice - item.earningPrice)>0 ? '#f56c6c':'#008000'}">{{ (item.salePrice - item.earningPrice) | toFixed2 }}<span v-if="item.salePrice - item.earningPrice">({{ (((item.salePrice - item.earningPrice) / item.earningPrice) * 10000) | toFixed2 }}%)</span></span></span> -->
<span style="margin-left: 10px">利润:
<span :style="{'color':(item.salePrice - item.earningPrice)>0 ? '#f56c6c':'#008000'}">
{{ (item.salePrice - item.earningPrice) | toFixed2 }}
<span v-if="item.salePrice - item.earningPrice">
({{ (((item.salePrice - item.earningPrice) / item.earningPrice) * 10000) | toFixed2 }}%)
</span>
</span>
</span>
</div>
<div style="color: #909399">
:
<span>京西: {{((item.shopPrice / 100) * item.count).toFixed(2)}}</span>
<span style="margin-left: 10px">售卖: {{((item.salePrice / 100) * item.count).toFixed(2)}}</span>
<span style="margin-left: 10px" v-if="item.actPrice">活动价: {{ ((item.actPrice / 100) * item.count).toFixed(2) }}</span>
<!-- <span style="margin-left: 10px;">平台: {{(item.vendorPrice / 100).toFixed(2)}}</span> -->
<span v-if="order.orderPayPercentage > 50 && item.earningPrice !== item.shopPrice ">
<span style="margin-left: 10px">活动结算: {{ item.storeSubID ? ((item.earningPrice / 100) * item.count).toFixed(2) : 0 }}</span>
<span style="margin-left: 10px">结算: {{((item.earningPrice / 100) * item.count).toFixed(2) }}</span>
</span>
</div>
</div>
<!-- v-if="getDns === 'gblm'" -->
<div class="locationCode" >
<div v-if="item.locationCode2 && item.locationCode2 !== 'EMPTY_VALUE'" >货架码{{ item.locationCode2 }}</div>
<div style="margin-top: 2px;">现库存{{ item.skuStock }}</div>
</div>
<div class="count">
<span>X{{ item.count }}</span>
<el-button icon="el-icon-search" type="text" @click="goStoreSku(item.skuID)"></el-button>
<el-button type="primary" v-if="order.earningType === 1 && withoutAuth" size="mini" @click="refreshGoodsPrice(item.skuID)" >刷新商品价</el-button>
<el-button type="danger" size="mini" v-if=" index != 0 && withoutAuth && orderSkus.length > 2 && (orderInfo.brandID == 1 || orderInfo.brandID == 38)" @click="delOrderSkuInfo(item.id)" >删除商品</el-button>
<el-button v-if="order.vendorID === 5 && order.status <= 10 && withoutAuth" style="margin-left: 0px" type="warning" size="mini" @click="prevDel(item.skuID, item.vendorOrderID)">售前删除</el-button>
</div>
</div>
</div>
</template>
<script>
import imgPreview from '@/tools/imgPreview.js'
import { mapGetters } from "vuex";
export default {
props:['orderSkus','order','orderInfo','withoutAuth','expectIncome'],
data(){
return {
partShopPrice:0, // 部分商品总金额
partActPrice:0, // 部分商品实际收入之和
isShowPartGoods:false,// 是否显示部分商品
}
},
computed:{
...mapGetters({
getDns:"getDns"
}),
orderSkusNew(){
if(this.orderSkus.length >0){
return this.orderSkus.map(item => {
return {
...item,
checked:false
}
})
}else return this.orderSkus
}
},
methods:{
// 选择商品信息
handleCheckedCitiesChange(e,index){
this.orderSkusNew[index].checked = e
// console.log(e,'eeeeeeeee,,,,,orderSkusNew',this.orderSkusNew[index])
// 计算商品总价格
this.computedGoodsAllPrice()
},
computedGoodsAllPrice(){
this.partShopPrice = 0
this.partActPrice = 0
let arr = this.orderSkusNew.filter(item => item.checked)
// console.log('expectIncome',this.expectIncome *100 )
if(arr.length > 0) this.isShowPartGoods = true
else return this.isShowPartGoods = false
this.orderSkusNew.forEach(element => {
if(element.checked){
this.partShopPrice = this.partShopPrice + element.count * element.shopPrice
}
})
this.partActPrice = this.partShopPrice - (-this.expectIncome *100 )
// console.log(this.orderSkusNew,'this.orderSkusNew','partShopPrice',this.partShopPrice,'this.partActPrice',this.partActPrice)
},
// 预览大图
imgPreview(url) {
imgPreview(url)
},
// 搜索商品
goStoreSku(skuID){
let routeData = this.$router.resolve({
name: 'StoreGoodsManager',
query: { storeID: this.order.jxStoreID, skuID },
})
window.open(routeData.href, '_blank')
},
// 刷新商品价
refreshGoodsPrice(val){
this.$emit('refreshGoodsPrice',val)
},
// 批量删除商品
delSelectPartSku(){
let arr = this.orderSkusNew.filter(item => item.checked)
if(arr.length === 0) return this.$toast('未选择商品')
console.log('批量删除商品列表',arr)
this.$confirm('此操作将删除选中的所有商品, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}).then(() => {
// console.log('确定删除商品')
this.$emit('delOrderSkuInfo',arr,'noTip')
})
},
// 删除商品
delOrderSkuInfo(val){
console.log('删除商品',val)
this.$confirm('此操作将删除该商品, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}).then(() => {
// console.log('确定删除商品',val)
this.$emit('delOrderSkuInfo',val)
})
},
// 售前删除
prevDel(skuID, vendorOrderID){
this.$confirm(`此操作会将[${skuID}]商品从此订单中删除`, '确认',{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}).then(() => {
this.$emit('prevDel',skuID, vendorOrderID)
})
}
}
}
</script>
<style lang="scss" scoped>
@import './index.scss'
</style>

View File

View File

@@ -0,0 +1,183 @@
<!-- 单门店时远程搜索 -->
<template>
<el-select
v-model="oneStoreID"
:size="size"
:filterable="filterable"
:remote="remote"
:clearable="clearable"
:placeholder="placeholder"
:remote-method="remoteMethod"
:loading="getStoreLoading"
:disabled="disabled"
:value-key="valueType.valueKey"
@change="onChange"
>
<el-option
v-for="item in options"
:key="item.id"
:label="optionsLable(item)"
:value="valueType.type === 'object' ? item : item.id" >
</el-option>
</el-select>
</template>
<script>
import { getStores } from "@/apis/controls/shop.js";
export default {
name: 'jxSelectPick',
props: {
value: {
// type: [String,Array]
// type: Number
},
filterable: {
type: Boolean,
default: true
},
remote: {
type: Boolean,
default: true
},
clearable: {
type: Boolean,
default: true
},
placeholder: {
type: String,
default: "请输入门店关键字"
},
size: {
type:String,
default:"small"
},
disabled: {
type: Boolean,
defult:false
},
vendorID: {
type: [String,Array]
},
valueType: {
type: Object,
default: () => {
return {
type:'',
valueKey: '',
label:['id','name']
}
}
},
vendorOrgCode: {
type: String,
default:''
}
},
data() {
return {
getStoreLoading: false,
options: [],
oneStoreID: null,
searchParams: {
keyword:'',
pageSize:10
}
}
},
created() {
// console.log('valueType',this.valueType)
},
watch: {
value: {
handler(val) {
if(val) this.oneStoreID = val
}
},
oneStoreID: {
handler(val) {
this.$emit("input", val)
}
},
vendorID: {
handler(val) {
if (val && val.length > 0) {
this.searchParams['vendorStoreCond'] = 'and'
let vendorStoreConds = {
0: '0', // 京东不限定
1: '0', // 美团不限定
2: '0', // e了么不限定
3: '0', // 饿百
4: '0',
5: '0',
9: '0', // 京西
11: '0',
14: '0', // 抖店
16: '0' // 淘鲜达
}
if (!Array.isArray(val)) {
vendorStoreConds[+val] = '1'
} else {
val.forEach(element => {
vendorStoreConds[+element] = '1'
})
}
this.searchParams['vendorStoreConds'] = JSON.stringify(vendorStoreConds)
this.oneStoreID = null
}
},
immediate:true
},
vendorOrgCode: {
handler(val) {
if (val && this.options.length > 0) {
this.options = this.options.filter(item => (item.StoreMaps.filter(i => i.vendorOrgCode === val)).length)
this.oneStoreID = null
}
},
immediate:true
}
},
methods: {
// 选中的值发生改变时
onChange(e) {
this.$emit("input", e)
this.$emit('change',e)
},
// label内容显示
optionsLable(item) {
let label = ''
if (this.valueType.label && this.valueType.label.length>0) {
this.valueType.label.forEach(i => {
if(i!== this.valueType.label[this.valueType.label.length-1]) label =label + item[i] + ' - '
else label = label + item[i]
})
}else label = item.id + ' - ' + item.name
return label
},
// 远程查找门店
async remoteMethod(storeKeyWord) {
this.getStoreLoading = true;
this.searchParams.keyword = storeKeyWord
try {
let { stores } = await getStores(this.searchParams,true)
stores = stores || [];
if (this.vendorOrgCode && stores.length) stores = stores.filter(item => (item.StoreMaps.filter(i => i.vendorOrgCode === this.vendorOrgCode)).length)
this.options = stores;
} catch (e) {
this.$message({
message: "远程查找门店失败",
type: "warning",
center: true,
});
} finally {
this.getStoreLoading = false;
}
}
}
}
</script>
<style lang="scss" scoped>
@import './index.scss'
</style>

View File

@@ -0,0 +1,50 @@
@import '@/assets/scss/_color.scss';
.cmp-store-pick {
border: 1px solid $border1;
border-radius: 10px;
padding: 10px;
width: 740px;
.btn-group {
margin-bottom: 10px;
}
.tree-wrapper {
height: 200px;
overflow-y: auto;
}
.level-title1 {
font-weight: bold;
}
.level2 {
display: inline-flex;
& > * {
display: block;
}
}
.level-title2 {
width: 280px;
white-space:nowrap;
overflow:hidden;
text-overflow:ellipsis;
// border: 1px solid #ccc;
}
.level-id {
width: 70px;
// border: 1px solid #ccc;
}
.level-bind{
width: 150px;
// border: 1px solid #ccc;
span {
color: $text4;
}
}
.level-person {
white-space:nowrap;
overflow:hidden;
text-overflow:ellipsis;
}
span.bindActive {
font-weight: bold;
color: $primary;
}
}

View File

@@ -0,0 +1,720 @@
<template>
<div class="cmp-store-pick" v-loading="loading">
<div
class="btn-group"
style="display: flex; align-items: center; flex-wrap: wrap;"
>
<el-button size="mini" @click="handleAllCheck">全选</el-button>
<el-button size="mini" @click="handleAllClear">清空</el-button>
<el-input
size="mini"
style="width: 160px;"
placeholder="输入关键字进行过滤"
clearable
@input="filterTextChange"
v-model="filterText"
ref="spInput"
></el-input>
<span @click="showType2">已选择: {{ checkStores.length }}</span>
<el-checkbox v-model="showDisabled" style="margin-left: 20px;">显示禁用和休息</el-checkbox>
<el-checkbox-group style="margin-left: 10px;" size="mini" v-model="storeLevels">
<el-checkbox-button
v-for="item in ['A', 'B', 'C', 'D', 'E']"
:label="item"
:key="item">
{{ item }}
</el-checkbox-button>
</el-checkbox-group>
<div style="display: flex; width: 100%;" v-if="type2Show">
<el-input
ref="type2Input"
size="mini"
placeholder="支持多个输入以空格分隔可以直接从excel中粘贴一列"
></el-input>
<el-button size="mini" type="primary" @click="confirmType2">确定</el-button>
</div>
</div>
<div class="tree-wrapper">
<el-tree
ref="storesTree"
:data="cityStores"
:default-checked-keys="defaultStores"
:props="defaultProps"
show-checkbox
:node-key="'id'"
accordion
:filter-node-method="filterNode"
@check="handleCheck"
@node-click="handleNodeClick"
>
<div class="custom-tree-node" slot-scope="{ node, data }">
<span class="level1 level-title1" v-if="node.level === 1">{{ data.name }}({{ data.children.length }})</span>
<!-- 二级 -->
<div class="level2" v-if="node.level === 2">
<span class="level-title2">{{ data.name }}</span>
<span class="level-id">{{ data.id }}</span>
<span class="level-bind">
<span :class="{ bindActive: data.storeMapsJD }"></span>
<span :class="{ bindActive: data.storeMapsJG }"></span>
<span :class="{ bindActive: data.storeMapsMT }"></span>
<span :class="{ bindActive: data.storeMapsEB }">饿</span>
<span :class="{ bindActive: data.storeMapsJX }">西</span>
<span :class="{ bindActive: data.storeMapsDD }"></span>
<span :class="{ bindActive: data.storeMapsTao }"></span>
</span>
<span class="level-person">{{ data.marketManName }} {{ data.operatorName }}{{ data.operatorName2 }}</span>
</div>
</div>
</el-tree>
</div>
</div>
</template>
<script>
/* eslint-disable */
// import { getCity } from "@/apis/common";
import { getStores } from "@/apis/controls/shop.js";
// import { showLoad, hideLoad } from "@/tools/loading";
import { debounce } from "@/utils/underscore";
import { mapGetters } from "vuex";
/* eslint-disable */
export default {
name: "StorePick",
props: [
"vendorIDs",
"vendorOrgCode",
"myStore",
"checkedArr",
"brandID",
"storeForOperation",
"isGoods",
"initDia",
],
data() {
return {
myPhone: null,
defaultStores: [],
loading: false,
AllcityStores: [],
cityStores: [],
defaultProps: {
children: "children",
label: "name",
},
curInitData: [],
checkStores: [],
filterText: "",
places: [],
stores: [],
timer: null,
mapArr: [
"storeMapsJD",
"storeMapsMT",
"",
"storeMapsEB",
// "storeMapsYB",
"storeMapsDD",
"storeMapsTao",
"storeMapsJG",
"",
"",
"",
"storeMapsJX",
"",
"storeMapsWM",
],
type2Show: false,
showDisabled: false,
storeLevels: this.isNewPriceDisplay
? ["A", "B", "C", "E"]
: ["A", "B", "C"],
};
},
created() {
this.initFn();
},
beforeDestroy() {
// 清除 vuex里面的stores
this.$store.commit("DEL_STORES");
},
computed: {
// storesPick
...mapGetters({
userInfo: "userInfo",
actCheckedArr: "actCheckedArr",
isNewPriceDisplay: "isNewPriceDisplay",
cityData:"jxStorePick/allCity"
}),
storesPick() {
let stores = [...this.$store.getters.stores];
// console.error('------------------------------------------------', stores)
return stores;
},
},
methods: {
async initFn() {
const { mobile } = this.userInfo;
this.myPhone = mobile;
this.loading = true;
if(this.cityData.length === 0) await this.$store.dispatch('jxStorePick/getCity')
let places = this.cityData
let { stores } = await getStores(
{
pageSize: -1,
statuss: JSON.stringify([-2, -1, 0, 1]),
briefLevel: 1,
},
true
);
this.places = this.mapPlaces(places);
this.stores = this.mapStores(stores || []);
stores = this.mapVendorIDs(this.stores);
stores = stores.filter((item) =>
this.showDisabled ? true : item.status > -1
);
// 筛选 选中等级的城市
stores = stores.filter((item) =>
this.storeLevels.includes(item.storeLevel)
);
// 过滤掉平台账号的门店
if (this.vendorOrgCode) {
let brr = []
stores.map((item => {
item.storeMaps.map((i) => {
if (i.vendorOrgCode === this.vendorOrgCode) {
brr.push(item)
}
})
}))
stores = brr
}
this.cityStores = this.groupPlacesStores(this.places, stores);
// this.cityStores = this.AllcityStores
// 检查store里面是否有值
if (this.storesPick.length > 0) {
this.checkStores = [...this.storesPick];
this.setCheckedKeys(this.checkStores);
// this.getCheckedKeys()
this.$emit("updateStoreIDs", this.checkStores);
}
if (this.actCheckedArr.length > 0) {
this.checkStores = [...this.actCheckedArr];
this.setCheckedKeys(this.checkStores);
// this.getCheckedKeys()
this.$emit("updateStoreIDs", this.checkStores);
}
this.loading = false;
if (this.checkedArr && this.checkedArr.storeIDs.length > 0) {
this.defaultStores = this.checkedArr.storeIDs;
this.checkStores.splice(0, this.checkStores);
this.defaultStores.length &&
this.defaultStores.forEach((item) => this.checkStores.push(item));
}
},
// 组合城市门店
groupPlacesStores(places, stores) {
let arr = [];
let json = {};
stores.forEach((store) => {
if (!json[store.cityCode]) {
json[store.cityCode] = [];
}
json[store.cityCode].push(store);
});
arr = places.map((item) => {
return {
...item,
children: json[item.code] || [],
};
});
// 去掉没有门店的城市
arr = arr.filter((item) => item.children.length !== 0);
return arr;
},
// 过滤城市
mapPlaces(arr) {
return arr.map((item) => ({
code: item.code,
name: item.name,
id: "c" + item.code,
}));
},
// 过滤门店
mapStores(arr) {
return arr.map((item) => {
let storeMapsJD = false;
let storeMapsJG = false;
let storeMapsMT = false;
let storeMapsEB = false;
let storeMapsJX = false;
// let storeMapsYB = false;
let storeMapsDD = false
let storeMapsTao = false
if (item.StoreMaps) {
let storeMaps = item.StoreMaps;
if (storeMaps.find((item) => item.vendorID === 0)) storeMapsJD = true;
if (storeMaps.find((item) => item.vendorID === 1)) storeMapsMT = true;
if (storeMaps.find((item) => item.vendorID === 3)) storeMapsEB = true;
// if (storeMaps.find((item) => item.vendorID === 4)) storeMapsYB = true;
if (storeMaps.find((item) => item.vendorID === 14)) storeMapsDD = true
if (storeMaps.find((item) => item.vendorID === 16)) storeMapsTao = true
if (storeMaps.find((item) => item.vendorID === 5)) storeMapsJG = true;
if (storeMaps.find((item) => item.vendorID === 9)) storeMapsJX = true;
}
return {
id: item.id,
name:
`(${item.storeLevel})` +
item.name +
`(${item.payPercentage / 10}折)`,
cityCode: item.cityCode,
cityName: item.cityName,
brandID: item.brandID,
storeMapsJD,
storeMapsJG,
storeMapsMT,
storeMapsEB,
// storeMapsYB,
storeMapsDD,
storeMapsTao,
storeMapsJX,
storeMaps: item.StoreMaps
? item.StoreMaps.map((item) => ({
vendorStoreID: item.vendorStoreID,
vendorID: item.vendorID,
vendorOrgCode: item.vendorOrgCode || "",
}))
: [],
marketManName: item.marketManName,
marketManPhone: item.marketManPhone,
operatorName: item.operatorName,
operatorPhone: item.operatorPhone,
operatorName2: item.operatorName2,
operatorPhone2: item.operatorPhone2,
status: item.status,
storeLevel: item.storeLevel,
};
});
},
//门店过滤(所有运营
mapStoresByOperatorPhone(arr) {
try {
let arr1 = JSON.parse(JSON.stringify(arr));
let arr2 = [];
this.storeForOperation.forEach((item) => {
arr2.push(...arr1.filter((v) => v.operatorPhone == item));
});
return arr2;
} catch (e) {
}
},
distinct(arr, key) {
const set = new Set();
return arr.reduce(
(p, c) => set.has(c[key] ? p : (set.add(c[key]), [...p, c])),
[]
);
},
//我负责的门店过滤(平台
mapStoresByTel(arr) {
try {
let arr1 = JSON.parse(JSON.stringify(arr));
let arr2 = this.distinct(
arr1.filter((item) => item.marketManPhone === this.myPhone),
"id"
);
return arr2;
} catch (e) {
}
},
// 过滤vendorIDs
mapVendorIDs(stores) {
try {
let arr = JSON.parse(JSON.stringify(stores))
let vendorIDs = JSON.parse(JSON.stringify(this.vendorIDs || []));
// 兼容 -1
if (vendorIDs[0] === -1) vendorIDs = [];
this.vendorIDs &&
this.vendorIDs.length &&
(arr = arr.filter((item) => {
let res = item.storeMaps.filter((v) =>
this.vendorIDs.includes(v.vendorID)
);
return res.length;
}));
return arr;
} catch (e) {
}
},
// 通过key设置勾选
setCheckedKeys(arr) {
this.$refs.storesTree.setCheckedKeys(arr);
},
// 点击节点
handleNodeClick(data) {
},
// 获取勾选的节点
getCheckedKeys() {
let checked = this.$refs.storesTree.getCheckedKeys(true);
this.checkStores = Array.from(new Set([...this.checkStores, ...checked]));
this.$emit("updateStoreIDs", this.checkStores);
},
// 选择
handleCheck(node, data) {
this.$store.commit("SET_VENDORIDS", data.checkedNodes);
if (data.checkedNodes.indexOf(node) === -1) {
// 不勾选
this.checkStores = this.checkStores.filter((item) => item !== node.id);
if (node.hasOwnProperty("children")) {
let childrenIDs = node.children.map((item) => item.id);
this.checkStores = this.checkStores.filter(
(item) => childrenIDs.indexOf(item) === -1
);
}
}
this.getCheckedKeys();
},
// 全选
handleAllCheck() {
// 调清空再全选,解决等级改变后 再点全选,选择不变的问题
this.handleAllClear();
this.$refs.storesTree.setCheckedKeys(
this.cityStores.map((item) => item.id)
);
this.getCheckedKeys();
},
// 清空
handleAllClear() {
this.$refs.storesTree.setCheckedKeys([]);
this.$store.commit("DEL_STORES");
// this.getCheckedKeys()
this.checkStores = [];
this.$emit("updateStoreIDs", this.checkStores);
},
// 过滤关键字
filterNode(value, data) {
if (!value) {
let nodes = this.$refs.storesTree.store._getAllNodes();
for (let i = 0; i < nodes.length; i++) {
nodes[i].expanded = false;
}
return true;
}
let str = JSON.stringify(data);
return str.indexOf(value) !== -1;
},
// 关键字改变
// filterTextChange (val) {
// val = val.trim()
// // 防抖
// if (!this.timer) {
// this.timer = debounce((val) => {
// this.filterText = val
// }, 500, false)
// }
// this.timer && this.timer(val)
// }
filterTextChange: debounce(
function(val) {
val = val.trim();
this.filterText = val;
},
1000,
false
),
// 显示类型2筛选
showType2() {
this.type2Show = !this.type2Show;
},
confirmType2() {
const str = this.$refs.type2Input.currentValue;
const storeIDs = Array.from(new Set(str.split(/\s/))).map(
(item) => +item
);
this.$emit("updateStoreIDs", storeIDs);
// Array.from(new Set(this.skuID.split(/\s/)
},
},
watch: {
checkedArr: {
handler(newValue) {
this.curInitData.length &&
this.curInitData.splice(0, this.curInitData.length);
newValue.storeInfo &&
newValue.storeInfo.forEach((item) => this.curInitData.push(item.id));
this.$refs.storesTree.setCheckedNodes([]);
this.defaultStores = newValue.storeIDs;
},
deep: true,
},
actCheckedArr: {
handler(newValue) {
this.$refs.storesTree.setCheckedNodes([]);
this.defaultStores = newValue;
this.initFn();
},
deep: true,
},
initDia: {
handler() {
this.storeLevels.length &&
(this.storeLevels.splice(0, this.storeLevels.length),
this.storeLevels.push(...["A", "B", "C"]));
this.isInit = true;
},
deep: true,
},
filterText: function(val) {
let stores = this.stores.filter(
(item) => JSON.stringify(item).indexOf(val) !== -1
);
stores = this.mapVendorIDs(stores);
stores = stores.filter((item) =>
this.showDisabled ? true : item.status > -1
);
stores = stores.filter((item) =>
this.storeLevels.includes(item.storeLevel)
);
if (this.brandID) {
stores = stores.filter((item) => item.brandID === this.brandID);
}
this.storeForOperation &&
this.isGoods &&
(stores = this.mapStoresByOperatorPhone(stores));
this.cityStores = this.groupPlacesStores(this.places, stores);
this.$refs.storesTree.filter(val);
this.setCheckedKeys(this.checkStores);
},
vendorIDs: function(val, from) {
// if (JSON.stringify(val) === JSON.stringify(from)) return false;
// 厂商改变重新计算数据
let stores = this.stores;
stores = stores.filter(
(item) => JSON.stringify(item).indexOf(this.filterText) !== -1
);
if (this.brandID) {
stores = stores.filter((item) => item.brandID === this.brandID);
}
stores = stores.filter((item) =>
this.showDisabled ? true : item.status > -1
);
stores = stores.filter((item) =>
this.storeLevels.includes(item.storeLevel)
);
stores = this.mapVendorIDs(stores);
stores = stores.filter((item) => {
let res = item.storeMaps.filter((v) =>
this.vendorIDs.includes(v.vendorID)
);
return res.length;
});
// (this.storeForOperation && this.isGoods) && (stores = this.mapStoresByOperatorPhone(stores))
this.cityStores = this.groupPlacesStores(this.places, stores);
this.handleAllClear();
},
storeForOperation: function(val) {
let stores = this.stores;
if (val.length) {
this.storeForOperation &&
this.isGoods &&
(stores = this.mapStoresByOperatorPhone(stores));
if (this.filterText)
stores = this.stores.filter(
(item) => JSON.stringify(item).indexOf(this.filterText) !== -1
);
stores = this.mapVendorIDs(stores);
this.cityStores = this.groupPlacesStores(this.places, stores);
stores = stores.filter((item) => {
return this.showDisabled ? true : item.status > -1;
});
if (this.brandID) {
stores = stores.filter((item) => item.brandID === this.brandID);
}
stores = stores.filter((item) =>
this.storeLevels.includes(item.storeLevel)
);
this.cityStores = this.groupPlacesStores(this.places, stores);
this.handleAllClear();
} else {
if (this.filterText)
stores = this.stores.filter(
(item) => JSON.stringify(item).indexOf(this.filterText) !== -1
);
stores = stores.filter((item) =>
this.showDisabled ? true : item.status > -1
);
if (this.brandID) {
stores = stores.filter((item) => item.brandID === this.brandID);
}
stores = stores.filter((item) =>
this.storeLevels.includes(item.storeLevel)
);
stores = this.mapVendorIDs(stores);
this.cityStores = this.groupPlacesStores(this.places, stores);
this.handleAllClear();
}
},
myStore: function(val) {
let stores = this.stores;
if (val) {
stores = this.mapStoresByTel(stores);
if (this.filterText)
stores = this.stores.filter(
(item) => JSON.stringify(item).indexOf(this.filterText) !== -1
);
stores = this.mapVendorIDs(stores);
this.cityStores = this.groupPlacesStores(this.places, stores);
stores = stores.filter((item) =>
this.showDisabled ? true : item.status > -1
);
stores = stores.filter((item) =>
this.storeLevels.includes(item.storeLevel)
);
this.handleAllClear();
} else {
if (this.filterText)
stores = this.stores.filter(
(item) => JSON.stringify(item).indexOf(this.filterText) !== -1
);
stores = stores.filter((item) =>
this.showDisabled ? true : item.status > -1
);
stores = stores.filter((item) =>
this.storeLevels.includes(item.storeLevel)
);
stores = this.mapVendorIDs(stores);
this.cityStores = this.groupPlacesStores(this.places, stores);
this.handleAllClear();
}
},
brandID: function(val) {
let stores = this.stores;
if (val) {
if (this.filterText)
stores = stores.filter(
(item) => JSON.stringify(item).indexOf(this.filterText) !== -1
);
stores = stores.filter((item) =>
this.showDisabled ? true : item.status > -1
);
stores = stores.filter((item) => item.brandID === this.brandID);
stores = this.mapVendorIDs(stores);
this.cityStores = this.groupPlacesStores(this.places, stores);
this.handleAllClear();
} else {
let stores = this.stores.filter(
(item) => JSON.stringify(item).indexOf(val) !== -1
);
stores = this.mapVendorIDs(stores);
stores = stores.filter((item) =>
this.showDisabled ? true : item.status > -1
);
stores = stores.filter((item) =>
this.storeLevels.includes(item.storeLevel)
);
this.cityStores = this.groupPlacesStores(this.places, stores);
this.$refs.storesTree.filter(val);
this.setCheckedKeys(this.checkStores);
}
},
showDisabled: function(val) {
let stores = this.stores;
if (this.filterText)
stores = this.stores.filter(
(item) => JSON.stringify(item).indexOf(this.filterText) !== -1
);
stores = this.mapVendorIDs(stores);
stores = stores.filter((item) =>
this.showDisabled ? true : item.status > -1
);
stores = stores.filter((item) =>
this.storeLevels.includes(item.storeLevel)
);
this.storeForOperation &&
this.isGoods &&
(stores = this.mapStoresByOperatorPhone(stores));
this.cityStores = this.groupPlacesStores(this.places, stores);
// this.handleAllClear();
},
storeLevels: function(val) {
// level 选择会触发此函数
if (val.length > 0) {
let stores = this.stores;
// levels 改变 关键字查询依然有效
if (this.filterText)
stores = this.stores.filter(
(item) => JSON.stringify(item).indexOf(this.filterText) !== -1
);
stores = this.mapVendorIDs(stores);
stores = stores.filter((item) =>
this.showDisabled ? true : item.status > -1
);
this.brandID &&
(stores = stores.filter((item) => item.brandID === this.brandID));
stores = stores.filter((item) => val.includes(item.storeLevel));
this.storeForOperation &&
this.isGoods &&
(stores = this.mapStoresByOperatorPhone(stores));
this.cityStores = this.groupPlacesStores(this.places, stores);
// this.handleAllClear();
} else {
let stores = this.stores;
if (this.filterText)
stores = this.stores.filter(
(item) => JSON.stringify(item).indexOf(this.filterText) !== -1
);
stores = this.mapVendorIDs(stores);
this.storeForOperation &&
this.isGoods &&
(stores = this.mapStoresByOperatorPhone(stores));
this.cityStores = this.groupPlacesStores(this.places, stores);
this.handleAllClear();
}
if (this.isInit) {
this.isInit = false;
this.type2Show = false;
this.filterText = "";
this.checkStores.length &&
this.checkStores.splice(0, this.checkStores.length);
this.curInitData &&
this.curInitData.forEach((item) => this.checkStores.push(item));
this.setCheckedKeys(this.checkStores);
}
},
storesPick: function(val) {
if (val.length > 0) {
this.checkStores = val;
this.setCheckedKeys(this.checkStores);
this.getCheckedKeys();
}
},
vendorOrgCode: function(val) {
// 厂商改变重新计算数据
let stores = this.stores;
if (this.filterText)
stores = this.stores.filter(
(item) => JSON.stringify(item).indexOf(this.filterText) !== -1
);
stores = this.mapVendorIDs(stores);
this.cityStores = this.groupPlacesStores(this.places, stores);
this.handleAllClear();
}
},
};
</script>
<style lang="scss">
@import "./index.scss";
</style>

View File

@@ -0,0 +1,781 @@
<template>
<div class="cmp-store-pick" v-loading="loading">
<div
class="btn-group"
style="display: flex; align-items: center; flex-wrap: wrap;"
>
<el-button size="mini" @click="handleAllCheck">全选</el-button>
<el-button size="mini" @click="handleAllClear">清空</el-button>
<el-input
size="mini"
style="width: 160px;"
placeholder="输入关键字进行过滤"
clearable
@input="filterTextChange"
v-model="filterText"
ref="spInput"
></el-input>
<span @click="showType2">已选择: {{ checkStores.length }}</span>
<el-checkbox v-model="showDisabled" style="margin-left: 20px;">显示禁用和休息</el-checkbox>
<el-checkbox-group style="margin-left: 10px;" size="mini" v-model="storeLevels">
<el-checkbox-button
v-for="item in ['A', 'B', 'C', 'D', 'E']"
:label="item"
:key="item">
{{ item }}
</el-checkbox-button>
</el-checkbox-group>
<div style="display: flex; width: 100%;" v-if="type2Show">
<el-input
ref="type2Input"
size="mini"
placeholder="支持多个输入以空格分隔可以直接从excel中粘贴一列"
></el-input>
<el-button size="mini" type="primary" @click="confirmType2">确定</el-button>
</div>
</div>
<div class="tree-wrapper">
<el-tree
ref="storesTree"
:data="cityStores"
:default-checked-keys="defaultStores"
:props="defaultProps"
show-checkbox
:node-key="'id'"
accordion
:filter-node-method="filterNode"
@check="handleCheck"
@node-click="handleNodeClick"
>
<div class="custom-tree-node" slot-scope="{ node, data }">
<span class="level1 level-title1" v-if="node.level === 1">{{ data.name }}({{ data.children.length }})</span>
<!-- 二级 -->
<div class="level2" v-if="node.level === 2">
<span class="level-title2">{{ data.name }}</span>
<span class="level-id">{{ data.id }}</span>
<span class="level-bind">
<span :class="{ bindActive: data.storeMapsJD }"></span>
<span :class="{ bindActive: data.storeMapsJG }"></span>
<span :class="{ bindActive: data.storeMapsMT }"></span>
<span :class="{ bindActive: data.storeMapsEB }">饿</span>
<span :class="{ bindActive: data.storeMapsJX }">西</span>
<span :class="{ bindActive: data.storeMapsDD }"></span>
<span :class="{ bindActive: data.storeMapsTao }"></span>
</span>
<span class="level-person">{{ data.marketManName }} {{ data.operatorName }}{{ data.operatorName2 }}</span>
</div>
</div>
</el-tree>
</div>
</div>
</template>
<script>
/* eslint-disable */
// import { getCity } from "@/apis/common";
import { getStores } from "@/apis/controls/shop.js";
// import { showLoad, hideLoad } from "@/tools/loading";
import { debounce } from "@/utils/underscore";
import { mapGetters } from "vuex";
/* eslint-disable */
export default {
name: "StorePick",
props: [
"vendorIDs",
"vendorOrgCode",
"myStore",
"checkedArr",
"brandID",
"storeForOperation",
"isGoods",
"initDia",
"isInit"
],
data() {
return {
myPhone: null,
defaultStores: [],
loading: false,
AllcityStores: [],
cityStores: [],
defaultProps: {
children: "children",
label: "name",
},
curInitData: [],
checkStores: [],
filterText: "",
places: [],
stores: [],
timer: null,
mapArr: [
"storeMapsJD",
"storeMapsMT",
"",
"storeMapsEB",
// "storeMapsYB",
"storeMapsDD",
"storeMapsTao",
"storeMapsJG",
"",
"",
"",
"storeMapsJX",
"",
"storeMapsWM",
],
type2Show: false,
showDisabled: false,
storeLevels: this.isNewPriceDisplay
? ["A", "B", "C", "E"]
: ["A", "B", "C"],
};
},
created() {
if(!this.isInit) this.initFn();
},
beforeDestroy() {
// 清除 vuex里面的stores
this.$store.commit("DEL_STORES");
},
computed: {
// storesPick
...mapGetters({
userInfo: "userInfo",
actCheckedArr: "actCheckedArr",
isNewPriceDisplay: "isNewPriceDisplay",
cityData:"jxStorePick/allCity",
storesAll:"jxStorePick/stores",
}),
storesPick() {
let stores = [...this.$store.getters.stores];
// console.error('------------------------------------------------', stores)
return stores;
},
},
methods: {
async initFn() {
const { mobile } = this.userInfo;
this.myPhone = mobile;
this.loading = true;
if(this.cityData.length === 0) await this.$store.dispatch('jxStorePick/getCity')
let places = this.cityData
// 判断是否立即进行初始化
let stores = []
if(this.storesAll && this.storesAll.length>0){
stores = this.storesAll
}else{
console.log('zou')
let res = await getStores(
{
pageSize: -1,
statuss: JSON.stringify([-2, -1, 0, 1]),
briefLevel: 1,
},
true
);
stores = res.stores
}
this.places = this.mapPlaces(places);
this.stores = this.mapStores(stores || []);
stores = this.mapVendorIDs(this.stores);
stores = stores.filter((item) =>
this.showDisabled ? true : item.status > -1
);
// 筛选 选中等级的城市
stores = stores.filter((item) =>
this.storeLevels.includes(item.storeLevel)
);
// 过滤掉平台账号的门店
if (this.vendorOrgCode) {
let brr = []
stores.map((item => {
item.storeMaps.map((i) => {
if (i.vendorOrgCode === this.vendorOrgCode) {
brr.push(item)
}
})
}))
stores = brr
}
this.cityStores = this.groupPlacesStores(this.places, stores);
// this.cityStores = this.AllcityStores
// 检查store里面是否有值
if (this.storesPick.length > 0) {
this.checkStores = [...this.storesPick];
this.setCheckedKeys(this.checkStores);
// this.getCheckedKeys()
this.$emit("updateStoreIDs", this.checkStores);
}
if (this.actCheckedArr.length > 0) {
this.checkStores = [...this.actCheckedArr];
this.setCheckedKeys(this.checkStores);
// this.getCheckedKeys()
this.$emit("updateStoreIDs", this.checkStores);
}
this.loading = false;
if (this.checkedArr && this.checkedArr.storeIDs.length > 0) {
this.defaultStores = this.checkedArr.storeIDs;
this.checkStores.splice(0, this.checkStores);
this.defaultStores.length &&
this.defaultStores.forEach((item) => this.checkStores.push(item));
}
},
// 组合城市门店
groupPlacesStores(places, stores) {
let arr = [];
let json = {};
stores.forEach((store) => {
if (!json[store.cityCode]) {
json[store.cityCode] = [];
}
json[store.cityCode].push(store);
});
arr = places.map((item) => {
return {
...item,
children: json[item.code] || [],
};
});
// 去掉没有门店的城市
arr = arr.filter((item) => item.children.length !== 0);
return arr;
},
// 过滤城市
mapPlaces(arr) {
return arr.map((item) => ({
code: item.code,
name: item.name,
id: "c" + item.code,
}));
},
// 过滤门店
mapStores(arr) {
return arr.map((item) => {
let storeMapsJD = false;
let storeMapsJG = false;
let storeMapsMT = false;
let storeMapsEB = false;
let storeMapsJX = false;
// let storeMapsYB = false;
let storeMapsDD = false
let storeMapsTao = false
if (item.StoreMaps) {
let storeMaps = item.StoreMaps;
if (storeMaps.find((item) => item.vendorID === 0)) storeMapsJD = true;
if (storeMaps.find((item) => item.vendorID === 1)) storeMapsMT = true;
if (storeMaps.find((item) => item.vendorID === 3)) storeMapsEB = true;
// if (storeMaps.find((item) => item.vendorID === 4)) storeMapsYB = true;
if (storeMaps.find((item) => item.vendorID === 14)) storeMapsDD = true
if (storeMaps.find((item) => item.vendorID === 16)) storeMapsTao = true
if (storeMaps.find((item) => item.vendorID === 5)) storeMapsJG = true;
if (storeMaps.find((item) => item.vendorID === 9)) storeMapsJX = true;
}
return {
id: item.id,
name:
`(${item.storeLevel})` +
item.name +
`(${item.payPercentage / 10}折)`,
cityCode: item.cityCode,
cityName: item.cityName,
brandID: item.brandID,
storeMapsJD,
storeMapsJG,
storeMapsMT,
storeMapsEB,
// storeMapsYB,
storeMapsDD,
storeMapsTao,
storeMapsJX,
storeMaps: item.StoreMaps
? item.StoreMaps.map((item) => ({
vendorStoreID: item.vendorStoreID,
vendorID: item.vendorID,
vendorOrgCode: item.vendorOrgCode || "",
}))
: [],
marketManName: item.marketManName,
marketManPhone: item.marketManPhone,
operatorName: item.operatorName,
operatorPhone: item.operatorPhone,
operatorName2: item.operatorName2,
operatorPhone2: item.operatorPhone2,
status: item.status,
storeLevel: item.storeLevel,
};
});
},
//门店过滤(所有运营
mapStoresByOperatorPhone(arr) {
try {
let arr1 = JSON.parse(JSON.stringify(arr));
let arr2 = [];
this.storeForOperation.forEach((item) => {
arr2.push(...arr1.filter((v) => v.operatorPhone == item));
});
return arr2;
} catch (e) {
}
},
distinct(arr, key) {
const set = new Set();
return arr.reduce(
(p, c) => set.has(c[key] ? p : (set.add(c[key]), [...p, c])),
[]
);
},
//我负责的门店过滤(平台
mapStoresByTel(arr) {
try {
let arr1 = JSON.parse(JSON.stringify(arr));
let arr2 = this.distinct(
arr1.filter((item) => item.marketManPhone === this.myPhone),
"id"
);
return arr2;
} catch (e) {
}
},
// 过滤vendorIDs
mapVendorIDs(stores) {
try {
let arr = JSON.parse(JSON.stringify(stores))
let vendorIDs = JSON.parse(JSON.stringify(this.vendorIDs || []));
// 兼容 -1
if (vendorIDs[0] === -1) vendorIDs = [];
this.vendorIDs &&
this.vendorIDs.length &&
(arr = arr.filter((item) => {
let res = item.storeMaps.filter((v) =>
this.vendorIDs.includes(v.vendorID)
);
return res.length;
}));
return arr;
} catch (e) {
}
},
// 通过key设置勾选
setCheckedKeys(arr) {
this.$refs.storesTree.setCheckedKeys(arr);
},
// 点击节点
handleNodeClick(data) {
},
// 获取勾选的节点
getCheckedKeys() {
let checked = this.$refs.storesTree.getCheckedKeys(true);
this.checkStores = Array.from(new Set([...this.checkStores, ...checked]));
this.$emit("updateStoreIDs", this.checkStores);
},
// 选择
handleCheck(node, data) {
this.$store.commit("SET_VENDORIDS", data.checkedNodes);
if (data.checkedNodes.indexOf(node) === -1) {
// 不勾选
this.checkStores = this.checkStores.filter((item) => item !== node.id);
if (node.hasOwnProperty("children")) {
let childrenIDs = node.children.map((item) => item.id);
this.checkStores = this.checkStores.filter(
(item) => childrenIDs.indexOf(item) === -1
);
}
}
this.getCheckedKeys();
},
// 全选
handleAllCheck() {
// 调清空再全选,解决等级改变后 再点全选,选择不变的问题
this.handleAllClear();
this.$refs.storesTree.setCheckedKeys(
this.cityStores.map((item) => item.id)
);
this.getCheckedKeys();
},
// 清空
handleAllClear() {
this.$refs.storesTree.setCheckedKeys([]);
this.$store.commit("DEL_STORES");
// this.getCheckedKeys()
this.checkStores = [];
this.$emit("updateStoreIDs", this.checkStores);
},
// 过滤关键字
filterNode(value, data) {
if (!value) {
let nodes = this.$refs.storesTree.store._getAllNodes();
for (let i = 0; i < nodes.length; i++) {
nodes[i].expanded = false;
}
return true;
}
let str = JSON.stringify(data);
return str.indexOf(value) !== -1;
},
// 关键字改变
// filterTextChange (val) {
// val = val.trim()
// // 防抖
// if (!this.timer) {
// this.timer = debounce((val) => {
// this.filterText = val
// }, 500, false)
// }
// this.timer && this.timer(val)
// }
filterTextChange: debounce(
function(val) {
val = val.trim();
this.filterText = val;
},
1000,
false
),
// 显示类型2筛选
showType2() {
this.type2Show = !this.type2Show;
},
confirmType2() {
const str = this.$refs.type2Input.currentValue;
const storeIDs = Array.from(new Set(str.split(/\s/))).map(
(item) => +item
);
this.$emit("updateStoreIDs", storeIDs);
// Array.from(new Set(this.skuID.split(/\s/)
},
},
watch: {
checkedArr: {
handler(newValue) {
this.curInitData.length &&
this.curInitData.splice(0, this.curInitData.length);
newValue.storeInfo &&
newValue.storeInfo.forEach((item) => this.curInitData.push(item.id));
this.$refs.storesTree.setCheckedNodes([]);
this.defaultStores = newValue.storeIDs;
},
deep: true,
},
actCheckedArr: {
handler(newValue) {
this.$refs.storesTree.setCheckedNodes([]);
this.defaultStores = newValue;
this.initFn();
},
deep: true,
},
initDia: {
handler() {
this.storeLevels.length &&
(this.storeLevels.splice(0, this.storeLevels.length),
this.storeLevels.push(...["A", "B", "C"]));
this.isInit = true;
},
deep: true,
},
filterText: function(val) {
let stores = this.stores.filter(
(item) => JSON.stringify(item).indexOf(val) !== -1
);
stores = this.mapVendorIDs(stores);
stores = stores.filter((item) =>
this.showDisabled ? true : item.status > -1
);
stores = stores.filter((item) =>
this.storeLevels.includes(item.storeLevel)
);
if (this.brandID) {
stores = stores.filter((item) => item.brandID === this.brandID);
}
this.storeForOperation &&
this.isGoods &&
(stores = this.mapStoresByOperatorPhone(stores));
this.cityStores = this.groupPlacesStores(this.places, stores);
this.$refs.storesTree.filter(val);
this.setCheckedKeys(this.checkStores);
},
vendorIDs: function(val, from) {
// if (JSON.stringify(val) === JSON.stringify(from)) return false;
// 厂商改变重新计算数据
let stores = this.stores;
stores = stores.filter(
(item) => JSON.stringify(item).indexOf(this.filterText) !== -1
);
if (this.brandID) {
stores = stores.filter((item) => item.brandID === this.brandID);
}
stores = stores.filter((item) =>
this.showDisabled ? true : item.status > -1
);
stores = stores.filter((item) =>
this.storeLevels.includes(item.storeLevel)
);
stores = this.mapVendorIDs(stores);
stores = stores.filter((item) => {
let res = item.storeMaps.filter((v) =>
this.vendorIDs.includes(v.vendorID)
);
return res.length;
});
// (this.storeForOperation && this.isGoods) && (stores = this.mapStoresByOperatorPhone(stores))
this.cityStores = this.groupPlacesStores(this.places, stores);
this.handleAllClear();
},
storeForOperation: function(val) {
let stores = this.stores;
if (val.length) {
this.storeForOperation &&
this.isGoods &&
(stores = this.mapStoresByOperatorPhone(stores));
if (this.filterText)
stores = this.stores.filter(
(item) => JSON.stringify(item).indexOf(this.filterText) !== -1
);
stores = this.mapVendorIDs(stores);
this.cityStores = this.groupPlacesStores(this.places, stores);
stores = stores.filter((item) => {
return this.showDisabled ? true : item.status > -1;
});
if (this.brandID) {
stores = stores.filter((item) => item.brandID === this.brandID);
}
stores = stores.filter((item) =>
this.storeLevels.includes(item.storeLevel)
);
this.cityStores = this.groupPlacesStores(this.places, stores);
this.handleAllClear();
} else {
if (this.filterText)
stores = this.stores.filter(
(item) => JSON.stringify(item).indexOf(this.filterText) !== -1
);
stores = stores.filter((item) =>
this.showDisabled ? true : item.status > -1
);
if (this.brandID) {
stores = stores.filter((item) => item.brandID === this.brandID);
}
stores = stores.filter((item) =>
this.storeLevels.includes(item.storeLevel)
);
stores = this.mapVendorIDs(stores);
this.cityStores = this.groupPlacesStores(this.places, stores);
this.handleAllClear();
}
},
myStore: function(val) {
let stores = this.stores;
if (val) {
stores = this.mapStoresByTel(stores);
if (this.filterText)
stores = this.stores.filter(
(item) => JSON.stringify(item).indexOf(this.filterText) !== -1
);
stores = this.mapVendorIDs(stores);
this.cityStores = this.groupPlacesStores(this.places, stores);
stores = stores.filter((item) =>
this.showDisabled ? true : item.status > -1
);
stores = stores.filter((item) =>
this.storeLevels.includes(item.storeLevel)
);
this.handleAllClear();
} else {
if (this.filterText)
stores = this.stores.filter(
(item) => JSON.stringify(item).indexOf(this.filterText) !== -1
);
stores = stores.filter((item) =>
this.showDisabled ? true : item.status > -1
);
stores = stores.filter((item) =>
this.storeLevels.includes(item.storeLevel)
);
stores = this.mapVendorIDs(stores);
this.cityStores = this.groupPlacesStores(this.places, stores);
this.handleAllClear();
}
},
brandID: function(val) {
let stores = this.stores;
if (val) {
if (this.filterText)
stores = stores.filter(
(item) => JSON.stringify(item).indexOf(this.filterText) !== -1
);
stores = stores.filter((item) =>
this.showDisabled ? true : item.status > -1
);
stores = stores.filter((item) => item.brandID === this.brandID);
stores = this.mapVendorIDs(stores);
this.cityStores = this.groupPlacesStores(this.places, stores);
this.handleAllClear();
} else {
let stores = this.stores.filter(
(item) => JSON.stringify(item).indexOf(val) !== -1
);
stores = this.mapVendorIDs(stores);
stores = stores.filter((item) =>
this.showDisabled ? true : item.status > -1
);
stores = stores.filter((item) =>
this.storeLevels.includes(item.storeLevel)
);
this.cityStores = this.groupPlacesStores(this.places, stores);
this.$refs.storesTree.filter(val);
this.setCheckedKeys(this.checkStores);
}
},
showDisabled: function(val) {
let stores = this.stores;
if (this.filterText)
stores = this.stores.filter(
(item) => JSON.stringify(item).indexOf(this.filterText) !== -1
);
stores = this.mapVendorIDs(stores);
stores = stores.filter((item) =>
this.showDisabled ? true : item.status > -1
);
stores = stores.filter((item) =>
this.storeLevels.includes(item.storeLevel)
);
this.storeForOperation &&
this.isGoods &&
(stores = this.mapStoresByOperatorPhone(stores));
this.cityStores = this.groupPlacesStores(this.places, stores);
// this.handleAllClear();
},
storeLevels: function(val) {
// level 选择会触发此函数
if (val.length > 0) {
let stores = this.stores;
// levels 改变 关键字查询依然有效
if (this.filterText)
stores = this.stores.filter(
(item) => JSON.stringify(item).indexOf(this.filterText) !== -1
);
stores = this.mapVendorIDs(stores);
stores = stores.filter((item) =>
this.showDisabled ? true : item.status > -1
);
this.brandID &&
(stores = stores.filter((item) => item.brandID === this.brandID));
stores = stores.filter((item) => val.includes(item.storeLevel));
this.storeForOperation &&
this.isGoods &&
(stores = this.mapStoresByOperatorPhone(stores));
this.cityStores = this.groupPlacesStores(this.places, stores);
// this.handleAllClear();
} else {
let stores = this.stores;
if (this.filterText)
stores = this.stores.filter(
(item) => JSON.stringify(item).indexOf(this.filterText) !== -1
);
stores = this.mapVendorIDs(stores);
this.storeForOperation &&
this.isGoods &&
(stores = this.mapStoresByOperatorPhone(stores));
this.cityStores = this.groupPlacesStores(this.places, stores);
this.handleAllClear();
}
if (this.isInit) {
this.isInit = false;
this.type2Show = false;
this.filterText = "";
this.checkStores.length &&
this.checkStores.splice(0, this.checkStores.length);
this.curInitData &&
this.curInitData.forEach((item) => this.checkStores.push(item));
this.setCheckedKeys(this.checkStores);
}
},
storesPick: function(val) {
if (val.length > 0) {
this.checkStores = val;
this.setCheckedKeys(this.checkStores);
this.getCheckedKeys();
}
},
vendorOrgCode: function(val) {
// 厂商改变重新计算数据
let stores = this.stores;
if (this.filterText)
stores = this.stores.filter(
(item) => JSON.stringify(item).indexOf(this.filterText) !== -1
);
stores = this.mapVendorIDs(stores);
this.cityStores = this.groupPlacesStores(this.places, stores);
this.handleAllClear();
}
},
};
</script>
<style lang="scss" scoped>
@import '@/assets/scss/_color.scss';
.cmp-store-pick {
border: 1px solid $border1;
border-radius: 10px;
padding: 10px;
width: 740px;
.btn-group {
margin-bottom: 10px;
}
.tree-wrapper {
height: 200px;
overflow-y: auto;
}
.level-title1 {
font-weight: bold;
}
.level2 {
display: inline-flex;
& > * {
display: block;
}
}
.level-title2 {
width: 280px;
white-space:nowrap;
overflow:hidden;
text-overflow:ellipsis;
// border: 1px solid #ccc;
}
.level-id {
width: 70px;
// border: 1px solid #ccc;
}
.level-bind{
width: 150px;
// border: 1px solid #ccc;
span {
color: $text4;
}
}
.level-person {
white-space:nowrap;
overflow:hidden;
text-overflow:ellipsis;
}
span.bindActive {
font-weight: bold;
color: $primary;
}
}
</style>

View File

@@ -0,0 +1,22 @@
.jx-time-pick {
display:flex;
justify-content: space-between;
.label{
display:flex;
align-items: center;
width:fit-content;
}
.time-pick{
margin-left:4px;
}
/deep/ .inline-input{
height:30px;
width:140px;
// width:130px;height:30px;margin-left:0;
input{
height:30px;
}
}
}

View File

@@ -0,0 +1,196 @@
<template>
<div class="jx-time-pick">
<div class="label" v-if="label">{{ label }}</div>
<div class="time-pick">
<el-autocomplete
class="inline-input"
v-model="value1"
:maxlength="5"
:fetch-suggestions="querySearch"
:select-when-unmatched="true"
:clearable="clearable"
placeholder="开始时间(HH:mm)"
@blur="loseFocus"
@select="onChange"
></el-autocomplete>
<span></span>
<!-- querySearch22 -->
<el-autocomplete
class="inline-input"
v-model="value2"
:maxlength="5"
:fetch-suggestions="querySearch"
:select-when-unmatched="true"
:clearable="clearable"
placeholder="结束时间(HH:mm)"
@blur="loseFocus22"
@select="onChange1"
></el-autocomplete>
</div>
</div>
</template>
<script>
export default {
name: 'jxTimePick',
props: {
label: {
type: String,
default: ''
},
range: {
type: Array,
default: []
},
startlimit: {
type: Number,
default: 0
},
clearable: {
type: Boolean,
default: false
}
},
data() {
return {
value1: '',
value2:'',
timeRange: [0, 0]
}
},
// created() {
// if (this.range && this.range.length > 0) {
// if(this.range[0]) this.value1 = this.prefixZero(this.range[0] + '', 4)
// if (this.range[1]) this.value2 = this.prefixZero(this.range[1] + '', 4)
// this.timeRange = [this.range[0], this.range[1]]
// }
// },
watch: {
range: {
handler(to) {
if (to && to[0]) this.value1 = this.prefixZero(to[0] + '', 4)
else this.value1 = ''
if (to && to[1]) this.value2 = this.prefixZero(to[1] + '', 4)
else this.value2 = ''
this.timeRange = [to[0], to[1]]
this.$emit('onChange', this.timeRange)
},
immediate:true
}
},
methods: {
onChange() {
this.loseFocus()
},
onChange1() {
this.loseFocus22()
},
loseFocus() {
if (this.value1.length === 0) {
this.timeRange[0] = 0
this.timeRange[1] = 0
this.$emit('onChange', this.timeRange)
this.value1=''
this.value2=''
return
}
const regex = /[^0-9]/g
this.value1 = this.timeVerify(this.value1.replace(regex, ''),1)
this.timeRange[0] = Number(this.value1.replace(regex, ''))
this.$emit('onChange', this.timeRange)
},
loseFocus22() {
if (this.value2.length === 0) {
this.timeRange[0] = 0
this.timeRange[1] = 0
this.$emit('onChange', this.timeRange)
this.value1=''
this.value2=''
return
}
const regex = /[^0-9]/g
if(this.value2 && this.timeRange[0] === 0 ){
this.timeRange[0] = 1
this.value1 = this.prefixZero('1', 4)
}
this.value2 = this.timeVerify(this.value2.replace(regex, ''),2)
this.timeRange[1] = Number(this.value2.replace(regex, ''))
this.$emit('onChange', this.timeRange)
},
querySearch(queryString, cb) {
const regex = /[^0-9]/g
cb([{value:this.timeVerify(queryString.replace(regex, ''))}])
},
// querySearch22(queryString, cb) {
// const regex = /[^0-9]/g
// cb([{value:this.timeVerify(queryString.replace(regex, ''))}])
// },
// 前缀补0
prefixZero(num, n) {
let str = (Array(n).join(0) + num).slice(-n)
// return str.slice(0, 2) + ':' + str.slice(2) + ':00'
return str.slice(0, 2) + ':' + str.slice(2)
},
// 时间校验
timeVerify(num,type) {
if (type && type === 2 ) {
if (Number(num) <= this.timeRange[0]) {
this.$message({
message: '结束时间不得早于开始时间',
type: 'warning',
center: true
})
if(this.range[1]) return this.prefixZero(this.range[1] + '', 4)
else return ''
}
} else if (type && type === 1) {
if (Number(num) >= this.timeRange[1] && !this.startlimit) {
this.$message({
message: '开始时间应在结束时间之前',
type: 'warning',
center: true
})
return this.prefixZero(this.range[0] + '', 4)
}
if (this.startlimit) {
if (Number(num) <= this.startlimit) {
this.$message({
message: '营业时间2应在营业时间1之后',
type: 'warning',
center: true
})
return ''
}
}
}
let HH = ''
let mm = ''
if (num.length === 4) {
HH = Number(num.substr(0, 2)) >= 24?'23':num.substr(0, 2)
mm = Number(num.substr(2)) > 59?'59':num.substr(2)
} else if (num.length === 3){
HH = num.substr(0, 1)
mm = Number(num.substr(1)) > 59?'59':num.substr(1)
} else {
mm = Number(num) > 59 ?'59':num
}
let newNum = Number(HH + mm) === 0 ? 1 : Number(HH + mm)
return this.prefixZero(newNum, 4)
}
}
}
</script>
<style lang="scss" scoped>
@import './index.scss'
</style>

View File

@@ -0,0 +1,179 @@
.upload-img {
/deep/ .el-upload--picture-card{
background-color: #fff;
width: var(--width) !important;
height: var(--height) !important;
}
/deep/ .el-upload-dragger {
width: var(--width) !important;
height: var(--height) !important;
// line-height: var(--height);
}
/deep/ .el-upload-list--picture-card .el-upload-list__item{
width: var(--width) !important;
height: var(--height) !important;
}
/deep/ .el-upload__text{
width: var(--width) !important;
height: var(--height) !important;
line-height: var(--height) !important;
white-space: wrap;
}
.isPdf {
/deep/ .el-upload{
display:none !important;
}
}
.el-upload-list__item-thumbnail {
height: auto;
}
.tailor{
text-align: center;
.tailorImg{
border:1px solid #eee;
}
.tipTop{
padding:10px;
margin-bottom: 20px;
}
.title{
font-size: 32px;
font-weight: bold;
}
.tip{
margin-top: 20px;
transform: scale(1.3);
}
}
.footer{
margin-top:20px;
text-align: center;
transform: scale(1.5);
}
}
.hideUpload {
/deep/ .el-upload--picture-card {
display: none ;
}
}
.hideCardBorder{
/deep/ .el-upload--picture-card {
border: none ;
}
}
// .el-upload--picture-card{
// height: 148px !important;
// }
// }
/deep/ .el-carousel__button {
background-color: #747474;
}
/deep/ .el-carousel__item{
background-color: #fff !important;
}
.carousel{
overflow-x: hidden;
position: relative;
}
.carousel__arrow--left{
left: 16px;
}
.carousel__arrow--right{
right: 16px;
}
.el-carousel__container{
height: 800px;
position: relative;
}
.el-carousel__arrow{
border: none;
outline: 0;
padding: 0;
margin: 0;
height: 36px;
width: 36px;
cursor: pointer;
-webkit-transition: .3s;
transition: .3s;
border-radius: 50%;
background-color: rgba(31, 45, 61, .11);
color: #fff;
position: absolute;
top: 50%;
z-index: 10;
-webkit-transform: translateY(-50%);
transform: translateY(-50%);
text-align: center;
font-size: 12px;
}
.el-carousel__arrow--left{
left: 16px;
}
.el-carousel__arrow--right{
right: 16px;
}
.el-carousel{
overflow-x: hidden;
position: relative;
}
.el-carousel__indicator{
display: inline-block;
background-color: transparent;
// background-color: #747474;
padding: 12px 4px;
cursor: pointer;
}
.el-carousel__indicators{
position: absolute;
list-style: none;
margin: 0;
padding: 0;
z-index: 2;
}
.el-carousel__indicators--horizontal{
bottom: 0;
left: 50%;
transform: translateX(-50%);
}
.el-carousel__button{
background-color: #c0c4cc;
opacity: .24;
}
.carousel__img{
width: 800px;
height: 800px;
}
.isActive{
background-color: #000000;
}

View File

@@ -0,0 +1,676 @@
<!-- 上传图片或excel文件 -->
<template>
<div class="upload-img"
:style="messageStyle"
:class="{'hideCardBorder':drag}"
>
<el-upload
:disabled="disabled"
ref="imgUpload"
:file-list="imgList"
:action="action"
:limit="limit"
:drag="drag"
:list-type="listTypeCom"
:show-file-list="showFileList"
:auto-upload="false"
:on-preview="onPreview"
:on-change="onChange"
:on-exceed="onExceed"
:on-remove="onRemove"
:accept="!drag ? acceptType : '' "
:multiple="multiple"
:class="{
'hideUpload': imgList.length === limit && acceptType === 'image',
'isPdf': isShowBord
}"
>
<slot>
<i :class="iconClass"></i>
</slot>
</el-upload>
<!-- 预览图片 -->
<el-dialog :visible.sync="dialogVisible" @close="dialogImageUrl=''">
<img width="100%" :src="dialogImageUrl" alt="" v-if="imgList.length === 1" />
<div class="carousel" v-else>
<div class="el-carousel__container" >
<el-button
style="z-index: 999;"
icon="el-icon-arrow-left"
class="el-carousel__arrow el-carousel__arrow--left"
@click="arrow('left')">
</el-button>
<el-button
style="z-index: 999;"
icon="el-icon-arrow-right"
class="el-carousel__arrow el-carousel__arrow--right"
@click="arrow('right')">
</el-button>
<div
v-for="(item,index) in imgList"
:key="index"
:ref="index + 'img'"
class="el-carousel__item"
:style="{
'transform': `translateX(${arrIndex[index]}px) scale(1)`,
'text-align': 'center'
}">
<img :src="item.url" alt="" class="carousel__img">
</div>
</div>
<!-- 底部指示器 -->
<ul class="el-carousel__indicators el-carousel__indicators--horizontal">
<li v-for="item in imgList.length" class="el-carousel__indicator el-carousel__indicator--horizontal" @click="clickIndex(item -1)">
<div class="el-carousel__button" :class="{ 'isActive':isActive === item }"></div>
</li>
</ul>
</div>
</el-dialog>
<!-- 重塑图片尺寸 -->
<el-dialog :visible.sync="dialogVisible2" :show-close="false">
<div class="tailor">
<div class="tipTop">
<div class="title">请确认绘制后的图片</div>
<el-tag size="medium" type="danger" class="tip">图片的尺寸大小应为{{messageInfo}}需要重新绘制</el-tag>
</div>
<!-- 预览图 -->
<canvas id="resizedCanvas" class="tailorImg"></canvas>
</div>
<div class="footer">
<el-button @click="closeDialogIsTailor"> </el-button>
<el-button type="primary" @click="sureImg"> </el-button>
</div>
</el-dialog>
</div>
</template>
<!-- show-file-list -->
<script>
import Compressor from 'compressorjs'
import { getQiNiuToken } from '@/apis/qiniu.js'
import $ajax from 'axios'
import { importExcel2 } from "@/tools/excel.js";
import { hideLoad } from '@/tools/loading.js'
import { base64ToFile } from '@/tools/base64'
import Sortable from 'sortablejs';
// import {md5} from '@/tools/md5'
// auto-upload
export default {
name:'jxUploadFile',
props: {
value: { // v-model绑定的值
type: [String,Array],
// default:"https://image.jxc4.com/image/770693d0641d7794632e9832f8500838.png"
},
width: { // 拖拽范围的宽度
type: Number,
default:148
},
height: { // 拖拽范围的高度
type: Number,
default:148
},
action: {
type: String,
default:"http://up-z2.qiniup.com/"
},
limit: {
type: Number,
default:1
},
drag: { // 拖拽
type: Boolean,
default:false
},
multiple: { // 是否支持多选
type: Boolean,
default:false
},
showFileList: { // 是否显示已上传文件列表
type:Boolean,
default:true
},
listType: {
type: String,
// default:"picture-card"
default:"text"
},
autoUpload: { //是否在选取文件后立即进行上传
type: Boolean,
default:false
},
acceptType: {
type: String,
default:"image"
},
iconClass: {
type: String,
default:"el-icon-plus"
},
imgSize: { // 图片的内存大小
type: Number,
default:-1
},
isTmp: {
type: Boolean,
default:false
},
imgType: {
type: Array,
default:() => ["image/jpeg","image/png"]
},
imgWidth: { // 图片的宽度
type: Number,
default:-1
},
imgHeight: { // 图片的高度
type: Number,
default:-1
},
isUseMd5: { // 是否使用MD5加密
type: Boolean,
default:false
},
isUrl: {
type: Array,
default:() => []
},
name:{
type: String,
default:''
},
disabled:{
type:Boolean,
default:false
},
isGetBase64:{
type:Boolean,
default:false
}
},
data() {
return {
updateImgFile: "",
localDomain: "https://image.jxc4.com/", // 用来拼接图片地址
// imgUrlarr: [],
dialogVisible: false, // 预览图片开关
dialogImageUrl: "", // 预览图片的地址
imgList: [],
importData: [], // excel导出的数据
hideUploadCard: false,
imgMd5: '', // md5 加密后的数据
dialogVisible2:false, // 重塑图片dialog
tailorContent:{}, // 重塑图片数据
initialIndex:0, // 初始状态激活的幻灯片的索引
arrIndex:[0,977,1954,-1954,-977],
isActive:1, // 默认第一张图片
isShowBord:'',
isGetValue:true // 是否改变v-model的值
}
},
created() {
if (this.isUrl.length > 0 && !this.value) {
this.arrIndex = []
this.isUrl.map((item,index) => {
if (item) {
this.imgList.push({
name: 'current&' + index,
url:item
})
this.arrIndex.push(index * 977)
}
})
}
},
watch:{
value: {
handler(val) {
if (val && val.length > 0 && this.acceptType === 'image') {
if(!this.isGetValue) return this.isGetValue = true
if(Array.isArray(val)){
this.arrIndex = []
this.imgList = []
val.map((item,index) => {
if (item) this.imgList.push({ name: 'current&' + index, url: item })
this.arrIndex.push(index * 977)
})
}else this.imgList = [{ name: 'current&' + 0, url: val }]
this.initDragSort();
} else this.imgList = []
},
immediate:true
},
// 解析excel文件内容
importData: function (to) {
if (to && to.length > 0) {
this.$emit("input",to)
this.$emit("onChange", to)
}
},
// // 默认的图片数组改变
// isUrl:{
// handler(val){
// if(val && val.length){
// val.map((item,index) => {
// let findIndex = this.imgList.findIndex(i => i.url === item)
// if (item && findIndex === -1) {
// this.imgList.push({
// name: 'current&' + index,
// url:item
// })
// this.imgUrlarr.push({
// file: {
// name:'current&' + index,
// },
// url:item
// })
// }
// })
// }
// }
// }
},
computed: {
messageStyle() {
return {
'--width': this.width + 'px',
'--height':this.height + 'px',
// '--display':this.isShowBord,
}
},
messageInfo(){
return this.imgHeight !== -1 && this.imgWidth !== -1 ? this.imgWidth + '*' + this.imgHeight
: (this.imgWidth !== -1 && this.imgHeight === -1 ? '宽度为' + this.imgWidth
: (this.imgWidth === -1 && this.imgHeight !== -1 ? "高度为" + this.imgHeight : '')
)
},
listTypeCom(){
if(this.updateImgFile && JSON.stringify(this.updateImgFile)!== '{}'){
let type= this.getFileType(this.updateImgFile)
this.isShowBord = type === 'pdf' ? 'none' : ''
return type === 'pdf' ? 'text' : this.listType
}else{
this.isShowBord = ''
return this.listType
}
}
},
mounted(){
this.initDragSort();
},
methods: {
clickIndex(findIndex){
this.arrIndex = this.arrIndex.filter(item => item !== 0) // 切换图片
this.arrIndex = this.arrIndex.splice(0,findIndex).concat([0]).concat(this.arrIndex)
this.isActive = findIndex + 1
},
arrow(type){
if(type === 'left'){
let temp = this.arrIndex.splice(0,1)
this.arrIndex = this.arrIndex.concat(temp)
}else {
let temp = this.arrIndex.splice(this.imgList.length -1,1)
this.arrIndex = temp.concat(this.arrIndex)
}
this.isActive = this.arrIndex.findIndex(item => item === 0) + 1
},
// 初始化图片列表拖拽
initDragSort(){
// if(this.imgUrlarr.length <= 1) return
if(this.imgList.length <= 1) return
this.$nextTick(() => {
const el = this.$refs['imgUpload'].$el.querySelectorAll('.el-upload-list')[0];
Sortable.create(el, {
onEnd: ({ oldIndex, newIndex }) => {
swapArrayElements(this.imgList,oldIndex,newIndex)
this.$emit('onChange',this.imgList)
// 交换位置
function swapArrayElements(arr, indexA, indexB) {
const temp = arr[indexA];
arr.splice(indexA, 1);
arr.splice(indexB, 0, temp);
}
}
});
})
},
// 重塑图片尺寸
remodelingImg(img,file) {
this.$nextTick(()=>{
const canvas = document.getElementById('resizedCanvas');
const ctx = canvas.getContext('2d');
// 设置canvas的宽度和高度
canvas.width = this.imgWidth !== -1 ? this.imgWidth : img.width; // 新宽度
canvas.height = this.imgHeight !== -1 ? this.imgHeight : img.height; // 新高度
// 绘制图片到canvas上
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
// 将canvas的内容转换回图片
const resizedImg = canvas.toDataURL(file.raw.type, 1); // 第二个参数是图片质量
const fileName = file.name; // 文件的名字
const newFile = base64ToFile(resizedImg, fileName); // base64 转 file
this.tailorContent['tailorImg'] = {raw:newFile,size:newFile.size}
// 显示修改后的图片
// document.getElementById('resizedCanvas').style.display = 'block';
})
},
// 重塑图片 确认
sureImg(){
this.onChange(this.tailorContent.tailorImg) // 上传图片
},
// 重塑图片 取消
closeDialogIsTailor(){
this.imgList = [...this.imgList]
this.tailorContent = {}
this.dialogVisible2 = false
},
// 预览 关闭
closeDialog(){
this.dialogImageUrl = ''
this.dialogVisible = false
},
// 预览 确认
onPreview(e) {
this.dialogImageUrl = e.url
if(this.imgList.length > 1) {
let findIndex = this.imgList.findIndex(item => item.name === e.name)
if(findIndex !== 0){
this.arrIndex = this.arrIndex.filter(item => item !== 0)
this.arrIndex = this.arrIndex.splice(0,findIndex).concat([0]).concat(this.arrIndex)
}else this.arrIndex = [0,977,1954,-1954,-977]
this.isActive = findIndex + 1
}
this.dialogVisible = true
},
onChange(file, fileList) {
// console.log('上传文件的信息',file,'fileList',fileList)
// return
if (this.acceptType === '.xlsx') {
importExcel2(this, file.raw, "importData") // 解析excel数据
// this.$emit("onChange", file)
} else if (this.acceptType === 'image') {
this.uploadImgFun(file, fileList) // 上传图片
}
},
// pdf转base64
fileToBase64(file){
console.log('file',file)
var reader = new FileReader();
let that = this
reader.onloadend = function() {
var base64Data = btoa(reader.result);
that.imgUrl = file.url
that.imgList.push({
name:'current&' + (that.imgList.length + 1),
url: that.imgUrl,
raw:file.raw
})
if(typeof that.value === 'string') that.$emit("input", file.url)
let suffix = that.getFileType(file) // 文件后缀
that.$emit("onChange", {
attContext:base64Data,
attType:'',
attExtName:suffix,
fileName:file.raw.name,
file
})
};
reader.readAsBinaryString(file.raw);
},
// 上传图片
uploadImgFun(file, fileList) {
if (!this.autoUpload) {
if (this.value) this.$emit("input", file)
this.$emit("onChange", file, fileList)
} else {
// 上传图片
let isImgType = this.imgType.filter(item => item === file.raw.type)
if (isImgType.length === 0) {
// 格式错误
this.$message({
message: `请选择 ${JSON.stringify(this.imgType)}格式的图片进行上传`,
type: 'warning',
center: true,
})
this.imgList = [...this.imgList]
// this.$refs.imgUpload.clearFiles()
} else {
// 尺寸大小
this.widthOrHeight(file, (res,img) => {
if (!res) {
this.dialogVisible2 = true // 打开弹框
this.tailorContent = {
...file,
imgWidth:img.width,
imgHeight:img.height
}
this.remodelingImg(img,file) // 重塑图片尺寸
// this.$refs.imgUpload.clearFiles()
return
}
// 上传图片
// 内存大小
const isLt2M = this.imgSize !== -1 ? file.size < this.imgSize * 1024 * 1024 : false
if (!isLt2M && this.imgSize !== -1) {
// 压缩文件
this.$confirm(`您上传的图片大于${this.imgSize}M即将进行压缩是否继续`, '提示').then((res) => {
this.compressedPicture(file)
}).catch((err) => {
this.$message({
message: `图片大小不能超过${this.imgSize}M`,
type: 'warning',
center: true,
})
this.imgList = [...this.imgList]
// this.$refs.imgUpload.clearFiles()
})
} else {
// 格式正确
this.updateImgFile = file
// 是否获取base64
if(this.isGetBase64) return this.fileToBase64(file)
// 综合了该管理系统的图片上传功能其中有一个md5的功能没看出来有啥作用先注释掉
// 保存md5
if (this.isUseMd5) {
md5(file.raw, res => {
this.imgMd5 = res.toUpperCase()
this.uploadImg()
})
}else this.uploadImg()
}
})
}
}
},
// 文件超出个数限制时的钩子
onExceed() {
if(this.acceptType !== 'image') return
this.$message({
message: `最多上传${this.limit}`,
type: 'warning',
center: true,
})
},
// 文件列表移除文件时的钩子
onRemove(e) {
this.isGetValue = false
let findIndex = this.imgList.findIndex(item => item.name === e.name)
if(findIndex !== -1) {
this.imgList.splice(findIndex,1)
this.$emit("onChange", this.imgList)
}
this.$emit("onRemove", e)
if(!Array.isArray(this.value) && this.value) this.$emit("input", '')
else if(Array.isArray(this.value)){
let brr = this.imgList.map(item => item.url)
this.$emit("input", brr)
}
// let index = this.imgUrlarr.findIndex(item => item.file.name === e.name)
// if (index !== -1) {
// this.$emit("onRemove", this.imgUrlarr[index])
// this.imgUrlarr.splice(index, 1)
// this.imgList.splice(index, 1)
// if (this.value) this.$emit("input", '')
// this.$emit("onChange", this.imgUrlarr)
// } else {
// this.$emit("onRemove", e)
// }
},
// 上传图片
uploadImg(fnSuccess, fnFail) {
let suffix = this.getFileType(this.updateImgFile) // 后缀 // 后缀
if (this.isTmp) suffix = '.tem' + suffix // 临时图片标志
getQiNiuToken(suffix, this.imgMd5 ? this.imgMd5 : '', (res) => {
let formData = new FormData()
formData.append('token', res.token)
formData.append('key', res.fileName)
formData.append('file', this.updateImgFile.raw)
$ajax
.post(this.action, formData)
.then(
(res) => {
// res.data
if(fnSuccess) fnSuccess(res.data)
else{
let data = res.data
this.imgUrl = this.localDomain + data.key
this.imgList.push({
name:'current&' + (this.imgList.length + 1),
url: this.imgUrl,
raw:this.updateImgFile.raw
})
// console.log(this.updateImgFile,'this.updateImgFile',this.imgList)
if(this.acceptType === 'image') this.isGetValue = false
if(typeof this.value === 'string') this.$emit("input", this.imgUrl)
else{
// v-model绑定的多个值
let brr = this.imgList.map(item => item.url)
this.$emit("input", brr)
}
this.$emit("onChange", this.imgList)
if(this.dialogVisible2){
this.tailorContent = {}
this.dialogVisible2 = false // 关闭dialog
}
// md5加密后 注册图片 by this.$props.name
// if(this.name) this.registerSrc(this.imgMd5, this.localDomain + data.key, this.updateImgFile.raw.type, this.name || '')
}
hideLoad()
},
{
timeout: 40000,
}
)
.catch((err) => {
if(fnFail) fnFail(err.data)
else{
this.$message({
message: '图片上传失败,请重新尝试' + err.data,
type: 'warning',
center: true,
})
if(this.dialogVisible2) this.closeDialogIsTailor()
}
hideLoad()
})
})
},
// 压缩图片
compressedPicture(file) {
let that = this
let img = new Image
img.src = file.url
img.onload = function (e) {
const compressor = new Compressor(file.raw, {
maxWidth: img.width,
maxHeight: img.height,
quality: 0.5, // 压缩比例
success(result) {
that.onChange({raw:result,size:result.size})
},
error(err) {
that.$message({
message: '图片压缩失败,请重新尝试' + err,
type: 'warning',
center: true,
})
}
})
}
},
// 图片宽高是否符合要求
async widthOrHeight(file, fn) {
// let that = this
if (this.imgWidth !== -1 || this.imgHeight !== -1) {
let reader = new FileReader()
reader.readAsDataURL(file.raw)
reader.onload = (e) => {
let img = new Image()
img.src = e.target.result
img.onload = () => {
let flag = true
if (this.imgWidth !== -1 && this.imgHeight !== -1) {
flag = this.imgWidth === img.width && this.imgHeight === img.height
} else if (this.imgWidth !== -1 && this.imgHeight === -1) {
flag = this.imgWidth === img.width
} else if (this.imgWidth === -1 && this.imgHeight !== -1) {
flag = this.imgWidth === img.height
}
fn && fn(flag,img)
}
}
} else {
fn && fn(true)
}
},
// 文件格式
getFileType(file){
return file.raw.type === 'image/png' ? 'png' : (file.raw.type === "application/vnd.android.package-archive" ? 'apk': file.raw.type === 'application/pdf'? 'pdf' :'jpg' ) || "" // 后缀
}
// // 注册
// async registerSrc (hashCode, url, mimeType, name) {
// try {
// let queryString = `hashCode=${hashCode}&resourceURL=${url}&mimeType=${mimeType}`
// if (name) queryString += `&name=${name}`
// await api('v2/cms/RegisterDataResource', {
// method: 'POST',
// noLoading: true,
// data: queryString
// })
// } catch (e) {
// console.error(e)
// }
// }
}
}
</script>
<style lang="scss" scoped>
@import "./index.scss"
</style>

View File

@@ -0,0 +1,49 @@
@import '@/assets/scss/_bundle.scss';
.dia-city-pick {
.city-pick {
display: flex;
justify-content: center;
align-items: center;
}
.wrapper-left, .wrapper-right {
width: 240px;
}
.wrapper-center {
width: 100px;
display: flex;
align-items: center;
justify-content: center;
flex-flow: column;
}
.city-card {
border: 1px solid $border1;
border-radius: 5px;
// padding: 10px;
.op {
background: $border4;
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px;
}
.search-input {
padding: 10px;
}
.city-list {
height: 260px;
overflow: auto;
padding: 10px;
}
.city-item {
text-align: center;
padding: 5px 0;
cursor: pointer;
border-radius: 10px;
user-select: none;
&:hover {
background-color: $border3;
}
}
}
}

View File

@@ -0,0 +1,142 @@
<template>
<el-dialog
title="城市选择"
:visible.sync="diaShow"
:close-on-click-modal="false"
:before-close="close"
custom-class="dia-city-pick"
width="700px"
>
<div class="city-pick">
<div class="wrapper-left">
<div class="city-card">
<div class="op">
<el-button size="mini" type="primary" @click="allCheck(true)">全选</el-button>
<div class="count">{{leftCount}}</div>
</div>
<div class="search-input">
<el-input v-model.trim="leftFilterText" size="mini" prefix-icon="el-icon-search" type="text" placeholder="请输入城市名称" clearable></el-input>
</div>
<div class="city-list">
<div
class="city-item"
v-for="city in leftData"
:key="city.id"
v-show="filterCity('left', city)"
@click="dataClick(city)"
>
{{city.name}}
</div>
</div>
</div>
</div>
<div class="wrapper-center">
<i class="el-icon-d-arrow-right"></i>
<i class="el-icon-d-arrow-left"></i>
</div>
<div class="wrapper-right">
<div class="city-card">
<div class="op">
<el-button size="mini" type="danger" @click="allCheck(false)">全清</el-button>
<div class="count">{{rightCount}}</div>
</div>
<div class="search-input">
<el-input v-model.trim="rightFilterText" size="mini" prefix-icon="el-icon-search" type="text" placeholder="请输入城市名称" clearable></el-input>
</div>
<div class="city-list">
<div
class="city-item"
v-for="city in rightData"
:key="city.id"
v-show="filterCity('cghe', city) && city.check"
@click="dataClick(city)"
>
{{city.name}}
</div>
</div>
</div>
</div>
</div>
<div style="text-align: right;margin-top: 10px;">
<el-button size="mini" type="primary" @click="confirmSkus"> </el-button>
</div>
</el-dialog>
</template>
<script>
export default {
props: {
diaShow: {
type: Boolean,
default: false
},
cityList: {
type: Array,
default () {
return []
}
}
},
data () {
return {
leftCityList: [],
leftFilterText: '',
rightFilterText: ''
}
},
computed: {
leftData () {
return this.leftCityList.filter(item => !item.check)
},
rightData () {
return this.leftCityList.filter(item => item.check)
},
leftCount () {
return this.leftData.length
},
rightCount () {
return this.rightData.length
}
},
watch: {
cityList (to) {
if (to) {
this.leftCityList = JSON.parse(JSON.stringify(this.cityList)).map(item => ({
...item,
check: false
}))
}
}
},
methods: {
close () {
this.$emit('close')
},
// 确认
confirmSkus () {
this.$emit('confirm', this.rightData)
},
filterCity (filterType, city) {
if (filterType === 'left') {
return city.name.indexOf(this.leftFilterText) > -1
} else {
return city.name.indexOf(this.rightFilterText) > -1
}
},
dataClick (city) {
city.check = !city.check
},
// 全选全清
allCheck (boo) {
this.leftCityList = this.leftCityList.map(item => ({
...item,
check: boo
}))
}
}
}
</script>
<style lang="scss">
@import "./city-pick.scss";
</style>

View File

@@ -0,0 +1,52 @@
<template>
<el-popover
placement="top"
title=""
width=""
trigger="click"
@show="popoverShow"
>
<div v-loading="loading">
{{name || '未查询到'}}
</div>
<span class="hover-click" slot="reference">
<slot></slot>
</span>
</el-popover>
</template>
<script>
import {getOneUser} from '@/apis/controls/user.js'
export default {
props: {
// lastOperator: {
// type: String,
// default: ''
// }
},
data () {
return {
loading: false,
name: ''
}
},
methods: {
async popoverShow () {
try {
this.loading = true
const keyword = this.$slots.default[0].text
const user = await getOneUser(keyword)
if (user) this.name = user.name
} catch (e) {
console.error(e)
} finally {
this.loading = false
}
}
}
}
</script>
<style>
</style>

View File

@@ -0,0 +1,368 @@
<template>
<div>
<el-dialog
title=""
:visible.sync="dialogMapShow"
:before-close="close"
width="600px"
>
<el-cascader
size="mini"
style="width: 140px"
@change="cityChange"
placeholder="城市范围"
:options="cityL2"
filterable
change-on-select
clearable
:props="cityProps"
></el-cascader>
<div class="amap-wrapper2">
<!-- 搜索框 -->
<el-amap-search-box
class="search-box"
:search-option="searchOption"
:on-search-result="onSearchResult"
ref="bindsearch"
></el-amap-search-box>
<!-- 地图功能按钮 -->
<div class="confirmCenterBtn">
<span @click="moveAddress">{{canMoveAddress ? '禁止更改' : '更改坐标'}}</span>
</div>
<!-- 地图 -->
<el-amap
:zoom="zoom"
:center="storeItem2.center"
:doubleClickZoom="doubleClickZoom"
class="amap-demo"
>
<!-- 其他店铺 -->
<!-- 配送范围辅助线 -->
<div
v-for="i in 5"
:key="i+'dashed'"
>
<el-amap-circle
:center="storeItem2.center"
:radius="i * 1000"
:zIndex="storeItem2.zIndex + 1"
:fill-opacity="0"
:strokeColor="'#007acc'"
:strokeWeight="1"
:strokeStyle="'dashed'"
:fillColor="'#ffffff'"
>
</el-amap-circle>
<el-amap-polygon
v-if="storeItem2.deliveryRangeType === 2 && switchDeliverRange"
:path="storeItem2.deliveryRange2"
:editable="storeItem2.editable"
:fill-opacity="storeItem2.fillOpacity"
:strokeColor="storeItem2.strokeColor"
:events="storeItem2.events2"
:zIndex="storeItem2.zIndex"
:fillColor="storeItem2.fillColor"
>
</el-amap-polygon>
</div>
<el-amap-text
v-for="(item, index) in distanceList"
:key="index+'distance'"
:text="item.title"
:offset="item.offset"
:position="item.center"
:zIndex="item.zIndex"
>
</el-amap-text>
<!-- 配送范围辅助线 -->
<!-- 目标店铺 -->
<el-amap-circle
v-if="(storeItem2.deliveryRangeType === 3 && ismap) && switchDeliverRange"
:center="storeItem2.center"
:radius="tmpDeliveryRange"
:editable="storeItem2.editable"
:events="storeItem2.events2"
:zIndex="storeItem2.zIndex"
:fill-opacity="storeItem2.fillOpacity"
:strokeColor="storeItem2.strokeColor"
:fillColor="storeItem2.fillColor"
>
</el-amap-circle>
<el-amap-polygon
v-if="storeItem2.deliveryRangeType === 2 && switchDeliverRange"
:path="storeItem2.deliveryRange2"
:editable="storeItem2.editable"
:fill-opacity="storeItem2.fillOpacity"
:strokeColor="storeItem2.strokeColor"
:events="storeItem2.events2"
:zIndex="storeItem2.zIndex"
:fillColor="storeItem2.fillColor"
>
</el-amap-polygon>
<el-amap-text
:text="storeInfo.name"
:offset="storeItem2.offset"
:position="storeItem2.center"
:zIndex="storeItem2.zIndex"
>
</el-amap-text>
<el-amap-marker
:extData="storeItem2"
:position="storeItem2.center"
:title="'开启/关闭编辑模式'"
:draggable="canMoveAddress"
:events="storeItem2.events"
:zIndex="storeItem2.zIndex"
>
</el-amap-marker>
<!-- 辅助线 -->
<el-amap-polygon
v-if="subline25"
:path="subline25"
:fillOpacity="0"
:strokeWeight="4"
strokeColor="#008000"
>
</el-amap-polygon>
</el-amap>
</div>
<div slot="footer">
<el-button @click="close"> </el-button>
<el-button
type="primary"
@click="sureAddress"
> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import api from '@/utils/api'
import { showLoad, hideLoad } from '@/tools/loading.js'
export default {
props: ['dialogMapShow'],
data() {
return {
saveData:null,
cityL2: [],
cityProps: {
value: 'code',
label: 'name'
},
switchDeliverRange: true,
canMoveAddress: false,
zoom: 12, // 地图层级
ismap: true, // 控制禁止圆心拖动的额外参数
distanceList: [], // 配送范围辅助线集合
subline25: null,
subline6: null,
tmpDeliveryRange: 3000, // 中间变量暂存range
searchOption: { // 地图搜索组件city 在指定城市内搜索
city: '成都市',
citylimit: true
},
storeInfo: {
cityCode: null, // 510100,
districtCode: null, // 510105,
lat: null, // 30.657349,
lng: null, // 104.065837,
address: '',
deliveryRangeType: 2, // 2规划范围 3半径服务
deliveryRange: '', // 半径多少米
},
storeItem2: {
center: [104.065837, 30.657349],
deliveryRangeType: 3,
deliveryRange2: [],
zIndex: 11,
editable: true,
fillOpacity: 0.8,
strokeColor: '#49a72e',
fillColor: '#49a72e',
offset: [0, -45],
events: {
click: () => this.click()
},
events2: {
// end: () => this.endEdit(),
change: (e) => this.changeAmap(e),
move: (e) => this.move(e)
}
}, // 店铺信息
doubleClickZoom: false, // 是否允许双击放大地图false-禁止
oneCircle: { // 一键画圆参数
radius: 2000,
pointCount: 8
},
}
},
async created() {
let cityL2 = await this.getCitys({ level: 2 })
this.cityL2 = cityL2
hideLoad()
},
methods: {
close() {
this.$emit('closeMapDialog')
},
sureAddress() {
this.onSearchResult(this.saveData)
let json = {
radius: this.tmpDeliveryRange,
lng: this.storeInfo.lng,
lat: this.storeInfo.lat,
cityCode: this.storeInfo.cityCode,
}
this.$emit('getPosition', json)
this.storeInfo = {
cityCode: null, // 510100,
districtCode: null, // 510105,
lat: null, // 30.657349,
lng: null, // 104.065837,
address: '',
deliveryRangeType: 2, // 2规划范围 3半径服务
deliveryRange: '', // 半径多少米
}
this.close()
},
async getCitys(options) {
try {
let res = await api('v2/cms/GetPlaces', {
params: {
...options,
includeDisabled: true
}
})
return res.map(item => ({
id: item.id,
code: item.code,
level: item.level,
name: item.name,
parentCode: item.parentCode
}))
} catch (e) {
this.$alert(e, '错误')
}
},
cityChange(val) {
this.saveData = val
this.storeInfo.cityCode = val[0]
this.cityL2.forEach(item => {
if (item.code === val[0]) {
this.searchOption.city = item.name
this.$refs.bindsearch.changeTip({name: item.name})
}
})
},
moveAddress() {
this.canMoveAddress = !this.canMoveAddress
},
moveDistanceList() {
let distanceList = []
for (let i = 1; i <= 5; i++) {
let distance = {
center: [this.storeItem2.center[0], this.storeItem2.center[1] + 0.000009405717451407729 * i * -1000],
title: i + 'km',
offset: [0, 0],
zIndex: 8
}
distanceList.push(distance)
}
this.distanceList = distanceList
},
changeAmap: function (e) {
if (e.target.CLASS_NAME === 'AMap.Circle') {
this.tmpDeliveryRange = e.target.De.radius
}
if (e.target.CLASS_NAME === 'AMap.Polygon') {
// let path = []
// e.target.Uh.path.forEach(item => {
// path.push([item.lng, item.lat].join(','))
// })
// path = path.join(';')
// this.path = path
this.path = e.target.Uh.path.join(';')
}
},
move: function (e) {
this.ismap = false // 拉动圆心时,先隐藏圆,再显示。。。目前禁止圆心拖动并恢复圆心位置只能这样实现
this.$alert('请不要直接拉动圆心,可以拉动坐标定位点', '提示', {
confirmButtonText: '确定',
callback: () => {
this.ismap = true
}
})
},
onSearchResult(pois) {
this.saveData = pois
let center = []
center.push(pois[0].lng)
center.push(pois[0].lat)
let lngDistance = this.storeItem2.center[0] - center[0]
let latDistance = this.storeItem2.center[1] - center[1]
this.storeItem2.center = center
// 地址编辑辅助线偏移
this.moveDistanceList()
// 配送范围是多边形,才进行如下操作
if (this.storeItem2.deliveryRange2 instanceof Array && this.storeItem2.deliveryRange2.length > 0) {
let polygon = this.storeItem2.deliveryRange2.map(item => {
return [item.lng - lngDistance, item.lat - latDistance]
})
this.storeItem2.deliveryRange2 = polygon
let path = []
this.storeItem2.deliveryRange2.forEach(item => {
path.push([item[0], item[1]].join(','))
})
path = path.join(';')
this.path = path
}
this.storeInfo.lng = center[0]
this.storeInfo.lat = center[1]
},
}
}
</script>
<style lang="scss" scoped>
.amap-wrapper2 {
width: 100%;
padding: 5px 15px;
height: 400px;
font-size: 12px;
position: relative;
background: white;
box-sizing: border-box;
.search-box {
position: absolute;
top: 40px;
left: 40px;
height: 32px;
}
.confirmCenterBtn {
position: absolute;
top: 40px;
left: 440px;
z-index: 999;
color: #fff;
span {
background-color: #f37b1d;
cursor: pointer;
display: inline-block;
border-radius: 4px;
padding: 0px 5px;
margin: 0px 5px;
height: 32px;
line-height: 32px;
font-size: 12px;
text-align: center;
color: #fff;
min-width: 40px;
}
}
}
</style>

View File

@@ -0,0 +1,48 @@
@import '@/assets/scss/_color.scss';
@import '@/assets/scss/_bundle.scss';
.orderSkus-store {
.store-id {
margin-bottom: 10px;
}
.skus-list {
// width: 100%;
height: 300px;
overflow-y: auto;
}
.skus-item {
display: flex;
margin-bottom: 10px;
padding-bottom: 10px;
border-bottom: 1px solid $border1;
align-items: center;
}
.sku-left {
flex: none;
width: 60px;
height: 60px;
border-radius: 10px;
overflow: hidden;
box-sizing: border-box;
border: 1px solid $border1;
img {
width: 100%;
height: 100%;
}
}
.sku-center {
flex: 1;
margin-left: 10px;
font-size: 12px;
& > * {
margin-bottom: 10px;
}
}
.sku-right {}
.notSale {
color: $warning;
}
.notFocus {
color: $danger;
}
}

View File

@@ -0,0 +1,286 @@
<template>
<div class="orderSkus-store" v-loading="loading">
<div class="store-id">
当前门店: {{storeInfo.name}} {{storeID}} 总计 : {{nowTotalPrice | toFixed2}}
<el-button type="text" icon="el-icon-refresh" title="刷新商品数据" @click="handleRefresh"></el-button>
<!-- <div>
门店收益
预计收益:
</div>-->
</div>
<div class="skus-list">
<div class="skus-item" v-for="(sku, index) in skus" :key="index">
<div class="sku-left">
<img :src="sku.image + '?imageView2/1/w/60/h/60'" alt />
</div>
<div class="sku-center">
<div class="sku-name">({{sku.skuID}}){{sku.fullSkuName}}</div>
<div class="unit-price">
<div>
{{sku.unit}}价格:
<el-input style="width: 70px;" size="mini" v-model="sku.tmpUnitPrice" @input="handleInput($event, sku, index)"></el-input>
{{sku.specQuality}}{{sku.specUnit}}价格:
<b>{{sku.tmpShopPrice / 100}}</b>
</div>
<div style="margin-top: 10px;">
售卖:
<b>{{sku.salePrice / 100}}</b>
(利润率: {{(sku.salePrice - sku.tmpShopPrice) / sku.tmpShopPrice * 10000 | toFixed2}}%)
</div>
<!-- <el-button v-if="sku.isFocus" type="text" icon="el-icon-edit"></el-button> -->
</div>
<div>
状态:
<el-radio-group v-model="sku.status" size="mini">
<el-radio-button :label="0">不可售</el-radio-button>
<el-radio-button :label="1">可售</el-radio-button>
</el-radio-group>
</div>
</div>
<div class="sku-right">
<el-button size="mini" v-if="!sku.isFocus" type="danger" @click="handleFocus(sku)">关注</el-button>
<el-button size="mini" :disabled="storeID===102919" v-else type="success" @click="handleModify(sku)">修改</el-button>
</div>
</div>
</div>
</div>
</template>
<script>
import { getStoreSkus, updateStoreSkus } from "@/apis/controls/storeSku.js";
import msgWarning from "@/tools/msgwarning";
import { getOneStore } from "@/apis/controls/shop.js";
export default {
props: {
storeID: {
type: Number,
default: null
},
orderSkus: {
type: Array,
default() {
return [];
}
}
},
data() {
return {
skus: [],
loading: false,
statusName: {
"0": "不可售",
"1": "可售",
"3": "未关注"
},
storeInfo: {
name: "未知"
}
};
},
async created() {
this.skus = this.orderSkus.map(item => ({
count: item.count,
fullSkuName: item.fullSkuName,
image: item.image,
nameID: item.nameID,
salePrice: item.salePrice,
shopPrice: item.shopPrice,
skuID: item.skuID,
status: 1
}));
await this.refreshByStoreID(
this.storeID,
this.skus.map(item => item.skuID)
);
},
computed: {
nowTotalPrice() {
return this.skus.reduce((prev, next) =>
prev + next.tmpShopPrice * next.count, 0
) || 0
}
},
methods: {
async handleRefresh() {
await this.refreshByStoreID(
this.storeID,
this.skus.map(item => item.skuID)
);
},
async refreshByStoreID(storeID, skuIDs) {
try {
this.loading = true;
let { skus } = this;
const skuNames = await getStoreSkus(storeID, skuIDs);
const noFocusSkuNames = await getStoreSkus(storeID, skuIDs, false);
let refreshSkus = [];
for (let i = 0; i < skus.length; i++) {
const sku = skus[i];
const findSku = skuNames.find(item => item.skus[0].id === sku.skuID);
if (findSku) {
sku.shopPrice = findSku.skus[0].price;
sku.tmpShopPrice = findSku.skus[0].price;
sku.status = findSku.skus[0].storeSkuStatus;
sku.unitPrice = findSku.unitPrice;
sku.tmpUnitPrice = findSku.unitPrice / 100;
sku.unit = findSku.unit;
sku.specQuality = findSku.skus[0].specQuality;
sku.specUnit = findSku.skus[0].specUnit;
sku.isFocus = true;
} else {
// 从未关注种找
const notFocusSku = noFocusSkuNames.find(
item => item.skus[0].id === sku.skuID
);
if (notFocusSku) {
sku.shopPrice = notFocusSku.skus[0].price;
sku.tmpShopPrice = sku.salePrice * 0.7; // notFocusSku.skus[0].price
sku.status = notFocusSku.skus[0].storeSkuStatus;
sku.unitPrice = 0; // notFocusSku.unitPrice
sku.tmpUnitPrice = 0; // notFocusSku.unitPrice / 100
sku.unit = notFocusSku.unit;
sku.specQuality = notFocusSku.skus[0].specQuality;
sku.specUnit = notFocusSku.skus[0].specUnit;
sku.isFocus = false;
} else {
sku.shopPrice = 0;
sku.tmpShopPrice = 0;
sku.status = 0;
sku.unitPrice = 0;
sku.tmpUnitPrice = 0;
sku.unit = "份";
sku.specQuality = 500;
sku.specUnit = "g";
sku.isFocus = false;
}
}
refreshSkus.push(sku);
}
this.skus = refreshSkus;
} catch (e) {
msgWarning(e);
} finally {
this.loading = false;
}
},
async handleFocus(sku) {
// 关注
if (!sku.tmpUnitPrice || isNaN(sku.tmpUnitPrice)) {
this.$toast("请输入价格");
return false;
}
try {
this.loading = true;
await updateStoreSkus(
{
storeID: this.storeID,
isAsync: false,
isContinueWhenError: true,
payload: JSON.stringify([
{
nameID: sku.nameID,
unitPrice: Math.floor(sku.tmpUnitPrice * 100),
isFocus: 1,
skus: [
{
skuID: sku.skuID,
isSale: sku.status ? 1 : -1
}
]
}
])
},
true
);
this.$toast("成功");
await this.refreshByStoreID(
this.storeID,
this.skus.map(item => item.skuID)
);
} catch (e) {
msgWarning(e);
} finally {
this.loading = false;
}
},
async handleModify(sku) {
// 修改
try {
this.loading = true;
await updateStoreSkus(
{
storeID: this.storeID,
isAsync: false,
isContinueWhenError: true,
payload: JSON.stringify([
{
nameID: sku.nameID,
unitPrice: Math.floor(sku.tmpUnitPrice * 100),
skus: [
{
skuID: sku.skuID,
isSale: sku.status ? 1 : -1
}
]
}
])
},
true
);
this.$toast("成功");
await this.refreshByStoreID(
this.storeID,
this.skus.map(item => item.skuID)
);
} catch (e) {
msgWarning(e);
} finally {
this.loading = false;
}
},
// 计算修改时sku价格
computedPrice(price, item) {
if (item.unit === "份") {
let skuNamePrice = Math.floor(price * 100); // 一斤的价格
let specQuality = item.specQuality; // 质量
let specUnit = item.specUnit.toLowerCase(); // 单位
if (specUnit === "kg" || specUnit === "l") {
specQuality = specQuality * 1000;
}
let temPrice = Math.round((skuNamePrice * specQuality) / 500);
return temPrice / 100;
} else {
return price;
}
},
handleInput(val, sku, index) {
const tmpShopPrice = this.computedPrice(+val, sku) * 100;
const json = this.skus[index];
json.tmpShopPrice = tmpShopPrice;
this.$set(this.skus, index, json);
}
},
watch: {
async storeID(val) {
if (val && (val + "").length === 6) {
// 查询门店
// 开始查询门店商品
const { stores } = await getOneStore(val);
if (stores) this.storeInfo = stores[0];
await this.refreshByStoreID(
val,
this.skus.map(item => item.skuID)
);
}
},
}
};
</script>
<style lang="scss">
@import "./orderSkus-store.scss";
</style>

View File

@@ -0,0 +1,23 @@
@import '@/assets/scss/_color.scss';
@import '@/assets/scss/_bundle.scss';
.pick-store-bylocation {
.range-input {
display: flex;
align-items: center;
}
@extend %tinyTable;
.cell {
padding-left: 0;
padding-right: 0;
}
.current-pick {
text-align: right;
b {
color: $primary;
}
}
.status1 {
color: $primary;
}
}

View File

@@ -0,0 +1,153 @@
<template>
<div class="pick-store-bylocation" v-loading="loading">
<div class="range-input">
<span>半径范围:</span>
<el-input style="width: 100px;" size="mini" v-model.number="range"></el-input>
<span></span>
<el-button type="success" size="mini" @click="handleSearch">查询</el-button>
</div>
<el-table :data="list" style="width: 100%; font-size: 12px;" height="300" empty-text="暂无数据" stripe>
<el-table-column label="ID" align="center" width>
<div slot-scope="{row}">{{row.storeID}}</div>
</el-table-column>
<el-table-column label="名称" align width>
<div slot-scope="{row}">{{row.name}}</div>
</el-table-column>
<!-- <el-table-column label="备注" align width>
<div slot-scope="{row}">{{row.comment}}</div>
</el-table-column> -->
<el-table-column label="门店等级" align="center" width>
<div slot-scope="{row}">{{row.storeLevel}}</div>
</el-table-column>
<el-table-column label="结算比例" align="center" width>
<div slot-scope="{row}">{{row.payPercentage}}</div>
</el-table-column>
<el-table-column label="地区" align width>
<div slot-scope="{row}">
<!-- {{row.provinceName}} -->
{{row.cityName}}
</div>
</el-table-column>
<el-table-column label="状态" align="center" width>
<div slot-scope="{row}" :class="{status1: row.status === '营业中'}">{{row.status}}</div>
</el-table-column>
<el-table-column label="距离" align="center" width>
<div slot-scope="{row}">{{row.distance}}m</div>
</el-table-column>
<el-table-column label="平台" align="center" width>
<div slot-scope="{row}">{{row.storeMaps}}</div>
</el-table-column>
<!-- <el-table-column
label="负责人"
align="center"
width="">
<div slot-scope="{row}">
{{row.marketManName}},{{row.operatorName}},{{row.operatorName2}},{{row.operatorName3}}
</div>
</el-table-column>-->
<el-table-column label="操作" align="center" width>
<div slot-scope="{row}">
<el-button size="mini" type="success" @click="pick(row)">选择</el-button>
</div>
</el-table-column>
</el-table>
<div class="current-pick" style="margin-top: 10px;">
当前选择门店:
<el-input style="width: 200px;" size="mini" v-model.number="current.storeID" @input="handleChange" clearable></el-input>
</div>
</div>
</template>
<script>
import { getStores } from '@/apis/controls/shop.js'
import msgWarning from '@/tools/msgwarning.js'
import { getDistance } from '@/utils'
import { mapGetters } from 'vuex'
export default {
props: {
lng: {
type: Number,
required: true
},
lat: {
type: Number,
required: true
},
curStoreID: {
type: Number
}
},
data() {
return {
loading: false,
range: 5000,
list: [],
current: {
name: '暂无',
storeID: 0
}
}
},
computed: {
...mapGetters({
cms: 'cms'
})
},
created() {
const { lat, lng } = this
},
methods: {
async handleSearch() {
if (!this.range || isNaN(this.range)) {
this.$toast('请输入正确半径范围')
return false
}
try {
this.loading = true
const { lat: mapLatitude, lng: mapLongitude, range: mapRadius, curStoreID } = this
const { stores, totalCount } = await getStores({
mapLongitude,
mapLatitude,
mapRadius,
statuss: [1, 0, -1],
pageSize: -1
}, true)
// .filter(item => item.id !== curStoreID) 过滤原门店
this.list = (stores || []).map(item => {
const storeMaps = (item.StoreMaps || []).map(item => this.ConVendorNameMap.get(item.vendorID).nick).join(',')
return {
storeID: item.id,
storeLevel: item.storeLevel,
payPercentage: item.payPercentage,
name: item.name,
provinceName: item.provinceName,
cityName: item.cityName,
status: this.cms.storeStatus[item.status],
storeMaps,
marketManName: item.marketManName,
operatorName: item.operatorName,
operatorName2: item.operatorName2,
operatorName3: item.operatorName3,
distance: Math.floor(getDistance(mapLatitude, mapLongitude, item.lat, item.lng))
}
}).sort((n1, n2) => n1.distance - n2.distance)
} catch (e) {
msgWarning(e)
} finally {
this.loading = false
}
},
pick(store) {
this.current = store
this.$emit('pcikStore', store.storeID)
},
handleChange(val) {
this.$emit('pcikStore', +val)
}
}
}
</script>
<style lang="scss">
@import "./pick-store-bylocation";
</style>

View File

@@ -0,0 +1,150 @@
<template>
<div class="right-goods-search">
<div class="list-wrapper" :style="'transform: translate(' + offsetX + 'px, ' + offsetY +'px)'">
<div class="tips" @mousedown="handleDown">相关商品<br>(如有相同商品请勿重复创建)</div>
<div class="list" v-loading="loading">
<!-- <div class="list-item" v-for="skuName in skuNames" :key="skuName.skuID" :class="{danger: skuName.status === 0}">
<el-collapse-item :title="skuName.fullName" >
</el-collapse-item>
{{}}
</div> -->
<el-collapse accordion>
<el-collapse-item class="list-item" :title="skuName.fullName" v-for="skuName in skuNames" :key="skuName.skuID" :class="{off: skuName.status === 0}">
<div class="text3">nameID: {{skuName.nameID}}</div>
<div class="text3">skuID: {{skuName.skuID}}</div>
<div class="text3">状态: {{skuName.status ? '上架' : '下架'}}</div>
</el-collapse-item>
</el-collapse>
</div>
</div>
</div>
</template>
<script>
import {debounce, computedName} from '@/utils'
import {getSkuNames} from '@/apis/controls/skuNames.js'
export default {
props: {
keyword: {
type: String,
default: ''
}
},
data () {
return {
skuNames: [],
loading: false,
down: false,
// clickMx: 0,
// clickMy: 0,
// clickDx: 0,
// clickDy: 0,
oldX: 0,
oldY: 0,
offsetX: 0,
offsetY: 0
}
},
created () {
window.addEventListener('mouseup', this.handleUp)
window.addEventListener('mousemove', this.handleMove)
},
beforeDestroy () {
window.removeEventListener('mouseup', this.handleUp)
window.removeEventListener('mousemove', this.handleMove)
},
methods: {
// 关键字查询商品库
async search (keyword) {
try {
this.loading = true
const {skuNames} = await getSkuNames({keyword, isBySku: true, pageSize: -1}, true)
this.skuNames = skuNames ? skuNames.map(item => ({
nameID: item.id,
skuID: item.skus[0].id,
status: item.skus[0].status,
fullName: computedName(item, item.skus[0])
})) : []
} catch (e) {
} finally {
this.loading = false
}
},
handleDown (e) {
this.down = true
const {x, y} = e
this.oldX = x - this.offsetX
this.oldY = y - this.offsetY
},
handleUp (e) {
this.down = false
},
handleMove (e) {
const {down} = this
if (down) {
const {oldX, oldY} = this
const {x, y} = e
this.offsetX = x - oldX
this.offsetY = y - oldY
}
}
},
watch: {
keyword: debounce(function (to) {
if (to.trim()) this.search(to.trim())
}, 1000)
}
}
</script>
<style lang="scss">
.right-goods-search {
position: fixed;
top: 80px;
right: 150px;
color: #606266;
font-size: 14px;
.list-wrapper {
border: 2px solid #E6A23C;
height: 300px;
width: 220px;
background: rgba(white, .7);
/* padding: 10px 0; */
box-shadow: 0 0 4px rgba(#ccc, 1), 0 2px 4px rgba(#ccc, 1), 0 3px 4px rgba(#ccc, 1);
border-radius: 5px;
/* :style="'transform: translate(' + offsetX + 'px, ' + offsetY +'px)'" */
transform: translate(0, 0)
}
.tips {
text-align: center;
color: #F56C6C;
font-weight: bold;
border-bottom: 1px solid #E4E7ED;
cursor: move;
user-select: none;
padding: 5px 0;
}
.list {
overflow-y: scroll;
height: 250px;
}
.list-item {
box-sizing: border-box;
padding: 5px;
}
.el-collapse-item__header {
height: auto;
line-height: 1.2;
padding: 5px 0;
}
.off {
.el-collapse-item__header {
color: #F56C6C;
}
}
.text3 {
color: #909399;
}
}
</style>

View File

@@ -0,0 +1,43 @@
<template>
<el-dialog
title="角色选择"
custom-class="role-pick"
@closed="diaClose"
@open="diaOpen"
width="800px"
:visible.sync="show"
>
<CmpSystemConfig @pickRole="confirmRole" configName="角色" configKey="Role" type="rolePick"></CmpSystemConfig>
</el-dialog>
</template>
<script>
import CmpSystemConfig from '@/components/system/cmp-system-config'
export default {
name: 'UserPickHigh',
props: [],
components: {
CmpSystemConfig
},
data () {
return {
show: false,
key: ''
}
},
methods: {
diaClose () {
this.show = false
},
diaOpen () {},
confirmRole (user) {
this.show = false
this.$emit('confirmUser', {key: this.key, user})
}
}
}
</script>
<style lang="scss">
@import './role-pick.scss';
</style>

View File

@@ -0,0 +1,3 @@
@import '@/assets/scss/_color.scss';
.role-pick {}

View File

@@ -0,0 +1,101 @@
<template>
<el-popover
placement="left"
width="160"
trigger="click"
popper-class="search-from-role"
>
<div class="user-list" v-loading="userListLoading">
<div v-for="user in userList" :key="user.userID">
{{user.name}} {{user.mobile}}
</div>
<div v-if="userList.length === 0">暂无</div>
</div>
<div slot="reference" class="search-users" @click="searchUsers"><i class="el-icon-search"></i>{{btnName || '查看人员'}}</div>
</el-popover>
</template>
<script>
import api from '@/utils/api'
export default {
name: 'SearchFromRole',
props: ['role', 'btnName'],
data () {
return {
userList: [],
userListLoading: false
}
},
created () {
},
methods: {
// 选择人员
pickRole (user) {
this.$emit('pickRole', user)
},
// 查看人员
async searchUsers () {
let item = this.role
try {
this.userListLoading = true
this.userList = await this.apiRolesUserList(item.key)
} catch (e) {
console.error(e)
this.$message({
message: e,
type: 'error',
center: true
})
} finally {
this.userListLoading = false
}
},
// 获取角色中的用户
async apiRolesUserList (roleName) {
try {
let res = await api(`v2/user2/GetRolesUserList?roleNames=${JSON.stringify([roleName])}`, {
noLoading: true
})
res = res[Object.keys(res)[0]]
if (res) {
return await this.apiGetUserList(res)
} else {
return []
}
} catch (e) {
console.error(e)
// this.$alert(e, '错误')
throw e
}
},
// 获取所有用户列表
async apiGetUserList (userIDs = [], pageSize = 50) {
try {
let params = {
userType: 12,
offset: 0,
pageSize
}
if (userIDs.length > 0) params.userIDs = JSON.stringify(userIDs)
let {data} = await api(`v2/user2/GetUsers`, {
noLoading: true,
params
})
return data || []
} catch (e) {
console.error(e)
throw e
}
}
}
}
</script>
<style lang="scss">
.search-users {
display: inline-block;
margin-right: 10px;
cursor: pointer;
color: #409EFF;
}
</style>

View File

@@ -0,0 +1,53 @@
<template>
<el-popover
placement="left"
width=""
trigger="click"
popper-class="search-from-role"
>
<div class="user-list" v-loading="loading">
<div>
{{store ? store.name : '暂无'}}
</div>
</div>
<div slot="reference" class="search-users" @click="searchStore">{{btnName || '查看人员'}}</div>
</el-popover>
</template>
<script>
import {getOneStore} from '@/apis/controls/shop.js'
export default {
props: ['btnName'],
data () {
return {
store: null,
loading: false
}
},
created () {},
methods: {
// 查看人员
async searchStore () {
let storeID = Number(this.btnName)
try {
this.loading = true
const {stores} = await getOneStore(storeID)
if (stores) this.store = stores[0]
} catch (e) {
this.store = null
console.error(e)
} finally {
this.loading = false
}
}
}
}
</script>
<style lang="scss">
.search-users {
display: inline-block;
cursor: pointer;
color: #409EFF;
}
</style>

View File

@@ -0,0 +1,42 @@
<template>
<el-dialog
title="人员选择"
custom-class="user-pick"
@closed="diaClose"
@open="diaOpen"
width="800px"
:visible.sync="show"
>
<UserManager v-if="show" :btnName="btnName" type="userPick" @confirmUser="confirmUser" :filterTypeID="filterTypeID" :userIDs="userIDs"></UserManager>
</el-dialog>
</template>
<script>
import UserManager from '@/components/system/user-role-manager/cmp-user-manager'
export default {
name: 'UserPickHigh',
props: ['btnName', 'filterTypeID', 'userIDs'],
components: {
UserManager
},
data () {
return {
show: false
}
},
methods: {
diaClose () {
this.show = false
},
diaOpen () {},
confirmUser (user) {
this.show = false
this.$emit('confirmUser', user)
}
}
}
</script>
<style lang="scss">
@import './user-pick.scss';
</style>

View File

@@ -0,0 +1,9 @@
@import '@/assets/scss/_color.scss';
.user-pick {
.table {
td {
padding: 5px 0;
}
}
}

View File

@@ -0,0 +1,120 @@
<template>
<el-dialog
title="人员选择"
width="400px"
custom-class="user-pick"
@closed="diaClose"
@open="diaOpen"
:visible.sync="show"
>
<!-- 检索框 -->
<el-input
size="small"
v-model.trim="keyword"
style="width: 100%;"
clearable
placeholder="检索关键字,回车确定"
@keypress.enter.native="handleSearch"
@input="keyWordChange"
>
<span slot="prepend" class="el-icon-search"></span>
</el-input>
<!-- 数据 -->
<el-table
class="table"
:data="userList"
style="width: 100%"
height="300"
>
<el-table-column
prop="name"
label="姓名"
align="center">
</el-table-column>
<el-table-column
prop="mobile"
label="电话"
align="center">
</el-table-column>
<el-table-column
label="操作"
align="center">
<div slot-scope="scope">
<el-button size="mini" type="success" @click="handlePick(scope.row)">选择</el-button>
</div>
</el-table-column>
</el-table>
</el-dialog>
</template>
<script>
import api from '@/utils/api'
import {hideLoad} from '@/tools/loading'
export default {
name: 'USERPICK',
data () {
return {
show: false,
userList: [],
keyword: ''
}
},
computed: {
userTypeName () {
let {userTypeName = {}} = this.$store.getters.CMS
return userTypeName
}
},
methods: {
// close
diaClose () {
this.show = false
},
// open
async diaOpen () {
this.userList = await this.apiGetUserList()
},
// 获取用户列表
async apiGetUserList (keyword) {
try {
let params = {
userType: 12,
offset: 0,
pageSize: -1
}
if (keyword) params.keyword = keyword
let {data} = await api('v2/user2/GetUsers', {
params
})
return data || []
} catch (e) {
console.error(e)
this.$alert(e, '错误')
this.diaClose()
} finally {
hideLoad()
}
},
// 关键字改变
async keyWordChange (val) {
if (!val) this.userList = await this.apiGetUserList()
},
// 查询
async handleSearch () {
this.userList = await this.apiGetUserList(this.keyword)
},
// 选择
handlePick (user) {
this.$emit('confirUser', {
name: user.name,
mobile: user.mobile
})
this.diaClose()
}
}
}
</script>
<style lang="scss">
@import './user-pick.scss';
</style>

View File

@@ -0,0 +1,13 @@
<template>
<div class="cmp-cookbook-detail"></div>
</template>
<script>
export default {
name: 'CmpCookBookDetail'
}
</script>
<style>
</style>

View File

@@ -0,0 +1,575 @@
<template>
<div class="cookbook-detail baselayout">
<h2 style="display: flex; align-items: center;"><el-button icon="el-icon-back" size="mini" style="margin-right: 20px;" @click="btnPrev" v-if="!id">返回</el-button>{{id ? '编辑' : '创建'}}菜谱</h2>
<div class="wrapper">
<el-tabs v-model="activeName" @tab-click="tabClick" tab-position="left">
<el-tab-pane label="基本信息" name="base">
<!-- 表单基本信息 -->
<div class="base-info">
<el-form
:model="form"
size="small"
:inline="true"
ref="submitForm"
@submit.native.prevent
:rules="rules"
label-width="130px"
label-position="right"
>
<!-- 名字 -->
<el-form-item label="菜谱名" prop="name">
<el-input v-model.trim="form.name" style="width: 744px" placeholder="请填写菜谱名,例如:不用油的炸土豆" clearable></el-input>
</el-form-item>
<!-- 制作时长 -->
<el-form-item label="制作时长" prop="timeInMinute">
<el-input v-model.number.trim="form.timeInMinute" placeholder="请填写制作时长" clearable>
<span slot="prepend"></span>
<span slot="append">分钟</span>
</el-input>
</el-form-item>
<!-- 描述 -->
<br>
<el-form-item label="描述" prop="description">
<el-input v-model.trim="form.description" style="width: 744px" placeholder="请填写描述,例如:好吃简单的炸土豆,在家就能轻松制作" clearable></el-input>
</el-form-item>
<!-- 菜谱图片 -->
<br>
<el-form-item label="菜谱图片" prop="img">
<jx-upload-file
:listType="'picture-card'"
:imgType="['image/jpeg','image/png']"
:autoUpload="true"
:drag="true"
:isUseMd5="true"
v-model="form.img"
:name="form.name"
@removeImg="delImg"
@getUrl="addImg"
>
</jx-upload-file>
</el-form-item>
</el-form>
</div>
</el-tab-pane>
<el-tab-pane label="食材" name="items">
<!-- 食材 -->
<div class="book-item-wrapper">
<div class="book-item-scroll">
<div class="book-items" v-for="item in recipeItems" :key="item.id">
<div class="item-name">
<div class="item-label">食材</div>
<el-input style="width: 300px;" v-model.trim="item.name" size="small" placeholder="请输入一种食材,例如:土豆" clearable></el-input>
</div>
<div class="item-skus">
<div class="item-label">
<el-button size="small" type="success" @click="showSkuPick(item.id, item.name)" plain round>选择建议商品</el-button>
<!-- <el-button size="small" type="success" @click="showSkuPick(item.id)">全部删除</el-button> -->
</div>
<!-- <div>
<el-button size="small" type="success" @click="showSkuPick(item.id)">选择商品</el-button>
</div> -->
<div class="pick-skus">
<div class="sku-item" v-for="sku in item.skus" :key="sku.skuID">
<img :src="sku.img | appendImgURL" alt="略缩图">
<div class="name">{{sku.fullName}}</div>
<el-button class="sku-delete" type="danger" size="mini" icon="el-icon-delete" @click="deleteSku(item.id, sku.skuID)"></el-button>
</div>
</div>
</div>
<!-- 右上角删除按钮 -->
<el-button class="item-delete" type="danger" size="small" icon="el-icon-close" @click="deleteItem(item.id)"></el-button>
</div>
</div>
<!-- 添加食材按钮 -->
<div>
<el-button plain type="success" size="small" style="width: 100%;" @click="addRecipeItem">添加食材</el-button>
</div>
</div>
<!-- 食材 -->
</el-tab-pane>
<el-tab-pane label="做法" name="steps">
<!-- 做法 -->
<div class="book-steps-wrapper">
<div class="book-step-list">
<div class="book-step-item" v-for="(step, index) in recipeSteps" :key="step.id">
<div class="step-count">步骤 {{index + 1}}</div>
<div style="width: 100%;">
<div class="input-frame">
<div class="item-label">步骤名称</div>
<el-input style="width: 300px;" v-model.trim="step.name" size="small" placeholder="请输入步骤名称,例如:加入土豆" clearable></el-input>
</div>
<div class="input-frame">
<div class="item-label">步骤描述</div>
<el-input style="width: 100%" v-model.trim="step.description" size="small" placeholder="请输入步骤描述例如油温烧到7成热后放入切好的土豆注意..." clearable></el-input>
</div>
<div class="input-frame">
<div class="item-label img">步骤插图</div>
<jx-upload-file
:listType="'picture-card'"
:imgType="['image/jpeg','image/png']"
:autoUpload="true"
:drag="true"
:isUseMd5="true"
:name="form.name + ((index + 1) * 1)"
v-model="step.img"
@removeImg="delStepImg(step.id)"
@getUrl="addStepImg($event, step.id)"
>
</jx-upload-file>
</div>
</div>
<!-- 右上角删除按钮 -->
<el-button class="item-delete" type="danger" size="small" icon="el-icon-close" @click="deleteStep(step.id)"></el-button>
</div>
</div>
<div>
<el-button plain type="success" size="small" style="width: 100%;" @click="addStep">添加步骤</el-button>
</div>
</div>
<!-- 做法 -->
</el-tab-pane>
</el-tabs>
<div style="margin-left: 105px; margin-top: 20px" v-if="id === 0">
<el-button type="primary" size="" @click="submitForm('create')">创建菜谱</el-button>
</div>
<div style="margin-left: 105px; margin-top: 20px" v-else>
<el-button type="primary" size="" @click="submitForm('update')">修改菜谱</el-button>
</div>
</div>
<!-- 选择商品dialog -->
<SkusPick
ref="diaSkuPick"
:diaSkuShow="diaSkuShow"
:catLevel1="catLevel1"
:catLevel2="catLevel2"
@confirmSkus="confirmSkus"
@handleClose="handleClose"
type="normal"
reqApi="storeSkus"
></SkusPick>
</div>
</template>
<script>
/* eslint-disable */
import {require, requireNum} from '@/utils/rules'
import SkusPick from '@/components/promotion/cmp/dia-pick-skus'
import {getJxCat} from '@/apis/common.js'
import msgWarning from '../../tools/msgwarning'
import {showLoad, hideLoad} from '@/tools/loading'
import {computedName} from '@/utils'
import api from '@/utils/api'
/* eslint-disable */
export default {
name: 'CookBookDetail',
components: {
SkusPick,
jxUploadFile: () => import("@/components/cmp/uploadFile")
},
data () {
return {
id: 0,
form: {
name: '',
description: '',
img: '',
timeInMinute: null
},
rules: {
name: [
require('必须填写菜谱名')
],
description: [
require('必须填写描述')
],
img: [
require('必须选择菜谱图片')
],
timeInMinute: [
requireNum('必须填写制作时长')
]
},
recipeItems: [
{
id: (Math.random() * 1000000000).toString(16).substring(0, 6),
name: '',
skus: [] // fullName skuID img
}
],
recipeSteps: [
{
id: (Math.random() * 1000000000).toString(16).substring(0, 6),
name: '',
description: '',
img: ''
}
],
activeName: 'base',
diaSkuShow: false,
catLevel1: [],
catLevel2: [],
currentSkusPick: '',
maxCount: 10,
original: {}
}
},
async created () {
try {
let cat = await getJxCat()
this.catLevel1 = cat.catLevel1
this.catLevel2 = cat.catLevel2
const {id = 0} = this.$route.query
this.id = +id
if (this.id) {
// 编辑
// 请求数据,洗数据
let detail = await this.apiGetRecipeDetail(this.id)
this.dealEditorDetail(detail)
} else {
// 创建
console.log('创建')
}
} catch (e) {
console.error(e)
msgWarning(e)
} finally {
hideLoad()
}
},
methods: {
// api请求菜谱详情
async apiGetRecipeDetail (id) {
try {
let res = await api('v2/foodrecipe/GetRecipeDetail', {
noLoading: true,
params: {
recipeID: id
}
})
return res
} catch (e) {
console.error(e)
msgWarning(e)
} finally {
hideLoad()
}
},
// 编辑组装数据
dealEditorDetail (json) {
this.form.name = json.name
this.form.description = json.description
this.form.img = json.img
this.form.timeInMinute = json.timeInMinute
this.recipeItems = json.itemList.map(item => ({
id: item.id,
name: item.name,
skus: item.itemChoiceList.map(sku => ({
fullName: sku.skuName,
skuID: sku.skuID,
img: sku.img
}))
}))
this.recipeSteps = json.stepList.map(step => ({
id: step.id,
name: step.name,
description: step.description,
img: step.img
}))
this.updateOriginal()
},
// 更新 original
updateOriginal () {
this.original = {
name: this.form.name,
description: this.form.description,
img: this.form.img,
timeInMinute: this.form.timeInMinute,
recipeItems: JSON.parse(JSON.stringify(this.recipeItems.map(item => ({
name: item.name,
skuIDs: item.skus.map(item => item.skuID)
})))),
recipeSteps: JSON.parse(JSON.stringify(this.recipeSteps.map(item => ({
name: item.name,
description: item.description,
img: item.img || ''
}))))
}
},
// 返回上一页
btnPrev () {
this.$router.back()
},
computedName (skuName, sku) {
return computedName(skuName, sku)
},
addImg (url) {
this.form.img = url
},
delImg () {
this.form.img = ''
},
// 校验食材 recipeItems
validItems () {
let item = this.recipeItems.find(item => !item.name || item.skus.length === 0)
if (item) {
return false
} else {
return true
}
},
// 校验步骤 recipeSteps
validSteps () {
let item = this.recipeSteps.find(item => !item.name || !item.description)
if (item) {
return false
} else {
return true
}
},
// 提交表单
submitForm (type) {
this.$refs['submitForm'].validate(async (valid) => {
if (!valid) {
this.$message({
message: '请检查【基本信息】是否填写完整',
type: 'warning',
center: true
})
this.activeName = 'base'
return false
}
if (!this.validItems()) {
this.$message({
message: '请检查【食材】是否填写完整',
type: 'warning',
center: true
})
this.activeName = 'items'
return false
}
if (!this.validSteps()) {
this.$message({
message: '请检查【做法】中步骤是否填写完整',
type: 'warning',
center: true
})
this.activeName = 'steps'
return false
}
// 校验通过,组装数据
let json = {}
json.name = this.form.name
json.description = this.form.description
json.img = this.form.img
json.timeInMinute = this.form.timeInMinute
json.recipeItems = this.recipeItems.map(item => ({
name: item.name,
skuIDs: item.skus.map(item => item.skuID)
}))
json.recipeSteps = this.recipeSteps.map(item => ({
name: item.name,
description: item.description,
img: item.img || ''
}))
if (type === 'create') {
await this.apiCreateFoodRecipe(json)
this.btnPrev()
} else if (type === 'update') {
if (JSON.stringify(this.original) === JSON.stringify(json)) {
this.$message({
message: '未做任何修改',
type: 'warning',
center: true
})
} else {
const original = this.original
for (let attr in json) {
if (typeof json[attr] === 'object') {
if (JSON.stringify(json[attr]) === JSON.stringify(original[attr])) delete json[attr]
} else {
if (json[attr] === original[attr]) delete json[attr]
}
}
await this.apiUpdateFoodRecipe(this.id, json)
// 更新原数据
this.updateOriginal()
}
}
})
},
// api 创建菜谱
async apiCreateFoodRecipe (json) {
try {
await api('v2/foodrecipe/CreateFoodRecipe', {
method: 'POST',
data: `name=${json.name}&description=${json.description}&img=${json.img}&timeInMinute=${json.timeInMinute}&recipeItems=${encodeURIComponent(JSON.stringify(json.recipeItems))}&recipeSteps=${encodeURIComponent(JSON.stringify(json.recipeSteps))}`
})
this.$message({
message: '菜谱创建成功',
type: 'success',
center: true
})
} catch (e) {
console.error(e)
msgWarning(e)
} finally {
hideLoad()
}
},
// api 修改菜谱
async apiUpdateFoodRecipe (id, json) {
let formStr = `recipeID=${id}&`
for (let attr in json) {
if (typeof json[attr] === 'object') {
formStr += `${attr}=${encodeURIComponent(JSON.stringify(json[attr]))}&`
} else {
formStr += `${attr}=${json[attr]}&`
}
}
formStr = formStr.substring(0, formStr.length - 1)
try {
await api('v2/foodrecipe/UpdateFoodRecipe', {
method: 'PUT',
data: formStr
})
this.$message({
message: '菜谱修改成功',
type: 'success',
center: true
})
} catch (e) {
console.error(e)
msgWarning(e)
} finally {
hideLoad()
}
},
// 打开选择商品
showSkuPick (id, keyword) {
this.diaSkuShow = true
this.currentSkusPick = id
if (keyword) {
this.$refs.diaSkuPick.keyword = keyword
this.$refs.diaSkuPick.getGoods()
}
},
// 点击tab
tabClick (tab) {
console.log(tab.name)
},
// 去重
unique (array) {
let obj = {};
return array.filter(item => obj.hasOwnProperty(item.skuID) ? false : obj[item.skuID] = true)
},
confirmSkus (skuNames) {
// 重置选择组件的内容
this.$refs.diaSkuPick.reset()
let id = this.currentSkusPick
let recipeItem = this.recipeItems.find(item => item.id === id)
let arr = skuNames.map(skuName => ({
fullName: computedName(skuName, skuName.skus[0]),
skuID: skuName.skus[0].id,
img: skuName.img
}))
let arr2 = this.unique([...recipeItem.skus, ...arr])
if (arr2.length > this.maxCount) {
this.$message({
message: '最多添加10个商品',
type: 'warning',
center: true
})
} else {
recipeItem.skus = arr2
}
},
handleClose () {
this.diaSkuShow = false
this.$refs.diaSkuPick.reset()
},
// 删除某个sku
deleteSku (id, skuID) {
let recipeItem = this.recipeItems.find(item => item.id === id)
recipeItem.skus = recipeItem.skus.filter(item => item.skuID !== skuID)
},
// 添加 食材
addRecipeItem () {
if (this.recipeItems.length === this.maxCount) {
this.$message({
message: `只能添加${this.maxCount}个食材`,
type: 'warning',
center: true
})
} else {
this.recipeItems.push({
id: (Math.random() * 1000000000).toString(16).substring(0, 6),
name: '',
skus: []
})
this.$nextTick(() => {
document.querySelector('.book-item-wrapper').scrollTop = document.querySelector('.book-item-scroll').offsetHeight
})
}
},
// 删除食材
deleteItem (id) {
if (this.recipeItems.length === 1) {
this.$message({
message: `至少要有一个食材`,
type: 'warning',
center: true
})
} else {
this.recipeItems = this.recipeItems.filter(item => item.id !== id)
}
},
/* ------- 步骤 --------- */
// 添加步骤图片
addStepImg (url, id) {
let findStep = this.recipeSteps.find(item => item.id === id)
if (findStep) findStep.img = url
},
// 删除步骤图片
delStepImg (id) {
let findStep = this.recipeSteps.find(item => item.id === id)
if (findStep) findStep.img = ''
},
// 删除步骤
deleteStep (id) {
if (this.recipeSteps.length === 1) {
this.$message({
message: `至少要有一个步骤`,
type: 'warning',
center: true
})
} else {
this.recipeSteps = this.recipeSteps.filter(item => item.id !== id)
}
},
// 添加步骤
addStep () {
if (this.recipeSteps.length === this.maxCount * 2) {
this.$message({
message: `只能添加${this.maxCount * 2}个步骤`,
type: 'warning',
center: true
})
} else {
this.recipeSteps.push({
id: (Math.random() * 1000000000).toString(16).substring(0, 6),
name: '',
skus: []
})
this.$nextTick(() => {
document.querySelector('.book-steps-wrapper').scrollTop = document.querySelector('.book-step-list').offsetHeight
})
}
}
}
}
</script>
<style lang="scss">
@import './detail.scss';
</style>

View File

@@ -0,0 +1,65 @@
@import '@/assets/scss/_color.scss';
.cookbook-manager {
height: calc(100vh - 140px);
.booklist-book {
display: flex;
align-items: center;
.book-img {
flex: none;
width: 60px;
height: 60px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 10px;
border: 1px solid $border3;
line-height: 0;
margin-right: 20px;
img {
max-width: 100%;
max-height: 100%;
}
}
.book-name-description {
text-align: left;
.book-name {
font-size: 16px;
font-weight: bold;
}
.book-description {
color: $text3;
border-left: 4px solid $border2;
padding-left: 10px;
}
}
}
.zan-cai {
button {
padding: 0;
}
}
.book-zan, .book-cai {
display: flex;
align-items: center;
justify-content: space-between;
}
.book-zan {
color: $success;
}
.book-cai {
color: $info;
}
.page {
text-align: center;
margin-top: 10px;
}
.tiny-btn{
padding: 2px 5px;
font-size: 12px;
}
.operate-wall {
// border-top: 1px solid $border2;
}
}

View File

@@ -0,0 +1,350 @@
<template>
<div class="cookbook-manager baselayout">
<!-- 表单 -->
<el-form
:model="query"
size="mini"
:inline="true"
ref="searchForm"
@submit.native.prevent
label-width="90px">
<el-form-item label="创建人:" style="display: inline-flex;">
<el-input v-model.trim="query.authorID" placeholder="请选择用户" clearable @input="keyWordChange"></el-input>
</el-form-item>
<el-form-item style="display: inline-flex;">
<el-button type="success" @click="openUserPick">选择</el-button>
</el-form-item>
<el-form-item label="关键字:" style="display: inline-flex;">
<el-input v-model.trim="query.keyword" placeholder="请输入关键字查询" @keypress.enter.native="handleSearch" clearable @input="keyWordChange"></el-input>
</el-form-item>
<el-form-item style="display: inline-flex;">
<el-button type="primary" @click="handleSearch" style="width: 100px;">&emsp;</el-button>
<el-button type="success" @click="createBook" style="width: 100px;">创建菜谱</el-button>
</el-form-item>
</el-form>
<!-- 表单 -->
<!-- 操作面板 -->
<div class="operate-wall">
<el-button type="danger" size="mini" class="tiny-btn" @click="batDeleteBook" :disabled="!checkBooks.length">批量删除</el-button>
</div>
<!-- 操作面板 -->
<!-- 表格 -->
<el-table
class="table"
:data="bookList"
height="calc(100vh - 280px)"
tooltip-effect="dark"
stripe
@selection-change="handleSelectionChange"
>
<!-- 多选框 -->
<el-table-column
type="selection"
width="50">
</el-table-column>
<!-- ID -->
<el-table-column
prop="id"
label="ID"
align="center"
width="50"
></el-table-column>
<!-- 菜谱信息 -->
<el-table-column
label="菜谱"
align="center"
>
<div class="booklist-book" slot-scope="scope">
<div class="book-img">
<el-popover
placement="right"
width="300"
trigger="hover">
<div>
<img :src="scope.row.img" width="100%" alt="放大图">
</div>
<img slot="reference" :src="scope.row.img | appendImgURL" alt="略缩图">
</el-popover>
</div>
<div class="book-name-description">
<div class="book-name">{{scope.row.name}}</div>
<div class="book-description">{{scope.row.description}}</div>
</div>
</div>
</el-table-column>
<!-- 制作时间 -->
<el-table-column
prop="timeInMinute"
label="制作时间"
align="center"
width="80"
></el-table-column>
<!-- 创建人 -->
<el-table-column
label="创建人"
align="center"
width="130"
>
<div slot-scope="scope">
<div style="line-height: 1.2;font-size: 12px;">
<span>{{scope.row.authorName}}</span><br>
<span>{{scope.row.createdAt | timeToLLL}}</span>
</div>
</div>
</el-table-column>
<!-- 评价信息 -->
<el-table-column
label="评价信息"
align="center"
width="140"
>
<div class="zan-cai" slot-scope="scope">
<div class="book-zan">
<div>点赞: {{scope.row.upvoteCount}}</div>
<el-button type="text" icon="el-icon-circle-plus-outline"
v-if="(scope.row.actionType & 2) !== 2"
@click="handleVote(scope.row, 1)"
title="点赞"
></el-button>
<el-button type="text" icon="el-icon-remove-outline"
v-if="(scope.row.actionType & 2) === 2"
@click="handleVote(scope.row, 0)"
title="取消"
></el-button>
</div>
<div class="book-cai">
<div>被踩: {{scope.row.downvoteCount}}</div>
<el-button type="text" icon="el-icon-circle-plus-outline"
v-if="(scope.row.actionType & 4) !== 4"
@click="handleVote(scope.row, -1)"
title="踩"
></el-button>
<el-button type="text" icon="el-icon-remove-outline"
v-if="(scope.row.actionType & 4) === 4"
@click="handleVote(scope.row, 0)"
title="取消"
></el-button>
</div>
</div>
</el-table-column>
<!-- 最后操作 -->
<el-table-column
label="最后操作"
align="center"
width="130"
>
<div slot-scope="scope">
<div style="line-height: 1.2;font-size: 12px;">
<span>{{scope.row.lastOperator}}</span><br>
<span>{{scope.row.updatedAt | timeToLLL}}</span>
</div>
</div>
</el-table-column>
<el-table-column
label="操作"
align="center"
width="200"
>
<div slot-scope="scope">
<el-button size="mini" type="primary" @click="toEditor(scope.row.id)">编辑</el-button>
<el-button size="mini" type="danger" @click="handleDelete([scope.row])">删除</el-button>
</div>
</el-table-column>
</el-table>
<!-- 表格 -->
<!-- 分页 -->
<div class="page">
<el-pagination
@size-change="sizeChange"
@current-change="handleCurrentChange"
:page-sizes="[15, 30, 50]"
:page-size.sync="query.pageSize"
layout="total, sizes, prev, pager, next"
:current-page="page"
:total="totalCount">
</el-pagination>
</div>
<!-- 分页 -->
<UserPick ref="userPick" @confirmUser="confirmUser" btnName="选择" :filterTypeID="-1"></UserPick>
</div>
</template>
<script>
import api from '@/utils/api'
import {hideLoad, showLoad} from '@/tools/loading'
import msgWarning from '@/tools/msgwarning'
import UserPick from '@/components/commons/user-pick-high'
export default {
name: 'CookBookManager',
components: {
UserPick
},
data () {
return {
query: {
keyword: '',
authorID: '',
offset: 0,
pageSize: 50
},
page: 1,
bookList: [],
totalCount: 0,
checkBooks: []
}
},
async created () {
await this.getRecipes()
},
methods: {
// 获取菜谱
async apiGetRecipes (json) {
try {
let {totalCount, data} = await api(`v2/foodrecipe/QueryFoodRecipes`, {
noLoading: true,
params: json
})
return {totalCount, data}
} catch (e) {
console.error(e)
throw e
} finally {
hideLoad()
}
},
async getRecipes (json) {
try {
showLoad()
let {totalCount, data} = await this.apiGetRecipes(json)
this.totalCount = totalCount
this.bookList = data || []
} catch (e) {
msgWarning(e)
} finally {
hideLoad()
}
},
// 查询
async handleSearch (json = this.query) {
await this.getRecipes(json)
},
// sizechange
async sizeChange () {
await this.handleSearch()
},
// 点击页数
async handleCurrentChange (num) {
let {keyword, pageSize} = this.query
this.page = num
await this.getDatas({keyword, pageSize, offset: (this.page - 1) * pageSize})
if (document.querySelector('.table .el-table__body-wrapper')) document.querySelector('.table .el-table__body-wrapper').scrollTop = 0
},
// 关键字清空
async keyWordChange (val) {
if (!val) await this.handleSearch()
},
// 打开用户选择
openUserPick () {
this.$refs.userPick.show = true
},
// 确定用户
async confirmUser (user) {
this.query.authorID = user.userID
await this.handleSearch()
},
// 创建菜谱
createBook () {
this.$router.push('/cookbook/0')
},
// 编辑菜谱
toEditor (id) {
let routeData = this.$router.resolve({
name: 'CookBookDetail',
query: {
id
}
})
window.open(routeData.href, '_blank')
},
// 赞踩
async handleVote (book, voteType) {
try {
await api('v2/foodrecipe/VoteFoodRecipe', {
method: 'POST',
data: `recipeID=${book.id}&voteType=${voteType}`
})
// 成功
if (voteType === -1) {
// 踩
book.downvoteCount += 1
// 如果当前是赞
if ((book.actionType & 2) === 2) book.upvoteCount -= 1
book.actionType = 4
} else if (voteType === 1) {
// 点赞
book.upvoteCount += 1
// 如果当前是踩
if ((book.actionType & 4) === 4) book.downvoteCount -= 1
book.actionType = 2
} else if (voteType === 0) {
// 取消
if ((book.actionType & 2) === 2) {
// 当前是赞,取消点赞
book.upvoteCount -= 1
book.actionType = 0
} else if ((book.actionType & 4) === 4) {
// 当前是踩,取消踩
book.downvoteCount -= 1
book.actionType = 0
}
}
} catch (e) {
console.error(e)
msgWarning(e)
} finally {
hideLoad()
}
},
// 删除
async handleDelete (books) {
let confirmText = ''
if (books.length === 1) {
confirmText = `是否删除该菜谱[${books[0].name}]`
} else {
confirmText = `是否批量删除这些菜谱`
}
this.$confirm(confirmText, '确认').then(async () => {
try {
let ids = books.map(item => item.id)
await api(`v2/foodrecipe/DeleteRecipes?recipeIDs=${JSON.stringify(ids)}`, {
method: 'DELETE'
})
this.$message({
message: '删除成功',
type: 'success',
center: true
})
this.handleSearch()
} catch (e) {
console.error(e)
msgWarning(e)
} finally {
hideLoad()
}
})
},
// 批量删除食谱
batDeleteBook () {
this.handleDelete(this.checkBooks)
},
// 多选
handleSelectionChange (book) {
this.checkBooks = book
}
}
}
</script>
<style lang="scss">
@import './cookbook-manager.scss';
</style>

View File

@@ -0,0 +1,140 @@
@import '@/assets/scss/_color.scss';
%box {
box-sizing: border-box;
border: 1px solid $success;
border-radius: 10px;
padding: 10px 10px 10px 0;
margin-bottom: 10px;
position: relative;
}
%item-delete {
position: absolute;
right: 0;
top: 0;
border-radius: 0;
border: {
top-right-radius: 9px;
bottom-left-radius: 5px;
}
}
%scroll-area {
height: calc(100vh - 300px);
overflow-y: auto;
}
.cookbook-detail {
height: calc(100vh - 130px);
.el-tabs__item.is-left {
text-align: center;
}
.base-info {
@extend %scroll-area;
}
.wrapper {
width: 1000px;
margin: 0 auto;
}
// 用料
.book-item-wrapper {
@extend %scroll-area;
}
.book-items {
@extend %box;
.item-delete {
@extend %item-delete;
}
.item-name {
display: flex;
align-items: center;
}
.item-skus {
display: flex;
margin-top: 10px;
}
}
.input-frame {
display: flex;
align-items: center;
padding-bottom: 10px;
width: 100%;
}
.item-label {
width: 118px;
text-align: right;
font-size: 14px;
color: $text2;
flex: none;
margin-right: 12px;
&:before {
content: "*";
color: $danger;
margin-right: 4px;
}
}
.pick-skus {
// padding: 10px;
// border: 1px solid $border2;
width: 100%;
display: flex;
flex-flow: row wrap;
.sku-item {
display: flex;
align-items: center;
padding: 4px;
border: 1px solid $border1;
border-radius: 5px;
margin: 0 20px 5px 0;
width: 29%;
img {
flex: none;
border-radius: 8px;
box-shadow: 0 0 2px rgba(black, .2);
}
.name {
flex: auto;
font-size: 12px;
color: $text2;
margin: 0 10px;
}
.sku-detele {
flex: none;
}
}
}
// 做法
.book-steps-wrapper {
@extend %scroll-area;
.item-label {
width: 90px;
&.img {
&:before {
content: "";
}
}
}
.book-step-list {
}
.book-step-item {
@extend %box;
display: flex;
align-items: center;
.step-count {
flex: none;
text-align: center;
font-size: 20px;
padding-left: 20px;
font-weight: bold;
// font-style: italic;
line-height: 1.5;
color: $primary;
width: 30px;
}
.item-delete {
@extend %item-delete;
}
}
}
}

View File

@@ -0,0 +1,198 @@
<template>
<div id="electronicFence">
<h2 style="text-align: center; margin: 0">批量设置电子围栏</h2>
<div style="display:flex;">
<!-- 平台 -->
<el-select v-model="selectValue" filterable style="margin:auto 10px;width:230px;" placeholder="请选择平台账号">
<el-option label="美好菜市(68032645)" value="68032645" />
<el-option label="京西花园(92037439)" value="92037439" /> <!-- 京西同城配送 -->
<el-option label="京西到家(超市)(68023619)" value="68023619" />
<el-option label="京西菜市速食(57939570)" value="57939570" />
<el-option label="抖音小时达测试店铺(63141688)" value="63141688" />
</el-select>
<!-- 上传框 -->
<div class="upload-root" style="display: flex; align-items: center;margin-left:20px;">
<el-upload action="" :multiple="false" drag :auto-upload="false" accept=".xlsx" :on-change="electronicFence" :show-file-list="false">
<div class="el-upload__text">拖拽<em>excel</em>到此处</div>
</el-upload>
<div class="btn" v-if="electronicFenceData != ''" @click="sendElectronicFence"> 确定创建围栏</div>
<div class="btn" @click="downloadTable">下载样表</div>
</div>
</div>
<div class="center">
<div v-if="electronicFenceData == ''">
<h3>
样表样表中的
<span style="color: red">ID</span> 两个英文字母必须是大写
</h3>
<img
src="https://image.jxc4.com/image/8d052157f5bc9a7e3751bae29c3c48dd.tem.png"
/>
</div>
<div v-else class="table-root">
<h3>
批量创建模板门店数据
<span style="color: red">本次一共同步 {{ electronicFenceData.length }} 个门店</span>
</h3>
<div class="table bg-table">
<p>京西门店ID</p>
<p>抖店门店ID</p>
</div>
<div class="table" v-for="(item, index) in electronicFenceData" :key="index">
<p>{{ item.京西门店ID }}</p>
<p>{{ item.抖店门店ID }}</p>
</div>
</div>
<div></div>
</div>
</div>
</template>
<script>
import { json2Excel, importExcel2 } from '@/tools/excel.js'
import $ajax from 'axios'
import { showLoad, hideLoad } from '@/tools/loading'
export default {
data() {
return {
electronicFenceData: '',
sendData: '',
selectValue:''
}
},
methods: {
electronicFence(file, fileList) {
if(!this.selectValue){
this.$message({
message: `请选择平台账号`,
type: 'warning',
center: true,
})
return
}
importExcel2(this, file.raw, 'electronicFenceData')
},
downloadTable() {
let json = [
{
京西门店ID: '7346348',
抖店门店ID: '684521',
},
{
京西门店ID: '6545634',
抖店门店ID: '78452',
},
]
// 下载表格
json2Excel(json, '批量设置电子围栏样表')
},
async sendElectronicFence() {
let formData = new FormData()
formData.append('payload', JSON.stringify(this.sendData))
await $ajax.post('v2/store/CreateDDStoreFence', formData).then((res) => {
if (res.data.code != 0) {
this.$message({
message: `批量同步电子围栏失败-错误信息:${res.data.desc}`,
type: 'warning',
center: true,
})
} else {
this.$message({
message: `批量同步电子围栏成功`,
type: 'success',
center: true,
})
this.electronicFenceData = ''
}
hideLoad()
})
},
},
watch: {
electronicFenceData(newVal, oldVal) {
let newArrData = []
newVal.forEach((item) => {
let newObjData = {
storeID: parseInt(item.京西门店ID) + '',
vendorStoreID: parseInt(item.抖店门店ID) + '',
}
newArrData.push(newObjData)
})
// let sendData = {
// 57939570: newArrData,
// }
let sendData = {}
sendData[this.selectValue] = newArrData
this.sendData = sendData
},
},
}
</script>
<style lang="scss">
#electronicFence {
background-color: #fff;
margin: 10px;
border-radius: 5px;
height: calc(100vh - 140px);
overflow: auto;
padding: 10px;
.upload-root {
margin-top: 10px;
display: flex;
align-content: center;
flex-wrap: wrap;
.el-upload-dragger {
height: 100px;
line-height: 100px;
}
.btn {
background-color: #4da6ff;
padding: 0px 25px;
height: 35px;
line-height: 35px;
border-radius: 5px;
color: #fff;
margin-left: 15px;
cursor: pointer;
transition: all 0.5s;
}
.btn:hover {
background-color: #3194f7;
}
}
.center {
text-align: center;
border-top: 1px solid rgb(202, 202, 202);
margin-top: 15px;
img {
width: 100%;
}
.bg-table {
background-color: rgb(211, 211, 211);
}
.table {
display: flex;
justify-content: space-around;
border: 1px solid rgb(238, 238, 238);
}
.table:nth-child(even) {
background-color: rgb(248, 248, 248);
}
}
}
</style>

View File

@@ -0,0 +1,230 @@
<template>
<div id="electronicFence">
<h2 style="text-align: center; margin: 0">批量创建运费模板</h2>
<div style="display:flex;">
<!-- 平台 -->
<el-select v-model="selectValue" filterable style="margin:auto 10px;width:230px;" placeholder="请选择平台账号">
<el-option label="美好菜市(68032645)" value="68032645" />
<el-option label="京西花园(92037439)" value="92037439" /> <!-- 京西同城配送 -->
<el-option label="京西到家(超市)(68023619)" value="68023619" />
<el-option label="京西菜市速食(57939570)" value="57939570" />
<el-option label="抖音小时达测试店铺(63141688)" value="63141688" />
</el-select>
<!-- 上传框 -->
<div class="upload-root" style="display: flex; align-items: center;margin-left:20px;">
<el-upload class="upload-demo" action="" :multiple="false" drag :auto-upload="false" accept=".xlsx" :on-change="electronicFence" :show-file-list="false">
<div class="el-upload__text">拖拽<em>excel</em>到此处</div>
</el-upload>
<div class="btn" v-if="electronicFenceData != ''" @click="sendElectronicFence">确定创建运费模板</div>
<div class="btn" @click="downloadTable">下载样表</div>
<div class="input-money">
<span></span>
<input type="text" placeholder="0" v-model.number="shipFee" />
<span>元免运费</span>
</div>
</div>
</div>
<div class="center">
<div v-if="electronicFenceData == ''">
<h3>
样表样表中的
<span style="color: red">ID</span> 两个英文字母必须是大写
</h3>
<img
src="https://image.jxc4.com/image/8d052157f5bc9a7e3751bae29c3c48dd.tem.png"
/>
</div>
<div v-else class="table-root">
<h3>
批量创建模板门店数据
<span style="color: red"
>本次一共同步 {{ electronicFenceData.length }} 个门店</span
>
</h3>
<div class="table bg-table">
<p>京西门店ID</p>
<p>抖店门店ID</p>
</div>
<div
class="table"
v-for="(item, index) in electronicFenceData"
:key="index"
>
<p>{{ item.京西门店ID }}</p>
<p>{{ item.抖店门店ID }}</p>
</div>
</div>
<div></div>
</div>
</div>
</template>
<script>
import { json2Excel, importExcel2 } from '@/tools/excel.js'
import $ajax from 'axios'
import { showLoad, hideLoad } from '@/tools/loading'
export default {
data() {
return {
electronicFenceData: '',
sendData: '',
shipFee: 0,
selectValue:''
}
},
methods: {
electronicFence(file, fileList) {
if(!this.selectValue){
this.$message({
message: `请选择平台账号`,
type: 'warning',
center: true,
})
return
}
importExcel2(this, file.raw, 'electronicFenceData')
},
async sendElectronicFence() {
if (this.shipFee == '') {
return this.$message({
message: '请输入满减费用',
type: 'warning',
center: true,
})
}
let formData = new FormData()
formData.append('payload', JSON.stringify(this.sendData))
formData.append('shipFee', this.shipFee)
await $ajax
.post('v2/store/CreateFreeShipTemplates', formData)
.then((res) => {
if (res.data.code != 0) {
this.$message({
message: `批量创建运费模板失败-错误信息:${res.data.desc}`,
type: 'warning',
center: true,
})
} else {
this.$message({
message: `批量创建运费模板成功`,
type: 'success',
center: true,
})
this.electronicFenceData = ''
}
hideLoad()
})
},
downloadTable() {
let json = [
{
京西门店ID: '7346348',
抖店门店ID: '684521',
},
{
京西门店ID: '6545634',
抖店门店ID: '78452',
},
]
// 下载表格
json2Excel(json, '批量创建运费模板样表')
},
},
watch: {
electronicFenceData(newVal, oldVal) {
let newArrData = []
newVal.forEach((item) => {
let newObjData = {
storeID: parseInt(item.京西门店ID) + '',
vendorStoreID: parseInt(item.抖店门店ID) + '',
}
newArrData.push(newObjData)
})
// let sendData = {
// 57939570: newArrData,
// }
let sendData = {}
sendData[this.selectValue] = newArrData
this.sendData = sendData
},
},
}
</script>
<style lang="scss">
#electronicFence {
background-color: #fff;
margin: 10px;
border-radius: 5px;
height: calc(100vh - 140px);
overflow: auto;
padding: 10px;
.upload-root {
.el-upload-dragger {
height: 100px;
line-height: 100px;
}
.btn {
background-color: #4da6ff;
padding: 0px 25px;
height: 35px;
line-height: 35px;
border-radius: 5px;
color: #fff;
margin-left: 15px;
cursor: pointer;
transition: all 0.5s;
}
.btn:hover {
background-color: #3194f7;
}
}
.input-money {
margin-left: 20px;
input {
width: 80px;
text-align: center;
outline: none;
border: 1px solid #4da6ff;
border-radius: 4px;
}
}
.center {
text-align: center;
border-top: 1px solid rgb(202, 202, 202);
margin-top: 15px;
img {
width: 100%;
}
.bg-table {
background-color: rgb(211, 211, 211);
}
.table {
display: flex;
justify-content: space-around;
border: 1px solid rgb(238, 238, 238);
}
.table:nth-child(even) {
background-color: rgb(248, 248, 248);
}
}
}
</style>

View File

@@ -0,0 +1,125 @@
<template>
<div class="setDdWarehouse baselayout">
<el-form>
<el-form-item label="平台账号:">
<el-select v-model="searchForm.vendorOrgCode" filterable>
<el-option
v-for="(item, index) in DyVendorArr"
:label="item.name + '(' + item.key + ')'"
:value="item.key"
:key="index"
></el-option>
</el-select>
</el-form-item>
<!-- <StoresPick
:vendorIDs="[14]"
:vendorOrgCode="searchForm.vendorOrgCode"
@updateStoreIDs="updateStoreIDs"
></StoresPick> -->
<el-form-item label="单门店:">
<jx-select-pick
v-model="storeIDs"
:placeholder="'请输入门店关键字'"
:vendorID="'14'"
:vendorOrgCode="searchForm.vendorOrgCode"
:valueType="{
type:'object',
valueKey:'id'
}"
>
</jx-select-pick>
</el-form-item>
<el-form-item>
<el-button
:disabled="storeIDs && storeIDs.id? false : true"
type="primary"
@click="createDdWarehouse"
style="margin-top: 20px"
>立即创建
</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
import $ajax from "axios";
import { mapGetters } from "vuex";
import { showLoad, hideLoad } from "@/tools/loading";
// import StoresPick from "@/components/cmp/storePick/index.vue";
import jxSelectPick from '@/components/cmp/selectPick'
export default {
components: {
// StoresPick,
jxSelectPick
},
data() {
return {
searchForm: {
vendorOrgCode: "",
},
storeIDs: [],
};
},
computed: {
...mapGetters({
DyVendorArr: "DyVendorArr",
}),
},
methods: {
// // 选择门店信息
// updateStoreIDs(storeIDs) {
// if (storeIDs.length === 0) this.storeIDs = [];
// else if (storeIDs.length === 1) {
// this.storeIDs = storeIDs;
// } else {
// return this.$message.error("只能选择一个门店");
// }
// },
async createDdWarehouse() {
if (!this.searchForm.vendorOrgCode) {
this.$message({
message: "未选择平台账号",
type: "warning",
center: true,
});
return;
}
let ddStore = this.storeIDs.storeMaps.filter(
(item) => item.vendorID === 14
);
// console.log(this.storeIDs, "ddStore", ddStore);
let form = new FormData();
form.append("vendorOrgCode", this.searchForm.vendorOrgCode + "");
form.append("vendorStoreID", Number(ddStore[0].vendorStoreID));
form.append("storeID", this.storeIDs.id);
await $ajax
.post("v2/store/CreateDDWarehouse", form)
.then((res) => {
hideLoad();
if (res.data.code == 0) {
this.$message({
message: `创建抖店仓库成功`,
type: "success",
center: true,
});
} else {
this.$message({
message: `创建抖店仓库失败`,
type: "error",
center: true,
});
}
})
.catch((err) => {
hideLoad();
});
},
},
};
</script>
<style lang="scss" scoped>
</style>

View File

@@ -0,0 +1,216 @@
<template>
<div class="getCem">
<div style="display:flex;">
<!-- 平台 -->
<el-select v-model="selectValue" filterable style="margin:auto 10px;width:230px;" placeholder="请选择平台账号">
<el-option label="美好菜市(68032645)" value="68032645" />
<el-option label="京西花园(92037439)" value="92037439" /> <!-- 京西同城配送 -->
<el-option label="京西到家(超市)(68023619)" value="68023619" />
<el-option label="京西菜市速食(57939570)" value="57939570" />
<el-option label="抖音小时达测试店铺(63141688)" value="63141688" />
</el-select>
<div class="heider" style="margin-left:20px;">
<el-upload class="upload-demo" action="" :multiple="false" drag :auto-upload="false" accept=".xlsx" :on-change="getData" :show-file-list="false">
<div class="el-upload__text">拖拽<em>excel</em>到此处</div>
</el-upload>
<el-button type="success" @click="downLoadTable">下载样表</el-button>
<el-button type="primary" @click="GetStoreAutoCallRiderInfo">查询运力</el-button>
</div>
</div>
<div class="center">
<div v-if="RiderInfoData.length == 0">
<h3>
样表样表中的
<span style="color: red">ID</span> 两个英文字母必须是大写
</h3>
<img
src="https://image.jxc4.com/image/a0005310e6837fcf46941525d1e7ce4f.png"
/>
</div>
<div v-if="RiderInfoData.length !== 0 && shippingAbilityList.length===0" class="table-root">
<div class="table bg-table">
<p>抖店平台ID</p>
</div>
<div class="table" v-for="(item, index) in RiderInfoData" :key="index">
<p>{{ item.抖店平台ID }}</p>
</div>
</div>
<!-- 表格 -->
<el-table
v-if="shippingAbilityList && shippingAbilityList.length>0"
:data="shippingAbilityList"
style="width: 100%">
<el-table-column
prop="id"
label="抖店平台ID"
align="center">
</el-table-column>
<el-table-column
prop="service_type"
label="服务类型"
align="center">
<template slot-scope="scope">
<div v-if="scope.row.service_type===1">接单后延迟呼叫</div>
<div v-else>接单后立即呼叫</div>
</template>
</el-table-column>
<el-table-column
prop="service_status"
label="服务状态"
align="center">
<template slot-scope="scope">
<div v-if="scope.row.service_status === 0 ">暂未设置</div>
<div v-if="scope.row.service_status === 1 ">关闭</div>
<div v-else>开启</div>
</template>
</el-table-column>
<el-table-column
prop="delay_time"
label="延迟时间"
align="center">
<template slot-scope="scope">
<div>{{ scope.row.delay_time }}分钟</div>
</template>
</el-table-column>
</el-table>
</div>
</div>
</template>
<script>
import $ajax from 'axios'
import { showLoad, hideLoad } from '@/tools/loading'
import { json2Excel, importExcel2 } from '@/tools/excel.js'
export default {
data() {
return {
RiderInfoData: [],
sendData: [],
shippingAbilityList: [],
selectValue:''
}
},
methods: {
// 获取表格数据
getData(file) {
importExcel2(this, file.raw, 'RiderInfoData')
},
// 下载样表
downLoadTable() {
let json = [
{
抖店平台ID: '7346348',
},
{
抖店平台ID: '6545634',
},
]
json2Excel(json, '批量查询门店运力样表')
},
async GetStoreAutoCallRiderInfo() {
if(!this.selectValue){
this.$message({
message: `请选择平台账号`,
type: 'warning',
center: true,
})
return
}
this.shippingAbilityList = []
let storeIDs = this.sendData
console.log(storeIDs)
let res = await $ajax.get(
`v2/store/GetStoreAutoCallRiderInfo?vendorOrgCode=${this.selectValue}&storeIDs=${storeIDs}`
)
this.shippingAbilityList = this.objToArray(JSON.parse(res.data.data))
hideLoad()
if (res.data.code != 0) {
this.$message({
message: '查询失败',
type: 'error',
center: true,
})
}
},
objToArray(obj){
let arr = []
for(let i in obj){
let obj_item = {
id:i,
service_type:obj[i].service_type,
service_status:obj[i].service_status,
delay_time:obj[i].delay_time
}
arr.push(obj_item)
}
return arr
}
},
watch: {
RiderInfoData(newVal) {
let newData = []
newVal.forEach((item) => {
if (
item.抖店平台ID != undefined &&
item.抖店平台ID != '' &&
!isNaN(parseInt(item.抖店平台ID))
) {
newData.push(`${item.抖店平台ID}`)
}
})
this.sendData = newData.join(',')
},
},
}
</script>
<style lang="scss">
.getCem {
.heider {
height: 60px;
display: flex;
align-items: center;
flex-wrap: wrap;
.el-upload-dragger {
height: 60px;
line-height: 60px;
margin-right: 15px;
}
}
.center {
text-align: center;
border-top: 1px solid rgb(202, 202, 202);
margin-top: 15px;
img {
width: 100%;
}
.bg-table {
background-color: rgb(228, 228, 228);
}
.table {
display: flex;
justify-content: space-around;
border: 1px solid rgb(238, 238, 238);
}
.table:nth-child(even) {
background-color: rgb(248, 248, 248);
}
}
}
</style>

View File

@@ -0,0 +1,25 @@
<template>
<div class="setRiderInfo baselayout">
<!-- type="border-card" -->
<el-tabs >
<el-tab-pane label="批量查询门店运力">
<getCom></getCom>
</el-tab-pane>
<el-tab-pane label="批量设置门店运力">
<setCom></setCom>
</el-tab-pane>
</el-tabs>
</div>
</template>
<script>
import getCom from './getCom/getCom.vue'
import setCom from './setCom/setCom.vue'
export default {
components: { getCom, setCom },
}
</script>
<style lang="scss" scoped>
@import './index.scss';
</style>

View File

@@ -0,0 +1,185 @@
<template>
<div class="setCem">
<div style="display:flex">
<!-- 平台 -->
<el-select v-model="selectValue" filterable style="margin:auto 10px;width:230px;" placeholder="请选择平台账号">
<el-option label="美好菜市(68032645)" value="68032645" />
<el-option label="京西花园(92037439)" value="92037439" /> <!-- 京西同城配送 -->
<el-option label="京西到家(超市)(68023619)" value="68023619" />
<el-option label="京西菜市速食(57939570)" value="57939570" />
<el-option label="抖音小时达测试店铺(63141688)" value="63141688" />
</el-select>
<div class="heider" style="margin-left:20px;">
<el-upload class="upload-demo" action="" :multiple="false" drag :auto-upload="false" accept=".xlsx" :on-change="getData" :show-file-list="false">
<div class="el-upload__text">拖拽<em>excel</em>到此处</div>
</el-upload>
<el-button type="success" @click="downLoadTable">下载样表</el-button>
<el-button type="primary" @click="setStoreAutoCallRider">确定设置</el-button>
</div>
</div>
<div class="center">
<div v-if="RiderInfoData.length == 0">
<h3>
样表样表中的
<span style="color: red">ID</span> 两个英文字母必须是大写
</h3>
<img
src="https://image.jxc4.com/image/f91eb6f9dd94b4071c4a9ae249f5e627.png"
/>
</div>
<div v-else class="table-root">
<div class="table bg-table">
<p>自动关闭运力抖店ID</p>
<p>自动打开运力抖店ID</p>
</div>
<div class="table" v-for="(item, index) in RiderInfoData" :key="index">
<p>{{ item.自动关闭运力抖店ID ? item.自动关闭运力抖店ID : '无' }}</p>
<p>{{ item.自动打开运力抖店ID ? item.自动打开运力抖店ID : '无' }}</p>
</div>
</div>
<div></div>
</div>
</div>
</template>
<script>
import $ajax from 'axios'
import { showLoad, hideLoad } from '@/tools/loading'
import { json2Excel, importExcel2 } from '@/tools/excel.js'
export default {
data() {
return {
RiderInfoData: [], // 监听数据
openData: [], // 自动打开运力
closeData: [], // 自动关闭运力
selectValue:''
}
},
methods: {
// 获取表格数据
getData(file) {
importExcel2(this, file.raw, 'RiderInfoData')
},
// 下载样表
downLoadTable() {
let json = [
{
自动打开运力抖店ID: '1346348',
自动关闭运力抖店ID: '72853482',
},
{
自动打开运力抖店ID: '346348',
自动关闭运力抖店ID: '1853482',
},
]
json2Excel(json, '批量设置门店运力样表')
},
// 确定创建运力
async setStoreAutoCallRider() {
if(!this.selectValue){
this.$message({
message: `请选择平台账号`,
type: 'warning',
center: true,
})
return
}
let form = new FormData()
form.append('vendorOrgCode', +this.selectValue)
form.append('openIDs', this.openData)
form.append('closeIDs', this.closeData)
await $ajax.post('v2/store/SetStoreAutoCallRider', form).then((res) => {
hideLoad()
if (res.data.code == 0) {
this.$message({
message: `设置运力成功`,
type: 'success',
center: true,
})
} else {
this.$message({
message: `设置运力失败`,
type: 'warning',
center: true,
})
}
})
},
},
watch: {
RiderInfoData(newVal) {
let openIDs = []
let closeIDs = []
newVal.forEach((item) => {
if ( item.自动打开运力抖店ID != undefined && item.自动打开运力抖店ID != '' && !isNaN(parseInt(item.自动打开运力抖店ID))) {
let str = item['自动打开运力抖店ID'] +''
if (str.includes('\t')) {
openIDs.push(String(item['自动打开运力抖店ID']).substring(1))
} else {
openIDs.push('' + item.自动打开运力抖店ID)
}
}
if ( item.自动关闭运力抖店ID != undefined && item.自动关闭运力抖店ID != '' && !isNaN(parseInt(item.自动关闭运力抖店ID)) ) {
let str = item['自动关闭运力抖店ID'] +''
if (str.includes('\t')) {
closeIDs.push(String(item['自动关闭运力抖店ID']).substring(1))
} else {
closeIDs.push('' + item.自动关闭运力抖店ID)
}
}
})
this.openData = openIDs.join(',')
this.closeData = closeIDs.join(',')
},
},
}
</script>
<style lang="scss">
.setCem {
.heider {
height: 60px;
display: flex;
align-items: center;
flex-wrap: wrap;
.el-upload-dragger {
height: 60px;
line-height: 60px;
margin-right: 15px;
}
}
.center {
text-align: center;
border-top: 1px solid rgb(202, 202, 202);
margin-top: 15px;
img {
width: 100%;
}
.bg-table {
background-color: rgb(228, 228, 228);
}
.table {
display: flex;
justify-content: space-around;
border: 1px solid rgb(238, 238, 238);
}
.table:nth-child(even) {
background-color: rgb(248, 248, 248);
}
}
}
</style>

View File

@@ -0,0 +1,132 @@
<template>
<div class="jd-settlement baselayout">
<!-- 京东结算 -->
<div>
<!-- <div style="height: 50px;padding-top: 10px;">
<div style="float: left;">
<el-button style="margin-left: 10px;" size="small" type="primary" @click="submitUpload" v-if="uploadBtnShow" icon="el-icon-upload">上传到服务器</el-button>
<el-button style="margin-left: 10px;" size="small" type="danger" @click="deleteList" v-if="deleteBtnShow" icon="el-icon-delete">清空上传列表</el-button>
<span>文件数量: {{fileList.length}}</span>
</div>
</div> -->
<el-upload
class="upload-demo"
multiple
:limit="4"
drag
action="/v2/settlement/upload/cfg"
:auto-upload="false"
accept=".xlsx"
:file-list="fileList"
:on-change="dataChange"
:on-exceed="dataOverLimit"
:on-remove="dataRemove">
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处<em>点击上传</em>
<div style="color: #303133">
<i style="color: #F56C6C;" class="el-icon-warning"></i> 请上传: <b>活动信息.xlsx</b>
</div>
</div>
</el-upload>
</div>
</div>
</template>
<script>
import {getCookie} from '@/tools/'
import {hideLoad} from '@/tools/loading.js'
import $ajax from 'axios'
// import msgWarning from '@/tools/msgwarning.js'
export default {
name: 'JDSettlement',
data () {
return {
headers: {
token: getCookie('Token')
},
fileList: [],
// 活动信息
activity_config: '',
// 商家信息
merchant_info: '',
// 京东商品信息
jd_sku_info: '',
// 市场负责人信息
city_manager_info: ''
}
},
created () {
// 解决火狐拖拽 下载问题
document.body.ondrop = ev => {
ev = ev || event
ev.dataTransfer = ev.originalEvent.dataTransfer
ev.stopPropagation()
ev.preventDefault()
}
},
methods: {
// 文件改变
dataChange (file, fileList) {
if (file.name.indexOf('活动') !== -1) {
// 活动信息
this.activity_config = file
this.uploadFile(file, 'activity_config')
} else if (file.name.indexOf('商家') !== -1) {
this.merchant_info = file
this.uploadFile(file, 'merchant_info')
} else if (file.name.indexOf('商品') !== -1) {
this.jd_sku_info = file
this.uploadFile(file, 'jd_sku_info')
} else if (file.name.indexOf('负责人') !== -1) {
this.city_manager_info = file
this.uploadFile(file, 'city_manager_info')
}
this.fileList = fileList
},
// 上传文件
uploadFile (file, type) {
let formData = new FormData()
formData.append('uploadfile', file.raw)
formData.append('type', type)
$ajax.post('v3/settlement/upload/cfg', formData, {
timeout: 1000 * 60 * 30
}).then(res => {
hideLoad()
file.status = 'success'
}).catch(err => {
hideLoad()
})
},
// 文件超过数量限制
dataOverLimit () {
this.$message({
message: '最多一个文件',
type: 'warning',
center: true
})
},
// 文件删除
dataRemove (file, fileList) {
if (file.name.indexOf('活动') !== -1) {
// 活动信息
this.activity_config = ''
} else if (file.name.indexOf('商家') !== -1) {
this.merchant_info = ''
} else if (file.name.indexOf('商品') !== -1) {
this.jd_sku_info = ''
} else if (file.name.indexOf('负责人') !== -1) {
this.city_manager_info = ''
}
this.fileList = fileList
}
}
}
</script>
<style lang="scss">
.jd-settlement {
.upload-demo {
display: inline-block;
}
}
</style>

View File

@@ -0,0 +1,225 @@
<template>
<div class="store-excel-send baselayout">
<!-- 门店账单推送 -->
<div>
<div style="height: 50px;padding-top: 10px;">
<div style="float: left;">
<el-button style="margin-left: 10px;" size="small" type="primary" @click="submitUpload" v-if="uploadBtnShow" icon="el-icon-upload">上传到服务器</el-button>
<el-button style="margin-left: 10px;" size="small" type="danger" @click="deleteList" v-if="deleteBtnShow" icon="el-icon-delete">清空上传列表</el-button>
<span>文件数量: {{fileList.length}}</span>
</div>
<div style="float: left; margin-left: 20px;width: 400px; display: flex;">
<el-select v-model="brandName" placeholder="请选择菜市名称" size="small" style="width: 150px;">
<el-option v-for="(item, index) in shopNameList" :value="item" :label="item" :key="index"></el-option>
</el-select>
<el-input size="small" placeholder="请输入账单名称" v-model="billName" style="flex: 1;"></el-input>
</div>
<div style="float: right">
<QueryTask></QueryTask>
</div>
</div>
<el-upload
class="upload-demo"
ref="upload"
drag
:headers="headers"
action="/v2/financial/SendFilesToStores"
:auto-upload="false"
accept=".xlsx"
name="userfiles"
:data="options"
:on-change="fileChange"
:on-remove="fileRemove"
:file-list="fileList"
multiple>
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处<em>点击上传</em>
<div style="color: #303133">
<i style="color: #F56C6C;" class="el-icon-warning"></i> 文件命名方式: <b>京西门店ID_城市_店名例如100014_苏州_国泰.xlsx</b>
</div>
</div>
</el-upload>
</div>
</div>
</template>
<script>
import { getServiceInfo } from '@/apis/getServiceInfo.js'
import { getCookie } from '@/tools/'
// import copyText from '@/tools/copytext.js'
import { hideLoad } from '@/tools/loading.js'
import $ajax from 'axios'
import QueryTask from '@/components/smalltools/querytask.vue'
import msgWarning from '@/tools/msgwarning.js'
export default {
name: 'StoreExcelSend',
components: {
QueryTask
},
data() {
return {
shopNameList: [],
brandName: '',
billName: '',
headers: {
token: getCookie('Token')
},
fileList: [],
uploadBtnShow: true,
deleteBtnShow: true,
options: {
isAsync: false // 是否异步
}
}
},
created() {
// 解决火狐拖拽 下载问题
document.body.ondrop = ev => {
ev = ev || event
ev.dataTransfer = ev.originalEvent.dataTransfer
ev.stopPropagation()
ev.preventDefault()
}
// 获取服务信息
getServiceInfo(res => {
try {
let metaData = JSON.parse(res.data).metaData
let shopNameList = []
shopNameList.push(metaData.vendorName['0'])
shopNameList.push(metaData.vendorName['1'])
shopNameList.push(metaData.vendorName['3'])
shopNameList.push(metaData.vendorName['5'])
shopNameList.push(metaData.vendorName['14'])
shopNameList.push(metaData.vendorName['16'])
this.shopNameList = shopNameList
} catch (e) {
this.$message({
message: '[获取菜市名称列表失败] ' + e,
type: 'error',
center: true
})
}
})
},
methods: {
// 手动上传文件
submitUpload() {
if (!this.brandName.trim() || !this.billName.trim()) {
this.$message({
message: '请选择菜市名称并输入账单名称!',
type: 'error'
})
return false
}
if (this.$refs.upload.uploadFiles.length > 0) {
// 上传的文件大于0个
this.$confirm('是否上传当前列表到服务器', '提示').then(() => {
// this.$refs.upload.submit()
// 上传文件
let formData = new FormData()
this.fileList.forEach(item => {
formData.append('userfiles', item.raw)
})
formData.append('isAsync', false)
formData.append('shopName', this.brandName)
formData.append('title', this.billName)
// 请求接口上传文件
$ajax.post('v2/financial/SendFilesToStores', formData, {
timeout: 1000 * 60 * 30
}).then(res => {
hideLoad()
res = res.data
if (res.code === '0') {
// 成功
let data = JSON.parse(res.data)
// if (data === 'Running') {
// let msg =
this.$message({
// message: `<div style="text-align:center">上传成功,服务器正在后台处理中<p style="margin: 10px 0;">查询进度taskID: ${data}<a href="javascript:;" id="copy" style="color:#409EFF;text-decoration: none;">复制</a></p></div>`,
// dangerouslyUseHTMLString: true,
// duration: 0,
// showClose: true
message: '推送成功',
type: 'success',
center: true
})
// document.querySelector('#copy').onclick = () => {
// copyText(data, () => {
// // 复制成功关闭message
// msg.close()
// this.$message({
// message: '复制成功',
// type: 'success',
// center: true
// })
// })
// }
// 改变文件上传状态
this.fileList.forEach(item => {
item.status = 'success'
})
// }
} else {
// 失败
// this.$message({
// message: '[上传失败] ' + res.desc,
// type: 'warning',
// center: true
// })
msgWarning('[上传失败] ' + res.desc)
}
}).catch(err => {
hideLoad()
// this.$message({
// message: '[上传失败] ' + err.data.desc,
// type: 'warning',
// center: true
// })
msgWarning('[上传失败] ' + err.data.desc)
})
})
} else {
// 没有上传的文件
this.$message({
message: '上传列表为空',
type: 'warning',
center: true
})
}
},
// 上传列表改变
fileChange(file, fileList) {
// raw.type application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
// fileList = fileList.filter(item => item.raw.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
this.fileList = fileList
return false
},
// 删除列表文件
fileRemove(file, fileList) {
this.fileList = fileList
},
// 清空上传列表
deleteList() {
if (this.$refs.upload.uploadFiles.length > 0) {
// 上传的文件大于0个
this.$confirm('是否清空当前上传列表', '提示').then(() => {
this.$refs.upload.clearFiles()
this.fileList = []
})
} else {
// 没有上传的文件
this.$message({
message: '上传列表为空',
type: 'warning',
center: true
})
}
}
}
}
</script>
<style lang="scss" scoped>
</style>

View File

@@ -0,0 +1,15 @@
<template>
<div class="baselayout">
畅销品查询
</div>
</template>
<script>
export default {
name: "bestSeller"
}
</script>
<style>
</style>

View File

@@ -0,0 +1,959 @@
<!-- <template>
<div class="cat-manager">
<el-container>
<el-aside width="360px">
<el-button type="primary" size="small" @click="addLevel1">新增一级分类</el-button>
<el-button
type="danger"
size="small"
@click="sortLevel1"
v-if="allowDrag"
>保存一级分类顺序</el-button
>
<el-button type="" size="small" @click="reset">还原</el-button>
分类
<div class="wrap" style="margin-top: 20px;">
<el-scrollbar wrap-class="list" :native="false">
:data="catData"
<el-tree
class="list"
:data="catData"
:props="defaultProps"
:allow-drop="allowDrop"
:highlight-current="true"
node-key="id"
accordion
:draggable="allowDrag"
@node-drag-start="dragStart"
@node-drag-enter="dragEnter"
@node-drag-leave="dragLeave"
@node-click="nodeClick"
@node-drag-over="dragOver"
@node-drag-end="dragEnd"
:default-expanded-keys="expandKey"
>
<div class="custom-tree-node" slot-scope="{ node, data }">
<span>{{ node.label }}</span>
<el-button-group
style="position: absolute; right: 5px; top: 9px;"
v-if="
(data.level === 1 && currentPick.parentID === data.id) ||
(data.level === 1 && currentPick.id === data.id)
"
>
<el-button type="" size="mini" @click.stop="addLevel2"
>+</el-button
>
<el-button size="mini" type="" @click.stop="saveLevel2(node)"
>保存二级分类顺序</el-button
>
</el-button-group>
</div>
</el-tree>
</el-scrollbar>
</div>
分类
</el-aside>
<el-main>
操作面板
新增一级分类
<div class="addLevel1Cat panel-frame" v-if="addLevel1Show">
<h3>新增一级分类</h3>
<el-form
:model="newCat"
:rules="rules"
ref="createLevel1"
label-width="130px"
label-position="right"
:inline="true"
size="small"
>
名称
<el-form-item label="分类名称:">
<el-input
v-model="newCat.exdName"
@change="checkValue('level1Name')"
ref="level1Name"
></el-input>
<span
style="color: #f56c6c;font-size: 12px;position: absolute;bottom: -25px;left:0;"
v-if="showCatNameError"
>请输入分类名称</span
>
</el-form-item>
名称
<br />
保存按钮
<el-button
type="primary"
size="medium"
style="margin-left: 130px;margin-top: 20px;"
@click="createLevel1('createLevel1')"
>保存</el-button
>
保存按钮
</el-form>
</div>
新增一级分类
新增二级分类
<div class="addLevel2Cat panel-frame" v-if="addLevel2Show">
<h3>新增二级分类</h3>
<el-form
:model="newCat"
:rules="rules"
ref="createLevel2"
label-width="130px"
label-position="right"
:inline="true"
size="small"
>
父级
<el-form-item label="父级名称:" style="color: #606266">
{{ parentPath }}
</el-form-item>
父级
<br />
名称
<el-form-item label="分类名称:">
<el-input
v-model="newCat.exdName"
ref="level2Name"
@change="checkValue('level2Name')"
></el-input>
<span
style="color: #f56c6c;font-size: 12px;position: absolute;bottom: -25px;left:0;"
v-if="showCatNameError"
>请输入分类名称</span
>
</el-form-item>
名称
<br />
饿百分类绑定
<el-form-item label="饿百分类绑定:">
<el-cascader
ref="createeBaiCategoryID"
placeholder="试试搜索:蔬菜"
filterable
clearable
:options="eBaiCatData"
:props="eBaiCatProp"
:value="newCat.ebaiCategoryID"
separator=">"
style="width: 300px;"
></el-cascader>
</el-form-item>
饿百分类绑定
<br />
按钮
<el-button
type="danger"
size="medium"
style="margin-left: 130px; margin-top: 20px;"
@click="returnLevel1"
>返回</el-button
>
<el-button
type="primary"
size="medium"
style="margin-top: 20px;"
@click="createLevel2('createLevel2')"
>保存</el-button
>
按钮
</el-form>
</div>
新增二级分类
点击编辑分类
<div class="clickCat panel-frame" v-if="clickCatShow">
<h3>编辑 {{ currentPick.level }} 级分类</h3>
<el-form
:model="currentPick"
:rules="rules"
ref="clickCat"
label-width="130px"
label-position="right"
:inline="true"
size="small"
>
路径
<div style="margin-bottom: 20px;">
<el-form-item label="分类路径:">
<el-breadcrumb
separator-class="el-icon-arrow-right"
style="padding: 9px 0;"
>
父级
<el-breadcrumb-item v-if="currentPick.parentID !== 0">{{
parentPath
}}</el-breadcrumb-item>
<el-breadcrumb-item>{{
currentPick.exdName
}}</el-breadcrumb-item>
</el-breadcrumb>
</el-form-item>
</div>
路径
名称
<el-form-item label="分类名称:">
<el-input
:value="currentPick.exdName"
ref="nameValue"
@change="checkValue('nameValue')"
></el-input>
<span
style="color: #f56c6c;font-size: 12px;position: absolute;bottom: -25px;left:0;"
v-if="showCatNameError"
>请输入分类名称</span
>
</el-form-item>
名称
<br />
<el-form-item
label="饿百分类绑定:"
v-if="
currentPick.level === 2 ||
!(
'children' in currentPick &&
currentPick.children.length !== 0
)
"
>
<el-cascader
ref="editoreBaiCategoryID"
placeholder="试试搜索:蔬菜"
filterable
clearable
:options="eBaiCatData"
:props="eBaiCatProp"
:value="switcheBaiCat"
separator=">"
style="width: 300px;"
></el-cascader>
</el-form-item>
<br />
保存按钮
<div style="margin-top: 20px;">
<el-tooltip
effect="light"
content="删除商品类别,只有无商品且无子类别的才能删除"
>
<el-button
type="danger"
size="medium"
style="margin-left: 130px;"
class="el-icon-delete"
@click="deleteCat"
>删除</el-button
>
</el-tooltip>
<el-button
type="primary"
size="medium"
class="el-icon-check"
style="margin-left: 20px;"
@click="updateCat('clickCat')"
>保存</el-button
>
</div>
保存按钮
</el-form>
</div>
点击编辑分类
操作面板
</el-main>
</el-container>
</div>
</template> -->
<!-- <script>
import { addCat, deleteCat, updateCat, sortCat } from "@/apis/cat.js";
import $ajax from "axios";
import { hideLoad } from "@/tools/loading.js";
import msgWarning from "@/tools/msgwarning.js";
export default {
name: "CMPCatManager",
props: [
"catLevel1",
"catLevel2",
"eBaiCatLevel1",
"eBaiCatLevel2",
"eBaiCatLevel3"
],
data() {
// 判断三方类别是否选择
let valid1 = (rule, value, callback) => {
// value = value.trim()
if (!value) {
return callback(new Error("分类不能为空"));
} else {
callback();
}
};
return {
catData: [], // 存储京西分类,已重新组装
// 规定树形结构读取字段
defaultProps: {
label: "exdName" // label读取数据中的name字段
// disabled: (data, node) => data.type === 0
},
currentPick: {}, // 当前激活的分类
// 添加一级分类可视状态
addLevel1Show: false,
// 添加二级分类可视状态
addLevel2Show: false,
// 编辑分类可视状态
clickCatShow: false,
// 创建新分类的存储对象
newCat: {
id: 1,
name: "",
exdName: "",
parentID: 0,
ebaiCategoryID: [],
level: 1,
seq: 0
},
// 验证
rules: {
name: [
{ required: true, message: "请输入分类名称", trigger: "change" }
],
jdCat: [{ validator: valid1, trigger: "change" }],
jdPricePercentage: [
{
required: true,
pattern: /^\d+$/,
message: "请输入正确百分数",
trigger: "change"
}
],
mtwmPricePercentage: [
{
required: true,
pattern: /^\d+$/,
message: "请输入正确百分数",
trigger: "change"
}
],
ebaiPricePercentage: [
{
required: true,
pattern: /^\d+$/,
message: "请输入正确百分数",
trigger: "change"
}
]
},
// 校验编辑时分类名称
showCatNameError: false,
expandKey: [], // 展开菜单
allowDrag: true, // 是否开启拖拽功能
// 饿百分类规定字段
eBaiCatProp: {
value: "vendorCategoryID",
label: "name"
},
eBaiCatData: [],
showeBaiCatError: false
};
},
created() {
this.catData = this.catLevel1;
// 组合一二级菜单
this.catData.forEach(level1 => {
let level2 = this.catLevel2.filter(item => item.parentID === level1.id);
level1.children = level2;
});
},
watch: {
eBaiCatLevel1(to) {
if (to) {
// 组合饿百分类
// 把三级挂载到二级上
let eBaiCatData = this.eBaiCatLevel1;
let temeBaiCat = this.eBaiCatLevel2;
temeBaiCat.forEach(le2 => {
let level3 = this.eBaiCatLevel3.filter(
le3 => Number(le3.parentID) === Number(le2.vendorCategoryID)
);
le2.children = level3;
});
// 把二级挂载到一级上
eBaiCatData.forEach(le1 => {
let level2 = temeBaiCat.filter(
le2 => Number(le2.parentID) === Number(le1.vendorCategoryID)
);
le1.children = level2;
});
this.eBaiCatData = eBaiCatData;
}
},
catLevel1(to) {
if (to) {
this.catData = this.catLevel1;
// 组合一二级菜单
this.catData.forEach(level1 => {
let level2 = this.catLevel2.filter(
item => item.parentID === level1.id
);
level1.children = level2;
});
}
},
catLevel2(to) {
if (to) {
this.catData = this.catLevel1;
// 组合一二级菜单
this.catData.forEach(level1 => {
let level2 = this.catLevel2.filter(
item => item.parentID === level1.id
);
level1.children = level2;
});
}
}
},
computed: {
parentPath() {
let level1 = "";
if (this.currentPick.parentID !== 0) {
level1 = this.catData.filter(
item => Number(item.id) === Number(this.currentPick.parentID)
)[0];
} else {
level1 = this.currentPick;
}
return level1.exdName;
},
// eBai分类转换
switcheBaiCat() {
if (this.currentPick.ebaiCategoryID) {
let leaf = this.currentPick.ebaiCategoryID + "";
let parent = this.eBaiCatLevel3.filter(
item => Number(item.vendorCategoryID) === Number(leaf)
)[0]
? this.eBaiCatLevel3.filter(
item => Number(item.vendorCategoryID) === Number(leaf)
)[0].parentID
: "";
let parentparent = this.eBaiCatLevel2.filter(
item => Number(item.vendorCategoryID) === Number(parent)
)[0]
? this.eBaiCatLevel2.filter(
item => Number(item.vendorCategoryID) === Number(parent)
)[0].parentID
: "";
return [parentparent, parent, leaf];
} else {
return [];
}
}
},
methods: {
// 设置是否可以拖动放置
allowDrop(draggingNode, dropNode, type) {
// 如果是正在拖动的是二级菜单,且放置对象是一级菜单,则不允许
if (draggingNode.data.level === 2 && dropNode.data.level === 1) {
return false;
}
if (draggingNode.data.level === 1 && dropNode.data.level === 2) {
return false;
}
if (type === "inner" || type === "") {
return false;
}
return true;
},
// 拖拽开始
dragStart(node, ev) {
if (node.data.level === 1) {
// // 添加一级分类可视状态
this.addLevel1Show = false;
// // 添加二级分类可视状态
this.addLevel2Show = false;
// // 编辑分类可视状态
this.clickCatShow = false;
this.currentPick = {};
}
},
// 拖拽进入
dragEnter(node, inNode, ev) {
// this.currentNode = inNode.key
inNode.checked = true;
},
// 拖拽离开
dragLeave(node, outNode, ev) {
outNode.checked = false;
},
// 拖拽end
dragEnd(curNode, tarNode, pos, ev) {
tarNode.checked = false;
},
// 拖拽经过
dragOver(curNode, overNode, ev) {
ev.dataTransfer.dropEffect = "move";
ev.stopPropagation();
ev.preventDefault();
},
// 条目被点击
nodeClick(data, node, cmp) {
this.clickCatShow = false;
this.$nextTick(() => {
// this.currentPick = {}
this.currentPick = JSON.parse(JSON.stringify(data));
this.addLevel1Show = false;
this.addLevel2Show = false;
this.clickCatShow = true;
// 关闭编辑分类的错误提示
// this.showCatNameError = false
// this.showjdCatError = false
this.showeBaiCatError = false;
// 如果是一级菜单的展开与收缩,要关闭保存二级分类按钮和编辑窗口
if (node.level === 1) {
if (node.expanded || node.childNodes.length === 0) {
// 展开
this.currentPick = JSON.parse(JSON.stringify(data));
this.addLevel1Show = false;
this.addLevel2Show = false;
this.clickCatShow = true;
} else {
// 关闭
this.currentPick = {};
this.addLevel1Show = false;
this.addLevel2Show = false;
this.clickCatShow = false;
}
}
});
},
// 新增一级分类按钮
addLevel1() {
this.newCat.name = "";
this.addLevel1Show = true; // 打开新增一级分类窗口
this.addLevel2Show = false; // 关闭新增二级分类窗口
this.clickCatShow = false; // 关闭编辑窗口
},
// 新增二级分类按钮
addLevel2() {
this.newCat.name = "";
this.addLevel1Show = false; // 打开新增一级分类窗口
this.addLevel2Show = true; // 关闭新增二级分类窗口
this.clickCatShow = false; // 关闭编辑窗口
},
// 保存一级分类
createLevel1(formName) {
if (!this.$refs.level1Name.currentValue) {
this.showCatNameError = true;
return false;
}
this.$refs[formName].validate(valid => {
if (valid) {
// 通过校验
// 一级分类seq
// 需要发送的一级分类数据
let data = {
level: 1,
name: this.newCat.exdName,
exdName: this.newCat.exdName,
// type: this.newCat.type,
parentID: 0,
seq: this.$props.catLevel1.length + 1,
exdSeq: this.$props.catLevel1.length + 1,
isExdSpec: 1
// img: this.newCat.img,
// status: this.newCat.status
};
addCat(data, res => {
if (res.code === "0") {
// 成功
this.$message({
message: "一级目录添加成功",
type: "success",
center: true
});
this.newCat.name = "";
// this.newCat.img = ''
// this.newCat.status = 1
// 将分类添加到数据中
this.catData.push(JSON.parse(res.data));
this.addLevel1Show = false;
} else {
// 失败
msgWarning(res.desc);
}
});
}
});
},
// 返回一级
returnLevel1() {
this.addLevel1Show = false; // 打开新增一级分类窗口
this.addLevel2Show = false; // 关闭新增二级分类窗口
this.clickCatShow = true; // 打开编辑窗口
},
// 保存二级分类
createLevel2(formName) {
if (!this.$refs.level2Name.currentValue) {
this.showCatNameError = true;
return false;
}
this.$refs[formName].validate(valid => {
if (valid) {
// 通过校验
// 找到父级
let parentNode = "";
if (this.currentPick.parentID !== 0) {
// 不是父级
let level1 = this.catData.filter(
item => Number(item.id) === Number(this.currentPick.parentID)
);
parentNode = level1[0];
} else {
parentNode = this.currentPick;
}
// seq
let seq = parentNode.children ? parentNode.children.length : 0;
// 需要发送的二级分类数据
let data = {
level: 2,
name: this.newCat.exdName,
exdName: this.newCat.exdName,
// type: parentNode.type,
parentID: parentNode.id,
seq: seq,
exdSeq: seq,
isExdSpec: 1,
ebaiCategoryID: Number(
this.$refs.createeBaiCategoryID.currentValue[2]
)
};
// return false
addCat(data, res => {
if (res.code === "0") {
// 成功
this.$message({
message: "二级目录添加成功",
type: "success",
center: true
});
this.newCat.name = "";
this.renewCat();
this.$nextTick(() => {
this.expandKey = [data.parentID];
});
this.addLevel2Show = false;
} else {
// 失败
msgWarning(res.desc);
}
});
}
});
},
// 删除分类
deleteCat() {
this.$confirm(`是否删除 [${this.currentPick.name}] 分类`, "警告").then(
() => {
// 确认
deleteCat(this.currentPick.id, res => {
if (res.code === "0" && res.data !== "0") {
// 删除成功
this.$message({
message: "删除成功",
type: "success",
center: true
});
// 找到current
// let n = this.catData.indexOf(this.currentPick)
this.catData = this.catData.filter(
item => item !== this.currentPick
); // 删除current
this.renewCat();
this.$nextTick(() => {
this.expandKey = [this.currentPick.parentID];
});
this.clickCatShow = false;
} else {
msgWarning("[删除分类失败] " + res.desc);
}
});
}
);
},
// 校验编辑分类时分类名称
checkValue(ref) {
if (!this.$refs[ref].currentValue.trim()) {
this.showCatNameError = true;
} else {
this.showCatNameError = false;
}
},
// 更新分类
updateCat() {
// 如果分类名称未填写
if (!this.$refs.nameValue.currentValue.trim()) {
this.showCatNameError = true;
return false;
}
// 保存饿百分类数组
let eBaiCatID = "";
if (
this.$refs.editoreBaiCategoryID &&
this.$refs.editoreBaiCategoryID.currentValue.length
) {
eBaiCatID = this.$refs.editoreBaiCategoryID.currentValue;
eBaiCatID = eBaiCatID[eBaiCatID.length - 1];
}
let data = {
id: this.currentPick.id,
exdName: this.$refs.nameValue.currentValue,
// isExdSpec: 1,
ebaiCategoryID: Number(eBaiCatID)
};
updateCat(data.id, data, res => {
if (res.code === "0") {
// 成功
this.$message({
message: "更新成功",
type: "success",
center: true
});
this.renewCat();
this.clickCatShow = false;
this.$nextTick(() => {
this.expandKey = [this.currentPick.parentID];
if (this.currentPick.level === 1) {
this.currentPick = {};
}
});
} else {
msgWarning("[更新分类失败] " + res.desc);
}
});
},
// 开启拖拽模式
handleAllowDrag() {
this.allowDrag = true;
},
// 还原分类
reset() {
this.currentPick = {};
this.addLevel1Show = false;
this.addLevel2Show = false;
this.clickCatShow = false;
this.renewCat();
this.expandKey = [];
},
// 保存一级分类顺序
sortLevel1() {
this.expandKey = [];
let parentID = 0;
let arr = [];
this.catData.forEach(item => {
arr.push(item.id);
});
sortCat(
parentID,
arr,
res => {
if (res.code === "0") {
// 成功
this.$message({
message: "调整一级菜单位置成功",
type: "success",
center: true
});
this.renewCat();
} else {
// 失败
this.$message({
message: "[调整一级菜单位置失败] " + res.desc,
type: "success",
center: true
});
this.renewCat();
}
},
true
);
},
// 保存二级菜单拖拽
saveLevel2(node) {
let parentID = node.data.id;
let arr = this.catData.filter(item => item.id === parentID)[0].children;
let arr2 = [];
arr.forEach(item => {
arr2.push(item.id);
});
sortCat(
parentID,
arr2,
res => {
if (res.code === "0") {
// 成功
this.$message({
message: "调整二级菜单位置成功",
type: "success",
center: true
});
this.renewCat();
this.$nextTick(() => {
this.expandKey = [parentID];
});
} else {
// 失败
this.$message({
message: "[调整二级菜单位置失败] " + res.desc,
type: "success",
center: true
});
this.renewCat();
this.$nextTick(() => {
this.expandKey = [parentID];
});
}
},
true
);
},
// 拖拽完成
handleDragEnd(node, parentNode) {
if (node.data.level === 1) {
// console.log("拖拽一级菜单");
} else {
let parentID = node.data.parentID;
let arr = this.catData.filter(item => item.id === parentID)[0].children;
let arr2 = [];
arr.forEach(item => {
arr2.push(item.id);
});
sortCat(parentID, arr2, res => {
if (res.code === "0") {
// 成功
this.$message({
message: "调整二级菜单位置成功",
type: "success",
center: true
});
this.renewCat();
this.$nextTick(() => {
this.expandKey = [parentID];
});
} else {
// 失败
this.$message({
message: "[调整二级菜单位置失败] " + res.desc,
type: "success",
center: true
});
this.renewCat();
this.$nextTick(() => {
this.expandKey = [parentID];
});
}
});
}
},
// 重新获取分类
async renewCat() {
try {
// 获取分类数据
let categories = (await $ajax.get("v2/sku/GetCategories?isExd=true"))
.data;
// 判断分类是否获取成功
if (categories.code !== "0") {
msgWarning("[获取分类列表失败] " + categories.desc);
} else {
categories = JSON.parse(categories.data);
let catLevel1 = categories.filter(item => item.level === 1);
let catLevel2 = categories.filter(item => item.level === 2);
this.catData = catLevel1;
this.catData.forEach(level1 => {
let level2 = catLevel2.filter(item => item.parentID === level1.id);
level1.children = level2;
});
}
} catch (err) {
this.$message({
message: err,
type: "error",
center: true
});
}
hideLoad(); // 关闭加载
}
}
};
</script> -->
<!-- <style lang="scss">
.cat-manager {
// width: 1000px;
// margin: 0 auto;
.pic {
display: flex;
align-items: center;
.des {
color: #666;
font-size: 12px;
margin-left: 10px;
}
}
.wrap {
height: calc(100vh - 280px);
overflow: hidden;
}
.list {
// max-height: 100vh;
max-height: calc(100vh - 280px);
margin-right: 10px;
user-select: none;
}
.custom-tree-node {
font-size: 14px;
padding: 20px 0;
}
.el-tree-node__children {
padding: 20px 0;
}
.el-tree-node__content {
padding: 10px 0;
}
.notUse {
opacity: 0.5;
}
.panel-frame {
padding-left: 50px;
h3 {
margin: 0;
border-bottom: 1px solid #efefef;
width: 600px;
height: 50px;
line-height: 50px;
margin-bottom: 20px;
}
}
.upload-cat-img {
.el-upload-list {
li {
width: 100px !important;
height: 100px !important;
}
}
.el-upload {
width: 100px !important;
height: 100px !important;
line-height: 110px !important;
}
}
}
</style> -->

View File

@@ -0,0 +1,122 @@
@import '@/assets/scss/_color.scss';
.cmp-goods-sort {
.content {
display: flex;
height: calc(100vh - 220px);
}
.scroll-list {
height: calc(100vh - 210px);
}
.left {
flex: none;
width: 200px;
margin-right: 10px;
.el-tree-node__content {
padding: 10px 0;
border-radius: 5px;
}
}
.right {
flex: 1;
// background: red;
height: 100px;
}
.top {
display: flex;
justify-content: flex-end;
align-items: center;
color: $text1;
& > * {
margin-left: 10px;
}
}
.ghost {
opacity: 0.5;
background: #c8ebfb;
}
.canDrag {
cursor: move;
}
.skuName-pick {
padding: 10px;
margin: 5px 0;
display: flex;
align-items: center;
border-radius: 10px;
color: $text1;
box-sizing: border-box;
&:hover {
background: rgba($border4, 1);
}
img {
flex: none;
width: 60px;
height: 60px;
background: url(https://image.jxc4.com/backstage_loading.gif) center center no-repeat;
background-size: 100%;
border: 1px solid $border2;
box-sizing: border-box;
border-radius: 5px;
}
.skuName-sku-id {
flex: none;
font-size: 12px;
width: 200px;
}
.skuName-name {
flex: auto;
padding: 0 20px;
// width: 400px;
// background: red;
align-self: stretch;
display: flex;
align-items: center;
}
.skuName-price {
flex: none;
width: 120px;
align-self: stretch;
display: flex;
align-items: center;
}
.seq-input {
flex: none;
// background: red;
width: 200px;
display: flex;
// align-items: center;
.seq-name {
flex: none;
display: flex;
justify-content: center;
align-items: center;
font-size: 12px;
color: $text3;
margin-right: 4px;
}
.input-input {
width: 50px;
color: $text1;
outline: none;
padding: 5px 20px;
font-size: 12px;
border-top-left-radius: 3px;
border-bottom-left-radius: 3px;
border: 1px solid $border1;
}
.input-btn {
flex: none;
background: $primary;
color: white;
display: flex;
justify-content: center;
align-items: center;
width: 3em;
cursor: pointer;
border-top-right-radius: 3px;
border-bottom-right-radius: 3px;
}
}
}
}

View File

@@ -0,0 +1,314 @@
<template>
<div class="cmp-goods-sort">
<div class="top">
<div>商品数量:{{totalCount}}</div>
<el-button-group>
<el-button size="mini" type="success" icon="el-icon-arrow-down" @click="toBottom">到底部</el-button>
<el-button size="mini" type="success" icon="el-icon-arrow-up" @click="toTop">到顶部</el-button>
</el-button-group>
<el-button size="mini" type="danger" @click="reLoad">还原</el-button>
<el-button size="mini" type="danger" @click="sortByPrice" :disabled="!skuNames.length">按价格排序{{sortType ? '↓' : '↑'}}</el-button>
<el-button size="mini" type="danger" @click="exportExcel" :disabled="!skuNames.length">导出该分类下商品顺序excel</el-button>
<el-button size="mini" type="primary" @click="saveSeq">保存该分类下的商品顺序</el-button>
</div>
<div class="content">
<div class="left" v-if="catData.length > 0">
<el-scrollbar wrap-class="scroll-list" :native="false">
<el-tree
:data="catData"
:highlight-current="true"
node-key="id"
@node-click="catClick"
accordion
:props="catProps">
</el-tree>
</el-scrollbar>
</div>
<div class="right">
<el-scrollbar wrap-class="scroll-list" :native="false">
<draggable
v-model="skuNames"
ghostClass="ghost"
class="draggable-scroll"
animation="100"
handle=".canDrag"
@change="dragChange"
@start="dragging = true"
@end="dragging = false"
:forceFallback="true"
>
<div class="skuName-pick" v-for="skuName in skuNames" :key="skuName.skus[0].id">
<!-- 图片 -->
<img :src="skuName.img + '?imageView2/1/w/60/h/60'" alt="" class="skuName-img canDrag">
<!-- 名称 -->
<div class="skuName-name canDrag">{{computedName(skuName, skuName.skus[0])}}</div>
<!-- 价格 -->
<div class="skuName-price canDrag">{{(skuName.skuPrice / 100).toFixed(2)}}</div>
<!-- id -->
<div class="skuName-sku-id canDrag">
<div>skuNameID: {{skuName.id}}</div>
<div>skuID: {{skuName.skus[0].id}}</div>
</div>
<!-- 顺序 -->
<div class="seq-input">
<div class="seq-name">顺序</div>
<input class="input-input" :value="skuName.skus[0].seq" @input="handleInput($event, skuName.skus[0].seq)" @blur="inputBlur($event, skuName.skus[0].seq)">
<div class="input-btn" @click="confirmInput(skuName, $event)"></div>
</div>
</div>
</draggable>
</el-scrollbar>
</div>
</div>
</div>
</template>
<script>
/* eslint-disable */
import api from '@/utils/api'
import msgWarning from '@/tools/msgwarning'
import {hideLoad} from '@/tools/loading'
import draggable from 'vuedraggable'
import {computedName} from '@/utils/index'
import {computedPrice} from '@/tools/index'
import {arr2excel} from '@/tools/excel2'
/* eslint-disable */
export default {
name: 'CmpGoodsSort',
props: ['catLevel1', 'catLevel2'],
components: {
draggable
},
data () {
return {
catProps: {
label: 'name'
},
categoryID: 0,
skuNames: [],
dragging: false,
dragDisabled: false,
totalCount: 0,
sortType: false
}
},
created () {
},
computed: {
catData () {
let catL1 = [...this.catLevel1]
let catL2 = [...this.catLevel2]
let catData = []
catL1.forEach(L1 => {
let level2 = catL2.filter(item => item.parentID === L1.id)
L1.children = level2
catData.push(L1)
})
return catData
}
},
methods: {
// 重置数据
resetData () {
this.categoryID = 0
this.skuNames = []
this.dragging = false
this.dragDisabled = false
this.totalCount = 0
this.sortType = false
},
async catClick (data, node) {
if (node.isLeaf) {
this.categoryID = data.id
this.skuNames = await this.getSkuNames()
}
},
// 还原
async reLoad () {
if (this.totalCount > 0) this.skuNames = await this.getSkuNames()
},
// 按价格从低到高排序
sortByPrice () {
this.sortType = !this.sortType
if (this.totalCount > 0) {
this.skuNames = this.mapSku(this.skuNames.sort((n1, n2) => {
if (this.sortType) {
return n1.skuPrice - n2.skuPrice
} else {
return n2.skuPrice - n1.skuPrice
}
}))
}n
},
async getSkuNames () {
this.toTop()
this.sortType = false
try {
if (this.skuNames.length > 0) {
this.skuNames = this.skuNames.map(item => ({
...item,
img: ''
}))
}
let {totalCount, skuNames} = await api(`v2/sku/GetSkuNames`, {
params: {
categoryID: this.categoryID,
isBySku: true,
pageSize: -1
}
})
this.totalCount = totalCount
return this.mapSku(skuNames || [])
} catch (e) {
console.error(e)
msgWarning(e)
} finally {
hideLoad()
}
},
// 过滤sku
mapSku (skuNames) {
return skuNames.map((skuName, index) => {
skuName.skus[0].seq = index + 1;
skuName.skuPrice = computedPrice(skuName.price / 100, skuName.skus[0], skuName)
return {...skuName}
})
},
// 拖拽
dragChange ({moved}) {
this.skuNames = this.mapSku(this.skuNames)
},
computedName (skuName, sku) {
return computedName(skuName, sku)
},
computedPrice (price, sku, skuName) {
if (skuName.unit === '份') {
return computedPrice(price, sku)
} else {
return price
}
},
// input 聚焦
inputFocus () {},
// input 失焦
inputBlur (e, oringinSeq) {
let value = e.target.value
if (!value) {
e.target.value = oringinSeq
}
},
// 保存顺序
saveSeq () {
if (this.totalCount === 0) return false
this.$confirm('是否修改该分类下的商品顺序?修改成功后,需要到【同步管理】-【京西门店商品同步到平台】中进行商品同步后,平台数据才会生效', '确认').then(async () => {
const skuIDs = this.skuNames.map(skuName => skuName.skus[0].id)
try {
let form = new FormData()
form.append('catID', this.categoryID)
form.append('skuIDs', JSON.stringify(skuIDs))
await api('v2/sku/SortCategorySkus', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
data: form
})
this.$message({
message: '调整成功',
type: 'success',
center: true
})
} catch (e) {
msgWarning(e)
} finally {
hideLoad()
}
})
},
// 确认顺序
confirmInput (skuName, e) {
let seq = e.target.previousElementSibling.value
if (!seq) {
this.$message({
message: '输入空',
type: 'warning',
center: true
})
e.target.previousElementSibling.value = skuName.skus[0].seq
return false
}
this.skuNames.splice(skuName.skus[0].seq - 1, 1)
this.skuNames.splice(seq - 1, 0, skuName)
this.skuNames = this.mapSku(this.skuNames)
},
// 输入
handleInput (e, oringinSeq) {
let seq = e.target.value
if(/^\d+$/.test(seq)) {
if (seq >= 1 && seq <= this.totalCount) {
} else {
this.$message({
message: `请输入1-${this.totalCount}`,
type: 'warning',
center: true
})
e.target.value = oringinSeq
}
} else {
if (seq) {
this.$message({
message: '请输入数字',
type: 'warning',
center: true
})
e.target.value = oringinSeq
} else {}
}
},
// 到底部
toBottom () {
let body = document.querySelector('.cmp-goods-sort .right .scroll-list')
let content = document.querySelector('.cmp-goods-sort .right .draggable-scroll')
body.scrollTop = content.offsetHeight
},
// 到顶部
toTop () {
document.querySelector('.cmp-goods-sort .right .scroll-list').scrollTop = 0
},
// 导出表格
exportExcel () {
let catData = [...this.catLevel1, ...this.catLevel2]
let cat = catData.find(item => item.id === this.skuNames[0].categoryID)
let catName = ''
if (cat) {
catName = cat.name
}
let excelData = []
let fileName = `${catName}商品顺序.xlsx`
// 标题
excelData.push([
'skuNameID',
'skuID',
'商品名称',
'分类',
'顺序'
])
this.skuNames.forEach((skuName, index) => {
excelData.push([
skuName.id,
skuName.skus[0].id,
this.computedName(skuName, skuName.skus[0]),
catName,
index + 1
])
})
arr2excel(excelData, fileName)
}
}
}
</script>
<style lang="scss">
@import './cmp-goods-sort.scss';
</style>

View File

@@ -0,0 +1,160 @@
<template>
<el-dialog
class="dia-batCreateGoods"
title="通过excel批量创建标品"
width="400px"
@closed="diaClose"
:visible.sync="diaShow">
<div class="bat-create-content">
<el-button @click="downLoad" type="primary" size="mini">下载样表</el-button>
<ul class="desc">
<li>商品编号 必填</li>
<li>商品名称单位重量售价 选填</li>
<li>单位重量售价 尽量填写</li>
<li>如果未查询到图片会自动填充一张暂无图片的占位图片</li>
<li>创建失败的报错会通过钉钉发送excel表格</li>
<li>分类与图片不正确的商品会发送钉钉消息进行提醒</li>
</ul>
<div style="display: flex; align-items: center;margin-top: 10px">
<div>上传到分类: </div>
<el-cascader
size="mini"
:options="catOptions"
:props="catProps"
@change="catChange"
v-model="categroyID">
</el-cascader>
</div>
<el-upload
class="upload-bat"
ref="upload"
drag
action=""
accept=".xls,.xlsx"
:multiple="false"
:auto-upload="false"
:on-change="fileChange19"
:show-file-list="false"
>
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处<em>点击上传</em>
<div style="color: #303133">
<!-- <i style="color: #F56C6C;" class="el-icon-warning"></i> 文件命名方式: <b>京西门店ID_城市_店名例如100014_苏州_国泰.xlsx</b> -->
</div>
</div>
</el-upload>
</div>
</el-dialog>
</template>
<script>
/* eslint-disable */
import msgWarning from '@/tools/msgwarning'
import {showLoad, hideLoad} from '@/tools/loading'
import {downloadFile} from '@/tools'
import $ajax from 'axios'
/* eslint-disable */
export default {
name: 'CatGoodsToCat',
props: {
catLevel1: {
type: Array,
deafult () {
return []
}
},
catLevel2: {
type: Array,
deafult () {
return []
}
}
},
data () {
return {
diaShow: false,
catProps: {
value: 'id',
label: 'name',
disabled: 'type' // 禁用type = 1
},
categroyID: [291]
}
},
computed: {
catOptions () {
let catData = []
catData = this.catLevel1.map(item => {
delete item.children
return {
...item
}
})
// 组合一二级菜单
catData.forEach(level1 => {
let level2 = this.catLevel2.filter(item => item.parentID === level1.id)
if (level2.length > 0) level1.children = level2
})
return catData
}
},
methods: {
diaClose () {
this.diaShow = false
},
downLoad() {
// 它的这个下载地址中不到对应的excel文件进行修改故而增加一个文件故另新增一个excel作为下载样表
// const url = 'http://www.jxc4.com/download/%E9%80%9A%E8%BF%87UPC%E5%88%9B%E5%BB%BA%E5%95%86%E5%93%81%E6%A0%B7%E8%A1%A8.xlsx'
const url = 'http://www.jxc4.com/download/通过UPC创建商品样表3.xlsx'
downloadFile(url)
},
catChange (id) {
console.log(id)
},
async fileChange19 (file, fileList) {
try {
showLoad()
let form = new FormData()
form.append('userfiles', file.raw)
form.append('categroyID', +this.categroyID[this.categroyID.length - 1])
let {data: res} = await $ajax.post('v2/sku/CreateUpcSkuByExcel', form)
let {code, data, desc} = res
if (code === '0') {
this.$message({
message: '提交成功,错误信息请留意钉钉消息',
type: 'success',
center: true
})
} else {
msgWarning(desc)
}
} catch (e) {
console.error(e)
msgWarning(e)
} finally {
hideLoad()
this.diaClose()
}
}
}
}
</script>
<style lang="scss">
.bat-create-content {
text-align: right;
.upload-bat {
margin-top: 20px;
}
.desc {
text-align: left;
padding: 0;
margin: 0;
margin-left: 20px;
/* list-style: none; */
li {
margin-bottom: 5px;
}
}
}
</style>

View File

@@ -0,0 +1,265 @@
<template>
<el-dialog
class="dia-catGoodsToCat"
title="按分类批量调整商品"
width="400px"
@closed="diaClose"
:visible.sync="diaShow">
<div style="margin-bottom: 20px;">
<span class="label">选择类型:</span>
<el-radio-group v-model="type" size="mini" @change="typeChange">
<el-radio :label="1" border>普通分类</el-radio>
<el-radio :label="2" border>饿鲜达分类</el-radio>
</el-radio-group>
</div>
<div>
<span class="label">源分类:</span>
<el-cascader
v-show="type === 1"
size="mini"
:options="catOptions"
:props="catProps"
@change="catChange"
v-model="srcCat">
</el-cascader>
<el-cascader
v-show="type === 2"
size="mini"
:options="catOptions2"
:props="catProps2"
@change="catChange"
v-model="srcCat">
</el-cascader>
</div>
<div style="margin: 20px 0;">调整所有商品至</div>
<div>
<span class="label">目标分类:</span>
<el-cascader
v-show="type === 1"
size="mini"
:options="catOptions"
:props="catProps"
@change="catChange"
v-model="desCat">
</el-cascader>
<el-cascader
v-show="type === 2"
size="mini"
:options="catOptions2"
:props="catProps2"
@change="catChange"
v-model="desCat">
</el-cascader>
</div>
<div class="footer">
<el-button size="small" type="danger" @click="diaClose">取消</el-button>
<el-button size="small" type="primary" @click="confirm">确定</el-button>
</div>
</el-dialog>
</template>
<script>
/* eslint-disable */
import api from '@/utils/api'
import msgWarning from '@/tools/msgwarning'
import {showLoad, hideLoad} from '@/tools/loading'
/* eslint-disable */
export default {
name: 'CatGoodsToCat',
props: ['catLevel1', 'catLevel2', 'exdCatL1', 'exdCatL2'],
data () {
return {
diaShow: false,
catProps: {
value: 'id',
label: 'name',
disabled: 'type' // 禁用type = 1
},
catProps2: {
value: 'id',
label: 'exdName',
disabled: 'type' // 禁用type = 1
},
srcCat: [175],
desCat: [175],
statusMap: ['未提交', '成功', '失败'],
type: 1
}
},
computed: {
// 组合种类
catOptions () {
let catData = []
catData = this.catLevel1.map(item => {
delete item.children
return {
...item
}
})
// 组合一二级菜单
catData.forEach(level1 => {
let level2 = this.catLevel2.filter(item => item.parentID === level1.id)
if (level2.length > 0) level1.children = level2
})
return catData
},
catOptions2 () {
let catData = []
catData = this.exdCatL1.map(item => {
delete item.children
return {
...item
}
})
// 组合一二级菜单
catData.forEach(level1 => {
let level2 = this.exdCatL2.filter(item => item.parentID === level1.id)
if (level2.length > 0) level1.children = level2
})
return catData
}
},
methods: {
// 分类类型改变
typeChange (val) {
},
diaClose () {
this.diaShow = false
},
catChange (id) {
},
async confirm () {
const srcCat = this.srcCat[this.srcCat.length - 1]
const desCat = this.desCat[this.desCat.length - 1]
if (srcCat === desCat) {
this.$message({
message: '无法将相同分类的商品进行调整',
type: 'warning',
center: true
})
return false
}
try {
let {totalCount, skuNames} = await this.getSkuNames(srcCat)
if (totalCount === 0) {
this.$message({
message: '源分类下无商品',
type: 'warning',
center: true
})
return false
}
showLoad()
// let nameIDs = skuNames.map(item => item.id)
let requestArr = []
for (let i = 0; i < skuNames.length; i++) {
requestArr.push(this.updateSkuName(skuNames[i].id, desCat, skuNames[i].name))
}
let responseArr = await Promise.all(requestArr)
this.dealResult(responseArr)
} catch (e) {
console.error(e)
msgWarning(e)
} finally {
hideLoad()
}
},
// 获取商品
async getSkuNames (catID) {
try {
let {totalCount, skuNames} = await api(`v2/sku/GetSkuNames`, {
params: {
categoryID: catID,
pageSize: -1
},
noLoading: true
})
return {totalCount, skuNames}
} catch (e) {
console.error(e)
throw e
}
},
// 更新商品
async updateSkuName (nameID, decCatID, name) {
try {
let res = await api('v2/sku/UpdateSkuName', {
noLoading: true,
method: 'PUT',
data: `nameID=${nameID}&payload=${JSON.stringify({categoryID: decCatID})}`,
noSyncAlert: true
})
if (res.code && res.code === '-105') {
throw new Error(res.desc)
} else {
return {
nameID,
name,
status: 1
}
}
} catch (e) {
let msg = e
if (Object.prototype.toString.call(msg).indexOf('Error') > -1) {
msg = msg.message
}
return {
nameID,
name,
status: 2,
desc: msg
}
}
},
dealResult (responseArr) {
let title = '处理结果'
let thead = ''
let tbody = ''
thead = `
<tr>
<th>商品</th>
<th>状态</th>
<th>备注</th>
</tr>
`
// let tbodyContent = ''
responseArr.forEach(item => {
tbody += `
<tr>
<td>${item.nameID} ${item.name}</td>
<td>${this.statusMap[item.status]}</td>
<td>${item.desc || ''}</td>
</tr>
`
})
let sumary = `总共:${responseArr.length},未提交:${responseArr.filter(item => item.status === 0).length},成功:${responseArr.filter(item => item.status === 1).length},失败:${responseArr.filter(item => item.status === 2).length}`
let html = `
${sumary}
<table class="errmsg-table">
<caption>${title}</caption>
<thead>
${thead}
</thead>
<tbody>
${tbody}
</tbody>
</table>`
msgWarning(html, '结果')
}
}
}
</script>
<style lang="scss">
.dia-catGoodsToCat {
.label {
display: inline-block;
width: 100px;
}
.footer {
margin-top: 20px;
display: flex;
justify-content: flex-end;
}
}
</style>

View File

@@ -0,0 +1,260 @@
<template>
<el-dialog
class="dia-catGoodsToCat"
title="调整选中商品的分类"
width="400px"
@closed="diaClose"
:visible.sync="diaShow">
<!-- <div style="margin: 20px 0;">调整选择商品至</div> -->
<div style="margin-bottom: 20px;">
<span class="label">选择类型:</span>
<el-radio-group v-model="type" size="mini">
<el-radio :label="1" border>普通分类</el-radio>
<el-radio :label="2" border>饿鲜达分类</el-radio>
</el-radio-group>
</div>
<div>
<span class="label" style="display: inline-block;width: 130px;">调整选择商品至:</span>
<el-cascader
v-show="type === 1"
size="mini"
:options="catOptions"
filterable
:props="catProps"
@change="catChange"
v-model="desCat">
</el-cascader>
<el-cascader
v-show="type === 2"
size="mini"
filterable
:options="catOptions2"
:props="catProps2"
@change="catChange"
v-model="desCat">
</el-cascader>
</div>
<div class="footer">
<el-button size="small" type="danger" @click="diaClose">取消</el-button>
<el-button size="small" type="primary" @click="confirm">确定</el-button>
</div>
</el-dialog>
</template>
<script>
/* eslint-disable */
import api from '@/utils/api'
import msgWarning from '@/tools/msgwarning'
import {showLoad, hideLoad} from '@/tools/loading'
/* eslint-disable */
export default {
name: 'CatGoodsToCat',
props: {
skuNames: {
type: Array,
default () {
return []
}
},
catLevel1: {
type: Array
},
catLevel2: {
type: Array
},
exdCatL1: {
type: Array
},
exdCatL2: {
type: Array
}
},
data () {
return {
diaShow: false,
catProps: {
value: 'id',
label: 'name',
disabled: 'type' // 禁用type = 1
},
catProps2: {
value: 'id',
label: 'exdName',
disabled: 'type' // 禁用type = 1
},
// srcCat: [175],
desCat: [175],
statusMap: ['未提交', '成功', '失败'],
type: 1
}
},
computed: {
// 组合种类
catOptions () {
let catData = []
if (this.type === 1) {
catData = this.catLevel1.map(item => {
delete item.children
return {
...item
}
})
// 组合一二级菜单
catData.forEach(level1 => {
let level2 = this.catLevel2.filter(item => item.parentID === level1.id)
if (level2.length > 0) level1.children = level2
})
} else if (this.type === 2) {
catData = this.exdCatL1.map(item => {
delete item.children
return {
...item
}
})
// 组合一二级菜单
catData.forEach(level1 => {
let level2 = this.exdCatL2.filter(item => item.parentID === level1.id)
if (level2.length > 0) level1.children = level2
})
}
return catData
},
catOptions2 () {
let catData = []
catData = this.exdCatL1.map(item => {
delete item.children
return {
...item
}
})
// 组合一二级菜单
catData.forEach(level1 => {
let level2 = this.exdCatL2.filter(item => item.parentID === level1.id)
if (level2.length > 0) level1.children = level2
})
return catData
}
},
methods: {
diaClose () {
this.diaShow = false
},
catChange (id) {
console.log(id)
},
async confirm () {
// const srcCat = this.srcCat[this.srcCat.length - 1]
const desCat = this.desCat[this.desCat.length - 1]
try {
// let {totalCount, skuNames} = await this.getSkuNames(srcCat)
let skuNames = JSON.parse(JSON.stringify(this.skuNames))
let totalCount = this.skuNames.length
if (totalCount === 0) {
this.$message({
message: '未选择商品',
type: 'warning',
center: true
})
return false
}
showLoad()
// let nameIDs = skuNames.map(item => item.id)
let requestArr = []
for (let i = 0; i < skuNames.length; i++) {
requestArr.push(this.updateSkuName(skuNames[i].id, desCat, skuNames[i].name))
}
this.$emit('searchGood')
let responseArr = await Promise.all(requestArr)
this.dealResult(responseArr)
} catch (e) {
console.error(e)
msgWarning(e)
} finally {
hideLoad()
}
},
// 更新商品
async updateSkuName (nameID, decCatID, name) {
try {
let res = await api('v2/sku/UpdateSkuName', {
noLoading: true,
method: 'PUT',
data: `nameID=${nameID}&payload=${JSON.stringify({categoryID: decCatID})}`,
noSyncAlert: true
})
if (res.code && res.code === '-105') {
throw new Error(res.desc)
} else {
return {
nameID,
name,
status: 1
}
}
} catch (e) {
let msg = e
if (Object.prototype.toString.call(msg).indexOf('Error') > -1) {
msg = msg.message
}
return {
nameID,
name,
status: 2,
desc: msg
}
}
},
dealResult (responseArr) {
let title = '处理结果'
let thead = ''
let tbody = ''
thead = `
<tr>
<th>商品</th>
<th>状态</th>
<th>备注</th>
</tr>
`
// let tbodyContent = ''
responseArr.forEach(item => {
tbody += `
<tr>
<td>${item.nameID} ${item.name}</td>
<td>${this.statusMap[item.status]}</td>
<td>${item.desc || ''}</td>
</tr>
`
})
let sumary = `总共:${responseArr.length},未提交:${responseArr.filter(item => item.status === 0).length},成功:${responseArr.filter(item => item.status === 1).length},失败:${responseArr.filter(item => item.status === 2).length}`
let html = `
${sumary}
<table class="errmsg-table">
<caption>${title}</caption>
<thead>
${thead}
</thead>
<tbody>
${tbody}
</tbody>
</table>`
msgWarning(html, '结果')
}
}
}
</script>
<style lang="scss">
.dia-catGoodsToCat {
.label {
display: inline-block;
width: 100px;
}
.footer {
margin-top: 20px;
display: flex;
justify-content: flex-end;
}
}
</style>

View File

@@ -0,0 +1,156 @@
<template>
<el-dialog
class="dia-reset-skus"
title="初始化门店商品"
width="400px"
@closed="diaClose"
:visible.sync="diaShow">
<!-- <div style="text-align: center; color: #F56C6C; margin-bottom: 20px;">此操作只适用于单门店模式平台</div> -->
<!-- 表单 -->
<el-form
:model="formData"
size="mini"
ref="formData"
style=""
:rules="rules"
label-width="120px">
<!-- 厂商 -->
<el-form-item label="选择厂商:">
<el-select v-model.number="formData.vendorIDs">
<el-option v-for="item in ConVendorName" :key="item.vendorID" :label="item.name" :value="item.vendorID"></el-option>
</el-select>
</el-form-item>
<!-- 厂商 -->
<!-- 门店ID -->
<el-form-item label="门店选择:" prop="storeIDs">
<el-select
style="width: 230px;"
v-model.number="formData.storeIDs"
filterable
remote
placeholder="请输入门店关键字"
:remote-method="remoteMethod"
:loading="getStoreLoading">
<el-option
v-for="item in options"
:key="item.id"
:label="item.id + ' - ' + item.name"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<!-- 门店ID -->
<!-- 是否异步 -->
<el-form-item label="是否后台处理:">
<el-checkbox border v-model="formData.isAsync">后台处理</el-checkbox>
</el-form-item>
<!-- 是否异步 -->
<div style="padding: 0 10px;font-size: 12px; color: #F56C6C
; margin-bottom: 10px;">后台处理不会立即返回处理结果可以通过taskID在系统管理-任务查询中查看处理结果非后台处理则会在此页面等待处理结果</div>
<div style="margin-left: 90px;">
<!-- 单个失败是否继续 -->
<el-checkbox
style=""
size="small"
border
v-model="formData.isContinueWhenError">单个失败继续</el-checkbox>
<!-- 单个失败是否继续 -->
<!-- 确认按钮 -->
<el-button type="primary" size="small" @click="syncStoresSkus"> </el-button>
<!-- 确认按钮 --></div>
</el-form>
<!-- 表单 -->
</el-dialog>
</template>
<script>
import {fullSyncStoresSkus} from '@/apis/sync.js'
import {getStores} from '@/apis/controls/shop.js'
export default {
name: 'DiaResetSkus',
props: [],
data () {
return {
diaShow: false,
formData: {
storeIDs: null,
vendorIDs: 0,
isAsync: false,
isContinueWhenError: false
},
rules: {
storeIDs: [
{ required: true, message: '请先选择门店', trigger: 'change' }
]
},
options: [],
getStoreLoading: true
}
},
created () {
this.remoteMethod('')
},
methods: {
// 关闭dialog
diaClose () {
this.$emit('closeDiaReset')
},
// 远程查找门店
async remoteMethod (storeKeyWord) {
this.getStoreLoading = true
try {
const {stores} = await getStores({
keyword: storeKeyWord,
pageSize: 50
}, true)
this.options = stores
this.getStoreLoading = false
} catch (e) {
this.$message({
message: '远程查找门店失败',
type: 'warning',
center: true
})
}
},
// 同步
syncStoresSkus () {
this.$refs.formData.validate(valid => {
if (valid) {
// this.$confirm('是否进行初始化(注意:初始化将删除所有商品)', '警告').then(() => {
// })
let storeIDs = JSON.stringify([this.formData.storeIDs])
let vendorIDs = JSON.stringify([this.formData.vendorIDs])
fullSyncStoresSkus(storeIDs, vendorIDs, this.formData.isAsync, this.formData.isContinueWhenError, res => {
if (this.formData.isAsync) {
// 异步
this.$message({
message: '初始化门店商品成功 taskID: ' + JSON.parse(res.data),
type: 'success',
center: true,
duration: 0,
showClose: true
})
} else {
// 同步
this.$message({
message: '初始化门店商品成功',
type: 'success',
center: true
})
}
})
}
})
}
}
}
</script>
<style lang="scss">
.dia-reset-skus {
.el-dialog__body {
padding: 10px 10px 30px;
}
}
</style>

View File

@@ -0,0 +1,254 @@
<template>
<el-dialog
class="dia-search-upc"
title="查询商品信息"
width="1000px"
@close="diaClose"
:close-on-click-modal="false"
:visible="diaShow">
<div class="dia-body">
<div class="search">
<el-input style="width: 200px;" v-model.trim="name" placeholder="请输入商品名" size="mini" @keypress.enter.native="handleSearch" clearable></el-input>
<el-input style="width: 200px;" v-model.trim="upcCode" placeholder="请输入UPC码" size="mini" @keypress.enter.native="handleSearch" clearable></el-input>
<el-button type="primary" size="mini" @click="handleSearch">查询</el-button>
</div>
<div class="table-wrapper">
<el-table
:data="dataList"
style="width: 100%"
stripe
height="calc(100vh - 600px)"
>
<el-table-column
label="全名"
align="left"
>
<template slot-scope="{row}">
<div style="font-size: 12px;">
{{row.originalName}}
</div>
</template>
</el-table-column>
<el-table-column
label="商品名"
align="left"
>
<template slot-scope="{row}">
<div style="font-size: 12px;">
{{row.name}}
</div>
</template>
</el-table-column>
<el-table-column
label="规格"
align="right"
>
<template slot-scope="{row}">
<div style="font-size: 12px;">
{{row.specQuality}}{{row.specUnit}}
</div>
</template>
</el-table-column>
<el-table-column
label="重量"
align="right"
>
<template slot-scope="{row}">
<div style="font-size: 12px;">
{{row.weight}}g
</div>
</template>
</el-table-column>
<el-table-column
label="图片"
align="left"
>
<template slot-scope="{row}">
<div v-for="(img, index) in row.imgList" :key="index" >
<el-popover
placement="left"
width="200"
trigger="hover"
>
<div>
<img :src="img" alt="" width="100%">
</div>
<a class="imgLink" slot="reference" :href="img" target="_blank">
{{img}}
</a>
</el-popover>
</div>
</template>
</el-table-column>
<el-table-column
label="UPC"
align="center"
>
<template slot-scope="{row}">
<div style="font-size: 12px;">
{{row.upcCode}}
</div>
</template>
</el-table-column>
<el-table-column
label="操作"
align="center"
>
<template slot-scope="{row}">
<!-- <el-button @click="transformImg(row)" size="mini" type="success">使用该数据</el-button> -->
<el-button @click="useData(row)" size="mini" type="success">使用该数据</el-button>
</template>
</el-table-column>
</el-table>
</div>
</div>
<!-- <div slot="footer">
<el-button size="mini" type="primary">确定</el-button>
</div> -->
</el-dialog>
</template>
<script>
import {APIGetJDUPC} from '@/apis/APISku.js'
import {showLoad, hideLoad} from '@/tools/loading.js'
import msgWarning from '@/tools/msgwarning.js'
// import {getQiNiuToken} from '@/apis/qiniu.js'
// import $ajax from 'axios'
export default {
props: {
diaShow: {
type: Boolean,
default: false
},
goodName: {
type: String,
default: ''
},
upc: {
type: String,
default:''
}
},
data () {
return {
name: '',
upcCode: '',
dataList: [],
zswNewImg: []
}
},
watch: {
goodName: {
handler (to) {
this.name = to
},
immediate: true
},
upc: {
handler(val) {
if (val) {
this.upcCode = val
this.name = ''
}
},
immediate: true
},
diaShow(val) {
if (val) {
this.handleSearch()
}
}
},
methods: {
// // 转换图片方法 获取每个平台的数量
// transformImg(oldImgList){
// let that = this
// let number = 0 // 定义初始化判断条件
// let imgLength = oldImgList.imgList.length // 获取转换图片数组长度
// oldImgList.imgList.forEach(item => {
// window.URL = window.URL || window.webkitURL;
// var xhr = new XMLHttpRequest();
// xhr.open("get", item, true);
// // 至关重要
// xhr.responseType = "blob";
// xhr.onload = function () {
// if (this.status == 200) {
// //得到一个blob对象
// let blob = this.response;
// let imgFile = new window.File([blob], Math.random(), { type: blob.type });
// let suffix = blob.type === 'image/png' ? '.png' : '.jpg'
// getQiNiuToken(suffix, '', res => {
// let formData = new FormData()
// formData.append('token', res.token)
// formData.append('key', res.fileName)
// formData.append('file', imgFile)
// $ajax.post('http://up-z2.qiniup.com/', formData).then(res => {
// let imgUrl = 'https://image.jxc4.com/' + res.data.key
// that.zswNewImg.push(imgUrl)
// number++
// if(number == imgLength) { // 判断循环是否执行完毕了
// oldImgList.imgList = that.zswNewImg // 重新赋值数组
// that.useData(oldImgList) // 传递图片
// setTimeout(() => {that.zswNewImg=[]}, 1500) // 清空数组
// console.log('最后一次')
// hideLoad()
// }
// }, {
// timeout: 40000
// }).catch(err => {
// fnFail && fnFail(err.data)
// hideLoad()
// })
// })
// }
// }
// xhr.send()
// })
// },
// 关闭
diaClose () {
this.$emit('close')
},
// 查询
async handleSearch () {
try {
showLoad()
let res = await APIGetJDUPC({
name: this.name,
upcCode: this.upcCode
})
this.dataList = res || []
this.$emit('getOldImgUrl', res || [])
} catch (e) {
console.error(e)
msgWarning(e)
} finally {
hideLoad()
}
},
useData (data) {
this.$emit('outputData', data)
this.diaClose()
}
}
}
</script>
<style lang="scss">
.dia-search-upc {
.search {
display: flex;
}
.imgLink {
display: block;
width: 100px;
white-space:nowrap;
overflow:hidden;
text-overflow:ellipsis;
font-size: 10px;
}
}
</style>

View File

@@ -0,0 +1,148 @@
<!-- <template>
<div class="baselayout">
<CMPExdManager
:catLevel1="exdCatL1"
:catLevel2="exdCatL2"
:eBaiCatLevel1="eBaiCatLevel1"
:eBaiCatLevel2="eBaiCatLevel2"
:eBaiCatLevel3="eBaiCatLevel3"
></CMPExdManager>
</div>
</template>
<script>
import api from '@/utils/api'
import { showLoad, hideLoad } from '@/tools/loading.js'
export default {
components: {
CMPExdManager: () => import('../cmp-exdcat-manager.vue'),
},
data() {
return {
createGoodBtnShow: true,
createGoodCMPShow: false,
updateGoodCMPShow: false,
managerCatShow: false,
exdCatShow: false,
cityData: [],
exdCatL1: [],
exdCatL2: [],
catLevel1: [],
catLevel2: [],
skuCatLevel1: [],
skuCatLevel2: [],
jdCatLevel1: [],
jdCatLevel2: [],
jdCatLevel3: [],
jgCatLevel1: [],
jgCatLevel2: [],
jgCatLevel3: [],
eBaiCatLevel1: [],
eBaiCatLevel2: [],
eBaiCatLevel3: [],
mTCatLevel1: [],
mTCatLevel2: [],
mTCatLevel3: [],
skuName: '' // 存储当前要修改的商品的信息
}
},
async created() {
const methods = [
api('v2/cms/GetPlaces?level=2', { noLoading: true }),
api('v2/sku/GetCategories', { noLoading: true }),
api('v2/sku/GetVendorCategories?vendorID=0&parentID=-1', { noLoading: true }),
api('v2/sku/GetVendorCategories?vendorID=3&parentID=-1', { noLoading: true }),
api('v2/sku/GetCategories?isExd=true', { noLoading: true }),
api('v2/sku/GetVendorCategories?vendorID=5&parentID=-1', { noLoading: true })
]
try {
showLoad()
const [cityData, categories, jDcat, eBaicat, exdCat, jGcat] = await Promise.all(methods)
// 判断饿分类是否获取成功
if (!eBaicat) {
this.$message({
message: '[获取饿百分类列表失败] ' + eBaicat.desc,
type: 'warning',
center: true
})
} else {
this.eBaiCatLevel1 = eBaicat.filter(item => item.level === 1)
this.eBaiCatLevel2 = eBaicat.filter(item => item.level === 2)
this.eBaiCatLevel3 = eBaicat.filter(item => item.level === 3)
}
// 判断城市是否获取成功
if (!cityData) {
this.$message({
message: '[获取城市列表失败] ' + cityData.desc,
type: 'warning',
center: true
})
} else {
this.cityData = cityData
}
// 饿鲜达
if (!exdCat) {
this.$message({
message: '[获取饿鲜达分类列表失败] ' + exdCat.desc,
type: 'warning',
center: true
})
} else {
this.exdCatL1 = exdCat.filter(item => item.level === 1)
this.exdCatL2 = exdCat.filter(item => item.level === 2)
}
// 判断分类是否获取成功
if (!categories) {
this.$message({
message: '[获取分类列表失败] ' + categories.desc,
type: 'warning',
center: true
})
} else {
// categories = JSON.parse(categories.data)
// 取商品分类
// let skuNameCategories = categories.filter(item => item.type === 0)
this.catLevel1 = categories.filter(item => item.level === 1)
this.catLevel2 = categories.filter(item => item.level === 2)
// 取sku分类
let skuCat = categories.filter(item => item.type === 1)
this.skuCatLevel1 = skuCat.filter(item => item.level === 1)
this.skuCatLevel2 = skuCat.filter(item => item.level === 2)
}
// 判断京东分类是否获取成功
if (!jDcat) {
this.$message({
message: '[获取京东分类列表失败] ' + jDcat.desc,
type: 'warning',
center: true
})
} else {
this.jdCatLevel1 = jDcat.filter(item => item.level === 1)
this.jdCatLevel2 = jDcat.filter(item => item.level === 2)
this.jdCatLevel3 = jDcat.filter(item => item.level === 3)
}
if (!jGcat) {
this.$message({
message: '[获取京狗分类列表失败] ' + jGcat.desc,
type: 'warning',
center: true
})
} else {
this.jgCatLevel1 = jGcat.filter(item => item.level === 1)
this.jgCatLevel2 = jGcat.filter(item => item.level === 2)
this.jgCatLevel3 = jGcat.filter(item => item.level === 3)
}
} catch (err) {
this.$message({
message: err,
type: 'error',
center: true
})
}
hideLoad() // 关闭加载
},
}
</script>
<style lang="scss" scoped>
</style> -->

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,64 @@
<template>
<div class="baselayout">
<!-- 京西类目管理 -->
<CMPCat
:catLevel1="catLevel1"
:catLevel2="catLevel2"
></CMPCat>
<!-- 京西类目管理 -->
</div>
</template>
<script>
import { showLoad, hideLoad } from '@/tools/loading.js'
import api from '@/utils/api'
export default {
components: {
// CMPCatManager:()=>import('../cmp-cat-manager.vue'),)
CMPCat:() => import('./cmp-cat-manager.vue')
},
data() {
return {
catLevel1: [],
catLevel2: [],
}
},
async created() {
const methods = [
api('v2/sku/GetCategories', { noLoading: true }),
]
try {
showLoad()
const [ categories] = await Promise.all(methods)
// 判断分类是否获取成功
if (!categories) {
this.$message({
message: '[获取分类列表失败] ' + categories.desc,
type: 'warning',
center: true
})
} else {
// categories = JSON.parse(categories.data)
// 取商品分类
// let skuNameCategories = categories.filter(item => item.type === 0)
this.catLevel1 = categories.filter(item => item.level === 1)
this.catLevel2 = categories.filter(item => item.level === 2)
// 取sku分类
let skuCat = categories.filter(item => item.type === 1)
this.skuCatLevel1 = skuCat.filter(item => item.level === 1)
this.skuCatLevel2 = skuCat.filter(item => item.level === 2)
}
} catch (err) {
this.$message({
message: err,
type: 'error',
center: true
})
}
hideLoad() // 关闭加载
},
}
</script>
<style lang="scss" scoped>
</style>

View File

@@ -0,0 +1,64 @@
<template>
<div class="baselayout">
<GoodsSort
ref="goodsSort"
:catLevel1="catLevel1"
:catLevel2="catLevel2"
></GoodsSort>
</div>
</template>
<script>
import api from '@/utils/api'
import GoodsSort from '../cmp-goods-sort'
import { showLoad, hideLoad } from '@/tools/loading.js'
export default {
components: {
GoodsSort
},
data() {
return {
catLevel1: [],
catLevel2: [],
}
},
async created() {
const methods = [
api('v2/sku/GetCategories', { noLoading: true }),
]
try {
showLoad()
const [categories] = await Promise.all(methods)
// 判断分类是否获取成功
if (!categories) {
this.$message({
message: '[获取分类列表失败] ' + categories.desc,
type: 'warning',
center: true
})
} else {
// categories = JSON.parse(categories.data)
// 取商品分类
// let skuNameCategories = categories.filter(item => item.type === 0)
this.catLevel1 = categories.filter(item => item.level === 1)
this.catLevel2 = categories.filter(item => item.level === 2)
// 取sku分类
let skuCat = categories.filter(item => item.type === 1)
this.skuCatLevel1 = skuCat.filter(item => item.level === 1)
this.skuCatLevel2 = skuCat.filter(item => item.level === 2)
}
} catch (err) {
this.$message({
message: err,
type: 'error',
center: true
})
}
hideLoad() // 关闭加载
},
}
</script>
<style lang="scss" scoped>
</style>

View File

@@ -0,0 +1,421 @@
<template>
<!-- <div> -->
<div class="watermark">
<div class="content">
<ul>
<li>前缀或水印图不传表示立即去掉商品前缀或水印图</li>
<li>操作是覆盖式的会用当前设置的数据进行刷新</li>
</ul>
<el-form
:model="form"
size="mini"
:inline="true"
ref="form"
label-width="90px"
>
<el-form-item label="厂商:">
<el-select
v-model="form.vendorID"
@change="vendorIDChange"
style="width: 162px;"
>
<el-option
v-for="item in ConVendorName"
:key="item.vendorID"
:label="item.name"
:value="item.vendorID"
:disabled="[4 , 9].includes(item.vendorID)"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="平台账号:">
<el-select
v-model="form.vendorOrgCode"
style="width: 200px"
filterable
placeholder="选择账号"
>
<!-- <el-option
v-for="item in vendorOrgCode[form.vendorID]"
:key="item"
:label="item"
:value="item"
></el-option> -->
<el-option
v-for="(item, index) in tempPlateForm"
:label="item.name + '(' + item.key + ')'"
:value="item.key"
:key="index"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="品牌:">
<el-select
style="width: 100px;"
size="mini"
v-model="form.brandID"
filterable
>
<el-option
:value="0"
label="全部"
>
<span>全部</span>
</el-option>
<el-option
v-for="item in brandList"
:value="item.id"
:key="item.id"
:label="item.name"
>
<span>{{item.name}}</span>
</el-option>
</el-select>
</el-form-item>
<el-form-item label="生效时间:">
<el-date-picker
size="mini"
style="width: 130px;"
v-model="form.fromDate"
type="date"
value-format="yyyy-MM-dd"
:clearable="false"
placeholder="选择日期"
></el-date-picker>
<span>-</span>
<el-date-picker
size="mini"
style="width: 130px;"
v-model="form.toDate"
type="date"
value-format="yyyy-MM-dd"
:clearable="false"
placeholder="选择日期"
></el-date-picker>
</el-form-item>
<br />
<el-form-item label="前缀:">
<el-input
v-model.trim="form.exPrefix"
type="text"
placeholder="请输入前缀"
></el-input>
</el-form-item>
<el-form-item label="水印图:">
<!-- <UploadImg
@addPic="addImgWaterMark"
@delPic="delImgWaterMark"
:imgUrl="form.imgWaterMark"
:imgSize="1"
:imgWidth="800"
:imgHeight="800"
></UploadImg> -->
<jx-upload-file
:listType="'picture-card'"
:imgType="['image/jpeg','image/png','image/gif']"
:imgWidth="800"
:imgHeight="800"
:imgSize="1"
:autoUpload="true"
:drag="true"
v-model="form.imgWaterMark"
>
</jx-upload-file>
</el-form-item>
<br />
<el-form-item label="nameIDs:">
<el-input
style="width: 500px;"
v-model="form.nameIDs"
placeholder="请输入nameID空格分隔支持直接从excel中粘贴一列"
></el-input>
</el-form-item>
<br />
<el-form-item label="同步设置:">
<el-checkbox
border
v-model="form.isAsync"
>不等待处理结果</el-checkbox>
</el-form-item>
<el-form-item>
<el-checkbox
border
v-model="form.isContinueWhenError"
>单个失败继续</el-checkbox>
</el-form-item>
</el-form>
<div
slot="footer"
class="dialog-footer"
>
<el-button
size="mini"
@click="close"
> </el-button>
<el-button
size="mini"
type="primary"
@click="handleConfirm"
> </el-button>
</div>
</div>
</div>
<!-- <div style="border: 1px solid red;text-align: center;margin-top: 100px;padding: 50px">
添加水印后的图片
<img :src="newUrl" alt="">
</div> -->
<!-- </div> -->
</template>
<script>
import api from "@/utils/api";
import { showLoad, hideLoad } from "@/tools/loading";
import msgWarning from "@/tools/msgwarning.js";
import syncMsg from "@/tools/syncMsg";
import { formatDate } from "@/utils";
import { getSkuNamesBySkuIDs } from "@/apis/controls/skuNames.js";
import { json2query } from "@/utils";
import { mapGetters } from "vuex";
import { getBrands } from "@/apis/controls/brand.js";
import jxUploadFile from '@/components/cmp/uploadFile';
export default {
name: "GoodsWatermarkprev",
components: {
jxUploadFile
},
data() {
return {
form: {
vendorID: 0,
exPrefix: "",
imgWaterMark: "",
nameIDs: "",
fromDate: "",
toDate: "",
isAsync: true,
vendorOrgCode: '',
brandID: 0,
isContinueWhenError: true,
// brandList: [],
},
brandList: [],
tempPlateForm: [],
newUrl:""
};
},
async created() {
this.form.vendorOrgCode = this.vendorOrgCode[0][0];
this.tempPlateForm =this.AllplateArr.filter(item => Number(item.code) === 0)
let res = await getBrands()
if (res) {
this.brandList = res
}
// let that = this
//
// console.log('添加水印的图片','https://image.jxc4.com/image/6961879d5160e4c72d2a1c60ca7150be.jpg?imageView2/1/w/60/h/60')
// // document.body.appendChild(img);
// this.addTextToImage('https://image.jxc4.com/image/6961879d5160e4c72d2a1c60ca7150be.jpg', '京西菜市', '40px Arial', 'rgba(255,255,255,0.8)', function(watermarkedImgSrc) {
// // const img = document.createElement('img');
// // img.src = watermarkedImgSrc;
// console.log(watermarkedImgSrc,'添加水印后的图片','that',that)
// that.newUrl = watermarkedImgSrc
// })
},
computed: {
...mapGetters({
AllplateArr: 'AllplateArr',
vendorOrgCode: "vendorOrgCode",
}),
},
methods: {
// imgChange(e) {
// this.form.imgWaterMark = e[0]?e[0].url:''
// },
vendorIDChange(key) {
this.form.vendorIDs = [key];
let arr = JSON.parse(JSON.stringify(this.AllplateArr))
if (key === 9) {
this.form.vendorOrgCode = "";
} else {
this.form.vendorOrgCode = this.vendorOrgCode[key][0];
this.tempPlateForm = arr.filter(item => Number(item.code) === key)
}
},
close() {
this.form.exPrefix = "";
this.form.imgWaterMark = "";
this.form.nameIDs = "";
this.form.isAsync = true;
this.form.isContinueWhenError = true;
this.$emit("closeDiaAct");
},
// 打开动作
async onOpen() {
// 先获取
const { id, vendorList, beginAt, endAt } = this.promotion;
this.form.vendorID = vendorList[0].vendorID;
this.form.fromDate = formatDate(beginAt); // , 'YYYY-MM-DD hh:mm:ss')
this.form.toDate = formatDate(endAt); // , 'YYYY-MM-DD hh:mm:ss')
try {
let { data: skuIDs } = await this.apiGetStoresSkus(id, [
vendorList[0].vendorID
]);
if (skuIDs) {
skuIDs = [...new Set(skuIDs.map(item => item.skuID))];
// 换取nameID
let { skuNames } = await getSkuNamesBySkuIDs(skuIDs);
if (skuNames) {
let nameIDs = [...new Set(skuNames.map(item => item.id))];
this.form.nameIDs = nameIDs.join(" ");
}
}
} catch (e) {
msgWarning(e);
} finally {
hideLoad();
}
},
// 获取活动门店商品
async apiGetStoresSkus(actID, vendorIDs, all = true) {
let params = { actID };
if (all) {
params.pageSize = 1000000000;
params.offset = 0;
} else {
params.pageSize = this.pageSize;
params.offset = (this.page - 1) * this.pageSize;
}
if (this.keyword && !all) params.keyword = this.keyword;
if (vendorIDs) params.vendorIDs = JSON.stringify(vendorIDs);
try {
let { totalCount, data } = await api(`v2/act/GetActStoreSkuInfo`, {
params
});
return {
totalCount,
data
};
} catch (e) {
this.$alert(e, "错误");
} finally {
hideLoad();
}
},
// 刷水印前缀
async apiUpdateGoodsPrefixImg(data, noLoading = true) {
try {
const res = await api("v2/sku/UpdateSkuExinfoMap", {
method: "PUT",
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
data: json2query(data),
noLoading
});
return res;
} catch (e) {
throw e;
}
},
async handleConfirm() {
// JSON.stringify(Array.from(new Set(skuIDs.split(/\s/).map(item => +item).filter(item => item))))
if (!this.form.nameIDs) {
this.$toast("请输入nameID");
return false;
}
const json = JSON.parse(JSON.stringify(this.form));
json.nameIDs = JSON.stringify(
Array.from(
new Set(
json.nameIDs
.split(/\s/)
.map(item => +item)
.filter(item => item)
)
)
);
try {
showLoad();
const res = await this.apiUpdateGoodsPrefixImg(json);
syncMsg(res);
} catch (e) {
msgWarning(e);
} finally {
hideLoad();
}
},
// addImgWaterMark(url) {
// this.form.imgWaterMark = url;
// // 通过
// },
// delImgWaterMark() {
// this.form.imgWaterMark = "";
// },
// 添加水印的方法
addTextToImage(imageSrc, text, font, color, callback){
const img = new Image();
img.src = imageSrc;
img.crossOrigin = 'Anonymous'
img.onload = function() {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
ctx.font = font || '20px Arial';
ctx.fillStyle = color || 'white';
ctx.shadowColor = 'rgba(255, 255, 255, 0.3)'; // 阴影颜色
ctx.shadowBlur = 1; // 阴影模糊程度
ctx.shadowOffsetX = 20; // 水平阴影偏移
ctx.shadowOffsetY = 20; // 垂直阴影偏移
// 将坐标系原点移到指定的位置
ctx.translate(img.width/2, img.height/2);
// 旋转坐标系
ctx.rotate(-Math.PI/4 ); // 旋转45度弧度计算
let width = img.width
let height = img.height
// x , y 轴长度
let xLength = Math.sqrt(Math.pow(width/2, 2) + Math.pow(height/2, 2))
for(let i = -xLength; i < width; ) {
for(let j=-xLength;j < height;){
ctx.fillText(text, i, j);
// console.log('坐标点位',i,j)
j = j+200 // 行间距
}
i=i+200 // 列间距
}
callback(canvas.toDataURL());
}
}
}
};
</script>
<style lang="scss" scoped>
.watermark {
display: flex;
justify-content: center;
align-items: center;
}
.dialog-footer {
text-align: center;
}
</style>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,38 @@
<template>
<div class="create-good">
<jx-goos-set
:catLevel1="$props.catLevel1"
:catLevel2="$props.catLevel2"
:currentPage="'createGood'"
@btnPrev="btnPrev"
@getClass="getClass">
</jx-goos-set>
</div>
</template>
<script>
export default {
name: "CMPCreateGood",
props: [
"catLevel1",
"catLevel2",
],
components: {
jxGoosSet: () => import("./goodSet/goodSet.vue")
},
methods: {
getClass(type) { this.$emit('getClass',type)},
// 返回上一个页面
btnPrev() {
this.$emit("closeCreateGood");
}
},
};
</script>
<style lang="scss" scoped>
.create-good {
max-width: 1000px;
margin: 0 auto;
}
</style>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,56 @@
<template>
<div class="update-good">
<jx-goos-set
:catLevel1="$props.catLevel1"
:catLevel2="$props.catLevel2"
:skuCatLevel1="$props.skuCatLevel1"
:skuCatLevel2="$props.skuCatLevel2"
:item="$props.item"
:exdCatL1="$props.exdCatL1"
:exdCatL2="$props.exdCatL2"
:currentPage="'updateGood'"
@btnPrev="btnPrev"
@getClass="getClass">
</jx-goos-set>
</div>
</template>
<script>
export default {
name: "CMPUpdateGood",
props: [
"item",
"catLevel1",
"catLevel2",
"skuCatLevel1",
"skuCatLevel2",
"exdCatL1",
"exdCatL2"
],
components: {
jxGoosSet: () => import("./goodSet/goodSet.vue")
},
computed: {
// 计算属性的 getter
skuNameString: function () {
return JSON.stringify(this.skuName);
},
},
methods: {
// 获取分类
getClass(type) {this.$parent.getClass(type)},
// 返回上一个页面
btnPrev() {
this.$emit("closeUpdateGood");
}
}
};
</script>
<style lang="scss" scoped>
.update-good {
max-width: 1000px;
margin: 0 auto;
}
</style>

View File

@@ -0,0 +1,37 @@
.separator {
border-top: 1px dashed #dcdfe6;
margin: 20px 0;
}
.attributeList-title{
text-align: center;
font-size:20px;
padding:10px 0;
margin:20px 0;
font-weight: bold;
color: #303133;
}
.limitBorder{
display: flex;
flex-wrap: wrap;
}
// 前缀*号
.labelPrefix::before{
content: '*';
color:#f56c6c;;
margin-right: 4px;
}
// 商品名超出长度限制
.strong {
font-weight: bold;
color: #f56c6c;
text-decoration: underline;
}
.defaultText {
font-weight: bold;
border:1px solid #ccc;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,225 @@
<template>
<div class="jx-goods-manager baselayout">
<!-- 创建商品模块 -->
<div v-if="createGoodCMPShow">
<CMPCreateGood
@closeCreateGood="closeCreateGood"
@getClass="getClass"
:catLevel1="catLevel1"
:catLevel2="catLevel2"
:skuCatLevel1="skuCatLevel1"
:skuCatLevel2="skuCatLevel2"
></CMPCreateGood>
</div>
<!-- 创建商品模块 -->
<!-- 修改商品模块 -->
<div v-if="updateGoodCMPShow">
<CMPUpdateGood
@closeUpdateGood="closeUpdateGood"
@getClassZSW="getClassZSW"
:item="skuName"
:catLevel1="catLevel1"
:catLevel2="catLevel2"
:skuCatLevel1="skuCatLevel1"
:skuCatLevel2="skuCatLevel2"
:exdCatL1="exdCatL1"
:exdCatL2="exdCatL2"
ref="updateGood"
></CMPUpdateGood>
</div>
<!-- 修改商品模块 -->
<div
:style="{height: (!createGoodCMPShow && !updateGoodCMPShow) ? 'auto': 0, overflow: 'hidden'}"
>
<CMPGoodsManager
@showUpdateGood="showUpdateGood"
@showCMPCreateGood="showCMPCreateGood"
:catLevel1="catLevel1"
:catLevel2="catLevel2"
:skuCatLevel1="skuCatLevel1"
:skuCatLevel2="skuCatLevel2"
:exdCatL1="exdCatL1"
:exdCatL2="exdCatL2"
@getClassZSW="getClassZSW"
ref="goodsManager"
></CMPGoodsManager>
</div>
</div>
</template>
<script>
import api from '@/utils/api'
// import { showLoad, hideLoad } from "@/tools/loading.js";
import {mapGetters} from 'vuex'
import store from '@/store'
export default {
name: 'JxGoodsManager',
components: {
// 三级的四个菜单本来是tab的 石老板叫改成3级菜单做权限的
CMPGoodsManager: () => import('./cmp-goods-manager.vue'),
CMPCreateGood: () => import('./cmp-create-good.vue'),
CMPUpdateGood: () => import('./cmp-update-good.vue'),
DiaResetSkus: () => import('../dialog/dia-reset-skus.vue'),
//GoodsSort
},
data () {
return {
activeName: 'storeManagerTab',
createGoodBtnShow: true,
createGoodCMPShow: false,
updateGoodCMPShow: false,
managerCatShow: false,
exdCatShow: false,
// cityData: [],
exdCatL1: [],
exdCatL2: [],
catLevel1: [],
catLevel2: [],
skuCatLevel1: [],
skuCatLevel2: [],
skuName: '', // 存储当前要修改的商品的信息
}
},
computed: {
...mapGetters({
userInfo: 'userInfo',
yunyingMap: 'yunyingMap',
jDCategoryData:'jDCategoryData',
jGCategoryData:'jGCategoryData',
mTCategoryData:'mTCategoryData',
dYCategoryData:'dYCategoryData',
eBCategoryData:'eBCategoryData'
})
},
methods: {
// 商品列表加载成功在调用方法初始化其它数据
getClassZSW() {
this.initData()
},
// ZSW-初始化数据
async initData() {
const methods = [
api('v2/sku/GetCategories', {noLoading: true}), // 京西分类
api('v2/sku/GetCategories?isExd=true', {noLoading: true}) // 饿鲜达
]
try {
const [categories, exdCat] = await Promise.all(methods)
// 获取京西分类
if (!categories) {
this.zswMessage('获取分类列表失败')
} else {
this.catLevel1 = categories.filter(item => item.level === 1)
this.catLevel2 = categories.filter(item => item.level === 2)
// 取sku分类
let skuCat = categories.filter(item => item.type === 1)
this.skuCatLevel1 = skuCat.filter(item => item.level === 1)
this.skuCatLevel2 = skuCat.filter(item => item.level === 2)
}
// 饿鲜达
if (!exdCat) {
this.zswMessage('获取饿鲜达分类列表失败')
} else {
this.exdCatL1 = exdCat.filter(item => item.level === 1)
this.exdCatL2 = exdCat.filter(item => item.level === 2)
}
} catch (err) {
this.$message({
message: err,
type: 'error',
center: true
})
}
},
// 进入创建商品模块
async showCMPCreateGood () {
this.createGoodCMPShow = true
// this.getCityZSW() // 获取城市列表
},
// 关闭创建商品页面
closeCreateGood () {
this.$refs.goodsManager.imgListInfo = []
this.createGoodCMPShow = false
this.$refs.goodsManager.getGoods()
},
// 进入修改商品模块
showUpdateGood (item) {
this.skuName = item
this.updateGoodCMPShow = true
// this.getCityZSW() // 获取城市列表
// this.geteBaicatZSW()
},
// 关闭修改商品模块
closeUpdateGood () {
this.$refs.goodsManager.imgListInfo = []
// console.log('this',this.$refs.goodsManager.imgListInfo)
this.updateGoodCMPShow = false
this.$refs.goodsManager.getGoods()
},
// 找出数组对象中最大属性
biggerID (arr, attr) {
// 先拷贝
let temArr = []
for (let i = 0; i < arr.length; i++) {
temArr.push(arr[i])
}
temArr.sort((n1, n2) => {
return n2[attr] - n1[attr]
})
return temArr[0][attr]
},
/**
* 二次封装信息提示
*/
zswMessage(msg, type='warning', center=true) {
this.$message({message: msg,type: type ,center: center})
},
/**
* 获取分类列表
*/
async getClass(type){
switch(type){
case 'JD':
// 京东
if(this.jDCategoryData && this.jDCategoryData.length>0) return
await store.dispatch('getCate',{vendorID:0,parentID:-1})
break
case 'JG':
// 京狗
if(this.jGCategoryData && this.jGCategoryData.length>0) return
await store.dispatch('getCate',{vendorID:5,parentID:-1})
break
case 'MT':
// 美团
if(this.mTCategoryData && this.mTCategoryData.length>0) return
await store.dispatch('getCate',{vendorID:1,parentID:-1})
break
case 'DD':
// 抖店
if(this.dYCategoryData && this.dYCategoryData.length>0) return
await store.dispatch('getCate',{vendorID:14,parentID:-1})
break
case 'EB':
// 饿百
if(this.eBCategoryData && this.eBCategoryData.length>0) return
await store.dispatch('getCate',{vendorID:3,parentID:-1})
break
}
}
}
}
</script>
<style lang="scss" scoped>
.jx-goods-manager {
position: relative;
min-height: calc(100vh - 140px);
}
</style>

View File

@@ -0,0 +1,409 @@
<template>
<div class="store-cat-manager baselayout">
<el-container>
<el-aside width="360px">
<div class="wrap" style="margin-top: 20px;" >
<el-scrollbar wrap-class="list" :native="false" >
<!-- :data="catData" -->
<el-tree class="list"
:data="catData"
:props="defaultProps"
:highlight-current="true"
node-key="vendorCategoryID"
@node-click="nodeClick"
accordion
:default-expanded-keys="expandKey">
<div class="custom-tree-node" slot-scope="{node, data}">
<span :class="{'notSync': node.data.isSync === 1}">{{node.label}}</span>
</div>
</el-tree>
</el-scrollbar>
</div>
<!-- 分类 -->
</el-aside>
<el-main>
<!-- 操作面板 -->
<!-- 点击编辑分类 -->
<div class="clickCat panel-frame" v-if="clickCatShow">
<h3>
编辑 {{currentPick.level}} 级分类
</h3>
<el-form :model="currentPick" ref="clickCat" label-width="130px" label-position="right"
:inline="true" size="small">
<!-- 路径 -->
<!-- <div style="margin-bottom: 20px;">
<el-form-item label="分类路径:">
<el-breadcrumb separator-class="el-icon-arrow-right" style="padding: 9px 0;">
<el-breadcrumb-item v-if="currentPick.parentID !== ''">{{parentPath}}</el-breadcrumb-item>
<el-breadcrumb-item>{{currentPick.name}}</el-breadcrumb-item>
</el-breadcrumb>
</el-form-item>
</div> -->
<!-- 路径 -->
<!-- 名称 -->
<el-form-item label="当前分类:">
<el-input :value="currentPick.name" disabled ref="nameValue" >
</el-input>
<span style="color: #f56c6c;font-size: 12px;position: absolute;bottom: -25px;left:0;"
v-if="showCatNameError">请输入分类名称</span>
</el-form-item>
<el-form-item label="京东分类绑定:">
<el-cascader v-if="jdCatData && jdCatData.length" ref="editorjdCategoryID" placeholder="试试搜索:蔬菜"
filterable clearable change-on-select :options="jdCatData" :props="jgCatProp"
:value="switchJdCat" separator=">" style="width: 300px;"></el-cascader>
</el-form-item>
<div style="margin-top: 20px;">
<el-button type="primary" size="medium" class="el-icon-check" style="margin-left: 20px;"
@click="updateCat('clickCat')">保存</el-button>
</div>
<!-- 保存按钮 -->
</el-form>
</div>
<!-- 点击编辑分类 -->
<!-- 操作面板 -->
</el-main>
</el-container>
</div>
</template>
<script>
import api from "@/utils/api";
import { showLoad, hideLoad } from "@/tools/loading.js";
import { mapGetters } from 'vuex'
import msgWarning from "@/tools/msgwarning.js";
import { getVendorCategoriesWithMap, updateMtCatToJd } from '@/apis/APISkuNames.js'
export default {
name: "mtcattoJdmanager",
data() {
return {
jdAccount: [],//京东平台账号
curJdAccount: '',
//复制门店显示关闭
copyCateShow: false,
//门店id
vendorIDs: [],
//模态框
diaStorePickShow: false,
catLevel1: [],
catLevel2: [],
catLevel3: [],
jdCatLevel1: [],
jdCatLevel2: [],
jdCatLevel3: [],
catData: [], // 存储京西分类,已重新组装
// 规定树形结构读取字段
defaultProps: {
label: "name", // label读取数据中的name字段
children: 'children2'
// disabled: (data, node) => data.type === 0
},
currentPick: {}, // 当前激活的分类
// 添加一级分类可视状态
addLevel1Show: false,
// 添加二级分类可视状态
addLevel2Show: false,
// 编辑分类可视状态
clickCatShow: false,
// 创建新分类的存储对象
// 校验编辑时分类名称
showCatNameError: false,
// 校验京东分类绑定是否填写
showjdCatError: false,
showjgCatError: false,
// 校验饿百分类绑定是否填写
showeBaiCatError: false,
showmTCatError: false,
jxcategoriesArr: [],
jgCatData: [], // 京东分类,一二三级已挂载
// 京东分类规定字段
jgCatProp: {
value: "vendorCategoryID",
label: "name",
},
expandKey: [], // 展开菜单
allowDrag: true, // 是否开启拖拽功能
};
},
watch: {
catLevel1(to) {
if (to) {
this.catData = this.catLevel1;
// 组合一二级菜单
this.catData.forEach((level1) => {
let level2 = this.catLevel2.filter(
(item) => item.parentID === level1.categoryID
);
level1.children = level2;
});
}
},
catLevel2(to) {
if (to) {
this.catData = this.catLevel1;
// 组合一二级菜单
this.catData.forEach((level1) => {
let level2 = this.catLevel2.filter(
(item) => item.parentID === level1.categoryID
);
level1.children = level2;
});
}
},
},
async created() {
const methods = [
api("v2/sku/GetVendorCategories?vendorID=0&parentID=-1", {
noLoading: true,
}),
];
try {
showLoad();
const [
jDcat,
] = await Promise.all(methods);
//判断京东分类是否获取成功
if (!jDcat) {
this.$message({
message: "[获取京东分类列表失败] " + jDcat.desc,
type: "warning",
center: true,
});
} else {
this.jdCatLevel1 = jDcat.filter((item) => item.level === 1);
this.jdCatLevel2 = jDcat.filter((item) => item.level === 2);
this.jdCatLevel3 = jDcat.filter((item) => item.level === 3);
}
} catch (error) {
this.$message({
message: error,
type: "error",
center: true,
});
}
hideLoad(); // 关闭加载
let jdCatData = this.jdCatLevel1;
let temCat = this.jdCatLevel2;
temCat.forEach((le2) => {
let level3 = this.jdCatLevel3.filter(
(le3) => Number(le3.parentID) === Number(le2.vendorCategoryID)
);
le2.children = level3;
});
// 把二级挂载到一级上
jdCatData.forEach((le1) => {
let level2 = temCat.filter(
(le2) => Number(le2.parentID) === Number(le1.vendorCategoryID)
);
le1.children = level2;
});
this.jdCatData = jdCatData;
this.renewCat()
},
computed: {
...mapGetters({
jdVendorArr: 'jdVendorArr'
}),
// 京东分类转换
switchJdCat() {
if (this.currentPick.catMapID) {
let leaf = this.currentPick.catMapID;
let parent = this.jdCatLevel3.filter(
(item) => Number(item.vendorCategoryID) === Number(leaf)
)[0]
? this.jdCatLevel3.filter(
(item) => Number(item.vendorCategoryID) === Number(leaf)
)[0].parentID
: "";
let parentparent = this.jdCatLevel2.filter(
(item) => Number(item.vendorCategoryID) === Number(parent)
)[0]
? this.jdCatLevel2.filter(
(item) => Number(item.vendorCategoryID) === Number(parent)
)[0].parentID
: "";
return [parentparent, parent, leaf];
} else {
return [];
}
},
},
methods: {
// 重新获取分类
async renewCat() {
try {
// 获取分类数据
let categories = await getVendorCategoriesWithMap(1) //获取美团分类
// 判断分类是否获取成功
if (categories) {
this.catLevel1 = categories.filter((item) => item.level === 1);
this.catLevel2 = categories.filter((item) => item.level === 2);
this.catLevel3 = categories.filter((item) => item.level === 3);
// 组合一二级菜单
let catData = this.catLevel1;
this.catLevel2.forEach((level2) => {
let arr = this.catLevel3.filter((item) => item.parentID === level2.vendorCategoryID)
level2.children2 = arr
})
catData.forEach((level1) => {
let arr = this.catLevel2.filter((item) => item.parentID === level1.vendorCategoryID)
level1.children2 = arr
});
this.catData = catData
}
} catch (error) {
this.$message({
message: error,
type: "error",
center: true,
});
}
hideLoad(); // 关闭加载
},
nodeClick(data, node, cmp) {
this.clickCatShow = false;
// this.$nextTick(() => {
this.currentPick = {};
this.currentPick = JSON.parse(JSON.stringify(data));
// 如果是一级菜单的展开与收缩,要关闭保存二级分类按钮和编辑窗口
if (node.level === 3) {
if (node.expanded || node.childNodes.length === 0) {
// 展开
this.currentPick = JSON.parse(JSON.stringify(data));
this.clickCatShow = true;
} else {
// 关闭
this.currentPick = {};
this.clickCatShow = false;
}
}
// });
},
// 校验编辑分类时分类名称
checkValue(ref) {
if (!this.$refs[ref].currentValue.trim()) {
this.showCatNameError = true;
} else {
this.showCatNameError = false;
}
},
// 校验京东饿百分类是否选择
// 更新分类
async updateCat() {
// 保存京东分类数组
let jdCatID = "";
if (
this.$refs.editorjdCategoryID &&
this.$refs.editorjdCategoryID.currentValue.length
) {
jdCatID = this.$refs.editorjdCategoryID.currentValue;
jdCatID = jdCatID[jdCatID.length - 1];
try {
await updateMtCatToJd(this.currentPick.vendorCategoryID, jdCatID)
this.$message.success('映射分类成功')
this.renewCat()
this.$nextTick(() => {
this.expandKey = [this.currentPick.parentID];
});
} catch (e) {
msgWarning(e)
}
} else {
this.$message.warning('请选择京东分类')
}
},
},
};
</script>
<style lang="scss">
.store-cat-manager {
// width: 1000px;
// margin: 0 auto;
padding-top: 50px;
background-color: #ffffff;
width: 100%;
.mgin10 {
margin-top: 10px;
}
.pic {
display: flex;
align-items: center;
.des {
color: #666;
font-size: 12px;
margin-left: 10px;
}
}
.wrap {
height: calc(100vh - 280px);
overflow: hidden;
}
.list {
// max-height: 100vh;
max-height: calc(100vh - 280px);
margin-right: 10px;
user-select: none;
}
.custom-tree-node {
font-size: 14px;
padding: 20px 0;
}
.el-tree-node__children {
padding: 20px 0;
}
.el-tree-node__content {
padding: 10px 0;
position: relative;
}
.notUse {
opacity: 0.5;
}
.panel-frame {
padding-left: 50px;
h3 {
margin: 0;
border-bottom: 1px solid #efefef;
width: 600px;
height: 50px;
line-height: 50px;
margin-bottom: 20px;
}
}
.upload-cat-img {
.el-upload-list {
li {
width: 100px !important;
height: 100px !important;
}
}
.el-upload {
width: 100px !important;
height: 100px !important;
line-height: 110px !important;
}
}
.notSync {
color: #f56c6c !important;
}
}
</style>

View File

@@ -0,0 +1,182 @@
<template>
<div class="regressGood baselayout">
<div style="padding: 0 50px 50px 50px;font-size: 18px; color: #409EFF
;font-weight: bold; line-height: 1.5;">初化门店商品逻辑有调整不再影响已有商品的销量了所以多次初始化是安全无副作用的</div>
<!-- <el-dialog
class="dia-reset-skus"
title="初始化门店商品"
width="600"
:append-to-body="false"
:close-on-click-modal="false"
:close-on-press-escape="false"
:modal="false"
:modal-append-to-body="false"
:show-close="false"
:visible.sync="diaShow"> -->
<!-- <div style="text-align: center; color: #F56C6C; margin-bottom: 20px;">此操作只适用于单门店模式平台</div> -->
<!-- 表单 -->
<el-form
:model="formData"
size="mini"
ref="formData"
style=""
:rules="rules"
label-width="120px">
<!-- 厂商 -->
<el-form-item label="选择厂商:">
<el-select v-model.number="formData.vendorIDs">
<el-option v-for="item in ConVendorName" :key="item.vendorID" :label="item.name" :value="item.vendorID" :disabled="item.vendorID === 9"></el-option>
</el-select>
</el-form-item>
<!-- 厂商 -->
<!-- 门店ID -->
<el-form-item label="门店选择:" prop="storeIDs">
<!-- <el-select
style="width: 180px;"
v-model.number="formData.storeIDs"
filterable
remote
placeholder="请输入门店关键字"
:remote-method="remoteMethod"
:loading="getStoreLoading">
<el-option
v-for="item in options"
:key="item.id"
:label="item.id + ' - ' + item.name"
:value="item.id">
</el-option>
</el-select> -->
<!-- 门店选择 -->
<StoresPick
ref="storesPick1"
:vendorIDs="[formData.vendorIDs]"
@updateStoreIDs="updateStoreIDs"
>
</StoresPick>
</el-form-item>
<!-- 门店ID -->
<!-- 是否异步 -->
<!-- <el-form-item label="是否后台处理:">
<el-checkbox border v-model="formData.isAsync">后台处理</el-checkbox>
</el-form-item> -->
<!-- 是否异步 -->
<div style="padding: 0 10px;font-size: 12px; color: #F56C6C; margin-bottom: 10px;margin-left: 100px;">不等待处理结果不会立即返回处理结果可以通过taskID在系统管理-任务查询中查看处理结果或留意钉钉消息非后台处理则会在此页面等待处理结果</div>
<div style="padding: 0 10px;font-size: 12px; color: #F56C6C; margin-bottom: 10px;font-weight: bold; text-align: center">只会上传在京西是可售的商品</div>
<div style="margin-left: 20px;">
<el-checkbox
style="margin-left: 100px;"
size="small"
border
v-model="formData.isAsync">不等待处理结果</el-checkbox>
<!-- 单个失败是否继续 -->
<el-checkbox
style=""
size="small"
border
v-model="formData.isContinueWhenError">单个失败继续</el-checkbox>
<!-- 单个失败是否继续 -->
<!-- 确认按钮 -->
<el-button type="primary" size="small" @click="syncStoresSkus"> </el-button>
<!-- 确认按钮 --></div>
</el-form>
<!-- 表单 -->
<!-- </el-dialog> -->
</div>
</template>
<script>
import {fullSyncStoresSkus} from '@/apis/sync.js'
import syncMsg from '@/tools/syncMsg'
import {debounce} from '@/utils/underscore.js'
import StoresPick from "@/components/cmp/storePick/index.vue";
import {permissionTel} from '@/config.js'
import {mapGetters} from 'vuex'
// import {getStores} from '@/apis/controls/shop.js'
export default {
name: 'DiaResetSkus',
props: [],
components: {
StoresPick
},
data () {
return {
diaShow: true,
formData: {
storeIDs: null,
vendorIDs: 0,
isAsync: true,
isContinueWhenError: true
},
storeIDs: [],
rules: {
storeIDs: [
{ required: false, message: '请先选择门店', trigger: 'change' }
]
},
options: [],
getStoreLoading: true
}
},
computed: {
...mapGetters({
'userInfo': 'userInfo'
}),
permissionTel () {
return permissionTel
}
},
created () {
// this.remoteMethod('')
},
methods: {
// 远程查找门店
// async remoteMethod(storeKeyWord) {
// this.getStoreLoading = true
// try {
// const {stores} = await getStores({
// keyword: storeKeyWord,
// pageSize: 50
// }, true)
// this.options = stores
// this.getStoreLoading = false
// } catch (e) {
// this.$message({
// message: '远程查找门店失败',
// type: 'warning',
// center: true
// })
// }
// },
updateStoreIDs (storeIDs) {
this.storeIDs = storeIDs
},
// 同步
syncStoresSkus: debounce(function () {
this.$refs.formData.validate(valid => {
if (valid) {
// this.$confirm('是否进行初始化(注意:初始化将删除所有商品)', '警告').then(() => {
// })
let storeIDs = this.storeIDs.length ? JSON.stringify(this.storeIDs) : JSON.stringify([this.formData.storeIDs])
let vendorIDs = JSON.stringify([this.formData.vendorIDs])
fullSyncStoresSkus(storeIDs, vendorIDs, this.formData.isAsync, this.formData.isContinueWhenError, res => {
let data = JSON.parse(res.data)
syncMsg(data)
})
}
})
}, 1000, true)
}
}
</script>
<style lang="scss">
.regressGood{
position: relative;
.dia-reset-skus {
position: relative;
.el-dialog__body {
padding: 10px 10px 30px;
}
}
}
</style>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,39 @@
.card-part{
display: flex;
justify-content: space-between;
}
.accountBalance{
// border: 1px solid red;
text-align: center;
// height: 100px;
// line-height: 100px;
font-size: 22px;
box-sizing: border-box;
// font-weight: bold;
// margin:20px;
// padding: 10px;
display: flex;
padding-right: 20px;
border-right: 1px solid #eee;
// color:rgb(255, 0, 0);
// .text::before{
// content: '¥';
// }
.balance{
margin-top: 20px;
padding: 10px;
}
.balance>div{
margin-top:10px;
font-weight: bold;
}
}
.accountInfo{
// border: 1px solid green;
text-align: center;
}

View File

@@ -0,0 +1,895 @@
<template>
<div>
<el-card class="box-card" style="width: 100%;">
<div class="card-part">
<!-- 余额信息 -->
<div class="accountBalance" style="flex: 1;display: flex;flex-direction: column;align-items: center;">
<div>
<el-select
v-model="billBalanceInfo.payType"
placeholder="请选择账号类型"
@change="queryBillBalanceBut">
<el-option label="收款账户" value="01"></el-option>
<!-- <el-option label="付款账户" value="02"></el-option> -->
<el-option label="分账商户账户" value="03"></el-option>
<el-option label="分账接收方账户" value="04"></el-option>
<!-- <el-option label="充值代付账户" value="05"></el-option>
<el-option label="结算代付账户" value="06"></el-option> -->
</el-select>
<!-- 查询结果 -->
<div v-if="billBalanceInfo.result" style="" class="balance">
<div>账户状态:{{ billBalanceStatus(billBalanceInfo.result.acctSt) }}</div>
<div>预付余额:{{ billBalanceInfo.result.forceBalance }}</div>
<div>实时余额:{{ billBalanceInfo.result.reBalance }}</div>
<div>当前可用余额:{{ billBalanceInfo.result.curBalance }}</div>
</div>
<el-button type="primary" @click="withdrawQuery('提现')">提现</el-button>
</div>
</div>
<!-- 门店信息 -->
<div style="border-right: 1px solid #eee;flex: 1;display: flex;flex-direction: column;align-items: center;">
<div>门店信息</div>
<div>商户号{{ reportInfo.data.customerNo }}</div>
<div>机构号{{ reportInfo.data.orgCode }}</div> <!-- 京西菜市-小通分账 -->
<div style="margin-top: 20px;">{{ isFillImg }}</div> <!-- 补充照片的信息 -->
<el-button type="primary" style="margin-top: 20px;" @click="updateBasicInfoBut">修改基础信息</el-button>
</div>
<!-- 银联信息 -->
<div style="flex: 1;border-right: 1px solid #eee;text-align: center;padding:10px">
<div style="display: flex;flex-direction: column;align-items: center;">
<div>结算卡号1xxxxxxxx</div>
<!-- <div v-if="reportInfo.result">银联报备状态{{ reportInfo.result }}</div> -->
<div v-if="deviceInfo.result">{{ deviceInfo.result }}</div>
</div>
<el-button type="primary" style="margin-top: 20px;" @click="updateSettleInfo">修改结算信息</el-button>
</div>
<!-- 终端信息 -->
<!-- <div style="flex: 1;">
<div>终端设备信息</div>
</div> -->
</div>
</el-card>
<el-card style="margin-top: 20px;">
<div>
<el-button type="primary" @click="withdrawQuery('提现模式')" style="margin-top: 20px;">提现模式</el-button>
<el-button type="primary" @click="withdrawQuery('实名认证')" style="margin-top: 20px;">实名认证</el-button>
<el-button type="primary" @click="withdrawQuery('绑定')" v-if="customerInfo.customerNo != '141698705'" style="margin-top: 20px;" :disabled="customerInfo.separateReceiverInfo && customerInfo.separateReceiverInfo.bindRelations.length>0">绑定</el-button>
<el-button type="primary" @click="withdrawQuery('解绑')" v-if="customerInfo.customerNo != '141698705'" style="margin-top: 20px;" :disabled="!(customerInfo.separateReceiverInfo && customerInfo.separateReceiverInfo.bindRelations.length>0)">解绑</el-button>
<el-button type="primary" @click="withdrawQuery('分账账户')" v-if="customerInfo.customerNo != '141698705'" style="margin-top: 20px;" >分账账户</el-button>
<br v-if="customerInfo.customerNo != '141698705'" />
<el-button type="primary" @click="withdrawQuery('查询提现结果')" style="margin-top: 20px;">查询提现结果</el-button>
<el-button type="primary" @click="withdrawQuery('提现流水查询')" style="margin-top: 20px;">查询提现流水</el-button>
<br />
<el-button type="primary" style="margin-top: 20px;" @click="withdrawQuery('补充门店照片')">补充门店照片</el-button>
<br />
<el-button type="primary" @click="deviceStatus" style="margin-top: 20px;">银联报备-商户报备查询</el-button>
<el-button type="primary" @click="withdrawQuery('终端报备查询')" style="margin: 20px;">银联报备-终端报备查询</el-button>
</div>
</el-card>
<el-dialog
:title="dialog.title"
:visible.sync="dialog.dialogVisible"
width="30%"
@close="closeDia">
<div style="text-align: center;margin: 20px auto;padding: 10px;width: 520px;">
<!-- 提现流水 查询 -->
<div style="width: 500px;margin: 20px auto;" v-if="dialog.title === '提现流水查询'">
<el-form
label-width="180px"
:model="withdrawalData.data">
<el-form-item label="商户号"><el-input v-model="withdrawalData.data.merchantNo" style="width: 300px;" placeholder="请输入商户号"></el-input></el-form-item>
<el-form-item label="订单号"><el-input v-model="withdrawalData.data.drawJnl" style="width: 300px;" placeholder="请输入订单号"></el-input></el-form-item>
<el-form-item label="账户名"><el-input v-model="withdrawalData.data.acctName" style="width: 300px;" placeholder="请输入账户名"></el-input></el-form-item>
<el-form-item label="开始交易时间">
<el-date-picker
style="width:300px"
v-model="withdrawalData.data.startTime"
type="datetime"
value-format="yyyy-MM-dd HH:mm:ss"
placeholder="开始交易时间">
</el-date-picker>
</el-form-item>
<el-form-item label="结束交易时间">
<el-date-picker
style="width:300px"
v-model="withdrawalData.data.endTime"
type="datetime"
value-format="yyyy-MM-dd HH:mm:ss"
placeholder="结束交易时间">
</el-date-picker>
</el-form-item>
<el-form-item label="分账流水号"><el-input v-model="withdrawalData.data.separateNo" style="width: 300px;" placeholder="请输入分账流水号"></el-input></el-form-item>
<el-form-item style="text-align: center;">
<el-button type="primary" @click="queryWithdrawalNo">提现流水查询</el-button>
</el-form-item>
</el-form>
<!-- 提现流水的结果 -->
<div>{{ withdrawalData.result }}</div>
</div>
<!-- 查询 / 修改 提现模式 -->
<div style="width: 500px;margin: 20px auto;" v-if="dialog.title === '提现模式'">
<el-form
ref="ruleForm"
label-width="180px"
:model="withdrawPattern.data"
>
<el-form-item label="BMCP机构号" required >
<el-input v-model="withdrawPattern.data.bmcpNo" style="width: 300px;" placeholder="BMCP机构号" :disabled="true"></el-input>
</el-form-item>
<!-- 822商户号 receiveNo -->
<el-form-item label="商户号" required>
<el-input v-model="withdrawPattern.data.mercId" style="width: 300px;" placeholder="商户号" :disabled="true"></el-input>
</el-form-item>
<el-form-item label="钱包id" required>
<el-input v-model="withdrawPattern.data.ewalletId" style="width: 300px;" placeholder="" :disabled="true"></el-input>
</el-form-item>
<el-form-item label="提款模式" required>
<el-select
v-model="withdrawPattern.data.settleType"
style="width: 300px;"
placeholder="请选择提款模式">
<el-option label="主动提款" value="01"></el-option>
<el-option label="余额自动结算" value="02"></el-option>
<el-option label="交易自动结算" value="03"></el-option>
</el-select>
</el-form-item>
<el-form-item label="余额自动结算时间" >
<el-time-select
:disabled="withdrawPattern.data.settleType === '02'"
placeholder="余额自动结算时间"
style="width: 300px;"
v-model="withdrawPattern.data.settleTime"
:picker-options="{
start: '00:00',
step: '01:00',
end: '23:00'
}">
</el-time-select>
</el-form-item>
<el-form-item label="交易自动结算周期" :required="withdrawPattern.data.settleType === '03'">
<el-select
:disabled="withdrawPattern.data.settleType !== '03'"
v-model="withdrawPattern.data.settleCircle"
style="width: 300px;"
placeholder="请选择交易自动结算周期">
<!-- 次日结算 -->
<el-option label="D1" value="D1"></el-option>
<el-option label="T1" value="T1"></el-option>
</el-select>
<el-tag type="warning" style="width: 300px;">提款模式为 交易自动结算 才生效</el-tag>
</el-form-item>
<el-form-item label="结算账户类型" :required="withdrawPattern.data.settleType !== '01'">
<el-select
:disabled="withdrawPattern.data.settleType === '01'"
v-model="withdrawPattern.data.payType"
style="width: 300px;"
placeholder="请选择结算账户类型">
<!-- 针对 settleType 02 / 03 生效 -->
<el-option label="收款账户" value="01"></el-option>
<el-option label="分账接收方账户" value="04"></el-option>
</el-select>
<el-tag type="warning" style="width: 300px;">提款模式为 余额自动结算 / 交易自动结算 才生效</el-tag>
</el-form-item>
<el-form-item label="留存金额" :required="withdrawPattern.data.settleType === '02'" >
<el-input
:disabled="withdrawPattern.data.settleType !== '02'"
v-model="withdrawPattern.data.retainedAmt"
style="width: 300px;" placeholder="留存金额(单位:元)">
</el-input>
<el-tag type="warning" style="width: 300px;">提款模式为 余额自动结算 才生效</el-tag>
</el-form-item>
<el-form-item label="备注" >
<el-input v-model="withdrawPattern.data.remark" style="width: 300px;" placeholder="备注"></el-input>
</el-form-item>
<el-form-item label="摘要">
<el-input v-model="withdrawPattern.data.summary" style="width: 300px;" placeholder="摘要"></el-input>
</el-form-item>
<el-form-item style="text-align: center;" >
<el-button type="primary" @click="saveWithdrawPattern('ruleForm')">保存提款模式</el-button>
</el-form-item>
</el-form>
</div>
<!-- 查询 提现模式/提现 的结果 -->
<div v-if="dialog.title === '查询提现结果'">
<div>钱包id{{ withdrawInfo.ewalletId }}</div>
<div>请求日期{{ withdrawInfo.reqDate }}</div>
<div>提款流水号{{ withdrawInfo.drawJnl }}</div>
<div>提款金额含手续费{{ withdrawInfo.drawAmt }}</div>
<div>手续费{{ withdrawInfo.drawFee }}</div>
<div>提款模式(D0/D1){{ withdrawInfo.drawMode }}</div>
<div>结算模式{{ withdrawInfo.batchAutoSettle === '01' ? '主动提款' : withdrawInfo.batchAutoSettle === '02' ? '余额自动结算' : withdrawInfo.batchAutoSettle === '03' ? '交易自动结算' : '未知' }}</div>
<div>自动结算批次号{{ withdrawInfo.batchNo }}</div>
<div>结算账号{{ withdrawInfo.acctNo }}</div>
<div>结算账号名{{ withdrawInfo.acctName }}</div>
<div>提款状态{{ drawStatus(withdrawInfo.drawState) }}</div>
<div>结果信息{{ withdrawInfo.memo }}</div>
<div>商户订单号{{ withdrawInfo.merOrderNo }}</div>
<div>结算流水号{{ withdrawInfo.settleNo }}</div>
<div>银行行号{{ withdrawInfo.bankNo }}</div>
<div>银行名称{{ withdrawInfo.nbkName }}</div>
<div>商户号 {{ withdrawInfo.mercId }}</div>
<div>完成时间{{ withdrawInfo.completeTime }}</div>
<div>创建时间{{ withdrawInfo.createdTime }}</div>
</div>
<!-- 补充门店照片 -->
<div style="width: 500px;margin: 20px auto;" v-if="dialog.title === '补充门店照片'">
<el-form
:model="fillStoreImg"
label-width="180px"
label-position="right">
<el-form-item label="外部商户号">
<el-input v-model="fillStoreImg.extCustomerNo" :disabled="true" style="width: 300px;"></el-input>
</el-form-item>
<el-form-item label="附件数据">
<attachments :options="fillStoreImgOptions" v-model="fillStoreImg.attachments"></attachments>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submit">提交</el-button>
</el-form-item>
</el-form>
</div>
<!-- 终端报备查询 -->
<div v-if="dialog.title === '终端报备查询'">
<el-form
label-width="180px"
:model="deviceInfo.data">
<el-form-item label="代理商编号"><el-input v-model="deviceInfo.data.agentNo" style="width: 300px;" placeholder="请输入代理商编号"></el-input></el-form-item>
<el-form-item label="机构号"><el-input v-model="deviceInfo.data.orgCode" style="width: 300px;" placeholder="请输入机构号"></el-input></el-form-item>
<el-form-item label="商户号"><el-input v-model="deviceInfo.data.customerNo" style="width: 300px;" placeholder="请输入商户号"></el-input></el-form-item>
<el-form-item label="终端序列号"><el-input v-model="deviceInfo.data.posSn" style="width: 300px;" placeholder="请输入终端序列号"></el-input></el-form-item>
<el-form-item style="text-align: center;">
<el-button type="primary" @click="getDeviceInfo">查询</el-button>
</el-form-item>
</el-form>
</div>
<div v-if="dialog.title === '商户报备查询'">
<div>机构号{{ reportInfo.result.orgCode }}</div>
<div>代理商编号{{ reportInfo.result.agentNo }}</div>
<div>商户编号{{ reportInfo.result.externalCustomerNo }}</div>
<div>商户名称{{ reportInfo.result.customerName }}</div>
<div>操作类型{{ operationType(reportInfo.result.operationType)}}</div>
<div>报备结果{{ merStatusRes(reportInfo.result.merStatus) }}</div>
</div>
<bindSeparateReceiver v-if="dialog.title === '绑定' || dialog.title === '解绑' " :isUnbind="dialog.title === '绑定' " :merchantInfo="accountData" @closeDia="closeDia"></bindSeparateReceiver>
<!-- 修改结算信息 -->
<updateSettle v-if="dialog.title === '修改结算信息'" :merchantInfo="accountData" @closeDia="closeDia"></updateSettle>
<!-- 修改基础信息 -->
<updateBasic v-if="dialog.title === '修改基础信息'" :merchantInfo="accountData" @closeDia="closeDia"></updateBasic>
<!-- 实名认证 -->
<realNameAuth v-if="dialog.title === '实名认证'" :merchantInfo="accountData" @closeDia="closeDia"></realNameAuth>
<!-- 创建分账账户 -->
<createSepAcc v-if="dialog.title === '分账账户'" :merchantInfo="customerInfo" @closeDia="closeDia"></createSepAcc>
<!-- 提现金额 -->
<div v-if="dialog.title === '提现'">
<el-input v-model="drawAmt" style="width: 300px;" :placeholder="`请输入提现金额(单位:元)`" ></el-input>
<el-button type="primary" @click="withdraw" >确认提现</el-button>
</div>
</div>
</el-dialog>
</div>
</template>
<script>
import {
GetMerchantReportStatus,
GetMerchantTerminal,
EwalletWithdrawD1,
CheckIsUploadPhoto,
EwalletSettleQuery,
EwalletWithdrawQuery,
ImgSupplement,
WithdrawalList,
// SeparateQueryAmt,
SettleDrawPattern,
QueryBillBalance,
// UpdateBasicInfo,
SeparateQuery
} from '@/apis/lakala/lakala'
import attachments from '@/components/lklCmp/attachment'
import updateSettle from '@/components/lklCmp/updateSettle'
import updateBasic from '@/components/lklCmp/updateBasicInfo'
import realNameAuth from '@/components/lklCmp/realNameAuthNew'
import bindSeparateReceiver from '@/components/lklCmp/bindSeparateReceiver'
import createSepAcc from '@/components/lklCmp/createSepAcc'
import { hideLoad, showLoad } from '@/tools/loading'
import { filterObject } from '@/utils/index'
export default {
props:['accountData'],
components:{
attachments,
updateSettle,
updateBasic,
realNameAuth,
bindSeparateReceiver,
createSepAcc
},
data(){
return {
// 银联报备-商户报备查询
// 门店是否需要补充照片
reportInfo:{
data:{
customerNo:"", // externalCustomerNo
agentNo:"", // 代理商编号
orgCode:"983931", // 机构号
},
result:""
},
// 银联报备-终端报备查询
deviceInfo:{
data:{
agentNo:"",
orgCode:"983931",
customerNo:"", // externalCustomerNo
posSn:"47884567" // 机具序列号
},
result:""
},
drawAmt:"", // 0.00
isFillImg:"",
withdrawInfo:"",
fillStoreImg:{
attachments:[{
id:"merchant/null/20250701182426224749ID_CARD_FRONT.png",
type:"CHECKSTAND_IMG"
}],
extCustomerNo:""
},
fillStoreImgOptions:[
{
label:"收银台照片",
value:"CHECKSTAND_IMG"
},
{
label:'门头照片',
value:'SHOP_OUTSIDE_IMG'
},
{
label:"商铺内部照片",
value:"SHOP_INSIDE_IMG"
}
],
withdrawalData:{
data:{
merchantNo:"141429349",
drawJnl:"",
acctName:"",
startTime:"",
endTime:"",
separateNo:"",
offset:"0",
pageSize:"-1"
},
result:""
},
withdrawPattern:{
data:{
bmcpNo:"", // BMCP机构号 required
mercId:"", // 822商户号 或 receiveNo required
settleType:"", // 提款模式01主动提款 02余额自动结算 03交易自动结算
settleTime:"", // 余额自动结算时间(小时)- 默认值06。如08:00-09:00到账则传入08。 针对02余额自动结算生效
settleCircle:"", // 交易自动结算周期D1/T1(针对03交易自动结算生效)
payType:"", // 结算账户类型01收款账户 04 分账接收方账户) 针对02余额自动结算,03交易自动结算生效
// notifyUrl:"", // 提款通知URL 提款模式0203生效
retainedAmt:"", // 留存金额(单位:元) 提款模式02生效
remark:"", // 备注
summary:"", // 摘要
},
result:""
},
querySeparateAmt:{
merchantNo:"", // 银联商户号 822
logNo:"66222331035039",
vendorOrderId:"88492169496247",
logDate:"", // 拉卡拉对账单交易日期[yyyyMMdd]
result:""
},
// 账户余额查询
billBalanceInfo:{
merchantNo:"", // 银联商户号822
orgNo:"983931",
payType:"01", // 默认01
result:""
},
isOpenFillImg:false, // 补充照片
isOpenWithdrawPattern:0, // 提现模式
isOpenWithdrawalRecod:false, // 提现流水查询
customerInfo:"",
dialog:{ // 弹框信息
title:"",
dialogVisible:false
},
currentInfo:{
merchantInfo:""
},
}
},
watch:{
"withdrawPattern.data.settleType":{
handler(val){
if(val === '01'){
this.withdrawPattern.data.settleTime = ""
this.withdrawPattern.data.settleCircle = ""
this.withdrawPattern.data.payType = ""
this.withdrawPattern.data.retainedAmt = ""
}else if(val === '02'){
this.withdrawPattern.data.settleTime = ""
this.withdrawPattern.data.settleCircle = ""
this.withdrawPattern.data.payType = "06:00"
this.withdrawPattern.data.retainedAmt = "0"
}else if(val === '03'){
this.withdrawPattern.data.settleTime = ""
this.withdrawPattern.data.settleCircle = "D1"
this.withdrawPattern.data.payType = "06:00"
this.withdrawPattern.data.retainedAmt = ""
}
}
},
"isOpenFillImg":{
handler(val){
if(val) {
this.isOpenWithdrawPattern = 0
this.isOpenWithdrawalRecod = false
}
}
},
"isOpenWithdrawPattern":{
handler(val){
if(val) {
this.isOpenFillImg = false
this.isOpenWithdrawalRecod = false
}
}
},
"isOpenWithdrawalRecod":{
handler(val){
if(val) {
this.isOpenFillImg = false
this.isOpenWithdrawPattern = 0
}
}
},
"accountData":{
handler(val){
if(val && val.detail){
console.log('accountData',val)
this.customerInfo = val.detail.customer
}
},
deep:true,
immediate:true
},
// this.customerInfo.customerNo
"customerInfo":{
handler(val){
console.log('val,customerInfo,进件数据',val)
this.reportInfo.data.customerNo = val.externalCustomerNo
this.reportInfo.data.agentNo = val.agentNo
this.deviceInfo.data.customerNo = val.externalCustomerNo
this.deviceInfo.data.agentNo = '' + val.agentNo
this.deviceInfo.data.posSn = '' + val.posSn
this.fillStoreImg.extCustomerNo = val.externalCustomerNo
this.withdrawalData.data.merchantNo = val.externalCustomerNo + ''
this.withdrawPattern.data.mercId = val.externalCustomerNo // 822商户号 或 receiveNo
this.withdrawPattern.data.bmcpNo = '983931' // BMCP机构号
if(val.externalCustomerNo) this.storeIsFillImg() // 查询门店是否需要补充照片
this.billBalanceInfo.merchantNo = val.externalCustomerNo
this.queryBillBalanceBut()
this.querySeparateAmt.merchantNo = val.externalCustomerNo
// 查询商户分账信息
if(val.customerNo != '141698705') this.querySeparateMer(val.externalCustomerNo)
},
immediate:true,
deep:true
}
},
async created () {
// this.deviceStatus() // 获取银联报备状态
// 账管家余额查询
// this.queryBillBalanceBut()
},
methods:{
drawStatus(type){
let str = ""
switch (type){
case "DRAW.ACCEPTED":
str = "提款已受理"
break
case "DRAW.FREEZE":
str = "提款冻结"
break
case "DRAW.PROCESSING":
str = "提款处理中"
break
case "DRAW.SUCCESS":
str = "提款成功"
break
case "DRAW.FAILED":
str = "提款失败"
break
default:
str = "未知"
}
return str
},
// 分账商户查询
async querySeparateMer(merCupNo){
try {
let res = await SeparateQuery({
merInnerNo:merCupNo,
orgCode:"983931"
})
// this.isBindRec = res
this.customerInfo.separateReceiverInfo = res
console.log('分账商户查询',res)
} catch (error) {
hideLoad()
this.$message({
message:`查询分账接收方失败,${error}`,
type: 'error',
center:true
})
throw error
}
},
// 报备结果
merStatusRes(type){
let str = ""
switch (type){
case "SUCCESS":
str = "成功"
break
case "FAIL":
str = "失败"
break
case "U_SUCCESS":
str = "修改成功"
break
case "U_FAIL":
str = "修改失败"
break
case "D_SUCCESS":
str = "已注销"
break
default:
str = "未知"
}
return str
},
// 操作类型
operationType(type){
let str = ""
switch (type){
case "I":
str = "新增"
break
case "U":
str = "变更"
break
case "D":
str = "注销"
break
case "R":
str = "注销"
break
default:
str = "未知"
}
return str
},
// 修改基础信息
updateBasicInfoBut(){
this.dialog.title = '修改基础信息'
this.dialog.dialogVisible = true
},
// 修改结算信息
updateSettleInfo(){
this.dialog.title = '修改结算信息'
this.dialog.dialogVisible = true
},
// 账户余额类型
billBalanceStatus(type){
let str = ''
switch (type){
case "CLOSE":
str = "销户"
break
case "NORMAL":
str = "正常"
break
case "FREEZE":
str = "冻结"
break
case "STOPPAY":
str = "止付"
break
default:
str = "未知"
}
return str
},
// 账管家余额查询
async queryBillBalanceBut(e){
this.billBalanceInfo.result = ""
let res = await QueryBillBalance({
merchantNo:this.billBalanceInfo.merchantNo,
orgNo:"983931",
payType:e ? e : this.billBalanceInfo.payType // 账号类型
})
this.billBalanceInfo.result = res
console.log('查询余额后返回的结果',res)
},
// 关闭弹框的回调
closeDia(){
this.isOpenWithdrawalRecod = false
this.isOpenFillImg = false
this.dialog.dialogVisible = false
},
// 保存提款模式
async saveWithdrawPattern(formName){
this.$refs[formName].validate(async (valid) => {
if (valid) {
let obj = {
...this.withdrawPattern.data,
settleTime:this.withdrawPattern.data.settleTime.split(':')[0],
}
delete obj.ewalletId
obj = filterObject(obj)
let form = new FormData()
form.append('payload',JSON.stringify(obj))
let res = await SettleDrawPattern(form)
this.withdrawPattern.result = res
this.$message({
message: '修改成功',
type: 'success',
center: true
})
this.closeDia()
hideLoad()
}
});
},
// 提现流水查询
async queryWithdrawalNo(){
try {
let res = await WithdrawalList(this.withdrawalData.data)
this.withdrawalData.result = res
console.log('提现流水查询查询的数据',res)
} catch (error) {
console.log('error')
throw error
}
},
// 提现模式查询
async queryWithdrawPattern(){
try {
let res = await EwalletSettleQuery(this.customerInfo.externalCustomerNo,'983931')
console.log('查询提现模式的结果',res)
if(res){
// 为查询后的结果赋值
this.withdrawPattern.data = {
...res,
bmcpNo:'983931',
mercId: this.customerInfo.externalCustomerNo,
settleTime:res.settleTime + ':00',
remark:"",
summary:"",
retainedAmt:"" // 单位(元)
}
}
} catch (error) {
this.$message(error)
throw error
}
},
// 提现结果查询
async withdrawQuery(type){
try {
// console.log('type的值',type)
this.dialog.title = type
// EwalletSettleQuery 提现模式查询 / 修改
// EwalletWithdrawQuery 提现结果查询
// this.isOpenWithdrawPattern = type
// let res = ""
// if(type === '查询提现模式') await this.queryWithdrawPattern() // 提现模式查询
// else if(type === '修改提现模式' && !this.withdrawPattern.data.ewalletId) await this.queryWithdrawPattern()
// else if(type === '补充门店照片'){
// await this.storeIsFillImg() // 查看是否需要补充门店照片
// if(this.isFillImg = '暂无补充内容') return this.$toast('暂无补充的照片')
// }else if(type === "查询提现结果"){
// // 提现结果查询
// res = await EwalletWithdrawQuery({merchantNo:this.customerInfo.customerNo,orgNo:"983931",drawJnl:'111'})
// }
if(type === "提现模式") await this.queryWithdrawPattern() // 提现模式查询
else if(type === "查询提现结果") await this.queryEwalletRes()
else if(type === "补充门店照片") {
await this.storeIsFillImg() // 查看是否需要补充门店照片}
if(this.isFillImg = '暂无补充内容') return this.$toast('暂无补充的照片')
}
this.dialog.dialogVisible = true
} catch (error) {
console.log('withdrawQuery',error)
this.$message(error)
throw error
}
},
async queryEwalletRes(drawJnl = "250808175543727350749082"){
try {
console.log('this.customerInfo',this.customerInfo)
// let res = await EwalletWithdrawQuery({merchantNo:this.customerInfo.customerNo,orgNo:"983931",drawJnl:'250808180205525035679321'})
let res = await EwalletWithdrawQuery({merchantNo:this.customerInfo.externalCustomerNo,orgNo:"983931",drawJnl})
console.log('查询提现结果',res)
this.withdrawInfo = res
this.$message({
message:`查询成功,${res}`,
type:"success",
center:true
})
hideLoad()
} catch (error) {
hideLoad()
this.$message(error)
throw error
}
},
// 检查门店是否需要填充照片
async storeIsFillImg(){
try {
let res = await CheckIsUploadPhoto(this.customerInfo.externalCustomerNo)
this.isFillImg = '暂无补充内容'
if(res.isUploadPhoto === 'N') this.isFillImg = '请补充收银台照片'
if(res.isShopInside === 'N') this.isFillImg = this.isFillImg ? '商铺內部照片': '请补充商铺內部照'
if(res.isShopOutside === 'N') this.isFillImg = this.isFillImg ? '、门头照片': '请补充门头照片'
} catch (error) {
throw error
}
},
// 银联报备-商户报备查询
async deviceStatus(){
try {
// 获取银联报备状态
console.log(this.customerInfo,'银联报备,商户查询的参数',this.reportInfo.data)
let res = await GetMerchantReportStatus({
// externalCustomerNo:this.customerInfo.externalCustomerNo + '',
customerNo:this.customerInfo.externalCustomerNo + '',
agentNo:this.customerInfo.agentNo + '',
orgCode:this.reportInfo.data.orgCode + ''
})
console.log('res,,获取银联报备状态',res)
this.reportInfo.result = res || ""
this.$message({
message:`查询成功,${res}`,
type:"success",
center:true
})
this.withdrawQuery("商户报备查询")
hideLoad()
} catch (error) {
hideLoad()
this.$message(error)
throw error
}
},
// 获取终端设备信息
async getDeviceInfo(){
try {
console.log(this.deviceInfo,'打印终端设备信息',this.deviceInfo.result)
this.deviceInfo.result = await GetMerchantTerminal({
agentNo:'' + this.deviceInfo.data.agentNo,
orgCode:this.deviceInfo.data.orgCode,
customerNo:this.deviceInfo.data.customerNo,
posSn:this.deviceInfo.data.posSn || 'M3595962'
})
console.log('打印终端设备信息',this.deviceInfo.result)
this.$message({
message:`查询成功,${res}`,
type:"success",
center:true
})
hideLoad()
} catch (error) {
// console.log('error,GetMerchantTerminal',error)
hideLoad()
this.$message(error)
throw error
}
},
// D1提现
async withdraw(){
try {
if(+this.drawAmt > +this.billBalanceInfo.result.curBalance) return this.$toast(`超出提现范围,提现奖金额应小于等于${this.billBalanceInfo.result.curBalance}`)
showLoad()
console.log('提现',this.customerInfo)
let res = await EwalletWithdrawD1({
merchantNo:this.customerInfo.externalCustomerNo, // 822商户号SR分账接收方编号
orgNo:"983931",
payType:'01', // 分账接收方提现时需填04
drawAmt:this.drawAmt // 提现金额(单位:元)
// remark:"" // 备注
// summary:"" // 摘要
})
this.$message({
message:`D1提现次日到账请耐心等候`,
type:"success",
center:true
})
this.queryBillBalanceBut()
// console.log('提现结果查询',res)
} catch (error) {
hideLoad()
this.$message(error)
throw error
}
},
// 提交补充门店照片
async submit(){
try {
console.log('提交补充门店照片',this.fillStoreImg)
let json = {
extCustomerNo:this.fillStoreImg.extCustomerNo, // 外部商户号
attachments:[]
}
this.fillStoreImg.attachments.forEach(i => {
json.attachments.push({
imgType:i.type || "",
imgPath:i.id || "",
openplatformId:i.openplatformId || "",
showPath:i.showPath || ""
})
})
let form = new FormData()
form.append('payload',JSON.stringify(json))
let res = await ImgSupplement(form)
// console.log('提交补充门店的返回的数据0',res)
} catch (error) {
console.log('补充门店数据error',error)
this.$message({
message:`补充门店照片错误,${error}`,
type:'error',
center:true
})
throw error
}
}
}
}
</script>
<style lang="scss" scoped>
@import './index.scss';
</style>

View File

@@ -0,0 +1,164 @@
<template>
<el-form
label-width="180px"
label-position="right"
:model="businessLicense">
<el-form-item label="商户编号" required>
<el-input v-model="businessLicense.externalCustomerNo" style="width: 300px;" :disabled="true"></el-input>
</el-form-item>
<el-form-item label="营业执照号" required>
<el-input v-model="businessLicense.merBlis" placeholder="请输入营业执照号" style="width: 300px;"></el-input>
</el-form-item>
<el-form-item label="营业执照名称" required>
<el-input v-model="businessLicense.merBlisName" placeholder="请输入营业执照名称" style="width: 300px;"></el-input>
</el-form-item>
<el-form-item label="营业执照有效期" required>
<el-date-picker
style="width:300px"
v-model="businessLicense.merBlisExpDt"
type="date"
value-format="yyyy-MM-dd"
placeholder="无限不填">
</el-date-picker>
</el-form-item>
<el-form-item label="法人姓名">
<el-input v-model="businessLicense.larName" placeholder="请输入法人姓名" style="width: 300px;"></el-input>
</el-form-item>
<el-form-item label="法人证件号码">
<el-input v-model="businessLicense.larIdcard" placeholder="请输入法人证件号码" style="width: 300px;"></el-input>
</el-form-item>
<el-form-item label="法人证件有效期">
<el-date-picker
style="width:300px"
v-model="businessLicense.larIdcardExpDt"
type="date"
value-format="yyyy-MM-dd"
placeholder="无限不填">
</el-date-picker>
</el-form-item>
<el-form-item label="附件数据">
<attachment :options="businessLicense.other.options" v-model="businessLicense.fileData"></attachment>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitLicence">提交</el-button>
</el-form-item>
</el-form>
</template>
<script>
import {
queryCityCode,
QueryBankList,
MerchantIncoming,
QueryCustomerCategory,
QueryIncoming,
GetMerchant,
UnionPayMerInfo,
SupplementBusinessLicense,
LaKaLaApplyContract,
QueryElectronicContract,
QueryApplyContractList,
GetCardBin
} from '@/apis/lakala/lakala'
import attachment from '@/components/lklCmp/attachment'
import { hideLoad, showLoad } from '@/tools/loading'
export default {
props:['merchantInfo'],
components:{
attachment
},
data(){
return {
businessLicense:{
externalCustomerNo:"", // 外部商户编号
merBlis:"",
merBlisExpDt:"",
larName:"",
larIdcard:"",
larIdcardExpDt:"",
fileData:[], // imgPath imgType showPath
other:{
options:[
{
label:"身份证正面",
value:"ID_CARD_FRONT"
},
{
label:'身份证反⾯',
value:'ID_CARD_BEHIND'
},
{
label:"营业执照照⽚",
value:"BUSINESS_LICENCE"
}
]
}
},
}
},
watch:{
"merchantInfo":{
handler(val){
if(val && val.detail) this.businessLicense.externalCustomerNo = val.detail.customer.externalCustomerNo
},
immediate:true,
deep:true
}
},
methods:{
// 更改营业执照信息
async submitLicence(){
try {
showLoad()
let json = {
...this.businessLicense,
merBlisExpDt:this.businessLicense.merBlisExpDt ? this.businessLicense.merBlisExpDt : '9999-12-31',
larIdcardExpDt:this.businessLicense.larIdcardExpDt ? this.businessLicense.larIdcardExpDt : '9999-12-31'
}
delete json.other
if(this.businessLicense.fileData && this.businessLicense.fileData.length>0){
this.businessLicense.fileData.forEach(i => {
json.fileData.push({
imgPath:i.id ? i.id : i.imgPath,
imgType:i.type ? i.type : i.imgType,
showPath:i.showPath
})
})
}
let form = new FormData()
form.append('payload',JSON.stringify(json))
console.log('更新营业执照信息',json)
this.$message({
message: `添加成功,${res}`,
type: 'success',
center: true
})
let res = await SupplementBusinessLicense(form)
// console.log('更改营业执照信息*返回的数据0',res)
this.$emit('closeDia')
hideLoad()
} catch (error) {
// console.log('更改营业执照信息error',error)
hideLoad()
this.$message({
message:`${error}`,
type: 'error',
center:true
})
throw error
}
},
}
}
</script>

View File

@@ -0,0 +1,135 @@
<template>
<!-- <div style="width: 500px;margin:0 auto;"> -->
<el-form
label-width="180px"
:model="electron">
<el-form-item label="申请说明">
<el-input v-model="electron.apply_desc" placeholder="请输入反馈说明" style="width: 300px;"></el-input>
</el-form-item>
<el-form-item label="电子合同编号">
<el-input v-model="electron.ec_apply_id" placeholder="请输入反馈说明" style="width: 300px;"></el-input>
</el-form-item>
<el-form-item label="附件信息集合">
<!-- :jxStoreInfo="electron.proofMaterial" -->
<attachment
:isGetBase64="true"
:options="[
{label:'法人身份证正面',value:'FR_ID_CARD_FRONT'},
{label:'法人身份证反面',value:'FR_ID_CARD_BEHIND'},
{label:'身份证正⾯(同法人结算可不传)',value:'ID_CARD_FRONT'},
{label:'身份证反⾯(同法人结算可不传)',value:'ID_CARD_BEHIND'},
{label:'银行卡(必传)',value:'BANK_CARD'},
{label:'营业执照(企业必传,小微商户可不传)',value:'BUSINESS_LICENCE'},
// {label:'商户门头照(必传)',value:'MERCHANT_PHOTO'},
// {label:'商铺内部照片(必传)',value:'SHOPINNER'},
// {label:'线下纸质协议(线下签署,上传电子附件类型)',value:'XY'},
// {label:'电子协议',value:'NETWORK_XY'},
// {label:'租赁合同(报名教培优惠需要上传)',value:'HT'},
// {label:'合作资质证明',value:'COOPERATION_QUALIFICATION_PROOF'},
// {label:'食品经营相关资质',value:'FOOD_QUALIFICATION_PROOF'},
// {label:'联系人证件正面照片',value:'CONTACT_ID_DOC_COPY'},
// {label:'联系人证件反面照片',value:'CONTACT_ID_DOC_COPY_BACK'},
// {label:'其他',value:'OTHERS'},
]"
v-model="electron.file_data">
</attachment>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitFeedBack">提交人工审核</el-button>
</el-form-item>
</el-form>
<!-- </div> -->
</template>
<script>
import { hideLoad } from '@/tools/loading'
import attachment from '@/components/lklCmp/attachment'
import {
LaKaLaApplyContractByPeople
} from '@/apis/lakala/lakala'
export default {
props:['currentRow'],
components:{
attachment
},
data(){
return {
electron:{
apply_desc:"",
ec_apply_id:"",
file_data:[]
}
}
},
watch:{
currentRow:{
handler(val){
console.log('currentRow',val)
if(val){
this.electron.ec_apply_id = val.contractApplyId
}
}
}
},
methods:{
// 电子合同反馈,人工复核
async submitFeedBack(){
try {
// let res = {"code":"000000","msg":"成功","resp_data":{"order_no":"202507231106198332117026","ec_apply_id":1000358200623259648,"result_url":"https://esign.lakala.com/signature/s/463nhryuua4dut97?rdm=1753239981471"}}
// let res = {"code":"087900","msg":"2001认证不一致","resp_data":{"order_no":"202508141625017526779874","ec_apply_id":1008410934211735552,"result_url":""}}
let file_data = []
this.electron.file_data.forEach(i => {
file_data.push({
attach_type:i.attType,
attach_name:i.attachName,
attach_ext_name:i.attExtName,
attach_store_path:i.attFileId
})
})
let payload = JSON.stringify({
version:"1.0",
order_no:this.currentRow.contractId || "",
org_id:983931,
ec_apply_id:this.electron.ec_apply_id,
apply_desc:this.electron.data.apply_desc,
file_data
})
// 将ec_apply_id转化为长整型
let findIndex = payload.indexOf('ec_apply_id')
let newStr = payload.substring(0,findIndex+13) +payload.substring(findIndex+13 + 1,findIndex+13 + this.electron.ec_apply_id.length +1) + payload.substring(findIndex+13 + this.electron.ec_apply_id.length+1 +1)
// console.log('newStr','newStr3',newStr,'JSON',JSON.parse(newStr))
// {"order_no":"202508281435228400125682","org_id":"983931","ec_apply_id":1013456771342118912,"apply_desc":"信息一致","file_data":[{"attach_type":"FR_ID_CARD_FRONT","attach_name":"身份证正面.png","attach_ext_name":"png","attach_store_path":"MMS/20250828/172420-865c8f87621149d7890296fa290586a2.png"},{"attach_type":"FR_ID_CARD_BEHIND","attach_name":"身份证反面.png","attach_ext_name":"png","attach_store_path":"MMS/20250828/172445-b3394ff727464f309508df942644d89b.png"},{"attach_type":"BANK_CARD","attach_name":"银行卡.jpg","attach_ext_name":"jpg","attach_store_path":"MMS/20250828/172508-318661b2a1f347efa0db764565efb45e.jpg"}]}
let form = new FormData()
form.append("storeID",this.jxStoreInfo.storeID)
form.append("payload",newStr)
console.log(newStr,'反馈电子合同编号的参数',this.electron,'JOSN',JSON.parse(newStr),'payload',payload)
let res = await LaKaLaApplyContractByPeople(form) // 拉卡拉合同申请人工复核
console.log('申请成功返回的参数信息',res)
hideLoad()
this.$message({
message: `申请成功,待复核${res}`,
type: "success",
center: true,
});
// }
// QueryElectronicContract 查询合同申请状态
// QueryApplyContractList 门店合同申请记录查询
// LaKaLaApplyContractByPeople 拉卡拉合同申请人工复核
} catch (e) {
hideLoad()
this.$message(e)
throw e
}
}
}
}
</script>
<style lang="scss" scoped>
@import './index.scss';
</style>

View File

@@ -0,0 +1,409 @@
<template>
<div>
<div v-for="(item,index) in attrData" :key="index" style="margin: 10px;">
<div style="display: flex;">
<div style="width: 22px;">{{ index + 1 }}</div>
<div style="">
<!-- 类型 -->
<el-select v-model ="item.imgType" filterable style="width: 278px;margin-bottom: 20px;" placeholder="请选择文件类型">
<el-option
v-for="item in options"
:label="item.label"
:value="item.value"
:key="item.value">
</el-option>
</el-select>
<!-- 来源 -->
<el-select v-model ="item.sourcechnl" filterable style="width: 278px;margin-bottom: 20px;" placeholder="请选择文件来源">
<el-option
v-for="item in sourcechnl"
:label="item.label"
:value="item.value"
:key="item.value">
</el-option>
</el-select>
<!-- 5M以内 jpgpngpdf :disabled="!(item.sourcechnl && item.imgType)" 加上禁用 连删除都没了 -->
<jx-upload-file
:listType="'picture-card'"
:autoUpload="true"
:imgType="['image/jpeg','image/png','application/pdf']"
:disabled="!(item.sourcechnl && item.imgType)"
:drag="true"
:width="278"
:height="139"
:imgSize="5"
:isGetBase64="isGetBase64"
v-model="item.img"
@onChange="attachmentFileChange"
@onRemove="removeFile"
>
<div class="el-upload__text" >拖拽<em>excel</em>到此处或点击选择文件上传</div>
</jx-upload-file>
</div>
<div style="margin-left:20px;" v-if="index === attrData.length - 1" @click="addAttr">
<i class="el-icon-circle-plus"></i>
</div>
<div style="margin-left:20px;" v-if="attrData.length !==1" @click="delAttr(index)">
<i class="el-icon-remove" style="color:#ff0000"></i>
</div>
</div>
</div>
</div>
</template>
<script>
import jxUploadFile from '@/components/cmp/uploadFile'
import {
UploadImg,
UploadAttachmentImg
} from '@/apis/lakala/lakala'
import {showLoad, hideLoad} from '@/tools/loading'
export default {
props:{
"value":{
type:Array
},
"options":{
type:Array,
default:() => [
{
label:'身份证正⾯(必传)',
value:'ID_CARD_FRONT'
},
{
label:'身份证反⾯(必传)',
value:'ID_CARD_BEHIND'
},
{
label:'营业执照照⽚(企业必传)',
value:'BUSINESS_LICENCE'
},
{
label:'银行卡(对私必传,企业对公传)',
value:'BANK_CARD'
},
{
label:'协议(入网协议必传)',
value:'AGREE_MENT'
},
{
label:'开户许可证(企业对公需要传,对私不传)',
value:'OPENING_PERMIT'
},
{
label:'收银台照片(必传)',
value:'CHECKSTAND_IMG'
},
{
label:'上传门头照片(必传)',
value:'SHOP_OUTSIDE_IMG'
},
{
label:'商铺内部照片(必传)',
value:'SHOP_INSIDE_IMG'
},
{
label:'其他 无对应类型图片,请传其他类型',
value:'OTHERS'
},
{
label:'结算人身份证人像面',
value:'SETTLE_ID_CARD_FRONT'
},
{
label:'结算人身份证国徽面',
value:'SETTLE_ID_CARD_BEHIND'
},
{
label:'法人授权涵',
value:'LETTER_OF_AUTHORIZATION'
}
]
},
"isGetBase64":{
type:Boolean,
default:false
},
"jxStoreInfo":{
type:[String,Object],
// default:{}
}
},
components: {
jxUploadFile
},
data(){
return {
sourcechnl:[
{
label:'PC',
value:'0'
},
{
label:'安卓',
value:'1'
},
{
label:'IO',
value:'2'
}
],
// attchments:[{id:"merchant/null/20250709164133401133ID_CARD_FRONT.jpg",type:"ID_CARD_FRONT"}],
attchments:[{id:"",type:""}],
// attchments:[
// {id:"merchant/null/20250718110516555032ID_CARD_FRONT.jpg",type:"ID_CARD_FRONT"},
// {id:"merchant/null/20250718110625085745ID_CARD_BEHIND.jpg",type:"ID_CARD_BEHIND"},
// {id:"merchant/null/20250718110735475782BUSINESS_LICENCE.jpg",type:"BUSINESS_LICENCE"},
// {id:"merchant/null/20250718110904178219BANK_CARD.jpg",type:"BANK_CARD"},
// {id:"merchant/null/20250718111027639024AGREE_MENT.pdf",type:"AGREE_MENT"},
// {id:"merchant/null/20250718111117089939CHECKSTAND_IMG.jpg",type:"CHECKSTAND_IMG"},
// {id:"merchant/null/20250718111232248444SHOP_OUTSIDE_IMG.jpg",type:"SHOP_OUTSIDE_IMG"},
// {id:"merchant/null/20250718111331265578SHOP_INSIDE_IMG.jpg",type:"SHOP_INSIDE_IMG"},
// ],
// attchments:[],
attrData:[{imgType:"",img:"",sourcechnl:"",uploadInfo:""}]
// {attrType:"BANK_CARD",img:"https://image.jxc4.com/image/a1a2dd6139b13c4145456914a6f0cd2e.png",sourcechnl:""}
// attrData:[
// {imgType:"ID_CARD_FRONT",img:"https://image.jxc4.com/image/02281544a71de46b56b8fa9ca54fb3a8.jpg",sourcechnl:"0"},
// {imgType:"ID_CARD_BEHIND",img:"https://image.jxc4.com/image/59b74acdcd8c53f470f24c8d2764c23e.jpg",sourcechnl:"0"},
// {imgType:"BUSINESS_LICENCE",img:"https://image.jxc4.com/image/cdf5bb464ceb9f509bb44723948c4c6b.jpg",sourcechnl:"0"},
// {imgType:"CHECKSTAND_IMG",img:"https://image.jxc4.com/image/35ac627a0525934c1b1c504ac29e9e39.jpg",sourcechnl:"0"},
// {imgType:"SHOP_OUTSIDE_IMG",img:"https://image.jxc4.com/image/5446918f753ceb8b12e510b8794fc9b8.jpg",sourcechnl:"0"},
// {imgType:"SHOP_INSIDE_IMG",img:"https://image.jxc4.com/image/5446918f753ceb8b12e510b8794fc9b8.jpg",sourcechnl:"0"},
// ]
// attrData:[
// {imgType:"ID_CARD_FRONT",img:"https://image.jxc4.com/image/477873f7c190440aac9cb6c489783dae.jpg",sourcechnl:"0"},
// {imgType:"ID_CARD_BEHIND",img:"https://image.jxc4.com/image/316167f93d4752e52cf2f71b25e19a0e.jpg",sourcechnl:"0"},
// {imgType:"BUSINESS_LICENCE",img:"https://image.jxc4.com/image/1f2a1ae58d417c47f1bbf99c303a5123.jpg",sourcechnl:"0"},
// {imgType:"BANK_CARD",img:"https://image.jxc4.com/image/1845f3818084281546e0565627e7f7a5.jpg",sourcechnl:"0"},
// {imgType:"AGREE_MENT",img:"https://image.jxc4.com/image/fa1302a4bd97df511882e42698616a85.pdf",sourcechnl:"0"},
// {imgType:"CHECKSTAND_IMG",img:"https://image.jxc4.com/image/d7801b25c5f0e0d4118b5731bb63cbb6.jpg",sourcechnl:"0"},
// {imgType:"SHOP_OUTSIDE_IMG",img:"https://image.jxc4.com/image/1e19016dfba3965bdeb1d1887e1b1044.jpg",sourcechnl:"0"},
// {imgType:"SHOP_INSIDE_IMG",img:"https://image.jxc4.com/image/1700a33db73661878c5a062c9b0df5e8.jpg",sourcechnl:"0"},
// ]
// attrData:[{imgType:"CHECKSTAND_IMG",img:"https://image.jxc4.com/image/482dedde7bd6efcafb1ea0bdd27a75d6.jpg",sourcechnl:""},{attrType:"BANK_CARD",img:"https://image.jxc4.com/image/a1a2dd6139b13c4145456914a6f0cd2e.png",sourcechnl:""}]
// attrData:[{imgType:"",img:"https://image.jxc4.com/image/417733225e67cfd79cea3dd4beec1ad4.jpg",sourcechnl:"",uploadInfo:""}]
}
// attchments
// "https://image.jxc4.com/image/477873f7c190440aac9cb6c489783dae.jpg" "merchant/null/20250718110516555032ID_CARD_FRONT.jpg" "ID_CARD_FRONT" sourcechnl:0
// "https://image.jxc4.com/image/316167f93d4752e52cf2f71b25e19a0e.jpg" ""ID_CARD_BEHIND"" "merchant/null/20250718110625085745ID_CARD_BEHIND.jpg" sourcechnl:0
// "https://image.jxc4.com/image/1f2a1ae58d417c47f1bbf99c303a5123.jpg" "BUSINESS_LICENCE" "merchant/null/20250718110735475782BUSINESS_LICENCE.jpg"
// "https://image.jxc4.com/image/1845f3818084281546e0565627e7f7a5.jpg" "merchant/null/20250718110904178219BANK_CARD.jpg "BANK_CARD"
// "https://image.jxc4.com/image/fa1302a4bd97df511882e42698616a85.pdf" "AGREE_MENT" "merchant/null/20250718111027639024AGREE_MENT.pdf"
// "https://image.jxc4.com/image/d7801b25c5f0e0d4118b5731bb63cbb6.jpg" "CHECKSTAND_IMG" "merchant/null/20250718111117089939CHECKSTAND_IMG.jpg"
// "https://image.jxc4.com/image/1e19016dfba3965bdeb1d1887e1b1044.jpg" "SHOP_OUTSIDE_IMG" "merchant/null/20250718111232248444SHOP_OUTSIDE_IMG.jpg"
// "https://image.jxc4.com/image/1700a33db73661878c5a062c9b0df5e8.jpg" "SHOP_INSIDE_IMG" "merchant/null/20250718111331265578SHOP_INSIDE_IMG.jpg"
},
watch:{
attchments:{
handler(val){
this.$emit("input",val)
},
deep:true
},
jxStoreInfo:{
handler(val){
if(val && val.stores && val.stores.length>0){
let storeInfo = val.stores[0]
// console.log('jxStoreInfo',storeInfo)
// if(storeInfo.idCardFront) this.addFile(storeInfo.idCardFront,'FR_ID_CARD_FRONT') // 法人身份证正面
// if(storeInfo.idCardBack) this.addFile(storeInfo.idCardBack,'FR_ID_CARD_BEHIND') // 法人身份证正面
// if(storeInfo.licence) this.addFile(storeInfo.idCardBack,'BUSINESS_LICENCE') // 法人身份证正面
// this.storeInfo.idCardFront // 法人身份证正面 FR_ID_CARD_FRONT
// this.storeInfo.idCardBack // 法人身份证正面 FR_ID_CARD_BEHIND
// BANK_CARD
// this.storeInfo.licence // 营业执照 BUSINESS_LICENCE
// return
// console.log('val,,,,,jxStoreInfo',storeInfo)
//
if(storeInfo.idCardFront) this.addFile(storeInfo.idCardFront,'ID_CARD_FRONT') // 法人身份证正面
if(storeInfo.idCardBack) this.addFile(storeInfo.idCardBack,'ID_CARD_BEHIND') // 法人身份证正面
if(storeInfo.storeFrontPic) this.addFile(storeInfo.storeFrontPic,'SHOP_OUTSIDE_IMG') // 门面照
// if(storeInfo.storeFrontPic) this.addFile(storeInfo.idCardBack,'SHOP_OUTSIDE_IMG') // 收银台照片
if(storeInfo.storeInPic) this.addFile(storeInfo.storeInPic,'SHOP_INSIDE_IMG') // 门店内照片
if(storeInfo.licence && storeInfo.licenceType === 1) this.addFile(storeInfo.licence,'BUSINESS_LICENCE') // 营业执照照片(企业)
// if(storeInfo.licence) this.addFile(storeInfo.licence,'BUSINESS_LICENCE') // 营业执照照片(企业)
// // storeInfo.idCardFront || "" // 身份证正面
// // storeInfo.idCardBack || "" // 身份证正面
// // storeInfo.storeFrontPic || "" // 门面照
// // storeInfo.storeInPic || "" // 门店内照片
// // storeInfo.licence2Image || "" // 食品经营许可证
// // storeInfo.licence || "" // 营业执照照片
// console.log('打印门店信息',storeInfo)
// if(storeInfo.idCardFront){}
}
},
immediate:true
},
// options:{
// handler(val){
// if(val && val.length>0){
// console.log('监听options的值',val)
// }
// },
// immediate:true
// }
// attrData:{
// handler(val){
// val.forEach(async element => {
// console.log(element,'val,,,9999',element.imgType)
// if(!element.uploadInfo && element.imgType && element.img && element.sourcechnl){
// let form = new FormData()
// form.append('file',element.img)
// form.append('imgType',element.imgType)
// form.append('sourcechnl',element.sourcechnl)
// let res = await UploadImg(form)
// this.attchments.push({
// id:res.url || "",
// type:element.imgType
// })
// }
// });
// },
// deep:true
// }
},
created(){
// // this.attachmentFileChange()
// setTimeout(() => {
// this.attrData.forEach(element => {
// element.img = 'https://image.jxc4.com/image/02281544a71de46b56b8fa9ca54fb3a8.jpg'
// });
// })
// https://image.jxc4.com/image/1113986d03d1133ecee14d57a0e5fa6f.pdf PDF 入网协议
},
methods:{
// 新增文件
addFile(url,type){
// console.log(type,'url',url,'isGetBase64',this.isGetBase64)
if(this.attrData.length === 1 && !this.attrData[0].img){
this.attrData = [{
imgType:type,
img:url,
sourcechnl:"0",
uploadInfo:""
}]
}else{
this.attrData.push({
imgType:type,
img:url,
sourcechnl:"0",
uploadInfo:""
})
}
this.attachmentFileChange([{url:url,raw:[{name:""}]}])
},
// 新增附件类别
addAttr(){
this.attrData.push({attrType:"",img:"",uploadInfo:""})
},
// 删除附件类别
delAttr(index){
this.attrData = this.attrData.slice(0,index).concat(this.attrData.slice(index+1))
this.attchments = this.attchments.slice(0,index).concat(this.attchments.slice(index+1))
// this.$emit('attachmentFileChange',this.attchments)
// console.log(this.attchments,'删除附件类别',index)
},
async attachmentFileChange(file){
console.log(file,'attrData',this.attrData)
try {
showLoad()
if(!this.isGetBase64){
if(file){
let findIndex = this.attrData.findIndex(item => item.img === file[0].url)
if(findIndex === -1) return
let findItem = this.attrData[findIndex]
// console.log(this.attrData,'findItem',findItem)
// debugger
let form = new FormData()
form.append('file',findItem.img)
form.append('imgType',findItem.imgType)
form.append('sourcechnl',findItem.sourcechnl)
let res = await UploadImg(form,true)
// console.log('文件上传失败的数据',res)
if(res.status ==="00" && res.url){
// 兼容已写好的部分
if(!this.attchments[0].id) this.attchments = []
// this.attchments = []
this.attchments.push({
...res,
id:res.url || "",
type:findItem.imgType,
imgType:findItem.imgType,
sourcechnl:findItem.sourcechnl,
fileName:file[0].raw.name
})
// this.attrData[findIndex].uploadInfo = res
}else{
let findItem = this.options.find(i => i.value === findItem.imgType)
this.$message({
message:`${findItem ? findItem.label : ''}文件上传失败,请重试`,
type: 'error',
center: true
})
}
this.attrData[findIndex].uploadInfo = res
// console.log(this.attchments,'this.attchments',this.attrData)
}
}else{
let findIndex = this.attrData.findIndex(item => item.img == file.file.url )
let form = new FormData()
form.append('orgCode','983931')
form.append('attExtName',file.attExtName) // jpgpngpdf
form.append('attType',this.attrData[findIndex].imgType)
form.append('attContext',file.attContext) // Base64Utils.encodeToString()
// console.log('file的信息999',file)
// console.log(file.attExtName,'上传文件的类型',this.attrData[findIndex])
let res = await UploadAttachmentImg(form)
if(res && res.attFileId){
// this.attchments = this.attchments.length === 1 ? [] : this.attchments
if(this.attchments.length === 1 && !this.attchments[0].id) this.attchments = []
this.attchments.push({
...res,
id:res.attFileId,
type:this.attrData[findIndex].imgType,
attExtName:file.attExtName,
attachName:file.fileName, // 附件名称
attachType:res.attType, // 附件类型编码
attachStorePath:res.attFileId, // 附件路径
})
// console.log(file,'上传成功的信息,9999999999999',res,'this.attchments',this.attchments)
}else{
// console.log('文件上传失败,请重试',this.isGetBase64)
this.$message({
message:'文件上传失败,请重试',
type: 'error',
center: true
})
}
}
hideLoad()
} catch (error) {
hideLoad()
// console.log('上传文件错误',error)
this.$message({
message: `上传错误,请重新上传${error}`,
type: 'error',
center: true
})
throw error
}
},
// 移除的文件信息
removeFile(e){
console.log('e',e)
}
}
}
</script>

View File

@@ -0,0 +1,213 @@
<template>
<el-form
label-width="180px"
label-position="right"
:model="applyBind"
>
<!-- <el-form-item label="内部商户号" required>
<el-input v-model="applyBind.merInnerNo" placeholder="请输入内部商户号" style="width: 300px;" :disabled="true"></el-input>
</el-form-item> -->
<el-form-item label="商户银联商户号" required >
<el-input v-model="applyBind.merCupNo" placeholder="请输入商户银联商户号" style="width: 300px;" :disabled="true"></el-input>
</el-form-item>
<el-form-item label="分账接收方编号" required >
<!-- <el-input v-model="applyBind.receiverNo" placeholder="请输入内部商户号" style="width: 300px;" ></el-input> -->
<el-select
v-model="applyBind.receiverNo"
style="width: 300px;"
placeholder="请选择分账接收方"
:disabled="true">
<el-option
v-for="item in separateRecList"
:key="item.receiverNo"
:label="item.receiverName + item.receiverNo"
:value="item.receiverNo">
</el-option>
</el-select>
</el-form-item>
<el-form-item :label="isUnbind ? '合作协议附件名称' : '解除分账说明附件名称'" required>
<el-input v-model="applyBind.entrustFileName" placeholder="上传附件,自动生成" :disabled="true" style="width: 300px;"></el-input>
<br/>
</el-form-item>
<el-form-item :label="isUnbind ? '合作协议附件路径' : '解除分账说明附件路径'" required>
<el-input v-model="applyBind.entrustFilePath" placeholder="上传附件,自动生成" :disabled="true" style="width: 300px;"></el-input>
</el-form-item>
<a v-if="isUnbind" href="https://www.jxc4.com/download/%E9%97%A8%E5%BA%97%E5%90%88%E4%BD%9C%E5%8D%8F%E8%AE%AE.docx" target="_black">下载门店合作协议</a>
<el-form-item label="附件">
<attachment :isGetBase64="true" :options="lklDataList.applyOptions" v-model="applyBind.attachments"></attachment>
</el-form-item>
<el-form-item label="备注" v-if="!isUnbind" required>
<el-input v-model="applyBind.remark" placeholder="请输入备注" style="width: 300px;"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="applyBindBut">{{isUnbind ? '申请绑定' : '解绑'}}</el-button>
</el-form-item>
</el-form>
</template>
<script>
import { hideLoad, showLoad } from '@/tools/loading'
import attachment from '@/components/lklCmp/attachment'
import {
ApplyBind,
SeparateUnBind,
GetRecipient,
SeparateQuery
} from '@/apis/lakala/lakala'
import { lklOrderNo } from '@/utils/index'
export default {
props:["merchantInfo","isUnbind"],
components:{
attachment
},
data () {
return {
applyBind:{
version:"1.0",
orgCode:"983931",
orderNo:"",
// merInnerNo:"", // 分账商户内部商户号 merCupNo 与 merInnerNo 二选一
merCupNo:"", // 分账商户银联商户号 merCupNo 与 merInnerNo 二选一
receiverNo:"SR2024000117507", // 分账接收方编号
entrustFileName:"", // 门店合作协议 / 解除分账说明附件名称
entrustFilePath:"", // 门店合作协议 / 解除分账说明附件路径
attachments:[],
},
// isUnbind:false,
lklDataList:{
applyOptions:[
{
label:'其他(集市媒体公吿信息 / 门店合作协议)',
value:'OTHERS'
}
]
},
separateRecList:[{
receiverNo:"SR2024000117507",
receiverName:"成都若溪科技有限公司"
}],
isBindRec:""
}
},
watch:{
merchantInfo:{
handler(val){
if(val && val.detail){
let customer = val.detail.customer
this.applyBind.merInnerNo = customer.merInnerNo
this.applyBind.merCupNo = customer.externalCustomerNo
this.querySeparateRec(this.applyBind.merCupNo)
}
console.log('val,,,999****',val)
if(val && val.separateReceiverInfo){
// 绑定若溪科技的账号
this.applyBind.receiverNo = val.separateReceiverInfo.receiverNo
this.applyBind.remark = '' // 备注说明
}
// if(val && val.isUpdate.length>0) this.isUnbind = val.isUpdate
},
immediate:true,
deep:true
},
"applyBind.attachments":{
handler(val){
if(val && val.length){
this.applyBind.entrustFileName = val[0].attachType
this.applyBind.entrustFilePath = val[0].attachStorePath
}
}
}
},
async created(){
this.querySeparateRec()
},
// computed:{
// isUpdate(){
// return this.isUnbind
// }
// },
methods:{
// 查询分账接收方列表
async querySeparateRec(){
try {
let res = await GetRecipient({
orgCode:'983931',
offset:0,
pageSize:-1
})
this.separateRecList = res.data
console.log(this.separateRecList,'查询分账接收方列表',res)
} catch (error) {
hideLoad()
this.$message({
message:`查询分账接收方失败,${error}`,
type: 'error',
center:true
})
throw error
}
},
// 绑定 / 解绑
async applyBindBut(){
try {
showLoad()
let json = JSON.parse(JSON.stringify(this.applyBind))
json.orderNo = lklOrderNo(new Date())
if(this.applyBind.attachments && this.applyBind.attachments.length>0){
json.attachments = []
this.applyBind.attachments.forEach(element => {
json.attachments.push({
attachType:element.attachType,
attachName:element.attachName,
attachStorePath:element.attachStorePath,
})
});
}
let res = ""
if(!this.isUnbind){
let form = new FormData()
form.append('payload',JSON.stringify(json))
// console.log('申请解绑的参数',json)
res = await SeparateUnBind(form)
this.$message({
message: `申请解绑成功,待审核${res}`,
type: 'success',
center: true
})
console.log('申请解绑的结果',res)
}else{
// delete json.attachments
// console.log('申请绑定的参数',json)
let form = new FormData()
form.append('payload',JSON.stringify(json))
res = await ApplyBind(form)
this.$message({
message: `绑定成功,待审核${res}`,
type: 'success',
center: true
})
console.log('申请绑定的结果',res)
}
this.$emit('closeDia')
hideLoad()
} catch (error) {
hideLoad()
this.$message({
message:`${error}`,
type: 'error',
center:true
})
throw error
}
},
}
}
</script>

View File

@@ -0,0 +1,317 @@
<template>
<div>
<div style="margin-bottom: 20px;display: flex;justify-content: center;align-items: center;font-weight: bold;font-size: 28px;">{{ isUpdate ? "修改分账账户" : "创建分账账户" }}</div>
<el-form
label-width="180px"
label-position="right"
:model="separateAccount">
<!-- <el-form-item label="内部商户号">
<el-input v-model="separateAccount.merInnerNo" style="width: 300px;" placeholder="商户号与银联商户商户选填其一" :disabled="true"></el-input>
</el-form-item> -->
<el-form-item label="银联商户号">
<el-input v-model="separateAccount.merCupNo" style="width: 300px;" placeholder="商户号与银联商户商户选填其一" :disabled="true"></el-input>
</el-form-item>
<el-form-item label="联系手机号" required>
<el-input v-model="separateAccount.contactMobile" style="width: 300px;" placeholder="请填写手机号"></el-input>
</el-form-item>
<el-form-item label="最低分账比例" required>
<el-input v-model="separateAccount.splitLowestRatio" style="width: 300px;" placeholder="请填写最低分账比例"></el-input>
</el-form-item>
<el-form-item label="分账结算委托书文件名称" :required="!isUpdate">
<el-input v-model="separateAccount.splitEntrustFileName" style="width: 300px;" placeholder="上传结算授权委托书.pdf自动生成文件名" :disabled="true"></el-input>
</el-form-item>
<el-form-item label="分账结算委托书文件路径" :required="!isUpdate">
<el-input v-model="separateAccount.splitEntrustFilePath" style="width: 300px;" placeholder="上传结算授权委托书.pdf自动生文件路径" :disabled="true"></el-input>
</el-form-item>
<!-- 下载结算授权委托书 -->
<a href="https://www.jxc4.com/download/%E6%B8%85%E5%88%86%E7%BB%93%E7%AE%97%E6%8E%88%E6%9D%83%E5%A7%94%E6%89%98%E4%B9%A6.doc" target="_black">下载结算授权委托书</a>
<el-form-item label="附加资料">
<attachment :isGetBase64="true" :options="separateAccountOpt" v-model="separateAccount.attachments"></attachment>
</el-form-item>
<el-form-item label="分账范围">
<el-select v-model="separateAccount.splitRange" style="width: 300px;">
<el-option :label="'全部交易分账 (商户所有交易默认待分账)'" :value="'ALL'"></el-option>
<el-option :label="'标记交易分账(只有带分账标识交易待分账,其余交易正常结算) '" :value="'MARK'"></el-option>
</el-select>
</el-form-item>
<el-form-item label="分账规则来源" :required="separateAccount.splitLaunchMode !== 'MANUAL'" >
<el-select v-model="separateAccount.splitRuleSource" style="width: 300px;" placeholder="请选择分账规则来源">
<el-option :label="'商户分账规则'" :value="'MER'"></el-option>
<el-option :label="'平台分账规则分账 '" :value="'PLATFORM'"></el-option>
</el-select>
</el-form-item>
<el-form-item label="电子合同编号">
<el-input v-model="separateAccount.eleContractNo" style="width: 300px;" placeholder="请填写电子合同编号"></el-input>
</el-form-item>
<!-- 创建分账才会显示 -->
<el-form-item label="分账依据" v-if="!isUpdate">
<el-select v-model="separateAccount.sepFundSource" style="width: 300px;">
<el-option :label="'交易分账'" :value="'TR'"></el-option>
<el-option :label="'余额分账'" :value="'BA'"></el-option>
</el-select>
</el-form-item>
<el-form-item label="分账发起方式" v-if="!isUpdate">
<el-select v-model="separateAccount.splitLaunchMode" style="width: 300px;">
<el-option :label="'自动规则分账'" :value="'AUTO'"></el-option>
<el-option :label="'指定规则分账'" :value="'POINTRULE'"></el-option>
<el-option :label="'手动分账'" :value="'MANUAL'"></el-option>
</el-select>
</el-form-item>
<el-form-item label="提款类型" v-if="!isUpdate">
<el-select v-model="separateAccount.settleType" style="width: 300px;">
<el-option :label="'主动提款'" :value="'01'"></el-option>
<el-option :label="'交易自动结算'" :value="'03'"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitSeparateAccBut">{{ isUpdate ? '保存分账账户': '创建分账账户' }}</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
import attachment from '@/components/lklCmp/attachment'
import { showLoad,hideLoad } from '@/tools/loading'
import { lklOrderNo } from '@/utils/index'
import {
CreateSeparate,
SeparateModify
} from '@/apis/lakala/lakala'
export default {
props:['merchantInfo'],
components:{
attachment
},
data(){
return {
separateAccount:{
version:"1.0",
orderNo:"",
orgCode:"983931",
merInnerNo:"", // 内部商户号
merCupNo:"", // 银联商户号
contactMobile:"", // 联系手机号
splitLowestRatio:90, // 最低分赃比例
splitEntrustFileName:"", // 文件名称
splitEntrustFilePath:"", // 文件路径
attachments:[], // 附件
splitRange:"", // 分账范围 ALL MARK
eleContractNo:"", // 电子合同编号
// 创建分账
splitRuleSource:"", // 分账规则来源
sepFundSource:"", // 分账依据
splitLaunchMode:"", // 分账发起方式
settleType:"" // 提款类型
},
separateAccountOpt:[
{
label:'法人身份证正面(必传)',
value:'FR_ID_CARD_FRONT'
},
{
label:'法人身份证反面(必传)',
value:'FR_ID_CARD_BEHIND'
},
{
label:'(结算人)身份证正面(同法人可不传,反之必传)',
value:'ID_CARD_FRONT'
},
{
label:'(结算人)身份证反面(同法人可不传,反之必传)',
value:'ID_CARD_BEHIND'
},
{
label:'银行卡(必传)',
value:'BANK_CARD'
},
{
label:'营业执照(企业商户必传,小微商户可不传)',
value:'BUSINESS_LICENCE'
},
{
// //门头照 集市现场照片)
label:'门头照 / 集市现场照片(必传)',
value:'MERCHANT_PHOTO'
},
{
label:'商铺内部照片(必传)',
value:'SHOPINNER'
},
{
label:'线下纸质协议',
value:'XY'
},
{
label:'电子协议',
value:'NETWORK_XY'
},
{
label:'租赁合同',
value:'HT'
},
{
label:'合作资质证明',
value:'COOPERATION_QUALIFICATION_PROOF'
},
{
label:'食品经营相关资质',
value:'FOOD_QUALIFICATION_PROOF'
},
{
label:'非法人结算授权书',
value:'NO_LEGAL_PERSON_SETT_AUTH_LETTER'
},
{
label:'结算授权委托书',
value:'SPLIT_ENTRUST_FILE'
},
{
label:'集市方与场地方间的租赁协议',
value:'RENTAL_AGREEMENT'
},
{
label:'集市方与摊主间的合作协议',
value:'SPLIT_COOPERATION_FILE'
},
{
label:'其他(包含集市媒体公吿信息)',
value:'OTHERS'
},
],
isUpdate:false
}
},
watch:{
merchantInfo:{
handler(val){
console.log('进件信息',val)
if(val){
if(val.separateReceiverInfo) {
this.isUpdate = true
let separateInfo = val.separateReceiverInfo
this.separateAccount = {
version:"1.0",
orderNo:"",
orgCode:"983931",
merInnerNo:separateInfo.merInnerNo,
merCupNo:separateInfo.merCupNo,
contactMobile:'',
splitLowestRatio:separateInfo.splitLowestRatio,
splitEntrustFileName:"",
splitEntrustFilePath:"",
splitRange:separateInfo.splitRange,
splitRuleSource:separateInfo.splitRuleSource,
eleContractNo:"", // 电子合同编号
sepFundSource:"",
attachments:[],
}
}else this.isUpdate = false
this.separateAccount.merCupNo = val.externalCustomerNo
}
},
immediate:true,
deep:true
},
"createSeparateAccout.attachments":{
handler(val){
if(val && val.length> 0){
val.forEach(i => {
if(i.attachType === 'SPLIT_ENTRUST_FILE'){
// 结算授权委托书 赋值
this.createSeparateAccout.splitEntrustFileName = i.attachName
this.createSeparateAccout.splitEntrustFilePath = i.attachStorePath
}
})
}
}
},
},
methods: {
// 创建分账账户
async submitSeparateAccBut(){
try {
showLoad()
let json = JSON.parse(JSON.stringify(this.separateAccount))
json.orderNo = lklOrderNo(new Date())
json.splitLowestRatio = json.splitLowestRatio ? +json.splitLowestRatio : 0
if(this.separateAccount.attachments && this.separateAccount.attachments.length>0){
json.attachments = []
this.createSeparateAccout.attachments.forEach(element => {
json.attachments.push[{
attachType:element.attachType,
attachName:element.attachName,
attachStorePath:element.attachStorePath
}]
});
}else delete json.attachments
if(!this.isUpdate){
// 创建分账账户
delete json.merInnerNo
let form = new FormData()
form.append('payload',JSON.stringify(json))
// console.log('创建分账账户',json)
let res = await CreateSeparate(form)
// code: "0"
// data: "\"1000421143578705920\""
// desc: ""
// console.log('创建分账账户,返回的信息',res)
this.$message({
message: `创建成功,待审核${res}`,
type: 'success',
center: true
})
}else{
// 修改分账账户
// 修改之前,判断分账是否通过审核
json.splitLowestRatio = '' + json.splitLowestRatio
let form = new FormData()
form.append('payload',JSON.stringify(json))
// console.log('变更分账账户的参数信息',json)
let res = await SeparateModify(form)
this.$message({
message: `修改成功,待审核${res}`,
type: 'success',
center: true
})
// console.log('分账退回返回的数据结果',res)
}
this.$emit('closeDia')
hideLoad()
// 修改分账账户
} catch (error) {
hideLoad()
this.$message({
message: `出错了,${error}`,
type: 'error',
center: true
})
throw error
}
}
}
}
</script>
<style lang="scss" scoped>
</style>

View File

@@ -0,0 +1,377 @@
<template>
<el-form
style="margin:20px auto;"
label-width="180px"
label-position="right"
:model="separateRecipient"
>
<el-form-item label="分账接收方编号" required v-if="isUpdate">
<el-input v-model="separateRecipient.receiverNo" placeholder="分账接收方编号" style="width: 300px;"></el-input>
</el-form-item>
<el-form-item label="接收方状态" v-if="isUpdate" >
<el-select v-model="separateRecipient.status" style="width: 300px;" placeholder="请选择接收方状态">
<el-option :label="'有效'" :value="'VALID'" ></el-option>
<el-option :label="'无效'" :value="'INVALID'" ></el-option>
</el-select>
</el-form-item>
<el-form-item label="分账接收方名称" required>
<el-input v-model="separateRecipient.receiverName" placeholder="分账接收方名称" style="width: 300px;"></el-input>
</el-form-item>
<el-form-item label="联系手机号" required>
<el-input v-model="separateRecipient.contactMobile" placeholder="联系手机号" style="width: 300px;"></el-input>
</el-form-item>
<el-form-item label="收款账户账户类型" required>
<el-select v-model="separateRecipient.acctTypeCode" style="width: 300px;" placeholder="请选择收款账户账户类型">
<el-option :label="'对公'" :value="'57'" ></el-option>
<el-option :label="'对私'" :value="'58'" ></el-option>
</el-select>
</el-form-item>
<el-form-item label="营业执照号码" :required="separateRecipient.acctTypeCode === '57'" v-if="!isUpdate">
<el-input v-model="separateRecipient.licenseNo" placeholder="营业执照号码" style="width: 300px;"></el-input>
</el-form-item>
<el-form-item label="营业执照名称" :required="separateRecipient.acctTypeCode === '57'" v-if="!isUpdate">
<el-input v-model="separateRecipient.licenseName" placeholder="营业执照名称" style="width: 300px;"></el-input>
</el-form-item>
<el-form-item label="法人姓名" :required="separateRecipient.acctTypeCode === '57'" v-if="!isUpdate">
<el-input v-model="separateRecipient.legalPersonName" placeholder="法人姓名" style="width: 300px;"></el-input>
</el-form-item>
<el-form-item label="法人证件类型" :required="separateRecipient.acctTypeCode === '57'" v-if="!isUpdate">
<el-select v-model="separateRecipient.legalPersonCertificateType" style="width: 300px;" placeholder="请选择证件类型" :disabled="true">
<el-option :label="'身份证'" :value="'17'"></el-option>
<el-option :label="'护照'" :value="'18'" ></el-option>
<el-option :label="'港澳居民来往内地通行证'" :value="'19'" ></el-option>
<el-option :label="'台湾居民来往内地通行证'" :value="'20'" ></el-option>
</el-select>
<el-tag type="danger" style="width: 300px;">身份证外类型先咨询后再使用</el-tag>
</el-form-item>
<el-form-item label="法人证件号" :required="separateRecipient.acctTypeCode === '57'" v-if="!isUpdate">
<el-input v-model="separateRecipient.legalPersonCertificateNo" placeholder="法人证件号" style="width: 300px;"></el-input>
</el-form-item>
<el-form-item label="收款账户卡号9*" required>
<el-input v-model="separateRecipient.acctNo" placeholder="收款账户卡号" style="width: 300px;" @blur="getAcctOpen"></el-input>
</el-form-item>
<el-form-item label="收款账户名称" required v-if="!isUpdate">
<el-input v-model="separateRecipient.acctName" placeholder="收款账户名称" style="width: 300px;"></el-input>
</el-form-item>
<el-form-item label="收款账户证件类型" required v-if="!isUpdate">
<el-select v-model="separateRecipient.acctCertificateType" style="width: 300px;" placeholder="请选择收款账户证件类型" :disabled="true">
<el-option :label="'身份证'" :value="'17'"></el-option>
<el-option :label="'护照'" :value="'18'" ></el-option>
<el-option :label="'港澳居民来往内地通行证'" :value="'19'" ></el-option>
<el-option :label="'台湾居民来往内地通行证'" :value="'20'" ></el-option>
</el-select>
<el-tag type="danger" style="width: 300px;">身份证外类型先咨询后再使用</el-tag>
</el-form-item>
<el-form-item label="收款账户证件号" required v-if="!isUpdate">
<el-input v-model="separateRecipient.acctCertificateNo" placeholder="收款账户证件号" style="width: 300px;"></el-input>
</el-form-item>
<el-form-item label="收款账户开户行号" required>
<!-- 58 对私 参照卡BIN信息查询仅支持对私结算账户 -->
<el-input v-model="separateRecipient.acctOpenBankCode" placeholder="收款账户开户行号" style="width: 300px;" :disabled="separateRecipient.acctTypeCode === '58'"></el-input>
</el-form-item>
<el-form-item label="收款账户开户名称" required >
<el-input v-model="separateRecipient.acctOpenBankName" placeholder="收款账户开户名称" style="width: 300px;" :disabled="separateRecipient.acctTypeCode === '58'"></el-input>
</el-form-item>
<!-- 部分条件满足下必填 -->
<el-form-item label="收款账户清算行行号" required>
<!-- 58 对私 参照卡BIN信息查询仅支持对私结算账户-->
<el-input v-model="separateRecipient.acctClearBankCode" placeholder="收款账户清算行行号" :disabled="separateRecipient.acctTypeCode === '58'" style="width: 300px;"></el-input>
</el-form-item>
<el-form-item label="接收方附件资料" >
<attachment :isGetBase64="true" :options="lklDataList.separateOptions" v-model="separateRecipient.attachList"></attachment>
</el-form-item>
<el-form-item label="附件类型编码" >
<el-input v-model="separateRecipient.attachType" placeholder="附件类型编码" style="width: 300px;" :disabled="true"></el-input>
</el-form-item>
<el-form-item label="附件名称" >
<el-input v-model="separateRecipient.attachName" placeholder="附件名称" style="width: 300px;" :disabled="true"></el-input>
</el-form-item>
<el-form-item label="附件路径" >
<el-input v-model="separateRecipient.attachStorePath" placeholder="附件路径" style="width: 300px;" :disabled="true"></el-input>
</el-form-item>
<el-form-item label="提款类型" v-if="!isUpdate">
<el-select v-model="separateRecipient.settleType" style="width: 300px;">
<el-option :label="'主动提款'" :value="'01'"></el-option>
<el-option :label="'交易自动结算'" :value="'03'"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitSeparateReceiver">{{!isUpdate ? '创建' : '保存'}}</el-button>
</el-form-item>
</el-form>
</template>
<script>
import attachment from '@/components/lklCmp/attachment'
import { lklOrderNo } from '@/utils/index'
import {
CreateSeparateRecipient,
UpdateSeparateRecipient,
QuerySeparateRecipient
} from '@/apis/lakala/lakala'
import { showLoad,hideLoad } from '@/tools/loading'
import { getAcctOpenFun } from '../publicFun'
export default {
props:["receiverNo"],
components:{
attachment
},
data(){
return {
// querySeparate:{
// merInnerNo:'', // externalCustomerNo
// orgCode:'983931'
// },
// querySeparateResult:"",
// 分账接收方
separateRecipient:{
version:"1.0",
orderNo:"",
orgCode:"983931",
receiverName:"", // 接收方名称
contactMobile:"", // 联系手机号
licenseNo:"", // 营业执照号码(对公,必填)
licenseName:"", // 营业执照名称(对公,必填)
legalPersonName:"", // 法人姓名(对公,必填)
legalPersonCertificateType:"17", // 法人证件类型(对公,必填)
legalPersonCertificateNo:"", // 法人证件号(对公,必填)
acctNo:"", // 收款账户卡号
acctName:"", // 收款账户名称
acctTypeCode:"", // 收款账户账户类型 57对公 58对私
acctCertificateType:"17", // 收款账户证件类型(身份证外类型先咨询后再使用)
acctCertificateNo:"", // 收款账户证件号
acctOpenBankCode:"", // 收款账户开户行号
acctOpenBankName:"", // 收款账户开户名称
acctClearBankCode:"", // 收款账户清算行行号
attachList:[], // 接收方附件资料
attachType:"", // 附件类型编码
attachName:"", // 附件名称
attachStorePath:"", // 附件路径
settleType:"01" // 提款类型(不填默认01)
},
isUpdate:false,
lklDataList:{
separateOptions:[
{
label:'法人身份证正面',
value:'FR_ID_CARD_FRONT'
},
{
label:'法人身份证反面',
value:'FR_ID_CARD_BEHIND'
},
{
label:'结算人身份证正面(同法人可不传)',
value:'ID_CARD_FRONT'
},
{
label:'结算人身份证反面(同法人可不传)',
value:'ID_CARD_BEHIND'
},
{
label:'银行卡',
value:'BANK_CARD'
},
{
label:'营业执照(企业商户必传,小微商户可不传)',
value:'BUSINESS_LICENCE'
},
{
// 集市现场照片
label:'商户门头照',
value:'MERCHANT_PHOTO'
},
{
label:'商铺内部照片',
value:'SHOPINNER'
},
{
label:'线下纸质协议',
value:'XY'
},
{
label:'电子协议',
value:'NETWORK_XY'
},
{
label:'租赁合同',
value:'HT'
},
{
label:'合作资质证明',
value:'COOPERATION_QUALIFICATION_PROOF'
},
{
label:'食品经营相关资质',
value:'FOOD_QUALIFICATION_PROOF'
},
{
label:'非法人结算授权书',
value:'NO_LEGAL_PERSON_SETT_AUTH_LETTER'
},
{
label:'结算授权委托书',
value:'SPLIT_ENTRUST_FILE'
},
{
label:'集市方与场地方间的租赁协议',
value:'RENTAL_AGREEMENT'
},
{
label:'集市方与摊主间的合作协议',
value:'SPLIT_COOPERATION_FILE'
},
{
// 合作协议;集市媒体公吿信息;其他。
label:'其他(包含集市媒体公告信息)',
value:'OTHERS'
},
],
}
}
},
watch:{
receiverNo:{
handler(val){
if(val) {
// 查询分账接收方详情
this.querySeparateDetail({
receiverNo:val,
orgCode:"983931"
})
this.isUpdate = true
}else {
this.separateRecipient = {
version:"1.0",
orderNo:"",
orgCode:"983931",
receiverName:"", // 接收方名称
contactMobile:"", // 联系手机号
licenseNo:"", // 营业执照号码(对公,必填)
licenseName:"", // 营业执照名称(对公,必填)
legalPersonName:"", // 法人姓名(对公,必填)
legalPersonCertificateType:"17",// 法人证件类型(对公,必填)
legalPersonCertificateNo:"", // 法人证件号(对公,必填)
acctNo:"", // 收款账户卡号
acctName:"", // 收款账户名称
acctTypeCode:"", // 收款账户账户类型 57对公 58对私
acctCertificateType:"17", // 收款账户证件类型(身份证外类型先咨询后再使用)
acctCertificateNo:"", // 收款账户证件号
acctOpenBankCode:"", // 收款账户开户行号
acctOpenBankName:"", // 收款账户开户名称
acctClearBankCode:"", // 收款账户清算行行号
attachList:[], // 接收方附件资料
attachType:"", // 附件类型编码
attachName:"", // 附件名称
attachStorePath:"", // 附件路径
settleType:"01" // 提款类型(不填默认01)
},
this.isUpdate = false
}
},
immediate:true,
deep:true
}
},
created(){
console.log('receiverNo',this.receiverNo)
},
methods:{
// 查询分账接收方详情
async querySeparateDetail(obj){
try {
let res = await QuerySeparateRecipient(obj)
console.log('查询分账接收方详情',res)
this.separateRecipient = {
version:"1.0",
orderNo:"",
orgCode:"983931",
receiverNo:res.receiverNo, // 分账接收方编号
receiverName:res.receiverName, // 分账接收方名称
contactMobile:res.contactMobile, // 联系手机号
acctNo:res.acctNo, // 收款账户卡号
acctTypeCode:res.acctTypeCode, // 收款账户账户类型
acctOpenBankCode:res.acctOpenBankCode, // 收款账户开户行号
acctOpenBankName:res.acctOpenBankName, // 收款账户开户名称
acctClearBankCode:res.acctClearBankCode, // 收款账户清算行行号
attachList:[], // 附件资料
attachType:"", // 附件类型编码
attachName:"", // 附件名称
attachStorePath:"", // 附件路径
status:res.rowStatus, // 接收方状态
}
} catch (error) {
this.$message({
message:`查询分账接收方失败,${error}`,
type:'error',
center: true
})
throw error
}
},
// 对私账号 获取开户行的信息
async getAcctOpen(){
let res = await getAcctOpenFun(this.separateRecipient.acctTypeCode,this.separateRecipient.acctNo)
this.separateRecipient.acctOpenBankCode = res.bankCode
this.separateRecipient.acctClearBankCode = res.clearingBankCode
this.separateRecipient.acctOpenBankName = res.bankName
},
async submitSeparateReceiver(){
try {
showLoad()
let json = JSON.parse(JSON.stringify(this.separateRecipient))
json.orderNo = lklOrderNo(new Date())
if(this.separateRecipient.attachList && this.separateRecipient.attachList>0){
json.attachList = []
this.separateRecipient.attachList.forEach(element => {
json.attachList.push({
attachName:element.attachName,
attachStorePath:element.attachStorePath,
attachType:element.attachType
})
});
}
if(!this.isUpdate){
// 创建
showLoad()
let form = new FormData()
form.append('payload',JSON.stringify(json))
let res = await CreateSeparateRecipient(form)
this.$message({
message: `创建成功,${res}`,
type: 'success',
center: true
})
// console.log('创建分账接收方的结果999**',res)
// console.log('创建分账接收方的信息',this.separateRecipient)
}else{
// 修改
let res = await UpdateSeparateRecipient(form)
this.$message({
message: `保存成功,${res}`,
type: 'success',
center: true
})
}
this.$emit('closeDia')
hideLoad()
} catch (error) {
this.$message({
message: `${error}`,
type: 'error',
center: true
})
hideLoad()
throw error
}
}
}
}
</script>

View File

@@ -0,0 +1,3 @@
.order-table {
height: calc(100vh - 300px);
}

View File

@@ -0,0 +1,221 @@
<template>
<div >
<el-form
style="margin-top: 20px;"
:inline="true"
size="mini"
label-position="right"
:model="electron.data">
<el-form-item label="门店">
<!-- <el-input v-model="electron.data.storeId" placeholder=""></el-input> -->
<jx-select-pick
v-model="storeID"
:vendorID="'9'"
:placeholder="'请选择门店关键字'"
:valueType="{
type:'object',
valueKey:'id'
}"
>
</jx-select-pick>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="queryElectronList('')">查询</el-button>
</el-form-item>
</el-form>
<div class="order-table">
<el-table
stripe
border
tooltip-effect="dark"
style="width: 100%;"
empty-text="暂无数据请检查检索条件是否正确"
height="100%"
:data="electron.result"
>
<el-table-column prop="storeId" label="门店" align="center"> </el-table-column>
<el-table-column prop="createdAt" label="创建时间" align="center" >
<template slot-scope="scope">
{{ scope.row.createdAt | timeToLLL }}
</template>
</el-table-column>
<el-table-column prop="contractApplyId" label="合同编号" align="center"> </el-table-column>
<el-table-column prop="contractId" label="流水号" align="center"> </el-table-column>
<el-table-column prop="ContractStatus" label="状态" align="center">
<template slot-scope="scope">
<!-- {{ scope.row.ContractStatus }} -->
{{ scope.row.ContractStatus === 'WAIT_AUDIT ' ? '待审核' : scope.row.ContractStatus === 'PASS' ? '审核通过' : scope.row.ContractStatus === 'REFUSE' ? '审核拒绝' : scope.row.ContractStatus === 'CLOSE' ? '审核关闭' : scope.row.ContractStatus === 'people' ? '人工审核' : scope.row.ContractStatus === 'UNDONE' ? '未签约': '未知' }}
</template>
</el-table-column>
<el-table-column prop="applyType" label="类型" align="center">
<template slot-scope="scope">
{{ scope.row.applyType === 'EC007' ? '入网协议 + 结算授权委托书' : scope.row.applyType === 'EC008' ? '入网协议' : scope.row.applyType === 'EC009' ? '结算授权委托书' : ''}}
</template>
</el-table-column>
<el-table-column prop="lastOperator" label="操作人" align="center"></el-table-column>
<el-table-column prop="operation" label="操作" align="center" >
<template slot-scope="scope">
<el-button type="primary" size="mini" @click="queryElecTronStatus(scope.row,'1')" :disabled="!(scope.row.ContractStatus === 'people' || scope.row.ContractStatus === 'REFUSE')">查询人工</el-button>
<el-button type="primary" size="mini" @click="queryElecTronStatus(scope.row,'2')" :disabled="scope.row.ContractStatus !== 'UNDONE'">查询签署</el-button>
<el-button type="primary" size="mini" @click="backElec(scope.row)" :disabled="scope.row.ContractStatus !== 'WAIT_AUDIT '">反馈</el-button>
</template>
</el-table-column>
</el-table>
</div>
<!-- 分页 -->
<div class="page" style="text-align: center;" >
<el-pagination @size-change="sizeChange" @current-change="handleCurrentChange" :page-sizes="[15, 30, 50]"
:page-size.sync="electron.data.pageSize" layout="total, sizes, prev, pager, next" :current-page="electron.data.offset"
:total="electron.totalCount">
</el-pagination>
</div>
<el-dialog :title="dialog.title" :visible.sync="dialog.dialogVisible" width="30%">
<applyBack v-if="dialog.title === '电子合同反馈'" :currentRow="electron.currentRow"></applyBack>
</el-dialog>
</div>
</template>
<script>
import { hideLoad } from '@/tools/loading'
// import attachment from '@/components/lklCmp/attachment'
import jxSelectPick from '@/components/cmp/selectPick'
import applyBack from '@/components/lklCmp/applyBack'
import copyText from '@/tools/copytext.js'
import {
QueryElectronicContract,
QueryApplyContractList
} from '@/apis/lakala/lakala'
export default {
props:['currentRow'],
components:{
// attachment
jxSelectPick,
applyBack
},
data(){
return {
electron:{
data:{
storeId:"",
offset:0,
pageSize:-1
},
currentRow:"",
totalCount:0,
result:[]
},
dialog:{
title:"",
dialogVisible:false
},
storeID:[], // 京西门店信息
}
},
watch:{
storeID:{
handler(val){
if(val && val.id) this.electron.data.storeId = "" + val.id
else this.electron.data.storeId = ""
}
}
},
methods:{
// 每页个数改变
sizeChange() {
this.$nextTick(() => {
this.queryElectronList()
});
},
// 点击页码
handleCurrentChange(val) {
this.electron.data.offset = (val - 1) * this.electron.data.pageSize;
this.queryElectronList('',() => {
document.querySelector(".el-table__body-wrapper").scrollTop = 0;
});
},
// 查询合同列表
async queryElectronList(fn){
try {
let res = await QueryApplyContractList(this.electron.data) // 门店合同申请记录查询
this.electron.result = res.data || []
this.electron.totalCount = res.totalCount || 0
// console.log('res,查询合同列表',res)
fn && fn()
hideLoad()
} catch (error) {
hideLoad()
this.$message(error)
console.log('error',error)
throw error
}
},
// 打开合同反馈弹框
backElec(row){
console.log('当前数据',row)
this.electron.currentRow = row
this.dialog.title = "电子合同反馈"
this.dialog.dialogVisible = true
},
// 电子合同反馈,人工复核
async queryElecTronStatus(row,type){
try {
console.log('row',row)
debugger
let form = new FormData()
form.append('storeID',row.storeId)
form.append('orderNo',row.contractId)
form.append('orgId',"983931")
form.append('ecApplyId', BigInt(row.contractApplyId))
form.append('queryType', type)
let res = await QueryElectronicContract(form)
// console.log('row,QueryElectronicContract',res)
if(type === '2'){
if(res.ec_status === 'COMPLETED') this.$toast('商户已完成签约')
else this.$toast('商户签约未完成')
}else {
if(res.audit_status === "REFUSE") this.$toast(`人工审核情况:${res.audit_status}` + res.audit_desc)
else if(res.audit_status === "WAIT_AUDIT"){
this.$toast('待审核' + JSON.stringify(res))
}else if(res.audit_status === "PASS"){
// 审核通过,返回签约地址
// 、1633 916 818 798
this.$toast('签约过期时间:' + new Date(res.sign_h5_url_exp_tm))
this.$confirm(`是否打开新页面进行签约`, "确认", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
}).then(() => {
window.open(res.sign_h5_url,'_blank') // 在线签约
}).catch(() => {
this.$toast('已复制至剪贴板')
copyText('签约地址如下:' + (res.sign_h5_url));
this.$message({
message: "已复制到剪切板",
type: "success",
center: true,
});
})
}else{
this.$toast('审核已关闭' + JSON.stringify(res))
}
}
hideLoad()
} catch (error) {
hideLoad()
// console.log('error',error)
throw error
}
},
}
}
</script>
<style lang="scss" scoped>
@import './index.scss';
</style>

View File

View File

@@ -0,0 +1,177 @@
<template>
<div>
<div v-for="(item,index) in feeInfo" :key="index" style="margin: 10px;">
<div style="display: flex;">
<div v-if="isUpdate">{{ index + 1 }}</div>
<div :style="{display: !isUpdate ? 'flex' : ''}">
<el-select
v-model ="item.feeCode"
filterable
style="width: 300px;"
@change="emitEvent"
>
<el-option
v-for="item in options"
:label="item.label"
:value="item.value"
:key="item.value">
</el-option>
</el-select>
<div :style="{
'margin-top': isUpdate ? '10px' : '',
'margin-left': isUpdate ? '' : '10px'
}">
<!-- 百分比费率 "RANGE" -->
<el-input v-model="item.feeValue" @change="emitEvent" clearable placeholder="请输入费率值(百分比)" style="width: 300px;" ></el-input>
<el-tag v-if="item.rateType === 'RANGE'" type="warning">区间范围{{item.feeRateMin + '~' + item.feeRateMax }}</el-tag>
</div>
<div :style="{
'margin-top': isUpdate ? '10px' : '',
'margin-left': isUpdate ? '' : '10px'
}">
<!-- 单位为元 除借记卡和银联二维码借记卡其它类型不需要传封顶值 -->
<el-input v-model="item.topFee" clearable placeholder="封顶值,单位:元" @change="emitEvent" style="width: 300px;"></el-input>
<el-tag style="margin-top: 10px;" type="warning" v-if = "isUpdate">除借记卡和银联二维码借记卡其它类型不需要传封顶值</el-tag>
</div>
<!-- 费率范围 -->
</div>
<div style="margin-left:20px;" v-if="index === feeInfo.length - 1" v-show="isUpdate" @click="addAttr">
<i class="el-icon-circle-plus"></i>
</div>
<div style="margin-left:20px;" v-if="feeInfo.length !== 1" @click="delAttr(index)" v-show="isUpdate">
<i class="el-icon-remove" style="color:#ff0000"></i>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
props:{
value: {
type: Array
},
isUpdate:{
type:Boolean,
default:true
}
},
data(){
return {
options:[
{
"label": "贷记卡费率(云闪付必传)",
"value": "CREDIT_CARD"
},
{
"label": "借记卡费率(云闪付必传,此费率类型必须上送封顶值 topFee",
"value": "DEBIT_CARD"
},
{
"label": "微信(必传)",
"value": "WECHAT"
},
{
"label": "线上微信(资金类业务不需要传)",
"value": "LINE_WECHAT",
},
{
"label": "支付宝(必传)",
"value": "ALIPAY",
},
{
"label": "银联二维码借记卡(此费率类型必须上送封顶值 topFee资金类业务同借记卡费率",
"value": "UNIONPAY_WALLET_DEBIT_FEE"
},
{
"label": "银联二维码贷记卡(资金类业务同贷记卡费率)",
"value": "UNIONPAY_WALLET_CREDIT_FEE"
},
{
"label": "云闪付借记-优惠(资金类业务不需要传)",
"value": "YSF_DISCOUNT_DEBIT_FEE"
},
{
"label": "云闪付贷记-优惠(资金类业务不需要传)",
"value": "YSF_DISCOUNT_CREDIT_FEE"
},
{
"label": "银联二维码借记-优惠(资金类业务不需要传)",
"value": "YL_DISCOUNT_DEBIT_FEE",
},
{
"label": "银联二维码贷记-优惠(资金类业务不需要传)",
"value": "YL_DISCOUNT_CREDIT_FEE"
},
{
"label": "支付宝优惠费率(资金类业务不需要传)",
"value": "ALIPAY_DISCOUNT_FEE"
},
{
"label": "扫码d0费率扫码D0结算必传",
"value": "SCAN_PAY_SECOND"
},
{
"label": "刷卡D0费率刷卡D0结算必传",
"value": "CARD_SECOND"
},
{
"label": "商户秒提费率",
"value": "MER_WITHDRAWAL_SECOND"
},
{
"label": "云闪付小额优惠费率(资金类业务不需要传)",
"value": "YSF_LE_1000",
}
],
feeInfo:[{feeCode:"",feeValue:"",topFee:""}],
// isEmit:false
}
},
watch:{
value:{
handler(val){
if(val && val.length>0){
this.feeInfo = []
val.forEach(element => {
if(this.isUpdate){
this.feeInfo.push(element)
}else{
this.feeInfo.push({
...element,
feeCode:element.cardType,
feeValue:element.feeRate
})
}
});
}
},
immediate:true
}
},
methods:{
emitEvent(){
this.$emit("input",this.feeInfo)
},
// 新增附件类别
addAttr(){
this.feeInfo.push({feeCode:"",feeValue:"",topFee:""})
this.emitEvent()
},
// 删除附件类别
delAttr(index){
this.feeInfo = this.feeInfo.slice(0,index).concat(this.feeInfo.slice(index+1))
this.emitEvent()
},
}
}
</script>

View File

@@ -0,0 +1,4 @@
.page {
text-align: center;
margin-top: 10px;
}

View File

@@ -0,0 +1,484 @@
<template>
<div style="margin: 20px;">
<!-- <el-button type="primary" @click="backMerchantList" >返回</el-button> -->
<!-- 返回商户列表 -->
<!-- <el-button type="primary" @click="activeIndex = 6" :disabled="activeIndex === 6">分账记录查询 / 可分账金额查询 / 分账结果查询 / 分账记录查询</el-button> -->
<!-- <el-button type="primary" @click="activeIndex = 7" :disabled="activeIndex === 7">分账撤销/退回</el-button> -->
<div v-if="activeIndex === 6" style="margin: 20px auto;">
<el-form
:inline="true"
size="mini"
label-position="right"
:model="querySeparateRecord">
<el-form-item label="商户号">
<el-input v-model="querySeparateRecord.customerNo" placeholder="请输入商户号"></el-input>
</el-form-item>
<el-form-item label="流水类型">
<el-select v-model="querySeparateRecord.cmdType" placeholder="请输入流水类型">
<el-option :label="'分账'" :value="'EPARATE'"></el-option>
<el-option :label="'分账撤销'" :value="'CANCEL'"></el-option>
<el-option :label="'分账退回'" :value="'FALLBACK'"></el-option>
</el-select>
</el-form-item>
<el-form-item label="分账状态">
<el-input v-model="querySeparateRecord.status" placeholder="请输入分账状态"></el-input>
</el-form-item>
<el-form-item label="分账流水号">
<el-input v-model="querySeparateRecord.separateNo" placeholder="请输入分账流水号"></el-input>
</el-form-item>
<el-form-item label="开始交易时间">
<el-date-picker
style="width:300px"
v-model="querySeparateRecord.separateTimeStart"
type="datetime"
value-format="yyyy-MM-dd HH:mm:ss"
placeholder="选择开始日期">
</el-date-picker>
</el-form-item>
<el-form-item label="结束交易时间">
<el-date-picker
style="width:300px"
v-model="querySeparateRecord.separateTimeEnd"
type="datetime"
value-format="yyyy-MM-dd HH:mm:ss"
placeholder="选择开始日期">
</el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="querySeparateAmtRecord">查询分账记录</el-button>
</el-form-item>
</el-form>
<div style="height: calc(100vh - 300px);">
<el-table
:data="querySeparateRecordResult.data"
stripe
border
height="100%"
style="width: 100%">
<el-table-column
prop="storeId"
label="京西ID"
align="center">
</el-table-column>
<el-table-column
prop="merchantNo"
label="商户号"
align="center">
</el-table-column>
<el-table-column
prop="vendorOrderID"
label="订单号"
align="center">
</el-table-column>
<el-table-column
prop="createdAt"
label="创建时间"
align="center">
<div slot-scope="scope">
<div>{{ scope.row.createdAt | timeToLLL }}</div>
</div>
</el-table-column>
<el-table-column
prop="separateNo"
label="分账流水"
align="center">
</el-table-column>
<el-table-column
prop="logNo"
label="交易流水"
align="center">
</el-table-column>
<el-table-column
prop="cmdType"
label="指令类型"
align="center">
<template slot-scope="scope">
{{ scope.row.cmdType === 'SEPARATE' ? '分账' : scope.row.cmdType === 'CANCEL' ? '分账撤销' : scope.row.cmdType === 'FALLBACK' ? '分账回退' : '未知'}}
</template>
</el-table-column>
<el-table-column
prop="totalAmt"
label="分账金额(元)"
align="center">
<template slot-scope="scope">
{{ scope.row.totalAmt / 100 }}
</template>
</el-table-column>
<el-table-column
prop="status"
label="状态"
align="center">
<template slot-scope="scope">
{{ separateStatus(scope.row.status) }}
</template>
</el-table-column>
<el-table-column
prop="operation"
label="操作"
align="center"
width="90">
<template slot-scope="scope">
<el-popover
placement="left"
width="140"
trigger="hover"
>
<div >
<el-button type="text" size="medium" @click="separateResultBut(scope.row)" >分账详细</el-button>
<br />
<el-button type="text" size="medium" @click="openSeperte(scope.row,1)" >分账回退</el-button>
<br />
<el-button type="text" size="medium" @click="openSeperte(scope.row,2)" >分账撤回</el-button>
</div>
<div slot="reference" class="more-operations">更多操作</div>
</el-popover>
</template>
</el-table-column>
</el-table>
</div>
<!-- 分页 -->
<div class="page">
<el-pagination @size-change="sizeChange" @current-change="handleCurrentChange" :page-sizes="[15, 30, 50]"
:page-size.sync="querySeparateRecord.pageSize" layout="total, sizes, prev, pager, next" :current-page="querySeparateRecord.offset"
:total="querySeparateRecordResult.totalCount">
</el-pagination>
</div>
</div>
<!-- 弹框 -->
<el-dialog :title="dialog.title" :visible.sync="dialog.dialogVisible" width="30%">
<!-- 分账详细信息 -->
<div v-if="dialog.title === '分账明细'">
<div style="font-size: 20px;text-align: center;margin:10px auto">分账明细</div>
<div style="font-size: 16px;padding:10px 20px">
<div>分账指令流水号拉卡拉{{ separateResult.result.separate_no }}</div>
<div>商户分账指令流水号(京西){{ separateResult.result.out_separate_no }}</div>
<div>拉卡拉订单号{{ separateResult.result.log_no }}</div>
<div>交易日期{{ separateResult.result.log_date }}</div>
<div v-if="separateResult.result.cmd_type === 'SEPARATE'">分账计算类型{{ separateResult.result.cal_type === '0' ? '按照指定金额' : '按照指定比例' }}</div>
<div>分账日期{{ separateResult.result.separate_date }}</div>
<div>完成日期{{ separateResult.result.finish_date }}</div>
<div>总金额{{ separateResult.result.total_amt / 100 }}</div>
<div>类型{{ separateResult.result.cmd_type === 'SEPARATE' ? '分账' : separateResult.result.cmd_type === 'CANCEL' ? '分账撤销' : separateResult.result.cmd_type === 'FALLBACK' ? '分账回退' : '' }}</div>
<div>分账状态{{ separateStatus(separateResult.result.status) }}</div>
<div>处理状态{{ separateFinalStatus(separateResult.result.final_status) }}</div>
<div v-if="separateResult.result.front_rule_id">分账前置规则ID{{ separateResult.result.front_rule_id }}</div>
<div>实分金额{{ separateResult.result.actual_separate_amt / 100 }}</div>
<div>手续费金额{{ separateResult.result.total_fee_amt / 100 }}</div>
<div v-if="separateResult.result.acc_result_desc">账户处理错误描述{{ separateResult.result.acc_result_desc }}</div>
</div>
<div v-if="separateResult.result.detail_datas && separateResult.result.detail_datas.length>0" style="margin-top: 20px;">
<div style="font-size: 20px;text-align: center;margin:10px auto">分账接收方</div>
<div style="font-size: 16px;padding:10px 20px">
<div v-for="(item,index) in separateResult.result.detail_datas" :key="index" style="display: flex;">
<div>接收方编号{{ item.recv_no }} </div>
<div style="margin-left: 10px;">分账金额{{ item.amt / 100 }} </div>
<div v-if="item.actual_amt" style="margin-left: 10px;">实分金额{{ item.actual_amt }} </div>
<div v-if="item.fee_amt" style="margin-left: 10px;">手续费金额{{ item.fee_amt }}</div>
</div>
</div>
</div>
</div>
<!-- 分账回退 -->
<div v-if="dialog.title === '分账回退'">
<el-form
label-width="180px"
label-position="right"
:model="sepCanOrFallBackInfo">
<el-form-item lable="商户号">
<el-input v-model="sepCanOrFallBackInfo.merchantNo" style="width: 300px;" placeholder="请输入商户号" :disabled="true"></el-input>
</el-form-item>
<el-form-item lable="拉卡拉分账指令流水号">
<el-input v-model="sepCanOrFallBackInfo.separateNo" style="width: 300px;" placeholder="拉卡拉分账指令流水号" :disabled="true"></el-input>
</el-form-item>
<el-form-item lable="退回原因">
<el-input v-model="sepCanOrFallBackInfo.reason" style="width: 300px;" placeholder="请输入退回原因"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="separateFallBackBut">分账退回</el-button>
</el-form-item>
</el-form>
</div>
<!-- 分账撤销 -->
<div v-if="dialog.title === '分账撤销'">
<el-form
label-width="180px"
label-position="right"
:model="sepCanOrFallBackInfo">
<el-form-item lable="商户号">
<el-input v-model="sepCanOrFallBackInfo.merchantNo" style="width: 300px;" placeholder="请输入商户号" :disabled="true"></el-input>
</el-form-item>
<el-form-item lable="拉卡拉分账指令流水号">
<el-input v-model="sepCanOrFallBackInfo.separateNo" style="width: 300px;" placeholder="拉卡拉分账指令流水号" :disabled="true"></el-input>
</el-form-item>
<el-form-item lable="撤销金额(单位:元)">
<el-input v-model="sepCanOrFallBackInfo.totalAmt" style="width: 300px;" placeholder="请输入退回原因" :disabled="true"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="separateCancle">分账撤销</el-button>
</el-form-item>
</el-form>
</div>
</el-dialog>
</div>
</template>
<script>
import attachment from '@/components/lklCmp/attachment'
import {
GetSeparateAmt,
SeparateCancel,
SeparateFallBack,
SeparateResultQuery,
} from '@/apis/lakala/lakala'
import { hideLoad } from '@/tools/loading'
export default {
components: {
attachment
},
data(){
return {
dialog:{
title:"",
dialogVisible:false
},
activeIndex:6,
// 查询分账记录
querySeparateRecord:{
customerNo:"",
cmdType:"", // 流水类型
status:"",
separateNo:"",
separateTimeStart:"", // 开始交易时间[yyyy-mm-dd hh:mm:ss]
separateTimeEnd:"", // 结束交易时间[yyyy-mm-dd hh:mm:ss]
offset:0, // 列表起始序号以0开始缺省为0
pageSize:30, // 列表页大小缺省为50-1表示全部
},
querySeparateRecordResult:{
data:[],
totalCount:0
},
// 分账撤销 分账退回
sepCanOrFallBackInfo:{
merchantNo:"",
separateNo:"",
totalAmt:'0',
reason:""
},
sepCanOrFallBackResult:"",
// 可分账金额查询
querySeparateAmt:{
merchantNo:"822651059990E2S",
logDate:"", // 拉卡拉对账单交易日期[yyyyMMdd]
result:""
},
// 分账结果查询
separateResult:{
merchantNo:"141429349",
separateNo:"",
result:''
},
}
},
watch:{
"activeIndex":{
handler(val){
if(val === 3){
// 查询分账账户
// this.querySeparateReceiver()
}else if(val === 4){
this.querySeparateAmtRecord()
}else if(val === 5){
// this.querySeparateBus()
}
},
immediate:true
}
},
created(){
this.querySeparateAmtRecord()
},
methods:{
// 每页个数改变
sizeChange() {
this.$nextTick(() => {
this.querySeparateAmtRecord()
});
},
// 点击页码
handleCurrentChange(val) {
this.querySeparateRecord.offset = (val - 1) * this.querySeparateRecord.pageSize;
this.querySeparateAmtRecord(() => {
document.querySelector(".el-table__body-wrapper").scrollTop = 0;
});
},
// 处理状态
separateFinalStatus(type){
let str = ''
switch (type){
case 'ACCEPTED':
str = '已受理'
break
case 'PROCESSING':
str = '处理中'
break
case 'FAIL':
str = '失败'
break
case 'SUCCESS':
str = '成功'
break
default:
str = ''
}
return str
},
// 分账状态
separateStatus(type){
let str = ''
switch (type){
case 'ACCEPTED':
str = '销户'
break
case 'PROCESSING':
str = '处理中'
break
case 'FAIL':
str = '失败'
break
case 'SUCCESS':
str = '成功'
break
// (如果分账指令后有反向操作指令,则原分账指令会变更成以下的状态之一:)
case 'CANCELING':
str = '撤销中'
break
case 'CANCELED':
str = '撤销成功'
break
case 'CANCEL_FAIL':
str = '撤销失败'
break
case 'FALLBACKING':
str = '回退中'
break
case 'FALLBACK_END':
str = '回退结束'
break
default:
str = ''
}
return str
},
// // 返回商户列表
// backMerchantList(){
// this.$emit('jumpMerchantList')
// },
//
// 分账回退或撤回 主动发起查询与分账撤销 / 回退 指令动作之间间隔15秒以上。
async openSeperte(row,type){
if(!row.separateNo) return this.$toast('分账流水号不存在')
await this.separateResultBut(row,1)
if(this.separateResult.result === 'PROCESSING') return this.$toast('该分账正在处理钟,请稍后~~')
this.startSubmit(row,type)
},
startSubmit(row,type){
let merchantNo = row.merchantNo
let recvDatas = JSON.parse(row.detailData)
this.sepCanOrFallBackInfo = {
merchantNo:row.merchantNo,
separateNo:row.separateNo,
}
if(type === 1){
// 回退商户收款账户
if(merchantNo === recvDatas[0].recv_no) return this.$toast('该分账不需要回退')
this.sepCanOrFallBackInfo["reason"] = ""
}else this.sepCanOrFallBackInfo["totalAmt"] = row.totalAmt / 100 // 撤回至分账商户账户
this.dialog.title = type === 1 ? "分账回退" : "分账撤销"
this.dialog.dialogVisible = true
},
// 分账退回
async separateFallBackBut(){
try {
if(!this.sepCanOrFallBackInfo.reason) return this.$toast('请填写退回原因')
let res = await SeparateFallBack({
merchantNo: this.sepCanOrFallBackInfo.merchantNo,
separateNo: this.sepCanOrFallBackInfo.separateNo,
reason: this.sepCanOrFallBackInfo.reason,
}) // 分账退回
this.$message({
message:`退回成功,${res}`,
type: 'success',
center: true
})
hideLoad()
} catch (error) {
hideLoad()
this.$message(error)
throw error
}
},
// 分账撤销
async separateCancle(){
try {
let res = await SeparateCancel({
merchantNo: this.sepCanOrFallBackInfo.merchantNo,
separateNo: this.sepCanOrFallBackInfo.separateNo,
totalAmt: this.sepCanOrFallBackInfo.totalAmt,
})
this.$message({
message:`撤销成功,${res}`,
type: 'success',
center: true
})
hideLoad()
} catch (error) {
hideLoad()
this.$message(error)
throw error
}
},
// 分账结果查询
async separateResultBut(row,isOpenDia){
try {
let res = await SeparateResultQuery({merchantNo:row.merchantNo ? row.merchantNo : this.separateResult.merchantNo,separateNo:row.separateNo ? row.separateNo : this.separateResult.separateNo })
this.separateResult.result = res
if(!isOpenDia){
this.dialog.title = "分账明细"
this.dialog.dialogVisible = true
}
hideLoad()
} catch (error) {
hideLoad()
this.$message(error)
throw error
}
},
// 分账记录查询
async querySeparateAmtRecord(fn){
try {
let res = await GetSeparateAmt(this.querySeparateRecord)
this.querySeparateRecordResult = res
fn && fn()
} catch (error) {
hideLoad()
this.$message(error)
throw error
}
}
}
}
</script>
<style lang="scss" scoped>
@import './index.scss';
</style>

View File

@@ -0,0 +1,292 @@
<template>
<!-- modelData. -->
<div>
<el-form
:inline="true"
v-if="newData && newData.customer"
label-width="150px"
:model="newData">
<h1>商户信息</h1>
<el-form-item label="机构号:">
<el-input v-model="newData.customer.agencyNo" style="width:300px" :disabled="true"></el-input>
</el-form-item>
<el-form-item label="代理号:">
<el-input v-model="newData.customer.agentNo" style="width:300px" :disabled="true"></el-input>
</el-form-item>
<el-form-item label="业务类型:">
<el-select v-model ="newData.customer.bzPos" filterable style="width: 300px;">
<el-option
v-for="item in lklDataList.busiType"
:label="item.label"
:value="item.value"
:key="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="商户类型:">
<el-select v-model="newData.customer.channelType" style="width: 300px;">
<el-option label="企业" :value="'TP_MERCHANT'" :key="'TP_MERCHANT'"></el-option>
<el-option label="小微" :value="'TP_PERSONAL'" :key="'TP_PERSONAL'"></el-option>
</el-select>
</el-form-item>
<el-form-item label="城市名称:">
<el-input v-model="newData.customer.cityName" style="width:300px"></el-input>
</el-form-item>
<el-form-item label="联系人:">
<el-input v-model="newData.customer.contactManName" style="width:300px"></el-input>
</el-form-item>
<el-form-item label="省份名称:">
<el-input v-model="newData.customer.provinceName" style="width:300px"></el-input>
</el-form-item>
<el-form-item label="区县名称:">
<el-input v-model="newData.customer.countyName" style="width:300px"></el-input>
</el-form-item>
<!-- 详细地址除省区外 -->
<el-form-item label="详细地址:">
<el-input v-model="newData.customer.receiveDetail" style="width:300px"></el-input>
</el-form-item>
<el-form-item label="商户名称:">
<el-input v-model="newData.customer.customerName" style="width:300px"></el-input>
</el-form-item>
<el-form-item label="商户号:">
<el-input v-model="newData.customer.customerNo" style="width:300px"></el-input>
</el-form-item>
<el-form-item label="身份证号:">
<el-input v-model="newData.customer.identityNo" style="width:300px"></el-input>
</el-form-item>
<el-form-item label="身份证效期:">
<el-input v-model="newData.customer.identityNoExpire" style="width:300px"></el-input>
</el-form-item>
<el-form-item label="isStandard:">
<el-input v-model="newData.customer.isStandard" style="width:300px"></el-input>
</el-form-item>
<el-form-item label="法人:">
<el-input v-model="newData.customer.legalName" style="width:300px"></el-input>
</el-form-item>
<el-form-item label="营业执照号:">
<el-input v-model="newData.customer.licenseNo" style="width:300px"></el-input>
</el-form-item>
<el-form-item label="邮箱:">
<el-input v-model="newData.customer.mailbox" style="width:300px"></el-input>
</el-form-item>
<el-form-item label="mcc:">
<el-input v-model="newData.customer.mccCode" style="width:300px"></el-input>
<!-- <el-select v-model="modelData.customer.mccCod" style="width: 300px;">
<el-option
v-for="item in lklDataList.mccList"
:key="item.value"
:label="item.label"
:value="item.value" >
</el-option>
</el-select> -->
<!-- <div style="display: flex;margin-left: 10px;">
<el-select
v-model ="mccInfo.code"
filterable
style="width: 150px;"
placeholder="一级类目"
>
<el-option
v-for="item in lklDataList.mccList"
:label="item.name"
:value="item.code"
:key="item.code">
</el-option>
</el-select>
<el-select
v-model ="modelData.customer.mccCode"
filterable
style="width: 150px;"
placeholder="二级类目"
>
<el-option
v-for="item in mccInfo.level2"
:label="item.name"
:value="item.code"
:key="item.code">
</el-option>
</el-select>
</div> -->
</el-form-item>
<el-form-item label="营业执照效期:">
<el-input v-model="newData.customer.merLicenseExpire" style="width:300px"></el-input>
</el-form-item>
<el-form-item label="商户名称(经营名称):">
<el-input v-model="newData.customer.merName" style="width:300px"></el-input>
</el-form-item>
<el-form-item label="进件来源:">
<el-input v-model="newData.customer.merchantSource" style="width:300px"></el-input>
</el-form-item>
<el-form-item label="optimistic:">
<el-input v-model="newData.customer.optimistic" style="width:300px"></el-input>
</el-form-item>
<el-form-item label="phoneNo:">
<el-input v-model="newData.customer.phoneNo" style="width:300px"></el-input>
</el-form-item>
<el-form-item label="平台:">
<el-input v-model="newData.customer.platform" style="width:300px"></el-input>
</el-form-item>
<el-form-item label="奖励方式:">
<el-input v-model="newData.customer.rewardMode" style="width:300px"></el-input>
</el-form-item>
<!-- <el-form-item label="业务扩展信息(业务扩展信息):">
<el-input v-model="newData.customer.bizContent" style="width:300px"></el-input>
</el-form-item> -->
<el-form-item label="折扣:">
<el-input v-model="newData.customer.ysfDiscount" style="width:300px"></el-input>
</el-form-item>
<el-form-item label="外部商户号:">
<el-input v-model="newData.customer.externalCustomerNo" style="width:300px"></el-input>
</el-form-item>
<!-- 审核情况 -->
<el-form-item label="客户状态:">
<el-input v-model="newData.customer.customerStatus" style="width:300px"></el-input><!-- REJECT拒绝 -->
</el-form-item>
<el-form-item label="同意状态:">
<el-input v-model="newData.customer.agreementStatus" style="width:300px"></el-input>
</el-form-item>
<el-form-item label="审核评论:">
<el-input v-model="newData.customer.auditRemark" style="width:300px" :disabled="true"></el-input>
<!-- <el-button type="primary" @click="reSubmit" style="margin-left: 20px;">重新提交审核</el-button> -->
</el-form-item>
<!-- 活动号<el-input v-model="modelData.customer.activeNo"></el-input>
活动时间<el-input v-model="modelData.customer.activityTime"></el-input> -->
<!-- 业务扩展信息业务扩展信息<el-input v-model="modelData.customer.bizContent" style="width:300px"></el-input> -->
<!-- 关闭时间<el-input v-model="modelData.customer.closeTime" style="width:300px"></el-input> -->
<h1>费率信息</h1>
<div style="margin-left:40px">
<fees v-model="newData.customerFee" :isUpdate="false"></fees>
</div>
<!-- productVos -->
<h1>产品信息</h1>
<div v-for="(item,index) in newData.productVos" :key="index">
<el-form-item label="类型:">
<el-input v-model="item.product" style="width:300px"></el-input>
</el-form-item>
<el-form-item label="名称:">
<el-input v-model="item.productName" style="width:300px"></el-input>
</el-form-item>
</div>
<!-- 结算信息 -->
<br />
<h1>结算信息</h1>
<el-form-item label="账户类型:">
<el-select v-model ="newData.settleCard.accountKind" style="width: 300px;">
<el-option :label="'对公'" :value="'57'" :key="'57'"></el-option>
<el-option :label="'对私'" :value="'58'" :key="'58'"></el-option>
</el-select>
</el-form-item>
<el-form-item label="账户名称:"><el-input v-model="newData.settleCard.accountName" style="width:300px"></el-input></el-form-item>
<el-form-item label="银行卡号:"><el-input v-model="newData.settleCard.accountNo" style="width:300px"></el-input></el-form-item>
<el-form-item label="审核状态:"><el-input v-model="newData.settleCard.auditStatus" style="width:300px"></el-input></el-form-item>
<el-form-item label="开户行名称:"><el-input v-model="newData.settleCard.bankName" style="width:300px"></el-input></el-form-item>
<el-form-item label="开户行号:"><el-input v-model="newData.settleCard.bankNo" style="width:300px"></el-input></el-form-item>
<el-form-item label="清算行号:"><el-input v-model="newData.settleCard.clearingBankNo" style="width:300px"></el-input></el-form-item>
<el-form-item label="结算省份名称:"><el-input v-model="newData.settleCard.provinceName" style="width:300px"></el-input></el-form-item>
<el-form-item label="结算城市名称:"><el-input v-model="newData.settleCard.cityName" style="width:300px"></el-input></el-form-item>
<el-form-item label="ownNo"><el-input v-model="newData.settleCard.ownNo" style="width:300px"></el-input></el-form-item> <!-- ownNo 商户号 -->
<h1>终端信息</h1>
<div v-for="(item,index) in newData.terminalInfo" :key="index">
<el-form-item label="终端类型:">
<el-input v-model="item.termTypeCode" style="width:300px"></el-input>
</el-form-item>
<el-form-item label="终端名称:">
<el-input v-model="item.termTypeName" style="width:300px"></el-input>
</el-form-item>
</div>
</el-form>
<div v-else>拼命加载中......</div>
</div>
</template>
<script>
import {
QueryCustomerCategory
} from '@/apis/lakala/lakala'
import fees from '@/components/lklCmp/fees'
export default{
props:['modelData'],
components:{
fees
},
data(){
return {
lklDataList:{
provinceCode:[], // 省
cityCode:[], // 市
areaCode:[], // 区
branchList:[], // 银行列表
mccList:[], // 商户MCC编号
busiType:[{label:"专业化扫码",value:"WECHAT_PAY"},{label:"B2B收银台",value:"B2B_SYT"}],
larIdType:[{label:"身份证",value:"01"}],
// feeType:[{label:"银联借记卡",value:"300"}],
},
}
},
computed:{
newData(){
let obj = {}
if(this.modelData){
obj = JSON.parse(JSON.stringify(this.modelData))
if(obj.customer && obj.customer.merLicenseExpire && obj.customer.merLicenseExpire === '9999-12-31'){
obj.customer.merLicenseExpire = ''
}
}
// if( this.modelData){
// let mcc = this.modelData.customer.mccCode
// if(mcc) this.getMccInfo(this.modelData)
// }
// console.log('this.modelData',this.modelData)
return obj
}
},
created(){
this.getMccInfo()
},
methods:{
async getMccInfo(){
console.log('获取进件信息',)
// // let obj = { businessScene:this.storeInfo.bizContent.activityId === '319' ? '1' : '2' }
// let res = await QueryCustomerCategory({
// businessScene:'2',
// // parentCode:this.modelData.customer.mccCode
// })
// let res11 = await QueryCustomerCategory({
// businessScene:'2',
// parentCode:"12000"
// })
// console.log('获取mcc的值',res,'res11',res11)
let res = await fetch(`lkaData.json`)
let json = await res.json()
let lklDataList = json || []
this.lklDataList.mccList = lklDataList.mccList
console.log(' this.lklDataList.mccList', this.lklDataList.mccList)
if(this.lklDataList.mccList.length === 0){
this.lklDataList.mccList.push({
value:'5999',
label:'其他专门零售店'
})
}
},
// // 重新提交进件
// reSubmit(){
// console.log('重新提交商户进件')
// }
// switchFeeType(){
// let str =
// }
}
}
</script>
<style lang="scss" scoped>
</style>

View File

@@ -0,0 +1,75 @@
.module-box{
// display: flex;
// flex-wrap: wrap;
padding: 20px;
width:500px;
// margin:10px auto;
text-align: center;
margin: 20px auto;
// border:1px solid red;
}
.submit{
// border:1px solid red;
text-align: center;
}
// /deep/ .limitClass{
// }
// /deep/ .el-input-group__append{
// background-color: #fff;
// border-left: none;
// border-left-color: #ffffff;
// }
// /deep/ .businessContent > input{
// border-right-color: #ffffff;
// }
// .accountBalance{
// border: 1px solid red;
// text-align: center;
// height: 100px;
// line-height: 100px;
// font-size: 30px;
// box-sizing: border-box;
// font-weight: bold;
// color:rgb(255, 0, 0);
// .text::before{
// content: '¥';
// }
// }
// .accountInfo{
// border: 1px solid green;
// }
// .devicesMan{
// border:1px solid red
// }
// .operationButList{
// border:1px solid red;
// display: flex;
// justify-content: center;
// align-items: center;
// }
.more-operations {
cursor: pointer;
&:hover {
color: #409eff;
text-decoration: underline;
}
}
.page {
text-align: center;
margin-top: 10px;
}

View File

@@ -0,0 +1,432 @@
<template>
<div>
<!-- <div style="margin: 20px auto;"> -->
<!-- <el-button type="primary" @click="separateMan" v-if="jxStoreInfo.type !== 'storeMerchant'" >分账流水管理</el-button> -->
<!-- <el-button type="primary" @click="merchatIndex = 1" v-if="jxStoreInfo.type !== 'storeMerchant'" :disabled="merchatIndex !== 0 ">返回</el-button> -->
<!-- </div> -->
<div v-if="merchatIndex!==0" style="margin-top: 20px;">
<el-form
:inline="true"
size="mini"
label-position="right"
:model="storeMerInfo">
<el-form-item label="商户号">
<el-input v-model="storeMerInfo.customerNo" placeholder="请输入商户号"></el-input>
</el-form-item>
<el-form-item label="门店id">
<jx-select-pick
v-model="storesValue"
:placeholder="'请输入门店关键字'"
:vendorID="'9'"
:valueType="{
type:'object',
valueKey:'id'
}"
>
</jx-select-pick>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="queryMerchant('')">查询</el-button>
<el-button type="primary" @click="storeMerchant" :disabled="merchatIndex === 0">新增商户</el-button>
</el-form-item>
</el-form>
</div>
<div v-if="merchatIndex === 0 ">
<settleLakala :jxStoreInfo="jxStoreInfo"></settleLakala>
</div>
<el-table
v-if="merchatIndex !== 0"
stripe
border
style="width: 100%;"
:data="merChant.list"
@expand-change="expandChange">
<el-table-column align="center" type="expand" >
<template slot-scope="scope">
<merChantDetail :modelData="scope.row.detail"></merChantDetail>
</template>
</el-table-column>
<el-table-column prop="storeId" label="门店" align="center" width="120">
<template slot-scope="scope">
<el-tooltip class="item" effect="dark" content="点击进入收银台" placement="top-start">
<div @click="jumpCheckstand(scope.row)">{{ scope.row.storeId }}</div>
</el-tooltip>
</template>
</el-table-column>
<el-table-column prop="merchantNo" label="商户号" align="center"> </el-table-column>
<el-table-column prop="merchantNo2" label="银联商户号" align="center"> </el-table-column>
<el-table-column prop="merchantStatus" label="进件状态" align="center"> </el-table-column>
<!-- width="1000px" -->
<el-table-column prop="operation" label="操作" align="center" width="90" >
<template slot-scope="scope">
<el-popover
placement="left"
width="140"
trigger="hover"
>
<div >
<el-button type="text" size="medium" @click="updateMerchant(5,scope.row)" :disabled="scope.row.merchantStatus !== 'OPEN'">修改费率信息</el-button>
<br>
<el-button type="text" size="medium" @click="updateMerchant(8,scope.row)" :disabled="scope.row.merchantStatus !== 'OPEN'">添加营业执照</el-button><!-- 商户变更-添加营业执照 未测试 -->
<br>
<el-button type="text" size="medium" @click="updateMerchant(7,scope.row)" :disabled="scope.row.merchantStatus !== 'OPEN'">变更事件的审核状态</el-button>
<br>
<!-- <el-button type="text" size="medium" @click="updateMerchant(9,scope.row)" v-if="scope.row.merchantNo2 !== '822651059990E0M'" :disabled="scope.row.merchantStatus === 'OPEN'">创建分账账户</el-button>
<br v-if="scope.row.merchantNo2 !== '822651059990E0M'">
<el-button type="text" size="medium" @click="updateMerchant(9,scope.row,'update')" v-if="scope.row.merchantNo2 !== '822651059990E0M'" :disabled="scope.row.merchantStatus !== 'OPEN'">修改分账账户</el-button>
<br v-if="scope.row.merchantNo2 !== '822651059990E0M'"> -->
<!-- 接收方若溪 其余一律创建分账账户进行绑定若溪即可 -->
<!-- <el-button type="text" size="medium" @click="updateMerchant(10,scope.row)" v-if="scope.row.merchantNo2 === '822651059990E0M'" :disabled="scope.row.merchantStatus !== 'OPEN'">创建分账接收方</el-button> -->
<!-- <br v-if="scope.row.merchantNo2 === '822651059990E0M'"> -->
<!-- <el-button type="text" size="medium" @click="updateMerchant(10,scope.row,'update')" v-if="scope.row.merchantNo2 === '822651059990E0M'" :disabled="scope.row.merchantStatus !== 'OPEN'">修改分账接收方</el-button> -->
<!-- <br v-if="scope.row.merchantNo2 === '822651059990E0M'"> -->
<el-button type="text" size="medium" @click="orderManager(scope.row)" :disabled="scope.row.merchantStatus !== 'OPEN'">订单管理</el-button>
<br>
<el-button type="text" size="medium" @click="accountManager(scope.row)" :disabled="scope.row.merchantStatus !== 'OPEN'">账户管理</el-button>
</div>
<div slot="reference" class="more-operations">更多操作</div>
</el-popover>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<div class="page" v-if="merchatIndex !== 0">
<el-pagination @size-change="sizeChange" @current-change="handleCurrentChange" :page-sizes="[15, 30, 50]"
:page-size.sync="storeMerInfo.pageSize" layout="total, sizes, prev, pager, next" :current-page="storeMerInfo.offset"
:total="merChant.totalCount">
</el-pagination>
</div>
<el-dialog :title="dialog.title" :visible.sync="dialog.dialogVisible" width="30%">
<div style="text-align: center;margin: 20px auto;padding: 10px;width: 500px;">
<!-- 选择京西门店 -->
<jx-select-pick
v-if="merchatIndex === 12"
v-model="jxStoreInfo"
:placeholder="'请输入门店关键字'"
:vendorID="'9'"
:valueType="{
type:'object',
valueKey:'id'
}"
>
</jx-select-pick>
<el-button type="primary" v-if="merchatIndex === 12" @click="submitMerchant" :disabled="!jxStoreInfo || isMerchant" size="small">确定</el-button>
<!-- 修改费率信息 -->
<updateFees v-if="merchatIndex === 5" :merchantInfo="currentInfo.merchantInfo" @closeDia="closeDia"></updateFees>
<!-- 查询变更事件的审核状态 -->
<queryReviewStatus v-if="merchatIndex === 7" :merchantInfo="currentInfo.merchantInfo" @closeDia="closeDia"></queryReviewStatus>
<!-- 商户变更-添加营业执照 -->
<addLicenseInfo v-if="merchatIndex === 8" :merchantInfo="currentInfo.merchantInfo" @closeDia="closeDia"></addLicenseInfo>
</div>
</el-dialog>
</div>
</template>
<script>
import attachment from '@/components/lklCmp/attachment'
import updateFees from '@/components/lklCmp/updateFees'
import merChantDetail from '@/components/lklCmp/merChantDetail'
import addLicenseInfo from '@/components/lklCmp/addLicenseInfo'
import queryReviewStatus from '@/components/lklCmp/queryReviewStatus'
import createSepReceiver from '@/components/lklCmp/createSepReceiver'
import bindSeparateReceiver from '@/components/lklCmp/bindSeparateReceiver'
import settleLakala from '@/components/lklCmp/settleLakala'
import jxSelectPick from '@/components/cmp/selectPick'
import { getStores } from "@/apis/controls/shop.js";
// import StoresPick from "@/components/cmp/storePick/index.vue";
import {
SeparateQuery,
QueryIncoming,
GetMerchant,
} from '@/apis/lakala/lakala'
import { hideLoad } from '@/tools/loading'
export default {
components: {
attachment,
updateFees,
queryReviewStatus,
merChantDetail,
addLicenseInfo,
createSepReceiver,
bindSeparateReceiver,
settleLakala,
jxSelectPick,
},
data(){
return {
merchatIndex:1,
merChant:{
list:[],
detail:""
},
currentInfo:{
merchantInfo:""
},
dialog:{
dialogVisible:false,
title:'查询商户进件'
},
jxStoreInfo:"",
isMerchant:false,
storesValue:"",
storeMerInfo:{
customerNo:"",
storeID:"",
offset:0,
pageSize:20
}
}
},
watch:{
"merchatIndex":{
handler(val){
// console.log('merchatIndex',val)
if(val === 0){
// 新增
}else if(val === 1){
// 查询进件
this.queryMerchant()
// this.queryDetail()
}
},
immediate:true
},
"jxStoreInfo":{
handler(val){
if(val && val.id){
// console.log('见天给选择门店得信息',val.id,'获取门店进件信息')
this.queryMerchant(val.id,'tip')
}
}
},
"storesValue":{
handler(val){
console.log('storesValue',val)
if(val) this.storeMerInfo.storeID = val.id
else this.storeMerInfo.storeID = ""
}
}
},
async created(){
try {
if(this.$route.query.type === "storeMerchant") {
this.jxStoreInfo = this.$route.query
let res = await getStores({
storeID: this.jxStoreInfo.storeID
},false)
console.log('获取京西门店信息',res)
if(res.totalCount === 1){
this.jxStoreInfo = {
...res,
...this.jxStoreInfo
}
}
this.storeMerchant() // 门店入驻
}
hideLoad()
} catch (error) {
this.$message(error)
throw error
}
},
methods: {
// 每页个数改变
sizeChange() {
this.$nextTick(() => {
this.queryMerchant()
});
},
// 点击页码
handleCurrentChange(val) {
this.storeMerInfo.offset = (val - 1) * this.storeMerInfo.pageSize;
this.queryMerchant('','',() => {
document.querySelector(".el-table__body-wrapper").scrollTop = 0;
});
},
// 分账管理
separateMan(){
this.$emit('jumpSeparate')
},
async orderManager(row){
// console.log('订单管理')
let routeData = this.$router.resolve({
name: 'OrderManager',
query: {
storeID: row.storeId,
merchantNo:row.merchantNo2
},
})
// console.log(routeData,'row',row)
// return
window.open(routeData.href,'_blank')
},
submitMerchant(){
if(!this.jxStoreInfo) return
console.log('this.jxStoreInfo',this.jxStoreInfo)
// this.queryMerchant(val.id,'tip')
this.closeDia()
// this.merchatIndex = 0
let routeData = this.$router.resolve({
name: 'storeMerPage',
query: {
storeID: this.jxStoreInfo.id,
type:'storeMerchant'
// customerNo:row.merchantNo
},
})
window.open(routeData.href,'_blank') // 在线签约
},
// 门店入驻
storeMerchant(){
if(this.$route.query.type !== "storeMerchant") {
this.dialog.title = '选择京西门店'
this.dialog.dialogVisible = true
this.merchatIndex = 12
}else this.merchatIndex = 0
},
// // 创建分账接收方
// createSepRecevierBut(){
// this.merchatIndex = 2
// this.dialog.title = "创建分账接收方"
// this.dialog.dialogVisible = true
// },
// 关闭dialog
closeDia(){
this.dialog.dialogVisible = false
this.dialog.title = ""
},
// 跳到收银台
async jumpCheckstand(row){
let routeData = this.$router.resolve({
name: 'checkstand',
query: {
storeID: row.storeId,
customerNo:row.merchantNo,
merchantNo2:row.merchantNo2,
},
})
// console.log('row',row)
window.open(routeData.href,'_blank')
},
// 账户管理
async accountManager(row){
if(!row.detail) await this.expandChange(row)
this.$emit('jumpAccountMan',row)
},
// 修改进件信息
async updateMerchant(type,row,isUpdate){
this.currentInfo.merchantInfo = row
this.merchatIndex = type
if(!row.detail) await this.expandChange(row)
if(isUpdate && isUpdate.length>0 ) this.currentInfo.merchantInfo.isUpdate = isUpdate
if(type === 7) this.dialog.title = '查询变更事件'
else if(type === 8) this.dialog.title = '添加营业执照'
else if(type === 5) this.dialog.title = '修改费率信息'
else if(type === 10){
// if(isUpdate && isUpdate === 'update'){
// await querySeparateAccount({
// merInnerNo:row.detail.customer.externalCustomerNo,
// orgCode:'983931',
// // receiverNo:"",
// // receiverName:"",
// offset:0,
// pageSize:-1
// }) // 查询分账接收方信息
// if(!this.currentInfo.merchantInfo.separateReceiverInfo) return
// }
this.dialog.title = isUpdate && isUpdate === 'update' ? '修改分账接收方' : '创建分账接收方'
}
else if(type === 12) this.dialog.title = '选择京西门店'
else if(type === 13){
this.dialog.title = '实名认证'
}
this.dialog.dialogVisible = true
},
// // 查询分账信息
// async querySeparateInfo(obj){
// try {
// let res = await SeparateQuery(obj)
// this.currentInfo.merchantInfo.separateInfo = res
// } catch (error) {
// this.$message({
// message:error === '数据不存在' ? `${error},请先创建分账账户` : error,
// type: 'error',
// center: true
// })
// }
// },
// 展开行信息
async expandChange(e){
let findIndex = this.merChant.list.findIndex(i => i.merchantNo === e.merchantNo)
if(findIndex !==-1 && !this.merChant.list[findIndex].detail) await this.queryDetail(e,findIndex)
},
// 查询进件详情
async queryDetail(row,findIndex){
// 查询线上拉卡拉数据
let res = await GetMerchant({merchantNo:row.merchantNo})
this.$set(this.merChant.list[findIndex],'detail',res)
},
// 查询进件信息
async queryMerchant(storeID,tip,fn){
// 本地数据库
let obj = {
...this.storeMerInfo,
}
// delete obj.storeID
// console.log(obj,'obj','storeMerInfo',this.storeMerInfo,'storeID',storeID)
if(storeID) obj['storeID'] = storeID
this.isMerchant = false
// console.log('打印参数信息',obj)
let res = await QueryIncoming(obj)
// console.log('获取进件信息得结果',res)
if(res && res.data){
if(tip){
if(res.totalCount === 1 && res.data[0].merchantStatus === 'OPEN'){
this.isMerchant = true
this.$toast("该门店已经入驻成功")
}
}else{
this.merChant.list = []
res.data.forEach(i => {
this.merChant.list.push({
...i,
detail:''
})
})
this.merChant.totalCount = res.totalCount
fn && fn()
}
}
}
}
}
</script>
<style lang="scss" scoped>
@import './index.scss';
</style>

View File

@@ -0,0 +1,28 @@
import {
GetCardBin
} from '@/apis/lakala/lakala'
import { lklOrderNo } from '@/utils/index'
// 对私账号 获取开户行的信息
export const getAcctOpenFun = async (acctTypeCode,acctNo) => {
console.log('acctTypeCode',acctTypeCode,'acctNo',acctNo)
if(acctTypeCode === '58' && acctNo){
let json = {
version:"1.0",
orderNo:lklOrderNo(new Date()),
orgCode:"983931",
cardNo:acctNo }
let res = await GetCardBin(json)
return {
bankCode:res.bankCode,
clearingBankCode:res.clearingBankCode,
bankName:res.bankName
}
}else{
return {
bankCode:"",
clearingBankCode:"",
bankName:""
}
}
}

View File

@@ -0,0 +1,89 @@
<template>
<!-- <div>
商户号:<el-input v-model="examine.customerNo" :disabled="true" style="width: 300px;"></el-input>
变更id:<el-input v-model="examine.reviewRelatedId" placeholder="请输入变更事件的id" style="width: 300px;"></el-input>
<el-button type="primary" @click="queryEvent">查询</el-button>
<div style="margin-top: 20px;">查询审核状态{{ reviewStatus ? reviewStatus.status : '' }}</div>
</div> -->
<el-form
label-width="100px"
label-position="right"
:model="examine">
<el-form-item label="商户号">
<el-input v-model="examine.customerNo" style="width: 300px;" :disabled="true"></el-input>
</el-form-item>
<el-form-item label="变更id">
<el-input v-model="examine.reviewRelatedId" style="width: 300px;" placeholder="请输入变更事件的id"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="queryEvent">查询</el-button>
</el-form-item>
<el-form-item>
<div style="font-size: 32px;">
<div style="margin-top: 20px;" v-if="reviewStatus.status">查询审核状态{{ reviewStatus ? reviewStatus.status : '' }}</div>
<div style="margin-top: 20px;" v-if="reviewStatus.desc">错误信息{{ reviewStatus.desc }}</div>
</div>
</el-form-item>
</el-form>
</template>
<script>
import {
QueryExamine
} from '@/apis/lakala/lakala'
export default {
props:['merchantInfo'],
data(){
return {
reviewStatus:"",
examine:{
reviewRelatedId:"",
customerNo:""
}
}
},
watch:{
"merchantInfo":{
handler(val){
console.log('打印商户信息',val)
if(val && val.detail){
this.examine.customerNo = val.detail.customer.customerNo
}
},
deep:true,
immediate:true
}
},
methods:{
// 查询变更事件id
async queryEvent(){
try {
if(!this.examine.reviewRelatedId) return this.$toast('请填写事件id')
// console.log('查询变更事件的信息',this.examine)
let res = await QueryExamine(this.examine)
this.reviewStatus = res
if(res.status === 'PASS') this.$toast('已通过')
else if(res.status === 'UNPASS') this.$toast('未通过')
else if(res.status === 'PASSING') this.$toast('审核中')
else if(res.status === 'PREPARE') this.$toast('待提交')
// console.log('查询审核通过的信息',res)
this.$emit('closeDia')
} catch (error) {
this.$message({
message:`${error}`,
type: 'error',
center:true
})
throw error
}
}
}
}
</script>
<style lang="scss" scoped>
@import './index.scss';
</style>

View File

@@ -0,0 +1,419 @@
<template>
<div>
<!-- 实名认证 -->
<el-select v-if="active === 0" v-model="realNameType" placeholder="请选择实名认证类型" style="margin-top: 20px;">
<el-option :label="'微信实名认证'" :value="'WXZF'"></el-option>
<el-option :label="'支付宝实名认证'" :value="'ZFBZF'"></el-option>
</el-select>
<el-button style="margin-top: 12px;" @click="next" v-show="active === 0">进入</el-button>
<div v-if="active === 1">
<el-select v-model="merCurrentIndex" placeholder="请选择商户报备类型" style="width:300px;margin-top: 20px;">
<!-- :disabled="item.registerStatus === 'FAIL'" -->
<el-option
v-for="(item,index) in subReportList"
:key="index"
:label="item.channelId + '-' + item.registerChannelText + '-' +item.registerTypeText + '' + item.resultMessage + ''"
:value="index"
>
</el-option>
</el-select>
<br></br>
<el-button type="primary" @click="submitRealName">实名认证</el-button>
<el-button type="primary" @click="queryRealNameResult">查询实名认证结果</el-button>
<div v-if="authResultRes" style="margin-top: 20px;">
{{ authResultRes.authorizeState }}
<div>申请编号{{ authResultRes.applymentId }}</div>
<div>申请状态{{ authStateQuery(authResultRes.applymentState) }}</div>
<div>认证状态{{ authorizeState(authResultRes.authorizeState)}}</div>
<div>报备通道{{ authResultRes.registerChannel }}</div>
<div>驳回参数{{ authResultRes.rejectParameter }}</div>
<div>驳回原因{{ authResultRes.rejectReason }}</div>
<div style="display: flex;justify-content: center;align-items: center;"><img :src="realNameType === 'WXZF' ? 'data:image/jpg;base64,' + authResultRes.qrcodeData : authResultRes.qrcodeData" style="width: 200px;height: 200px;display: block;"></div>
</div>
</div>
<div v-if="active === 2">
<el-form
label-width="180px"
label-position="right"
:model="saveMerchantAuth">
<el-form-item label="联系人类型">
<el-select v-model="saveMerchantAuth.contactType" placeholder="请选择联系人类型" style="width:300px">
<el-option :label="'经营者/法人'" :value="'LEGAL'"></el-option>
<el-option :label="'经办人'" :value="'SUPER'"></el-option>
</el-select>
</el-form-item>
<el-form-item label="联系人名称"><el-input v-model="saveMerchantAuth.name" placeholder="请输入联系人名称" style="width:300px"></el-input></el-form-item>
<el-form-item label="联系人证件类型">
<el-select v-model="saveMerchantAuth.contactIdDocType" placeholder="请选择证件类型" style="width:300px">
<el-option :label="'中国大陆居民-身份证'" :value="'IDENTIFICATION_TYPE_IDCARD'"></el-option>
</el-select>
</el-form-item>
<el-form-item label="联系人证件号码"><el-input v-model="saveMerchantAuth.idCardNumber" placeholder="请输入联系人名称" style="width:300px"></el-input></el-form-item>
<el-form-item label="身份证开始日期">
<el-date-picker
style="width:300px"
v-model="saveMerchantAuth.contactPeriodBegin"
type="date"
value-format="yyyy-MM-dd"
placeholder="选择开始日期">
</el-date-picker>
</el-form-item>
<el-form-item label="效期结束时间">
<!-- <el-input v-model="saveMerchantAuth.contactPeriodEnd" placeholder="请输入联系人名称"></el-input> -->
<el-date-picker
style="width:300px"
v-model="saveMerchantAuth.contactPeriodEnd"
type="date"
value-format="yyyy-MM-dd"
placeholder="选择结束时间(无限不填)">
</el-date-picker>
</el-form-item>
<el-form-item label="联系人手机号"><el-input v-model="saveMerchantAuth.mobile" placeholder="请输入联系人名称" style="width:300px"></el-input></el-form-item>
<el-form-item>
<el-button type="primary" @click="submit">保存并提交实名认证</el-button>
</el-form-item>
</el-form>
</div>
<el-button type="text" @click="back" v-show="active !== 0" style="margin-top: 20px;font-size: 24px;">返回上一步</el-button>
</div>
</template>
<script>
import { lklOrderNo } from '@/utils/index'
import {
UpdateAuthentication,
SaveAuthentication,
QueryAuthentication,
AccountStatusQuery,
QuerySubMerInfo
} from '@/apis/lakala/lakala'
import { hideLoad } from '@/tools/loading'
export default {
props:['merchantInfo'],
data(){
return {
customerInfo:"", // 商户信息
subMerInfo:[], // 商户报备信息
active:0,
realNameType:"", // 微信 / 支付宝
// 联系人信息保存 SaveAuthentication 必传
saveMerchantAuth:{
version:"1.0",
orderNo:"",
orgCode:"983931",
merInnerNo:"",
contactType:"LEGAL", // 联系人类型 LEGAL经营者/法人 SUPER经办人。 (经办人:
name:"石锋", //
contactIdDocType:"IDENTIFICATION_TYPE_IDCARD", // IDENTIFICATION_TYPE_IDCARD 中国大陆居民-身份证
idCardNumber:"610126198012230014", // 联系人证件号码
contactPeriodBegin:"2013-01-25", // 联系人证件有效期开始时间 1991-01-01
contactPeriodEnd:"2033-01-25", // 联系人证件有效期结束时间格式YYYY-MM-DD长期9999-12-31
mobile:"18048531223" //
},
merCurrentIndex:0,
authResultRes:"",
}
},
watch:{
"merchantInfo":{
handler(val){
if(val && val.detail){
this.customerInfo = val.detail.customer
console.log('this.customerInfo',this.customerInfo)
console.log(val,'商户信息',this.customerInfo,'val.detail',val.detail.customer)
this.querySubMerInfo()
}
},
immediate:true,
deep:true
}
},
computed:{
subReportList(){
let arr = this.subMerInfo
arr = arr.filter(item => item.registerType === this.realNameType && item.registerStatus !== 'FAIL')
return arr
}
},
methods:{
// 返回
back(){
if(this.active !== 0) this.active--
},
// 校验开户信息
async validOpenStaus(){
try {
// console.log('下一步,校验开户信息')
let reportInfo = this.subReportList[this.merCurrentIndex]
let res = await AccountStatusQuery({
tradeMode:this.realNameType === 'WXZF' ? 'WECHAT' : 'ALIPAY',
subMerchantId:reportInfo.subMchId,
merchantNo:this.customerInfo.externalCustomerNo
})
// this.resultRes.mrchAuthStateRes = res
let status = res.checkResult=== 'AUTHORIZE_STATE_UNAUTHORIZED' ? '未授权' : res.checkResult=== 'AUTHORIZE_STATE_AUTHORIZED' ? '已授权' : '未知'
if(status !== '已授权'){
this.$message({
message:`开户状态${status}`,
type:"success",
center:true
})
}else{
// this.active++
// console.log('提交实名认证')
// 实名认证
this.submitRealNameBut(reportInfo)
}
hideLoad()
} catch (error) {
hideLoad()
this.$message(error)
throw error
}
},
// 提交实名认证
async submitRealNameBut(reportInfo){
try {
await this.queryRealNameResult()
console.log('authResultRes',this.authResultRes)
let obj = {
version:"1.0",
orgCode:"983931",
orderNo:lklOrderNo(new Date()),
merInnerNo:reportInfo.merInnerNo,
receOrgNo:reportInfo.receOrgNo,
subMchId:reportInfo.subMchId,
channelId:reportInfo.channelId,
applymentId:this.authResultRes.applymentId ? this.authResultRes.applymentId : ""
}
let form = new FormData()
form.append('authType',this.realNameType) // 为空,微信 ZFBZF:'支付宝'
form.append('payload',JSON.stringify(obj))
console.log('提交实名认证的参数',obj)
await UpdateAuthentication(form)
this.$message({
message:"提交成功",
type:"success",
center:true
})
let timer = setTimeout(() => {
clearTimeout(timer)
this.active = 1
this.queryRealNameResult()
},10000)
hideLoad()
} catch (error) {
hideLoad()
this.$message(error)
throw error
}
},
async submit(){
try {
let reportInfo = this.subReportList[this.merCurrentIndex]
this.saveMerchantAuth.orderNo =lklOrderNo(new Date())
this.saveMerchantAuth.merInnerNo = reportInfo.merInnerNo
let form = new FormData()
form.append('authType',this.realNameType)
form.append('payload',JSON.stringify(this.saveMerchantAuth))
console.log('saveMerchantAuth',this.saveMerchantAuth)
let res = await SaveAuthentication(form)
this.$message({
message:`保存成功,${res}`,
type:"success",
center:true
})
this.validOpenStaus()
// console.log(reportInfo,'保存商户信息',this.saveMerchantAuth)
hideLoad()
} catch (error) {
hideLoad()
this.$message(error)
throw error
}
},
// 申请状态
authStateQuery(type){
let arr = ''
if(this.realNameType === 'WXZF'){
switch(type) {
case 'APPLYMENT_STATE_FAIL':
arr = '提交失败'
break
case 'APPLYMENT_STATE_COMMIT':
arr = '已提交'
break
case 'APPLYMENT_STATE_WAITTING_FOR_AUDIT':
arr = '审核中'
break
case 'APPLYMENT_STATE_EDITTING':
arr = '编辑中'
break
case 'APPLYMENT_STATE_WAITTING_FOR_CONFIRM_CONTACT':
arr = '待确认联系信息'
break
case 'APPLYMENT_STATE_WAITTING_FOR_CONFIRM_LEGALPERSON':
arr = '待确认联系信息'
break
case 'APPLYMENT_STATE_PASSED':
arr = '审核通过'
break
case 'PPLYMENT_STATE_REJECTED':
arr = '审核驳回'
break
case 'APPLYMENT_STATE_FREEZED':
arr = '已冻结'
break
case 'APPLYMENT_STATE_CANCELED':
arr = '已作废'
break
default:
arr = '未知'
}
}else{
switch(type) {
case 'APPLYMENT_STATE_FAIL':
arr = '提交失败'
break
case 'APPLYMENT_STATE_COMMIT':
arr = '已提交'
break
// 实名状态
case 'AUDITING':
arr = '支付宝-审核中'
break
case 'CONTACT_CONFIRM':
arr = '支付宝-待联系人确认'
break
case 'LEGAL_CONFIRM':
arr = '支付宝-待法人确认'
break
case 'AUDIT_PASS':
arr = '支付宝-审核通过'
break
case 'AUDIT_REJECT':
arr = '支付宝-审核驳回'
break
case 'AUDIT_FREEZE':
arr = '支付宝-已冻结'
break
case 'CANCELED':
arr = '支付宝-已撤回'
break
default:
arr = '未知'
}
}
return arr
},
// 认证状态
authorizeState(type){
let arr = ''
if(this.realNameType === 'WXZF'){
switch(type) {
case 'AUTHORIZE_STATE_UNAUTHORIZED':
arr = '未授权'
break
case 'AUTHORIZE_STATE_AUTHORIZED':
arr = '已授权'
break
default:
arr = '未知'
}
}else{
switch(type) {
case 'UNAUTHORIZED':
arr = '支付宝-未授权'
break
case 'AUTHORIZED':
arr = '支付宝-已授权'
break
case 'CLOSED':
arr = '支付宝-已销户'
break
case 'SMID_NOT_EXIST':
arr = '支付宝-SMID不存在'
break
default:
arr = '未知'
}
}
return arr
},
// 查询实名认证的结果
async queryRealNameResult(){
try {
// 认证状态结果查询
this.authResultRes = ""
let reportInfo = this.subReportList[this.merCurrentIndex]
let obj = {
version:"1.0",
orgCode:"983931",
orderNo:lklOrderNo(new Date()),
merInnerNo:reportInfo.merInnerNo,
subMchId:reportInfo.subMchId,
channelId:reportInfo.channelId
}
let form = new FormData()
form.append('authType',this.realNameType)
form.append('payload',JSON.stringify(obj))
let res = await QueryAuthentication(form)
this.authResultRes = res
// console.log(this.authResultRes,'认证状态结果查询9999999999999999',res,'this.authResult',this.authResult)
hideLoad()
} catch (error) {
hideLoad()
this.$message(error)
throw error
}
},
// 提交实名认证
submitRealName(){
console.log('提交实名认证')
this.active = 2
},
// 下一步
next() {
if(this.active === 0 && !this.realNameType) return this.$toast('请选择实名认证的类型')
this.active++
},
// 查询商户报备信息
async querySubMerInfo(){
try {
console.log('this.customerInfo',this.customerInfo)
if(!this.customerInfo) return
let obj = {
version:"1.0",
orderNo:lklOrderNo(new Date()),
orgCode:"983931",
merCupNo:this.customerInfo.externalCustomerNo
}
console.log('商户报备的参数',obj)
this.subMerInfo = []
let res = await QuerySubMerInfo(obj)
this.subMerInfo = res.filter(i => i.channelId)
console.log(this.subMerInfo,'商户报备查询9999999999*********','res,',res)
hideLoad()
} catch (error) {
hideLoad()
this.$message(error)
throw error
}
}
}
}
</script>
<style lang="scss" scoped>
</style>

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More