初始上传

This commit is contained in:
2026-04-04 17:27:12 +08:00
parent 4d80d28eb4
commit b7e11774ee
11191 changed files with 1588469 additions and 0 deletions

View File

@@ -0,0 +1,183 @@
<template>
<base-page>
<view class="uni-flex uni-row page-height" @click="restoreFocus">
<view class="common-wrap left-wrap">
<view class="cashregister-header-box">
<view class="order-time">
<view class="title">消费时间</view>
<uni-datetime-picker v-model="billingOrderData.create_time" type="datetime" :clearIcon="false" />
</view>
<view class="header" v-if="globalMemberInfo">
<view class="headimg" @click="showMember">
<image class="header-image" :src="globalMemberInfo.headimg ? $util.img(globalMemberInfo.headimg) : $util.img(defaultImg.head)" @error="globalMemberInfo.headimg = defaultImg.head"/>
<view v-if="globalMemberInfo.member_level" class="member-nameplate">
{{ globalMemberInfo.member_level_name }}
</view>
</view>
<view class="head-info" @click="showMember">
<view class="head-info-top">
<view class="name">
<block v-if="globalMemberInfo.mobile">
<view class="mobile">{{ globalMemberInfo.mobile }}</view>
<view class="text">
<text></text>
<text class="nickname">{{globalMemberInfo.nickname }}</text>
<text></text>
</view>
</block>
<text v-else>{{ globalMemberInfo.nickname }}</text>
</view>
</view>
<view class="head-info-bottom point">积分{{ globalMemberInfo.point }}</view>
<view class="head-info-bottom balance">余额{{ (parseFloat(globalMemberInfo.balance_money) + parseFloat(globalMemberInfo.balance)) | moneyFormat}}</view>
</view>
<button class="switch primary-btn member-open" @click="openMember()">更换会员</button>
<button class="switch primary-btn replace-member" @click="replaceMember()">散客</button>
</view>
<view class="header" v-else>
<view class="headimg">
<image class="header-image" :src="$util.img(defaultImg.head)" />
</view>
<view class="head-info">
<view class="name">散客</view>
</view>
<button class="switch primary-btn" @click="openMember()">查询会员</button>
</view>
</view>
<view class="content">
<view class="content-list common-scrollbar">
<block v-if="billingOrderData.goods_list.length && Object.keys(billingGoodsData).length">
<view class="content-item settlement-select-focus" :class="{ 'focus bg-primary-color-9': leftIndexFocus == index }"
v-for="(item, index) in billingOrderData.goods_list" :key="item.editKey"
@click="callBox(item)" tabindex="0" :data-tab-index="index"
@blur="leftTabOrderSelectBlur(item)">
<view class="item-img">
<image v-if="item.goods_image == '@/static/goods/goods.png'" src="@/static/goods/goods.png" mode="widthFix"/>
<image v-else :src="$util.img(item.goods_image.split(',')[0], { size: 'small' })" mode="widthFix" @error="item.goods_image = '@/static/goods/goods.png'"/>
</view>
<view class="uni-flex flex-1 info-wrap">
<view class="info-top">
<view class="uni-flex justify-between items-center">
<view class="item-name">{{ item.goods_name }}</view>
<view class="item-del" @click.stop="deleteGoods(item)">
<text class="iconfont iconshanchu"></text>
<text>删除</text>
</view>
</view>
<view class="item-spe" v-if="item.spec_name">已选{{ item.spec_name }}</view>
</view>
<view class="info-bottom">
<view class="uni-flex items-flex-end">
<view class="item-price">{{ item.price | moneyFormat }}{{item.card_item_id > 0 ? '×'+item.num : ''}}</view>
<view class="item-subtotal" v-if="item.goods_class != $util.goodsClassDict.service && item.card_item_id == 0">
<view>
<text class="unit"></text>
<text>{{ item.goods_money | moneyFormat }}</text>
</view>
</view>
<view class="item-num" v-if="item.goods_class != $util.goodsClassDict.service && item.card_item_id == 0 && item.pricing_type == 'num'">
<view class="num-dec" @click.stop="dec(item)">-</view>
<view class="num" v-if="item.card_item_id && billingGoodsData['sku_' + item.sku_id + '_item_' + item.card_item_id]">{{ billingGoodsData['sku_' + item.sku_id + '_item_' + item.card_item_id].num }}</view>
<view class="num" v-else-if="billingGoodsData['sku_' + item.sku_id]">{{ billingGoodsData['sku_' + item.sku_id].num }}</view>
<view class="num" v-else>{{ item.num }}</view>
<view class="num-inc" @click.stop="inc(item)">+</view>
</view>
<view class="item-num weight" v-if="item.goods_class == $util.goodsClassDict.weigh && item.pricing_type == 'weight'">
<view class="num" v-if="item.card_item_id && billingGoodsData['sku_' + item.sku_id + '_item_' + item.card_item_id]">
{{ billingGoodsData['sku_' + item.sku_id + '_item_' + item.card_item_id].num }}
</view>
<view class="num" v-else-if="billingGoodsData['sku_' + item.sku_id]">{{ billingGoodsData['sku_' + item.sku_id].num }}</view>
<view class="num" v-else>{{ item.num }}</view>
<view>{{ item.unit }}</view>
</view>
</view>
<view class="card-deduction" v-if="item.card_info && Object.keys(item.card_info).length">
<text>使用卡项{{ item.card_info.goods_name }}</text>
</view>
</view>
</view>
</view>
</block>
<view class="empty" v-else>
<image src="@/static/cashier/cart_empty.png" mode="widthFix"/>
<view class="tips">点击右侧商品选择商品进行结账</view>
</view>
</view>
</view>
<view class="bottom">
<view class="bottom-info">
<view class="bottom-left">合计 {{ billingOrderData.goods_num.toFixed(2) }} </view>
<view class="bottom-right">
<text class="pay-money">{{ billingOrderData.pay_money | moneyFormat }}</text>
</view>
</view>
<view class="bottom-btn justify-between">
<view class="tag-parent">
<button class="comp-btn" :class="type == 'order' ? 'primary-btn' : 'default-btn'" @click="hangingOrder">/取单</button>
<text class="num-tag" v-if="pendOrderNum > 0">{{ pendOrderNum < 100 ? pendOrderNum : '99+' }}</text>
</view>
<button class="default-btn comp-btn" @click="wholeOrderCancel(true,true)">整单取消</button>
<button class="primary-btn btn-right" :disabled="billingOrderData.goods_num == 0" @click="pay('')">结账</button>
</view>
</view>
<view class="pay-shade" v-show="type == 'pay'"></view>
</view>
<view class="uni-flex uni-row" style="flex: 1;">
<view class="list-wrap flex-1">
<!-- 商品 -->
<view class="content" v-show="type == 'goods'">
<ns-goods @openCashBox="openCashBox" :indexFocus="rightIndexFocus" ref="goods" />
</view>
<view class="content payment-content common-wrap" v-show="type == 'pay'">
<ns-payment ref="payment" storeRoute="billing" @cancel="cancelPayment" @success="paySuccess" :outTradeNo="outTradeNo"/>
</view>
</view>
</view>
</view>
<!-- 选择会员 -->
<ns-select-member ref="selectMember" />
<!-- 会员详情弹出框 -->
<ns-member-detail-popup ref="memberDetailPopup" isShowMemberCard/>
<!-- 挂单弹出框 -->
<ns-pend-order-popup ref="pendOrderPopup"/>
</base-page>
</template>
<script>
import billing from './public/js/billing.js';
import nsSelectMember from '@/components/ns-select-member/ns-select-member.vue';
import nsMemberDetail from '@/components/ns-member-detail/ns-member-detail.vue';
export default {
components: {
nsSelectMember,
nsMemberDetail
},
mixins: [billing]
};
</script>
<style lang="scss" scoped>
@import './public/css/index.scss';
</style>
<style>
.cashregister-header-box>>>.uni-select-lay-select {
padding-right: 0.1rem !important;
}
.cashregister-header-box>>>.uni-select-lay-icon {
display: none !important;
}
.cashregister-header-box>>>.uni-select-lay-input-close {
display: none !important;
}
</style>

View File

@@ -0,0 +1,435 @@
.left-wrap {
position: relative;
width: 4rem;
display: flex;
flex-direction: column;
margin-right: 0.2rem;
-ms-flex-negative: 0;
-webkit-flex-shrink: 0;
flex-shrink: 0;
border-radius: 0.04rem 0.04rem 0 0;
.pay-shade {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
background-color: rgba($color: #fff, $alpha: 0.6);
z-index: 10;
}
.order-time {
display: flex;
align-items: center;
.title {
user-select: none;
position: relative;
z-index: 3;
height: 0.3rem;
padding: 0 0.1rem 0 0.1rem;
box-sizing: border-box;
border-radius: 0.02rem;
border: 0.01rem solid #e5e5e5;
display: flex;
align-items: center;
font-size: 0.14rem;
color: #333;
}
.uni-date {
flex: 1;
margin-left: 0.1rem;
}
/deep/ .uni-date-x {
height: 0.28rem;
}
}
.content {
color: #303133;
flex: 1;
height: 0;
display: flex;
flex-direction: column;
.title {
font-size: 0.14rem;
display: flex;
justify-content: space-between;
}
.clear {
display: flex;
align-items: center;
text {
&:nth-child(1) {
font-size: 0.18rem;
}
&:nth-child(2) {
margin-left: 0.03rem;
font-size: 0.14rem;
}
}
}
.content-list {
flex: 1;
height: 0;
overflow-y: scroll;
padding: 0 0.2rem;
.content-head {
display: flex;
margin: 0.1rem 0;
view {
flex: 1;
font-size: 0.13rem;
}
.center {
text-align: center;
}
.right {
text-align: right;
}
}
.content-item {
position: relative;
display: flex;
align-items: start;
flex-wrap: wrap;
justify-content: space-between;
border-bottom: 0.01rem solid #e6e6e6;
padding-top: 0.08rem;
padding-bottom: 0.08rem;
&.focus,
&:focus {
outline: none;
}
.flex {
display: flex;
align-items: center;
}
.info-wrap {
margin-left: 0.1rem;
flex-wrap: wrap;
min-height: 0.6rem;
}
.item-img {
width: 0.6rem;
height: 0.6rem;
display: flex;
align-items: center;
image {
width: 100%;
}
}
.item-name {
font-size: 0.14rem;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
width: 2.04rem;
height: 0.20rem;
font-weight: 500;
color: #222222;
line-height: 0.20rem;
}
.item-del {
cursor: pointer;
font-size: 0.14rem;
display: flex;
align-items: center;
&:hover{
color: $primary-color;
}
.iconfont.iconshanchu{
font-size: 0.2rem;
}
}
.item-spe {
font-size: 0.12rem;
margin-top: 0.04rem;
width: 2.04rem;
height: 0.17rem;
font-weight: 500;
color: #808695;
line-height: 0.17rem;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.info-top{
width: 100%;
}
.info-bottom{
width: 100%;
align-self: flex-end;
}
.item-price{
flex: 1;
}
.item-subtotal {
flex: 1;
display: flex;
align-items: end;
.unit{
font-size: 0.12rem;
}
}
.item-num {
display: flex;
flex: 1;
justify-content: flex-end;
align-items: center;
margin-left: 0.1rem;
.num-dec {
width: 0.25rem;
height: 0.25rem;
background: #e6e6e6;
border: 0.01rem solid #e6e6e6;
border-radius: 30%;
text-align: center;
line-height: 0.23rem;
font-size: 0.25rem;
margin-right: 0.1rem;
cursor: pointer;
transition: 0.3s;
}
.num-inc {
width: 0.25rem;
height: 0.25rem;
background: $primary-color;
border: 0.01rem solid #e6e6e6;
border-radius: 30%;
text-align: center;
line-height: 0.23rem;
font-size: 0.25rem;
margin-left: 0.1rem;
cursor: pointer;
transition: 0.3s;
color: #fff;
}
}
.weight {
flex: 1;
justify-content: end;
}
.item-total-price {
font-size: 0.14rem;
margin-left: 0.1rem;
color: #fe2278;
}
.card-deduction {
width: 100%;
font-size: 0.12rem;
margin-top: 0.05rem;
color: #999;
}
}
}
.empty {
text-align: center;
image {
width: 60%;
margin-top: 0.4rem;
}
.tips {
color: #999;
margin-top: 0.15rem;
}
}
}
.bottom {
width: 100%;
padding:0.2rem 0.2rem 0.24rem 0.2rem;
box-sizing: border-box;
background-color: #ffffff;
.bottom-info {
display: flex;
align-items: center;
justify-content: space-between;
color: #303133;
font-weight: 500;
height: 0.27rem;
line-height: 0.27rem;
margin-bottom: 0.12rem;
.bottom-left {
font-size: 0.14rem;
}
.bottom-right {
font-size: 0.14rem;
.pay-money{
font-size: 0.27rem;
height: 0.22rem;
font-weight: 600;
font-family: AlibabaPuHuiTiM;
color: $primary-color;
line-height: 0.22rem;
}
}
}
.bottom-btn {
display: flex;
align-items: center;
margin-top: 0.2rem;
button{
width: 0.98rem;
margin: 0 !important;
height: 0.40rem;
line-height: 0.38rem;
border: 0.01rem solid #e6e6e6 !important;
&::after{
display: none;
}
&:hover{
border:0.01rem solid $primary-color !important;
}
}
.tag-parent {
position: relative;
.num-tag {
position: absolute;
background-color: #f00;
color: #fff;
height: 0.18rem;
line-height: 0.18rem;
padding: 0 0.06rem;
border-radius: 0.1rem;
font-size: 0.12rem;
text-align: center;
z-index: 1;
top: 0;
right: 0.12rem;
transform: translateY(-50%) translateX(100%);
}
}
.btn-right {
width: 1.4rem;
height: 0.4rem;
line-height: 0.4rem;
border:0 !important;
&:hover{
border:0 !important;
}
}
}
}
}
.comp-wrap {
min-width: 1rem;
border: 0.01rem solid #e6e6e6;
border-radius: 0.02rem;
padding: 0.2rem 0.17rem;
.comp-btn {
overflow: initial;
margin-bottom: 0.2rem;
}
}
.payment-content {
border-left: 0.01rem solid #e6e6e6;
padding-left: 0.17rem;
}
.list-wrap {
height: 100%;
box-sizing: border-box;
.content {
height: 100%;
}
.comp-btn {
width: 80%;
margin-top: 0.2rem;
}
.header {
height: 0.66rem;
line-height: 0.66rem;
text-align: left;
border-bottom: 0.01rem solid #e6e6e6;
color: #303133;
font-size: 0.14rem;
}
.body {
padding: 0.3rem;
}
}
.page-height {
height: 100%;
}
.common-wrap {
height: 100%;
}
.remark-wrap {
width: 6rem;
background-color: #fff;
border-radius: 0.04rem;
box-shadow: 0 0.01rem 0.12rem 0 rgba(0, 0, 0, 0.1);
.header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 0.15rem;
height: 0.45rem;
line-height: 0.45rem;
border-bottom: 0.01rem solid #e8eaec;
.iconfont {
font-size: $uni-font-size-lg;
}
}
.body {
padding: 0.15rem 0.15rem 0.1rem;
textarea {
border: 0.01rem solid #e6e6e6;
width: 100%;
padding: 0.1rem;
box-sizing: border-box;
font-size: 0.14rem;
}
.placeholder-class {
font-size: 0.14rem;
}
}
.footer {
height: 0.5rem;
padding-bottom: 0.05rem;
display: flex;
align-items: center;
justify-content: center;
button {
width: 95%;
}
}
}

View File

@@ -0,0 +1,730 @@
import {calculate, create} from '@/api/order_create.js'
import {addPendOrder, editPendOrder} from '@/api/pendorder.js'
import {mapGetters} from 'vuex';
export default {
data() {
return {
type: 'goods',
outTradeNo: '',
isRepeat: false,
leftIndexFocus: -1, // 左侧订单项 焦点索引
rightIndexFocus: -1, // 右侧选择商品 焦点索引
}
},
computed: {
...mapGetters(['billingGoodsData', 'billingOrderData', 'pendOrderNum', 'billingActive', 'billingIsScanTrigger','billingPendOrderId','memberSearchWayConfig'])
},
watch: {
pendOrderNum: function (nVal) {
if (nVal == 0) this.type = 'goods';
},
// 会员发生变化,重新计算价格
globalMemberInfo: function (nVal, oVal) {
this.calculation();
},
billingActive(nVal) {
if (nVal == 'SelectGoodsAfter') {
this.rightIndexFocus = -1; // 选择完商品后,取消选中焦点
}
},
billingGoodsData: {
// 每个属性值发生变化就会调用这个函数
handler(newVal, oldVal) {
this.calculation();
},
// 深度监听 属性的变化
deep: true
}
},
onLoad() {
uni.hideTabBar();
},
onShow() {
this.$store.commit('billing/setOrderData', {
create_time: this.$util.timeFormat(parseInt(new Date().getTime() / 1000))
});
// 添加组件的键盘监听事件
this.addKeyDownEvent();
if (this.$refs.goods) {
this.$refs.goods.init();
this.$refs.goods.addKeyDownEvent();
this.$refs.goods.addScanCodeEvent();
}
if (this.$refs.payment) {
this.$refs.payment.addKeyDownEvent();
}
},
onHide() {
this.removeKeyDownEvent();
// 移除组件的键盘监听事件
this.$refs.goods.removeKeyDownEvent();
this.$refs.goods.removeScanCodeEvent();
this.$refs.payment.removeKeyDownEvent();
},
methods: {
switchStoreAfter() {
this.wholeOrderCancel(true,true);
},
openMember() {
if (this.$refs.selectMember) {
this.$store.commit('billing/setActive', 'ShowMember');
this.$refs.selectMember.open(() => {
this.$store.commit('billing/setActive', 'ShowMemberAfter');
});
}
},
showMember() {
this.$store.commit('billing/setActive', 'ShowMember');
if (!this.globalMemberInfo) {
// 选择会员
if (this.$refs.selectMember) this.$refs.selectMember.open(() => {
this.$store.commit('billing/setActive', 'ShowMemberAfter');
});
} else {
// 打开会员信息弹出框
this.$refs.memberDetailPopup.open();
this.$store.commit('billing/setActive', 'ShowMemberAfter');
}
},
/**
* 切换为散客,清除会员、订单信息
*/
replaceMember() {
this.type = 'goods';
this.$store.commit('app/setGlobalMemberInfo', null);
this.$store.commit('billing/setOrderData', {
goods_num: 0,
pay_money: 0,
goods_list: [],
remark: '',
create_time: this.$util.timeFormat(parseInt(new Date().getTime() / 1000))
});
},
deleteGoods(data) {
var _billingGoodsData = this.$util.deepClone(this.billingGoodsData);
// 恢复调价
if (!data.card_item_id) {
for (let i = 0; i < this.$refs.goods.goodsData.list.length; i++) {
let item = this.$refs.goods.goodsData.list[i];
if (item.sku_id == data.sku_id) {
item.adjust_price = item.price;
item.adjust = {};
break;
}
}
}
delete _billingGoodsData[data.editKey];
//重组数据
var index = 0;
let tempGoodsData = {};
Object.keys(_billingGoodsData).forEach((key,index) =>{
if(_billingGoodsData[key].sku_id == data.sku_id){
let key_data = key.split('_');
key_data[key_data.length-1] = index;
index ++;
tempGoodsData[key_data.join('_')] = _billingGoodsData[key];
}else{
tempGoodsData[key] =_billingGoodsData[key];
}
});
let goodsIds = [];
Object.keys(tempGoodsData).forEach(key => {
let item = tempGoodsData[key];
if (!item.item_id && goodsIds.indexOf(item.goods_id) == -1) goodsIds.push(item.goods_id);
});
this.$store.commit('billing/setGoodsIds', goodsIds);
this.$store.commit('billing/setGoodsData', tempGoodsData);
if (!Object.keys(tempGoodsData).length) {
this.$store.commit('billing/setOrderData', {
goods_list: [],
goods_num: 0,
pay_money: 0,
create_time: this.$util.timeFormat(parseInt(new Date().getTime() / 1000))
});
}
},
/**
* 商品数量增加
* @param {Object} data
*/
inc(data) {
var _billingGoodsData = this.$util.deepClone(this.billingGoodsData);
if (data.card_item_id) {
let _data = _billingGoodsData['sku_' + data.sku_id + '_item_' + data.card_item_id];
if (_data.num >= data.stock) {
this.$util.showToast({
title: '商品库存不足'
});
return;
}
_billingGoodsData['sku_' + data.sku_id + '_item_' + data.card_item_id].num += 1;
} else {
var _data = _billingGoodsData[data.editKey];
if (_data.num >= data.stock) {
this.$util.showToast({
title: '商品库存不足'
});
return;
}
_billingGoodsData[data.editKey].num += 1;
}
this.$store.commit('billing/setGoodsData', _billingGoodsData);
},
/**
* 商品数量减少
* @param {Object} data
*/
dec(data) {
var _billingGoodsData = this.$util.deepClone(this.billingGoodsData);
if (data.card_item_id) {
let _data = _billingGoodsData['sku_' + data.sku_id + '_item_' + data.card_item_id];
if (_data.num == 1) return;
_billingGoodsData['sku_' + data.sku_id + '_item_' + data.card_item_id].num -= 1;
} else {
if (_billingGoodsData[data.editKey].num == 1) return;
_billingGoodsData[data.editKey].num -= 1;
}
this.$store.commit('billing/setGoodsData', _billingGoodsData);
},
/**
* 计算
*/
calculation() {
if (!Object.keys(this.billingGoodsData).length) {
this.$store.commit('billing/setOrderData', {
goods_num: 0
});
return;
}
let sku_array = [];
let goodsIds = [];
let editKeyData = {};
Object.keys(this.billingGoodsData).forEach(key => {
let item = this.billingGoodsData[key];
let skuData = {
sku_id: item.sku_id,
num: item.num,
card_item_id: item.item_id ? item.item_id : 0,
money: item.money ? item.money : 0 // 无码商品价格
};
if (item.is_adjust) {
skuData.price = item.price; // 手动调整价格
}
if (item.goods_money) skuData.goods_money = item.goods_money;
sku_array.push(skuData);
if (!item.item_id && goodsIds.indexOf(item.goods_id) == -1) goodsIds.push(item.goods_id);
//保存editKey数据
let editKeyIndex = skuData.sku_id+':'+skuData.card_item_id;
editKeyData[editKeyIndex] = key;
});
this.$store.commit('billing/setGoodsIds', goodsIds);
let data = {
sku_array: JSON.stringify(sku_array),
create_time: this.billingOrderData.create_time
};
if (this.globalMemberInfo) data.member_id = this.globalMemberInfo.member_id;
calculate(data).then(res => {
if (res.code == 0) {
let calculateOrderData = res.data;
calculateOrderData.goods_list.forEach((item, index) => {
let editKeyIndex = item.sku_id+':'+(item.card_item_id||0);
item.editKey = editKeyData[editKeyIndex];
});
this.$store.commit('billing/setOrderData', calculateOrderData);
} else {
this.$util.showToast({
title: res.message
})
}
})
},
/**
* 挂单
*/
hangingOrder() {
if (Object.keys(this.billingGoodsData).length) {
let data = {
goods: [],
order_id: this.billingPendOrderId,
remark: this.billingOrderData.remark
};
if (this.globalMemberInfo) data.member_id = this.globalMemberInfo.member_id;
Object.keys(this.billingGoodsData).forEach(key => {
let item = this.billingGoodsData[key];
let skuData = {
goods_id: item.goods_id,
sku_id: item.sku_id,
num: item.num,
money: item.money ? item.money : 0 // 无码商品价格
};
if (item.is_adjust) {
skuData.price = item.price; // 手动调整价格
}
data.goods.push(skuData)
});
data.goods = JSON.stringify(data.goods);
let api = this.billingPendOrderId ? editPendOrder(data) : addPendOrder(data);
api.then(res => {
if (res.code == 0) {
this.wholeOrderCancel();
this.$refs.pendOrderPopup.getOrder(0);
} else {
this.$util.showToast({
title: res.message
})
}
})
} else if (this.pendOrderNum) {
this.$refs.pendOrderPopup.open();
} else {
this.$util.showToast({
title: '当前没有挂单'
})
}
},
/**
* 整单取消
*/
wholeOrderCancel(isInit = false,isDelete = false) {
if (Object.keys(this.billingGoodsData).length) {
// 恢复调价
for (let i = 0; i < this.$refs.goods.goodsData.list.length; i++) {
let item = this.$refs.goods.goodsData.list[i];
item.adjust_price = item.price;
item.adjust = {};
}
// 清除当前会员
this.$store.commit('app/setGlobalMemberInfo', null);
// 清除商品数据
this.$store.commit('billing/setGoodsData', {});
this.$store.commit('billing/setGoodsIds', []);
if (isDelete && this.billingPendOrderId) {
this.$refs.pendOrderPopup.deleteOrder(this.billingPendOrderId);
}
this.$store.commit('billing/setPendOrderId',0);
// 清除订单数据
this.$store.commit('billing/setOrderData', {
goods_num: 0,
pay_money: 0,
goods_list: [],
remark: '',
create_time: this.$util.timeFormat(parseInt(new Date().getTime() / 1000)),
order_id: 0
});
this.outTradeNo = '';
} else {
if (!isInit) this.$util.showToast({
title: '当前没有订单数据!!'
})
}
},
/**
* 支付
*/
pay(type = '', callback) {
const memberId = this.globalMemberInfo ? this.globalMemberInfo.member_id : 0;
if (this.$refs.payment) this.$refs.payment.clearPay();
if (!Object.keys(this.billingGoodsData).length || this.isRepeat) return;
this.isRepeat = true;
if (this.outTradeNo) {
this.type = 'pay';
if (type) this.$refs.payment.type = type;
return;
}
this.$store.commit('billing/setActive', 'OrderCreate'); // 记录页面活跃值:创建订单
let data = {
remark: this.billingOrderData.remark,
create_time: this.billingOrderData.create_time,
member_id: memberId,
order_key: this.billingOrderData.order_key
};
create(data).then(res => {
this.isRepeat = false;
if (res.code == 0) {
this.outTradeNo = res.data.out_trade_no;
this.type = 'pay';
if (type) this.$refs.payment.type = type;
setTimeout(() => {
if (callback) callback();
}, 100)
} else {
this.$util.showToast({
title: res.message,
})
}
})
},
cancelPayment() {
this.outTradeNo = '';
this.$store.commit('billing/setActive', 'SelectGoodsAfter');
this.type = 'goods';
},
paySuccess() {
this.type = 'goods';
this.$store.commit('billing/setActive', '');
this.isRepeat = false;
this.wholeOrderCancel(false,true);
this.$refs.goods.getGoods();
},
// 调整商品价格,数量
callBox(data) {
//服务商品不支持修改
if(data.goods_class == this.$util.goodsClassDict.service) return;
if(data.card_item_id > 0) return;
data.status = 'edit'; // 调整商品标识
this.$refs.goods.goodsSelect(data);
},
/**
* 添加键盘监听事件
*/
addKeyDownEvent() {
// #ifdef H5
window.addEventListener("keydown", this.listenerKeyDown, true);
window.addEventListener("focus", this.listenerFocus, true);
// 监听F1~F12BACKSPACE
window.POS_HOTKEY_CALLBACK = (control, code) => {
this.posHotKeyCallback(code);
};
// #endif
},
/**
* 移除键盘监听事件
*/
removeKeyDownEvent() {
// #ifdef H5
window.removeEventListener("keydown", this.listenerKeyDown, true);
window.removeEventListener("focus", this.listenerFocus, true);
delete window.POS_HOTKEY_CALLBACK;
// #endif
},
// 监听焦点事件
listenerFocus(e) {
if (this.billingActive == 'OrderCreate') return;
let tab = {
// 聚焦 获取商品选择
TabGoodsFocus: {
className: 'goods-select-focus',
focusField: 'rightIndexFocus'
},
// 聚焦 获取订单结算商品
TabOrderFocus: {
className: 'settlement-select-focus',
focusField: 'leftIndexFocus'
}
};
for (let key in tab) {
if (e.target.className && e.target.className.indexOf(tab[key].className) != -1) {
this.leftIndexFocus = -1;
this.rightIndexFocus = -1;
for (let i = 0; i < e.target.attributes.length; i++) {
var item = e.target.attributes[i];
if (item.name == 'data-tab-index') {
this[tab[key].focusField] = parseInt(item.value);
break;
}
}
if (this[tab[key].focusField] > -1) {
this.$store.commit('billing/setActive', key);
}
}
}
},
// 监听键盘按下事件
listenerKeyDown(e) {
var code = e.code;
if (code == 'Tab') return;
// console.log('监听键盘按下事件 KeyDown', this.type, code, this.billingActive, this.billingIsScanTrigger, this.billingOrderData, e);
// 按键ESC解除占用
if (this.billingIsScanTrigger && code == 'Escape') this.$store.commit('billing/setIsScanTrigger', false);
// 正在输入商品编码 商品/项目名称
if (this.billingActive == 'inputSearchText') return;
// 关闭商品弹出框
if (code == 'Escape' && this.billingActive == 'SelectGoodsSku' && this.type == 'goods') {
this.$store.commit('billing/setActive', 'SelectGoodsAfter');
return;
}
if (this.type != 'pay' && this.billingActive != 'SelectGoodsSku' && code == 'KeyM') {
// 选择会员键盘快捷键【M】
this.openMember();
} else if (this.type == 'goods' && code == 'PageUp') {
// 切换左侧焦点
this.$store.commit('billing/setActive', 'TabOrderFocus');
this.leftIndexFocus = 0;
this.rightIndexFocus = -1;
code = 'ArrowUp';
} else if (this.type == 'goods' && code == 'PageDown') {
// 切换右侧焦点
this.$store.commit('billing/setActive', 'TabGoodsFocus');
this.rightIndexFocus = 0;
this.leftIndexFocus = -1;
code = 'ArrowLeft';
} else if (this.billingActive == 'TabGoodsFocus') {
// 使用tab键聚焦选择商品
this.tabGoodsFocusCallback(code);
} else if (this.billingActive == 'TabOrderFocus') {
// 使用tab键聚焦获取订单结算商品
this.tabOrderFocusCallback(code);
} else if(this.billingActive == 'ShowMember' && this.memberSearchWayConfig.way == 'list'){
// 按照会员列表进行搜索
if (code == 'Enter' || code == 'NumpadEnter') {
if(this.$refs.selectMember.searchFinish && this.$refs.selectMember.memberId){
this.$refs.selectMember.getMemberInfo(this.$refs.selectMember.memberId);
}
}
} else if (this.billingActive == 'ShowMemberAfter' || (this.billingOrderData.goods_num && this.billingActive == 'SelectGoodsAfter' && !this.billingIsScanTrigger)) {
// 活跃窗口:设置会员后,选择完商品后
if (code == 'Enter' || code == 'NumpadEnter') {
this.pay('');
}
}
},
/**
* 监听键盘事件回调
* @param {Object} code
*/
posHotKeyCallback(code) {
// console.log('POS ${code} 按键', code, this.type);
if (code == 'F2') {
// 选择商品
if (this.type != 'pay') {
this.type = 'goods';
this.$store.commit('billing/setActive', 'SelectGoodsAfter');
}
} else if (code == 'F3') {
// 挂/取单
if (this.type != 'pay') {
this.hangingOrder();
}
} else if (code == 'F4') {
// 选择会员
if (this.type != 'pay') {
this.showMember();
}
} else if (code == 'F12') {
// 整单取消
if (this.type != 'pay') {
this.wholeOrderCancel(false,true);
}
} else if (code == 'BACKSPACE') {
// 退格键
if (this.billingActive == 'UnnumberedGoods' && this.type == 'goods') {
if (this.$refs.goods) this.$refs.goods.deleteCode();
} else if (this.billingActive == 'OrderCreate') {
if (this.$refs.payment) {
if (this.$refs.payment.active == 'OpenMoneyPopup') {
this.$refs.payment.deleteCode();
}
}
}
} else if (code == 'X') {
// 打开钱箱快捷键Alt+X
this.openCashBox();
} else if (this.type == 'goods' && code == 'PAGEUP') {
// 切换左侧焦点
this.$store.commit('billing/setActive', 'TabOrderFocus');
this.leftIndexFocus = 0;
this.rightIndexFocus = -1;
this.tabOrderFocusCallback('ArrowUp');
} else if (this.type == 'goods' && code == 'PAGEDOWN') {
// 切换右侧焦点
this.$store.commit('billing/setActive', 'TabGoodsFocus');
this.rightIndexFocus = 0;
this.leftIndexFocus = -1;
this.tabGoodsFocusCallback('ArrowLeft');
} else {
// 触发左侧菜单按键回调
this.menuTriggerKeyCodeCallBack(code);
}
},
// 打开钱箱
openCashBox() {
try {
let data = {
message: '打开钱箱'
};
this.$pos.send('OpenCashBox', JSON.stringify(data));
} catch (e) {
console.log('打开钱箱异常', e)
}
},
/**
* 使用tab键聚焦选择商品 事件回调
* @param {string} code 按键代码
*/
tabGoodsFocusCallback(code) {
if (!this.$refs.goods) return;
let list = document.querySelectorAll(`.${this.$refs.goods.type}-focus.table-item`);
if (code == 'Enter' || code == 'NumpadEnter') {
if (this.$refs.goods.type == 'goods') {
// 添加实物商品
this.$refs.goods.goodsSelect(this.$refs.goods.goodsData.list[this.rightIndexFocus]);
} else if (this.$refs.goods.type == 'service') {
// 添加项目商品
this.$refs.goods.goodsSelect(this.$refs.goods.serviceData.list[this.rightIndexFocus]);
}
} else if (code == 'ArrowUp' && this.rightIndexFocus > -1) {
// 上箭头商品goods项目service
const query = uni.createSelectorQuery().in(this);
query.select(`.goods-container .list-wrap.${this.$refs.goods.type}`).boundingClientRect(data => {
this.rightIndexFocus -= Math.floor(data.width / 270); // 单个元素宽度270
// 超出,选择第一个
if (this.rightIndexFocus <= 0) this.rightIndexFocus = 0;
list[this.rightIndexFocus].focus();
}).exec();
} else if (code == 'ArrowDown' && this.rightIndexFocus > -1) {
// 下箭头商品goods项目service
const query = uni.createSelectorQuery().in(this);
query.select(`.goods-container .list-wrap.${this.$refs.goods.type}`).boundingClientRect(data => {
this.rightIndexFocus += Math.floor(data.width / 270); // 单个元素宽度270
// 超出,选择最后一个
if (this.rightIndexFocus >= list.length) this.rightIndexFocus = list.length - 1;
list[this.rightIndexFocus].focus();
}).exec();
} else if (code == 'ArrowRight' && this.rightIndexFocus > -1) {
// 右箭头
if (this.rightIndexFocus + 1 >= list.length) return;
this.rightIndexFocus++;
list[this.rightIndexFocus].focus();
} else if (code == 'ArrowLeft' && this.rightIndexFocus > -1) {
// 左箭头
if (this.rightIndexFocus <= 0) return;
this.rightIndexFocus--;
list[this.rightIndexFocus].focus();
}
},
/**
* 使用tab键聚焦 获取订单结算商品 事件回调
* @param {string} code 按键代码
*/
tabOrderFocusCallback(code) {
// 按键回车,弹框调整商品数量,注意,此时只能修改商品数量,不能更改规格
if (code == 'Enter' || code == 'NumpadEnter') {
if (this.billingOrderData.goods_list[this.leftIndexFocus]) {
let data = this.$util.deepClone(this.billingOrderData.goods_list[this.leftIndexFocus]);
data.status = 'edit'; // 修改商品数量标识
if (this.$refs.goods) this.$refs.goods.goodsSelect(data);
}
} else if (code == 'ArrowUp' && this.leftIndexFocus > -1) {
// 上箭头
let list = document.querySelectorAll(`.settlement-select-focus`);
if (this.leftIndexFocus <= 0) return;
this.leftIndexFocus--;
list[this.leftIndexFocus].focus();
} else if (code == 'ArrowDown' && this.leftIndexFocus > -1) {
// 下箭头
let list = document.querySelectorAll(`.settlement-select-focus`);
if (this.leftIndexFocus + 1 >= list.length) return;
this.leftIndexFocus++;
list[this.leftIndexFocus].focus();
} else if (code == 'Delete' && this.leftIndexFocus > -1) {
this.deleteGoods(this.billingOrderData.goods_list[this.leftIndexFocus], this.leftIndexFocus);
}
},
// 恢复焦点下标
restoreFocus() {
this.leftIndexFocus = -1;
this.rightIndexFocus = -1;
},
leftTabOrderSelectBlur(item){
this.$store.commit('billing/setActive', 'SelectGoodsAfter');
}
},
}

View File

@@ -0,0 +1,157 @@
<template>
<base-page>
<view class="uni-flex uni-row page-height">
<view class="common-wrap left-wrap">
<view class="cashregister-header-box">
<view class="order-time">
<view class="title">消费时间</view>
<uni-datetime-picker v-model="buyCardOrderData.create_time" type="datetime" :clearIcon="false" />
</view>
<view class="header" v-if="globalMemberInfo">
<view class="headimg" @click="showMember">
<image class="header-image" :src="globalMemberInfo.headimg ? $util.img(globalMemberInfo.headimg) : $util.img(defaultImg.head)" @error="globalMemberInfo.headimg = defaultImg.head"/>
<view v-if="globalMemberInfo.member_level" class="member-nameplate">
{{ globalMemberInfo.member_level_name }}
</view>
</view>
<view class="head-info" @click="showMember">
<view class="head-info-top">
<view class="name">
<block v-if="globalMemberInfo.mobile">
<view class="mobile">{{ globalMemberInfo.mobile }}</view>
<view class="text">
<text></text>
<text class="nickname">{{globalMemberInfo.nickname }}</text>
<text></text>
</view>
</block>
<text v-else>{{ globalMemberInfo.nickname }}</text>
</view>
</view>
<view class="head-info-bottom point">积分{{ globalMemberInfo.point }}</view>
<view class="head-info-bottom balance">余额{{ (parseFloat(globalMemberInfo.balance_money) + parseFloat(globalMemberInfo.balance)) | moneyFormat}}</view>
</view>
<button class="switch primary-btn member-open" @click="openMember()">更换会员</button>
<button class="switch primary-btn replace-member" @click="replaceMember()">散客</button>
</view>
<view class="header" v-else>
<view class="headimg">
<image class="header-image" :src="$util.img(defaultImg.head)" />
</view>
<view class="head-info">
<view class="name">散客</view>
</view>
<button class="switch primary-btn" @click="openMember()">查询会员</button>
</view>
</view>
<view class="content">
<!-- <view class="title">
<view>结算清单<text>{{ buyCardOrderData.goods_num }}</text></view>
<view class="clear" @click="clearGoods">
<text class="iconfont iconqingchushujuku"></text>
<text>清空</text>
</view>
</view> -->
<view class="content-list common-scrollbar">
<block v-if="buyCardOrderData.goods_list.length && Object.keys(buyCardGoodsData).length">
<view class="content-item" v-for="(item, index) in buyCardOrderData.goods_list" :key="index">
<view class="item-img">
<image :src="$util.img(item.goods_image.split(',')[0], { size: 'small' })" mode="widthFix"/>
</view>
<view class="uni-flex flex-1 info-wrap">
<view class="info-top">
<view class="uni-flex justify-between items-center">
<view class="item-name">{{ item.sku_name }}</view>
<view class="item-del" @click="deleteGoods(item)">
<text class="iconfont iconshanchu"></text>
<text>删除</text>
</view>
</view>
<view class="item-spe" v-if="item.spec_name" arrow-down>{{ item.spec_name }}</view>
</view>
<view class="info-bottom flex justify-between items-center">
<view class="item-price">{{ item.price | moneyFormat }}</view>
<view class="item-num">
<view class="num-dec" @click="dec(item)">-</view>
<view class="num">{{ buyCardGoodsData['sku_' + item.sku_id].num }}</view>
<view class="num-inc" @click="inc(item)">+</view>
</view>
</view>
</view>
</view>
</block>
<block v-else>
<view class="empty">
<image src="@/static/cashier/cart_empty.png" mode="widthFix"/>
<view class="tips">点击右侧商品选择商品进行结账</view>
</view>
</block>
</view>
</view>
<view class="bottom">
<view class="bottom-info">
<view class="bottom-left">合计 <text>{{ buyCardOrderData.goods_num }}</text> </view>
<text class="pay-money">{{ buyCardOrderData.pay_money | moneyFormat }}</text>
</view>
<view class="bottom-btn">
<button class="primary-btn btn-right" :disabled="buyCardOrderData.goods_num == 0" @click="pay('')">结账</button>
</view>
</view>
<view class="pay-shade" v-show="type == 'pay'"></view>
</view>
<view class="uni-flex uni-row" style="flex: 1;">
<view class="list-wrap flex-1">
<!-- 卡项商品 -->
<view class="content" v-show="type == 'goods'">
<ns-card :type="buyCardOrderData.card_type" ref="card"/>
</view>
<view class="content" v-show="type == 'pay'">
<ns-payment ref="payment" storeRoute="buycard" @cancel="cancelPayment" @success="paySuccess" :outTradeNo="outTradeNo"/>
</view>
</view>
</view>
</view>
<ns-select-member ref="selectMember"/>
<!-- 会员详情弹出框 -->
<ns-member-detail-popup ref="memberDetailPopup" />
</base-page>
</template>
<script>
import buycard from './public/js/buycard.js';
import nsSelectMember from '@/components/ns-select-member/ns-select-member.vue';
export default {
components: {
nsSelectMember
},
mixins: [buycard]
};
</script>
<style lang="scss" scoped>
@import './public/css/index.scss';
</style>
<style>
.cashregister-header-box>>>.uni-select-lay-select {
padding-right: 0.1rem !important;
}
.cashregister-header-box>>>.uni-select-lay-icon {
display: none !important;
}
.cashregister-header-box>>>.uni-select-lay-input-close {
display: none !important;
}
</style>

View File

@@ -0,0 +1,326 @@
.common-wrap.right-wrap{
background-color: transparent;
}
.left-wrap {
position: relative;
width: 4rem;
display: flex;
flex-direction: column;
margin-right: 0.2rem;
border-radius: 0.04rem;
.pay-shade {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
background-color: rgba($color: #fff, $alpha: 0.6);
z-index: 10;
}
.content {
color: #303133;
flex: 1;
height: 0;
display: flex;
flex-direction: column;
.title {
font-size: 0.14rem;
padding: 0.1rem 0.25rem;
justify-content: space-between;
display: flex;
}
.clear {
display: flex;
align-items: center;
text {
&:nth-child(1) {
font-size: 0.18rem;
}
&:nth-child(2) {
margin-left: 0.03rem;
font-size: 0.14rem;
}
}
}
.content-list {
margin-top: 0.1rem;
flex: 1;
height: 0;
overflow-y: scroll;
padding: 0 0.2rem;
.content-item {
position: relative;
display: flex;
align-items: start;
flex-wrap: wrap;
justify-content: space-between;
border-bottom: 0.01rem solid #e6e6e6;
padding-top: 0.08rem;
padding-bottom: 0.08rem;
&.focus,
&:focus {
outline: none;
}
.flex {
display: flex;
align-items: center;
}
.info-wrap {
margin-left: 0.1rem;
flex-wrap: wrap;
min-height: 0.6rem;
}
.item-img {
width: 0.6rem;
height: 0.6rem;
display: flex;
align-items: center;
image {
width: 100%;
}
}
.item-name {
font-size: 0.14rem;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
width: 2.04rem;
height: 0.20rem;
font-weight: 500;
color: #222222;
line-height: 0.20rem;
}
.item-del {
cursor: pointer;
font-size: 0.14rem;
display: flex;
align-items: center;
&:hover {
color: $primary-color;
}
.iconfont.iconshanchu {
font-size: 0.2rem;
}
}
.item-spe {
font-size: 0.12rem;
margin-top: 0.04rem;
width: 2.04rem;
height: 0.17rem;
font-weight: 500;
color: #808695;
line-height: 0.17rem;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.info-top {
width: 100%;
}
.info-bottom {
width: 100%;
align-self: flex-end;
}
.item-price {
flex: 1;
}
.item-subtotal {
flex: 1;
display: flex;
align-items: end;
.unit {
font-size: 0.12rem;
}
}
.item-num {
display: flex;
flex: 1;
justify-content: flex-end;
align-items: center;
margin-left: 0.1rem;
.num {
// min-width: 0.82rem;
// text-align: right;
}
.num-dec {
width: 0.25rem;
height: 0.25rem;
background: #e6e6e6;
border: 0.01rem solid #e6e6e6;
border-radius: 30%;
text-align: center;
line-height: 0.23rem;
font-size: 0.25rem;
margin-right: 0.1rem;
cursor: pointer;
transition: 0.3s;
}
.num-inc {
width: 0.25rem;
height: 0.25rem;
background: $primary-color;
border: 0.01rem solid #e6e6e6;
border-radius: 30%;
text-align: center;
line-height: 0.23rem;
font-size: 0.25rem;
margin-left: 0.1rem;
cursor: pointer;
transition: 0.3s;
color: #fff;
}
}
.weight {
flex: 1;
justify-content: end;
}
.item-total-price {
font-size: 0.14rem;
margin-left: 0.1rem;
color: #fe2278;
}
.card-deduction {
width: 100%;
font-size: 0.12rem;
margin-top: 0.05rem;
color: #999;
}
}
}
.empty {
text-align: center;
image {
width: 60%;
margin-top: 0.4rem;
}
.tips {
color: #999;
margin-top: 0.15rem;
}
}
}
.bottom {
width: 100%;
padding: 0.2rem 0.2rem 0.24rem 0.2rem;
box-sizing: border-box;
background-color: #ffffff;
.bottom-info {
display: flex;
align-items: center;
justify-content: space-between;
color: #303133;
font-weight: 500;
height: 0.27rem;
line-height: 0.27rem;
margin-bottom: 0.12rem;
.bottom-left {
font-size: 0.14rem;
color: #303133;
text{
display: inline-block;
margin: 0 .05rem;
}
.money {
color: #fe2278;
}
}
.pay-money {
font-size: 0.27rem;
height: 0.27rem;
font-weight: 600;
font-family: AlibabaPuHuiTiM;
color: $primary-color;
line-height: 0.22rem;
}
}
.bottom-btn {
display: flex;
align-items: center;
margin-top: 0.2rem;
justify-content: flex-end;
.btn-right {
width: 1.4rem;
height: 0.4rem;
line-height: 0.4rem;
border: 0 !important;
margin: 0;
}
}
}
}
.list-wrap {
border-radius: 0.02rem;
height: 100%;
border-left: 0;
box-sizing: border-box;
flex:1;
.content {
height: 100%;
}
.comp-btn {
width: 80%;
margin-top: 0.2rem;
}
.header {
height: 0.66rem;
line-height: 0.66rem;
text-align: left;
color: #303133;
font-size: 0.14rem;
}
.body {
padding: 0.3rem;
}
}
.page-height {
height: 100%;
}
.common-wrap {
height: 100%;
}

View File

@@ -0,0 +1,346 @@
import {cardCalculate, cardCreate} from '@/api/order_create.js'
import {mapGetters} from 'vuex';
export default {
data() {
return {
type: 'goods',
isRepeat: false,
outTradeNo: ''
};
},
computed: {
...mapGetters(['buyCardGoodsData', 'buyCardOrderData', 'buyCardActive', 'memberSearchWayConfig'])
},
watch: {
globalMemberInfo: function (nVal) {
this.calculation();
},
buyCardGoodsData: {
// 每个属性值发生变化就会调用这个函数
handler(newVal, oldVal) {
this.calculation();
},
// 深度监听 属性的变化
deep: true
}
},
onLoad(option) {
uni.hideTabBar();
this.$store.commit('buycard/setOrderData', {
card_type: option.type || 'oncecard'
});
if (this.globalMemberInfo) this.type = 'goods';
},
onShow() {
this.$store.commit('buycard/setOrderData', {
create_time: this.$util.timeFormat(parseInt(new Date().getTime() / 1000))
});
if (this.$refs.card) this.$refs.card.init();
this.calculation();
this.addKeyDownEvent();
// 添加组件的键盘监听事件
if (this.$refs.payment) this.$refs.payment.addKeyDownEvent();
},
onHide() {
this.removeKeyDownEvent();
// 移除组件的键盘监听事件
this.$refs.payment.removeKeyDownEvent();
},
methods: {
switchStoreAfter() {
if (this.$refs.card) this.$refs.card.init();
this.calculation();
},
openMember() {
if (this.$refs.selectMember) {
this.$store.commit('buycard/setActive', 'ShowMember');
this.$refs.selectMember.open(() => {
this.$store.commit('buycard/setActive', 'ShowMemberAfter');
});
}
},
showMember() {
this.$store.commit('buycard/setActive', 'ShowMember');
if (!this.globalMemberInfo) {
if (this.$refs.selectMember) this.$refs.selectMember.open(() => {
this.$store.commit('buycard/setActive', 'ShowMemberAfter');
});
} else {
// 打开会员信息弹出框
this.$store.commit('buycard/setActive', 'ShowMemberAfter');
this.$refs.memberDetailPopup.open();
}
},
/**
* 切换散客
*/
replaceMember() {
this.$store.commit('app/setGlobalMemberInfo', null);
this.type = 'goods';
},
calculation() {
if (!Object.keys(this.buyCardGoodsData).length) return;
let sku_array = [];
Object.keys(this.buyCardGoodsData).forEach(key => {
let item = this.buyCardGoodsData[key];
sku_array.push({
sku_id: item.sku_id,
num: item.num
});
});
let data = {
sku_array: JSON.stringify(sku_array),
create_time: this.buyCardOrderData.create_time
};
if (this.globalMemberInfo) data.member_id = this.globalMemberInfo.member_id;
cardCalculate(data).then(res => {
if (res.code == 0) {
this.$store.commit('buycard/setOrderData', res.data);
} else {
this.$util.showToast({
title: res.message
});
}
})
},
inc(data) {
let _buyCardGoodsData = this.$util.deepClone(this.buyCardGoodsData);
if (data.goods_type != '') {
_buyCardGoodsData['sku_' + data.sku_id].num += 1;
} else {
if (data.num < data.stock) _buyCardGoodsData['sku_' + data.sku_id].num += 1;
}
this.$store.commit('buycard/setGoodsData', _buyCardGoodsData);
},
dec(data) {
if (data.num > 1) {
let _buyCardGoodsData = this.$util.deepClone(this.buyCardGoodsData);
_buyCardGoodsData['sku_' + data.sku_id].num -= 1;
this.$store.commit('buycard/setGoodsData', _buyCardGoodsData);
}
},
deleteGoods(data) {
let _buyCardGoodsData = this.$util.deepClone(this.buyCardGoodsData);
delete _buyCardGoodsData['sku_' + data.sku_id];
this.$store.commit('buycard/setGoodsData', _buyCardGoodsData);
if (!Object.keys(_buyCardGoodsData).length) {
this.$store.commit('buycard/setOrderData', {
goods_list: [],
goods_num: 0,
pay_money: 0
});
}
},
clearGoods() {
this.$store.commit('buycard/setGoodsData', {});
this.$store.commit('buycard/setOrderData', {
goods_list: [],
goods_num: 0,
pay_money: 0
});
},
pay(type = '', callback) {
if (!this.globalMemberInfo) {
if (this.$refs.selectMember) {
this.$store.commit('buycard/setActive', 'ShowMember');
this.$refs.selectMember.open(() => {
this.$store.commit('buycard/setActive', 'ShowMemberAfter');
});
setTimeout(() => {
this.$refs.selectMember.inputFocus = true;
}, 200);
}
return false;
}
if (!Object.keys(this.buyCardGoodsData).length || this.isRepeat) return;
this.isRepeat = true;
if (this.outTradeNo) {
this.type = 'pay';
if (type) this.$refs.payment.type = type;
return;
}
this.$store.commit('buycard/setActive', 'OrderCreate'); // 记录页面活跃值:创建订单
let sku_array = [];
Object.keys(this.buyCardGoodsData).forEach(key => {
let item = this.buyCardGoodsData[key];
sku_array.push({
sku_id: item.sku_id,
num: item.num
});
});
let data = {
sku_array: JSON.stringify(sku_array),
remark: this.buyCardOrderData.remark,
create_time: this.buyCardOrderData.create_time,
order_key: this.buyCardOrderData.order_key
};
if (this.globalMemberInfo) data.member_id = this.globalMemberInfo.member_id;
cardCreate(data).then(res => {
this.isRepeat = false;
if (res.code == 0) {
this.outTradeNo = res.data.out_trade_no;
this.type = 'pay';
if (type) this.$refs.payment.type = type;
setTimeout(() => {
if (callback) callback();
}, 100)
} else {
this.$util.showToast({
title: res.message
});
}
});
},
cancelPayment() {
this.outTradeNo = '';
this.type = 'goods';
},
paySuccess() {
this.type = 'goods';
this.isRepeat = false;
this.$store.commit('buycard/setActive', '');
this.wholeOrderCancel();
this.$refs.card.onceCardData.page = 0;
this.$refs.card.onceCardData.total = 1;
this.$refs.card.timeCardData.page = 0;
this.$refs.card.timeCardData.total = 1;
this.$refs.card.commonCardData.page = 0;
this.$refs.card.commonCardData.total = 1;
this.$refs.card.getOnceCard();
this.$refs.card.getTimeCard();
this.$refs.card.getCommonCard();
},
/**
* 整单取消
*/
wholeOrderCancel() {
if (Object.keys(this.buyCardGoodsData).length) {
// 清除商品数据
this.$store.commit('buycard/setGoodsData', {});
let orderId = this.billingOrderData && (this.billingOrderData.order_id ? this.billingOrderData.order_id : 0) || 0
// 清除订单数据
this.$store.commit('buycard/setOrderData', {
goods_num: 0,
pay_money: 0,
goods_list: [],
remark: '',
create_time: this.$util.timeFormat(parseInt(new Date().getTime() / 1000)),
order_id: orderId
});
this.outTradeNo = '';
}
},
toGoods() {
this.type = 'goods';
},
/**
* 添加键盘监听事件
*/
addKeyDownEvent() {
// #ifdef H5
// 绑定监听事件
window.addEventListener("keydown", this.listenerKeyDown, true);
// 监听F1~F12BACKSPACE
window.POS_HOTKEY_CALLBACK = (control, code) => {
this.posHotKeyCallback(code);
};
// #endif
},
/**
* 移除键盘监听事件
*/
removeKeyDownEvent() {
// #ifdef H5
window.removeEventListener("keydown", this.listenerKeyDown, true);
delete window.POS_HOTKEY_CALLBACK;
// #endif
},
listenerKeyDown(e) {
var code = e.code;
// console.log('KeyDown', this.type, code, this.buyCardActive, e);
if (this.type != 'pay' && code == 'KeyM') {
// 选择会员键盘快捷键【M】
this.openMember();
} else if(this.buyCardActive == 'ShowMember' && this.memberSearchWayConfig.way == 'list'){
// 按照会员列表进行搜索
if (code == 'Enter' || code == 'NumpadEnter') {
if(this.$refs.selectMember.searchFinish && this.$refs.selectMember.memberId){
this.$refs.selectMember.getMemberInfo(this.$refs.selectMember.memberId);
}
}
} else if (this.buyCardActive == 'ShowMemberAfter') {
// 活跃窗口:设置会员后
if (code == 'Enter' || code == 'NumpadEnter') {
this.pay('');
}
} else if (this.buyCardOrderData.goods_num && this.buyCardActive == 'SelectGoodsAfter') {
// 选择卡项商品后
if (code == 'Enter' || code == 'NumpadEnter') {
this.pay('');
}
}
},
/**
* 监听键盘事件回调
* @param {Object} code
*/
posHotKeyCallback(code) {
if (code == 'F2') {
// 选择卡项
if (this.type != 'pay') {
this.toGoods();
this.$store.commit('buycard/setActive', 'SelectGoodsAfter');
}
} else if (code == 'F3') {
// 选择会员
if (this.type != 'pay') {
this.showMember();
}
} else if (code == 'BACKSPACE') {
// 退格键
if (this.buyCardActive == 'OrderCreate') {
if (this.$refs.payment) {
if (this.$refs.payment.active == 'openMoneyPopup') {
this.$refs.payment.deleteCode();
}
}
}
} else {
// 触发左侧菜单按键回调
this.menuTriggerKeyCodeCallBack(code);
}
}
}
}

View File

@@ -0,0 +1,229 @@
<template>
<base-page>
<view class="collect-money-config">
<view class="common-wrap common-form fixd common-scrollbar">
<view class="common-title">收款设置</view>
<view class="common-form-item">
<label class="form-label">优惠减现</label>
<view class="form-inline">
<radio-group @change="config.reduction = $event.detail.value" class="form-radio-group">
<label class="radio form-radio-item">
<radio value="1" :checked="config.reduction == 1" />
启用
</label>
<label class="radio form-radio-item">
<radio value="0" :checked="config.reduction == 0" />
关闭
</label>
</radio-group>
</view>
</view>
<view class="common-form-item">
<label class="form-label">积分抵扣</label>
<view class="form-inline">
<radio-group @change="config.point = $event.detail.value" class="form-radio-group">
<label class="radio form-radio-item">
<radio value="1" :checked="config.point == 1" />
启用
</label>
<label class="radio form-radio-item">
<radio value="0" :checked="config.point == 0" />
关闭
</label>
</radio-group>
</view>
<text class="form-word-aux-line">积分抵扣需要平台开启同时配置积分抵扣金额比率</text>
</view>
<view class="common-form-item">
<label class="form-label">使用余额</label>
<view class="form-inline">
<radio-group @change="config.balance = $event.detail.value" class="form-radio-group">
<label class="radio form-radio-item">
<radio value="1" :checked="config.balance == 1" />
启用
</label>
<label class="radio form-radio-item">
<radio value="0" :checked="config.balance == 0" />
关闭
</label>
</radio-group>
</view>
</view>
<view v-show="config.balance == 1">
<view class="common-form-item">
<label class="form-label">余额使用安全验证</label>
<view class="form-inline">
<radio-group @change="config.balance_safe = $event.detail.value" class="form-radio-group">
<label class="radio form-radio-item">
<radio value="1" :checked="config.balance_safe == 1" />
启用
</label>
<label class="radio form-radio-item">
<radio value="0" :checked="config.balance_safe == 0" />
关闭
</label>
</radio-group>
</view>
<text class="form-word-aux-line">关闭之后直接使用余额进行抵扣无需会员验证</text>
</view>
<view class="common-form-item" v-show="config.balance_safe == 1">
<label class="form-label">手机号验证</label>
<view class="form-inline">
<radio-group @change="config.sms_verify = $event.detail.value" class="form-radio-group">
<label class="radio form-radio-item">
<radio value="1" :checked="config.sms_verify == 1" />
启用
</label>
<label class="radio form-radio-item">
<radio value="0" :checked="config.sms_verify == 0" />
关闭
</label>
</radio-group>
</view>
<text class="form-word-aux-line">使用余额安全验证时是否可以使用短信验证码验证</text>
</view>
</view>
<view class="common-form-item">
<label class="form-label">收款方式</label>
<view class="form-inline">
<checkbox-group class="form-checkbox-group" @change="config.pay_type = $event.detail.value">
<label class="form-checkbox-item">
<checkbox value="third" :checked="config.pay_type.indexOf('third') != -1" />
付款码支付
</label>
<label class="form-checkbox-item">
<checkbox value="cash" :checked="config.pay_type.indexOf('cash') != -1" />
现金支付
</label>
<label class="form-checkbox-item">
<checkbox value="own_wechatpay" :checked="config.pay_type.indexOf('own_wechatpay') != -1" />
个人微信
</label>
<label class="form-checkbox-item">
<checkbox value="own_alipay" :checked="config.pay_type.indexOf('own_alipay') != -1" />
个人支付宝
</label>
<label class="form-checkbox-item">
<checkbox value="own_pos" :checked="config.pay_type.indexOf('own_pos') != -1" />
个人POS刷卡
</label>
</checkbox-group>
</view>
<text class="form-word-aux-line">付款码支付扫描会员微信或支付宝付款码进行收款</text>
</view>
<view class="common-btn-wrap">
<button type="default" class="screen-btn" @click="saveFn">保存</button>
</view>
</view>
</view>
</base-page>
</template>
<script>
import { getCollectMoneyConfig, setCollectMoneyConfig } from '@/api/config.js';
export default {
data() {
return {
config: {
reduction: 1,
point: 1,
balance: 1,
balance_safe: 0,
sms_verify: 0,
pay_type: ['third', 'cash', 'own_wechatpay', 'own_alipay', 'own_pos']
},
isRepeat: false
};
},
onLoad() {
this.getData();
},
onShow() { },
methods: {
getData() {
getCollectMoneyConfig().then(res => {
if (res.code >= 0) {
this.config = res.data;
}
});
},
saveFn() {
if (!this.config.pay_type.length) {
this.$util.showToast({ title: '至少需启用一种收款方式' });
return;
}
if (this.isRepeat) return;
this.isRepeat = true;
let data = this.$util.deepClone(this.config);
data.pay_type = JSON.stringify(data.pay_type);
setCollectMoneyConfig(data).then(res => {
this.isRepeat = false;
if (res.code >= 0) {
this.$util.showToast({
title: '设置成功'
});
} else {
this.$util.showToast({
title: res.message
});
}
})
}
}
};
</script>
<style lang="scss" scoped>
.collect-money-config {
position: relative;
.common-btn-wrap {
position: absolute;
left: 0;
bottom: 0;
right: 0;
padding: 0.24rem 0.2rem;
.screen-btn {
margin: 0;
}
}
.common-wrap.fixd {
padding: 30rpx;
height: calc(100vh - 0.4rem);
overflow-y: auto;
// padding-bottom: 1rem !important;
box-sizing: border-box;
}
.form-input {
font-size: 0.16rem;
}
.form-input-inline.btn {
height: 0.37rem;
line-height: 0.35rem;
box-sizing: border-box;
border: 0.01rem solid #e6e6e6;
text-align: center;
cursor: pointer;
}
.common-title {
font-size: 0.18rem;
margin-bottom: 0.2rem;
}
.common-form .common-form-item .form-label {
width: 1.5rem;
}
.common-form .common-form-item .form-word-aux-line {
margin-left: 1.5rem;
}
}
</style>

View File

@@ -0,0 +1,221 @@
<template>
<base-page>
<view class="goods-list">
<view class="screen-warp common-form">
<view class="common-form-item">
<view class="form-inline">
<label class="form-label">商品名称</label>
<view class="form-input-inline">
<input type="text" v-model="option.search_text" placeholder="请输入商品名称" class="form-input" />
</view>
</view>
<view class="form-inline">
<label class="form-label">商品编码</label>
<view class="form-input-inline">
<input type="text" v-model="option.sku_no" placeholder="请输入商品编码" class="form-input" />
</view>
</view>
<view class="form-inline">
<label class="form-label">商品类型</label>
<view class="form-input-inline">
<select-lay :zindex="10" :value="goods_class" name="goods_class" placeholder="请选择商品类型" :options="goodsClass" @selectitem="selectClass"/>
</view>
</view>
<view class="form-inline">
<label class="form-label">商品状态</label>
<view class="form-input-inline">
<select-lay :zindex="10" :value="status" name="status" placeholder="请选择商品状态" :options="statusList" @selectitem="selectStatus"/>
</view>
</view>
<view class="form-inline">
<label class="form-label">商品价格</label>
<view class="form-input-inline input-append">
<input type="text" v-model="option.start_price" placeholder="最低价格" class="form-input" />
<view class="unit"></view>
</view>
<view class="form-input-inline split-wrap">-</view>
<view class="form-input-inline input-append">
<input type="text" v-model="option.end_price" placeholder="最高价格" class="form-input" />
<view class="unit"></view>
</view>
</view>
<view class="form-inline common-btn-wrap">
<button type="default" class="screen-btn" @click="searchFn()">筛选</button>
<button type="default" @click="resetFn()">重置</button>
<button type="default" class="screen-btn" @click="printPriceTag()">打印价格标签</button>
<button type="default" class="screen-btn" @click="synchronous()" v-if="syncWeighGoods">同步称重商品</button>
</view>
</view>
</view>
<uniDataTable url="/cashier/storeapi/goods/page" :option="option" :cols="cols" ref="goodsListTable">
<template v-slot:action="dataTable">
<view class="action-btn-wrap">
<text class="action-item" @click="getDetail(dataTable.value.goods_id)">详情</text>
<text class="action-item" v-if="dataTable.value.store_status == 0 || dataTable.value.store_status == null" @click="goodsStatus(dataTable.value.goods_id, 1)">上架</text>
<text class="action-item" v-else @click="goodsStatus(dataTable.value.goods_id, 0)">下架</text>
<text class="action-item" @click="goodsSku(dataTable.value.goods_id)" v-if="(globalStoreInfo.stock_type == 'store') || dataTable.value.is_unify_price != 1">价格库存</text>
<text class="action-item" @click="isDeliveryRestrictions(dataTable.value.goods_id)" v-if="dataTable.value.goods_class == 1">
限制起送
</text>
<text class="action-item" @click="recordopen(dataTable.value.goods_id)" v-if="dataTable.value.is_virtual != 1 && globalStoreInfo.stock_type == 'store'">库存记录</text>
</view>
</template>
<template v-slot:batchaction="dataTable">
<text class="batch-item" @click="goodsStatus(dataTable, 1)">批量上架</text>
<text class="batch-item" @click="goodsStatus(dataTable, 0)">批量下架</text>
</template>
</uniDataTable>
<unipopup ref="goodsDetail" type="center" :pagesize="9">
<view class="goods-detail-wrap">
<view class="detail-head">
商品详情
<text class="iconfont iconguanbi1" @click="$refs.goodsDetail.close()"></text>
</view>
<view class="detail-body">
<block v-if="goodsDetail">
<view class="title">基本信息</view>
<view class="information-box">
<view class="box-left">
<view class="information">
<view>商品名称</view>
<view>{{ goodsDetail.goods_name }}</view>
</view>
<view class="information" v-if="goodsDetail.introduction">
<view>促销语</view>
<view>{{ goodsDetail.introduction }}</view>
</view>
<view class="information">
<view>商品类型</view>
<view>{{ goodsDetail.goods_class_name }}</view>
</view>
<view class="information" v-if="goodsDetail.brand_name">
<view>商品品牌</view>
<view>{{ goodsDetail.brand_name }}</view>
</view>
<view class="information" v-if="goodsDetail.unit">
<view>单位</view>
<view>{{ goodsDetail.unit }}</view>
</view>
<view class="information" v-if="goodsDetail.goods_class == 6">
<view>计价方式</view>
<view>{{ goodsDetail.pricing_type == 'num' ? '计数' : '计重' }}</view>
</view>
<view class="information">
<view>商品状态</view>
<view>
{{ goodsDetail.store_status == 0 || goodsDetail.store_status == null ? '仓库中' : '已上架' }}
</view>
</view>
</view>
</view>
<block v-if="goodsDetail.sku_list.length > 1">
<view class="title title2">价格库存</view>
<view class="table">
<view class="table-th table-all">
<view class="table-td" style="width:30%">商品规格</view>
<block v-if="goodsDetail.is_unify_price">
<view class="table-td" style="width:20%">销售价格</view>
</block>
<block v-else>
<view class="table-td" style="width:15%">统一价格</view>
<view class="table-td" style="width:15%">独立价格</view>
</block>
<view class="table-td" style="width:20%;">商品编码</view>
<view class="table-td table-group" style="width:15%;">
<text>商品库存</text>
<text title="商品库存指下单扣减后的剩余库存" class="iconfont iconwenhao"></text>
</view>
<view class="table-td table-group" style="width:15%;">
<text>实际库存</text>
<text title="实际库存指实际发货后的剩余库存" class="iconfont iconwenhao"></text>
</view>
</view>
<scroll-view class="table-tb" scroll-y="true">
<view class="table-tr table-all" v-for="(item, index) in goodsDetail.sku_list" :key="index">
<view class="table-td" style="width:30%">{{ item.spec_name }}</view>
<block v-if="goodsDetail.is_unify_price">
<view class="table-td" style="width:20%">{{ item.discount_price }}</view>
</block>
<block v-else>
<view class="table-td" style="width:15%">{{ item.discount_price }}</view>
<view class="table-td" style="width:15%">{{ item.store_price }}</view>
</block>
<view class="table-td" style="width:20%;">{{ item.sku_no }}</view>
<view class="table-td" style="width:15%;">{{ item.stock }}</view>
<view class="table-td" style="width:15%;">{{ item.real_stock }}</view>
</view>
</scroll-view>
</view>
</block>
<block v-else>
<view class="title title2">规格详情</view>
<view class="table">
<view class="single-specification">
<view class="item">
<view class="name">商品售价</view>
<view class="message" v-if="goodsDetail.is_unify_price == 1 || goodsDetail.sku_list[0].store_price == null">{{ goodsDetail.sku_list[0].discount_price }}</view>
<view class="message" v-else>{{ goodsDetail.sku_list[0].store_price }}</view>
</view>
<view class="item">
<view class="name">商品编码</view>
<view class="message">{{ goodsDetail.sku_list[0].sku_no ? goodsDetail.sku_list[0].sku_no : '无' }}</view>
</view>
<view class="item">
<view class="name">商品库存</view>
<view class="message">{{ goodsDetail.sku_list[0].stock || 0 }}</view>
</view>
<view class="item">
<view class="name">实际库存</view>
<view class="message">{{ goodsDetail.sku_list[0].real_stock || 0 }}</view>
</view>
</view>
</view>
</block>
</block>
<block v-else>
<image class="cart-empty" src="@/static/cashier/cart_empty.png" mode="widthFix"/>
</block>
</view>
</view>
</unipopup>
<unipopup ref="goodsSku" type="center">
<view class="record-body">
<ns-goods-sku :disabled="disabled" v-if="skuList.length&&goodsDetail" :isUnifyPrice="goodsDetail.is_unify_price" :skuList="skuList" @close="close('goodsSku')" />
</view>
</unipopup>
<unipopup ref="record" type="center">
<view class="record-body">
<ns-goods-sku-stock-record @close="close('record')" :goodsId="goodsId"/>
</view>
</unipopup>
</view>
<ns-scale-goods ref="scaleGoods"/>
</base-page>
</template>
<script>
import uniDataTable from '@/components/uni-data-table/uni-data-table.vue';
import unipopup from '@/components/uni-popup/uni-popup.vue';
import nsGoodsSkuStockRecord from '@/components/ns-goods-sku-stock-record/ns-goods-sku-stock-record.vue';
import nsGoodsSku from '@/components/ns-goods-sku/ns-goods-sku.vue';
import nsScaleGoods from '@/components/ns-scale-goods/ns-scale-goods.vue';
import goodsList from './public/js/goods_list.js';
export default {
components: {
unipopup,
nsGoodsSkuStockRecord,
nsGoodsSku,
uniDataTable,
nsScaleGoods,
},
mixins: [goodsList]
};
</script>
<style scoped lang="scss">
@import './public/css/goods_list.scss';
</style>

View File

@@ -0,0 +1,89 @@
<template>
<base-page>
<view class="stock-body">
<view class="content-wrap" @click="goodsShow = false">
<view class="title-back flex items-center cursor-pointer" @click="backFn">
<text class="iconfont iconqianhou1"></text>
<text class="left">返回</text>
<text class="content">|</text>
<text>打印价格标签</text>
</view>
<view class="batch-action" v-if="editPrintNum.show == false">
<text class="batch-item" @click="openSelectGoodsDialog()">选择商品</text>
<text class="batch-item" @click="batchDeleteGoods()">批量删除</text>
<!-- <text class="batch-item" @click="editPrintNumShow()">批量设置打印份数</text> -->
</view>
<view class="screen-warp common-form" v-if="editPrintNum.show == true">
<view class="common-form-item">
<view class="form-inline">
<view class="form-input-inline">
<input type="digit" placeholder="请输入打印份数" class="form-input" v-model="editPrintNum.value"/>
</view>
</view>
<view class="form-inline common-btn-wrap">
<button type="default" class="screen-btn" @click="editPrintNumConfirm">确定</button>
<button type="default" @click="editPrintNum.show = false">取消</button>
</view>
</view>
</view>
<view class="table-wrap">
<view class="table-head">
<view class="table-tr">
<view class="table-th" >
<text class="iconfont" :class="allSelected === true ? selectedIcon : (allSelected == 'harf' ? harfselectedIcon : unselectedIcon)" @click="changeGoodsAllSelected()"></text>
</view>
<!-- <view class="table-th" style="flex: 0.5;">打印份数</view> -->
<view class="table-th" style="flex: 3;">商品名称</view>
<view class="table-th" style="flex: 1;">条码</view>
<view class="table-th" style="flex: 1;">划线价</view>
<view class="table-th" style="flex: 1;">售价</view>
<view class="table-th" style="flex: 1;">单位</view>
<view class="table-th" style="flex: 1;">重量</view>
</view>
</view>
<view class="table-body">
<block v-for="(item, index) in goodsList" :key="index">
<view class="table-tr">
<view class="table-td" >
<text class="iconfont" :class="item.selected? selectedIcon : unselectedIcon" @click="changeGoodsSelected(index)"></text>
</view>
<!-- <view class="table-td" style="flex: 0.5;">{{ item.print_num }}</view> -->
<view class="table-td goods-name" style="flex: 3;">{{ item.sku_name }}</view>
<view class="table-td" style="flex: 1;">{{ item.sku_no }}</view>
<view class="table-td" style="flex: 1;">{{ item.market_price }}</view>
<view class="table-td" style="flex: 1;">{{ item.price }}</view>
<view class="table-td" style="flex: 1;">{{ item.unit }}</view>
<view class="table-td" style="flex: 1;">{{ item.weight }}</view>
</view>
</block>
<view class="table-tr table-empty" v-if="!goodsList.length">暂无数据请选择商品数据</view>
</view>
</view>
</view>
<view class="action-wrap">
<view class="table-total">合计 {{ goodsList.length }} 种商品</view>
<view class="btn-wrap">
<button type="default" class="stockout-btn" @click="designFn" :loading="isSubmit">设计模板</button>
<button type="default" class="stockout-btn" @click="printFn" :loading="isSubmit">打印</button>
<button type="default" class="stockout-btn" @click="exportFn" :loading="isSubmit">导出</button>
</view>
</view>
</view>
<goods-sku-select v-model="dialogVisible" :params="dialogParams" apiType="sku" :goodsClass="[1,6]" @selectGoods="selectGoodsComplete" />
</base-page>
</template>
<script>
import printPriceTag from "./public/js/print_price_tag.js"
import goodsSkuSelect from '@/components/ns-goods-sku-select/ns-goods-sku-select.vue';
export default {
components: {
goodsSkuSelect
},
mixins: [printPriceTag]
};
</script>
<style lang="scss" scoped>
@import './public/css/print_price_tag.scss';
</style>

View File

@@ -0,0 +1,312 @@
view {
color: #303133;
}
/deep/ .uni-scroll-view::-webkit-scrollbar {
width: 0.05rem;
height: 0.3rem;
}
/deep/ .uni-scroll-view::-webkit-scrollbar-thumb {
border-radius: 0.1rem;
box-shadow: inset 0 0 0.05rem rgba(0, 0, 0, 0.2);
background: rgba(193, 193, 193, 1);
}
.cart-empty {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 2.1rem;
}
.record-body {
width: 10rem;
min-height: 7rem;
}
// 筛选面板
.screen-warp {
padding: 0.15rem 0.15rem 0;
background-color: #f2f3f5;
margin-bottom: 0.15rem;
.common-form-item .form-label {
width: 1.2rem;
}
.common-btn-wrap {
margin-left: 1.2rem;
button{
margin-right: .1rem;
}
}
.goods-category .form-input-inline {
width: 2.8rem;
}
.form-inline {
margin-bottom: 0.15rem;
}
.common-form-item {
margin-bottom: 0;
}
.input-append {
position: relative;
.form-input {
padding-right: 0.3rem;
}
.unit {
position: absolute;
top: 0;
right: 0.1rem;
height: 0.35rem;
line-height: 0.35rem;
}
}
.form-input-inline.split-wrap {
width: initial;
background: none;
border: none;
}
}
.goods-list {
display: block;
width: 100%;
@extend %body-overhide;
padding: 0.15rem 0.15rem 0;
background-color: #fff;
/deep/ .goods-content {
display: flex;
.goods-img {
margin-right: 0.1rem;
width: 0.5rem;
height: 0.5rem;
min-width: 0.5rem;
}
.goods-name {
white-space: pre-wrap;
align-self: baseline;
}
.infos{
display: flex;
flex-direction: column;
.spec-name{
margin-top: 0.03rem;
color: #909399;
}
}
}
.action-btn-wrap {
display: flex;
flex-wrap: wrap;
.action-item {
margin-right: 0.1rem;
margin-top: 0.03rem;
margin-bottom: 0.03rem;
color: $primary-color;
&:first-of-type {
margin-left: 0;
}
}
}
/deep/ .batch-action {
.batch-item {
margin-right: 0.15rem;
border: 0.01rem solid rgba(0, 0, 0, 0.2);
padding: 0.05rem;
border-radius: 0.03rem;
}
}
}
// 商品详情
.goods-detail-wrap {
background-color: #fff;
border-radius: 0.05rem;
padding-bottom: 0.15rem;
.detail-head {
padding: 0 0.15rem;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 0.15rem;
height: 0.45rem;
border-bottom: 0.01rem solid #e8eaec;
.iconguanbi1 {
font-size: $uni-font-size-lg;
}
}
.detail-body {
width: 9rem;
height: 4.9rem;
padding: 0.2rem 0.2rem 0 0.2rem;
box-sizing: border-box;
overflow-y: auto;
position: relative;
.title {
font-size: 0.15rem;
margin-bottom: 0.2rem;
}
.information-box {
display: flex;
justify-content: space-between;
.box-left {
width: 5rem;
.information {
width: 100%;
padding-left: 0.1rem;
box-sizing: border-box;
display: flex;
align-items: center;
margin-bottom: 0.15rem;
view {
color: #303133;
font-size: 0.14rem;
}
view:nth-child(1) {
width: 0.7rem;
margin-right: 0.16rem;
text-align: right;
}
view:nth-child(2) {
flex: 1;
margin-right: 0.23rem;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
}
.information:last-child {
margin-bottom: 0.35rem;
}
}
.goods-img {
width: 2rem;
height: 2rem;
}
}
.table {
width: 100%;
max-height: 2.7rem;
box-sizing: border-box;
.single-specification {
width: 100%;
max-height: 100%;
padding-left: 0.1rem;
box-sizing: border-box;
.item {
width: 100%;
margin-bottom: 0.15rem;
display: flex;
align-items: center;
image {
width: 0.5rem;
}
.name {
display: flex;
align-items: center;
margin-right: 0.16rem;
width: 0.7rem;
text-align: right;
}
.message {
width: 74%;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
}
}
.table-all {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 0.38rem;
box-sizing: border-box;
.table-td {
font-size: 0.14rem;
text-align: left;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
}
.table-th {
height: 0.56rem;
background: #f7f8fa;
}
.table-tb {
width: 100%;
height: calc(100% - 0.56rem);
.table-tr {
height: 0.7rem;
border-bottom: 0.01rem solid #e6e6e6;
box-sizing: border-box;
.table-td {
image {
width: 0.5rem;
height: 0.5rem;
}
text-overflow: -o-ellipsis-lastline;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
line-clamp: 2;
-webkit-box-orient: vertical;
}
}
}
}
}
}
.table-group{
display: flex;
align-items: center;
text:last-of-type{
cursor: pointer;
margin-left: 0.05rem;
}
}

View File

@@ -0,0 +1,215 @@
.form-content {
display: flex;
flex-wrap: wrap;
margin-top: 0.2rem;
.store-info {
.form-inline {
padding-left: 0.05rem;
}
}
.form-item {
margin-bottom: 0.1rem;
display: flex;
.form-label {
width: 1.3rem;
text-align: right;
padding-right: 0.1rem;
box-sizing: border-box;
height: 0.32rem;
line-height: 0.32rem;
.required {
color: red;
margin-right: 0.03rem;
}
}
.form-inline {
width: 2.4rem;
line-height: 0.32rem;
margin-right: 0.1rem;
box-sizing: border-box;
&.input {
input {
padding: 0 0.1rem;
}
}
.form-input {
border-width: 0.01rem;
border-style: solid;
background-color: #fff;
color: rgba(0, 0, 0, 0.85);
border-radius: 0.02rem;
padding-left: 0.1rem;
height: 0.32rem;
line-height: 0.32rem;
font-size: 0.14rem;
border-color: #e6e6e6;
}
}
}
}
.stock-body{
position: relative;
height: 100%;
.common-form .common-btn-wrap {
margin-left: 0;
}
.content-wrap {
padding: 0.15rem;
background-color: #fff;
@extend %body-overhide;
box-sizing: border-box;
.title {
font-size: 0.18rem;
margin-bottom: 0.2rem;
text-align: center;
}
.batch-action {
.batch-item {
margin-right: 0.15rem;
border: 0.01rem solid rgba(0, 0, 0, 0.2);
padding: 0.05rem;
border-radius: 0.03rem;
cursor: pointer;
}
}
.table-wrap {
position: relative;
margin-top: 40rpx;
border: 1rpx solid #dcdfe6;
.iconcheckbox_weiquanxuan,
.iconfuxuankuang1,
.iconfuxuankuang2 {
color: $primary-color;
cursor: pointer;
font-size: 0.16rem;
transition: all 0.3s;
}
.iconfuxuankuang2{
color: #e6e6e6;
}
.table-head {
background-color: #f7f7f7;
}
.table-body {
@extend %body-overhide;
max-height: 6rem;
.table-tr {
&:last-of-type .table-td {
border-bottom: 0;
}
}
}
.table-tr {
display: flex;
}
.table-th,
.table-td {
display: flex;
align-items: center;
justify-content: center;
padding: 0.07rem 0.3rem;
border-bottom: 0.01rem solid #dcdfe6;
border-right: 0.01rem solid #dcdfe6;
text-align: center;
&:last-of-type {
border-right: 0;
justify-content: flex-end;
}
&.goods-name {
justify-content: flex-start;
text-align: left;
image {
width: 0.45rem;
height: 0.45rem;
flex-shrink: 0;
}
.name {
margin-left: 0.1rem;
}
}
}
.delete {
margin: 0;
font-size: $uni-font-size-base;
background-color: $primary-color;
color: #fff;
line-height: 0.32rem;
height: 0.32rem;
&::after{
border-width: 0;
}
}
.table-empty {
justify-content: center;
padding: 0.1rem;
color: #999;
/* border: 0.01rem solid #dcdfe6;
border-top: 0; */
}
}
}
.action-wrap {
position: absolute;
bottom: 0;
left: 0;
right: 0;
display: flex;
justify-content: space-between;
padding: 0.24rem 0.2rem;
align-items: center;
background-color: #fff;
z-index: 10;
.btn-wrap {
display: flex;
align-items: center;
justify-content: center;
button {
margin: 0;
min-width: 1.2rem;
height: 0.4rem;
line-height: 0.4rem;
font-size: $uni-font-size-base;
&.stockout-btn {
margin-right: 0.15rem;
background-color: $primary-color;
color: #fff;
&::after{
border-width: 0;
}
}
&.remark {
margin-right: 0.15rem;
min-width: 1.2rem;
}
}
}
}
}

View File

@@ -0,0 +1,231 @@
import {
setGoodsStatus,
getGoodsDetail,
} from '@/api/goods.js';
export default {
data() {
return {
page: 1, // 初始是请求第几页
page_size: 20, // 每次返回数据数
goodsDetail: null, // 商品详情数据
skuList: [], // 弹窗中所需要获取到的sku列表数据
status: '',
disabled:false,
goods_class: '',
goodsId: '',
option: {
page_size: 9,
search_text: '',
sku_no: '',
goods_class: 'all',
status: 'all',
start_price: '',
end_price: ''
},
goodsClass: [{
value: 1,
label: '实物商品'
}, {
value: 4,
label: '服务项目'
}, {
value: 5,
label: '卡项套餐'
}, {
value: 6,
label: '称重商品'
}],
statusList: [{
value: 1,
label: '仓库中'
}, {
value: 2,
label: '销售中'
}],
cols: [{
width: 6,
align: 'center',
checkbox: true
}, {
field: 'account_data',
width: 20,
title: '商品信息',
align: 'left',
templet: data => {
let img = this.$util.img(data.goods_image,{size: 'small'});
let html = `
<view class="goods-content">
<image class="goods-img" src="${img}" mode="aspectFit"/>
<text class="goods-name multi-hidden">${data.goods_name}</text>
</view>
`;
return html;
}
}, {
width: 14,
title: '商品类型',
align: 'center',
field: 'goods_class_name'
}, {
width: 10,
title: '价格',
align: 'center',
templet: function(data) {
return '¥' + data.discount_price;
}
}, {
field: 'stock',
width: 15,
title: '库存',
align: 'center'
}, {
width: 15,
title: '售卖模式',
templet: data => {
return (this.globalStoreInfo.stock_type == 'store' ? '独立库存' : '统一库存') + ' | ' + (data
.is_unify_price ? '统一设价' : '独立设价');
}
}, {
width: 15,
title: '状态',
align: 'center',
templet: function(data) {
var str = '';
if (data.store_status == 1) {
str = '销售中';
} else if (data.store_status == 0) {
str = '仓库中';
}
return str;
}
}, {
width: 20,
title: '操作',
align: 'right',
action: true
}],
};
},
onLoad() {},
computed: {
syncWeighGoods() {
try {
return this.addon.includes('weighgoods') && this.addon.includes('scale') && (window.POS_ || window
.ipcRenderer);
} catch (e) {
return false
}
}
},
methods: {
selectClass(index) {
this.goods_class = index == -1 ? '' : this.goodsClass[index].value.toString();
},
selectStatus(index) {
this.status = index == -1 ? '' : this.statusList[index].value.toString();
},
// 搜索商品
searchFn() {
if (this.status == 1) {
this.option.status = 0
} else if (this.status == 2) {
this.option.status = 1
} else {
this.option.status = 'all'
}
this.option.goods_class = this.goods_class ? this.goods_class : 'all';
this.$refs.goodsListTable.load({
page: 1
});
},
resetFn() {
this.status = '';
this.goods_class = '';
this.option.status = 'all';
this.option.goods_class = 'all';
this.option.search_text = '';
this.option.sku_no = '';
this.option.start_price = '';
this.option.end_price = '';
this.$refs.goodsListTable.load({
page: 1
});
},
// 查询商品详情
getDetail(id, type = '') {
uni.showLoading({
title: '加载中'
});
this.goodsDetail = null;
getGoodsDetail(id).then(res => {
if (res.code >= 0) {
this.goodsDetail = res.data;
this.goodsDetail.sku_list[0].goods_name = this.goodsDetail.goods_name;
this.skuList = this.goodsDetail.sku_list;
if (!type) {
this.$refs.goodsDetail.open();
} else {
this.$refs.goodsSku.open();
}
}
uni.hideLoading();
})
},
goodsStatus(id, status) {
let arr;
if (typeof id == 'object') {
arr = [];
id.value.length &&
id.value.forEach((item, index) => {
arr.push(item.goods_id);
});
if (!arr.length) {
this.$util.showToast({
title: '请选择要操作的数据'
});
return false;
}
} else arr = id;
let data = {
goods_id: arr.toString(),
status: status
};
setGoodsStatus(data).then(res => {
this.$util.showToast({
title: res.message
});
if (res.code >= 0) {
this.$refs.goodsListTable.load();
}
})
},
goodsSku(id) {
this.disabled = false
this.goodsId = id;
this.getDetail(id, 'goodsSku');
},
isDeliveryRestrictions(id){
this.disabled = true
this.goodsId = id;
this.getDetail(id, 'goodsSku');
},
// 日志记录弹窗
recordopen(id) {
this.goodsId = id;
this.$refs.record.open();
},
// 弹窗关闭
close(type) {
this.$refs[type].close();
},
synchronous() {
this.$refs.scaleGoods.open();
},
printPriceTag(){
this.$util.redirectTo('/pages/goods/print_price_tag');
},
}
}

View File

@@ -0,0 +1,206 @@
import {exportPrintPriceTagData} from '@/api/goods.js';
export default {
data() {
return {
goodsList: [], //已选择数据
allSelected:false,
isSubmit: false, //提交防抖
dialogParams:{},
dialogVisible: false, //弹框
editPrintNum:{
show:false,
value:1,
},
//选择图标
selectedIcon:'iconfuxuankuang1',
unselectedIcon:'iconfuxuankuang2',
harfselectedIcon:'iconcheckbox_weiquanxuan',
};
},
onLoad(option) {
},
methods: {
openSelectGoodsDialog() {
this.dialogVisible = true
},
selectGoodsComplete(data) { //选择数据
data.forEach((item, index) => {
let is_in = false;
this.goodsList.forEach((old_item, old_index)=>{
if(old_item.sku_id == item.sku_id){
is_in = true;
return;
}
})
if(!is_in){
item.selected = false;
item.print_num = 1;
this.goodsList.push(item);
}
})
},
changeGoodsAllSelected(){
if(this.goodsList.length == 0) return;
this.allSelected = this.allSelected === true ? false : true;
this.goodsList.forEach((item) => {
item.selected = this.allSelected;
})
this.$forceUpdate();
},
changeGoodsSelected(index){
this.goodsList[index].selected = !this.goodsList[index].selected;
let selected_num = 0;
this.goodsList.forEach((item) => {
if(item.selected) selected_num++;
})
if(selected_num == this.goodsList.length){
this.allSelected = true;
}else if(selected_num == 0){
this.allSelected = false;
}else{
this.allSelected = 'harf';
}
this.$forceUpdate();
},
getSelectedNum(){
let selected_num = 0;
this.goodsList.forEach((item) => {
if(item.selected) selected_num++;
})
return selected_num;
},
batchDeleteGoods(){
if(this.getSelectedNum() == 0){
this.$util.showToast({
title: '请选择要操作的数据',
});
return;
}
let goods_list = [];
this.goodsList.forEach((item) => {
if(!item.selected) goods_list.push(item);
})
this.goodsList = goods_list;
if(this.goodsList.length == 0) this.allSelected = false;
this.$forceUpdate();
},
editPrintNumShow(){
if(this.getSelectedNum() == 0){
this.$util.showToast({
title: '请选择要操作的数据',
});
return;
}
this.editPrintNum.show = true;
this.$forceUpdate();
},
editPrintNumConfirm(){
this.goodsList.forEach((item) => {
if(item.selected){
item.print_num = this.editPrintNum.value;
item.selected = false;
}
})
this.allSelected = false;
this.editPrintNum.value = 1;
this.editPrintNum.show = false;
this.$forceUpdate();
},
designFn(){
if(!this.isPos()){
this.$util.showToast({
title: '请在客户端程序中执行此操作',
});
return;
}
if(this.goodsList.length == 0){
this.$util.showToast({
title: '请先选择商品',
});
return;
}
let printFieldConfig = [
{field:'goods_name', name:'商品名称'},
{field:'spec_name', name:'规格'},
{field:'sku_no', name:'商品条码'},
{field:'market_price', name:'划线价'},
{field:'price', name:'零售价'},
{field:'unit', name:'单位'},
{field:'weight', name:'重量'},
{field:'category_names', name:'商品分类'},
{field:'brand_name', name:'品牌'},
{field:'supplier_name', name:'供应商'},
{field:'label_name', name:'标签'},
];
try{
this.$pos.send('DesignPriceTag', JSON.stringify(this.goodsList));
}catch(e){
this.$util.showToast({
title: '设计错误:'+JSON.stringify(e),
});
}
},
printFn() {
if(!this.isPos()){
this.$util.showToast({
title: '请在客户端程序中执行此操作',
});
return;
}
if(this.goodsList.length == 0){
this.$util.showToast({
title: '请先选择商品',
});
return;
}
try{
this.$pos.send('PrintPriceTag', JSON.stringify(this.goodsList));
}catch(e){
this.$util.showToast({
title: '打印错误:'+JSON.stringify(e),
});
}
},
exportFn(){
if(this.goodsList.length == 0){
this.$util.showToast({
title: '请先选择商品数据'
});
return;
}
if(this.isPos()){
try{
this.$pos.send('ExportPriceTag', JSON.stringify(this.goodsList));
}catch(e){
this.$util.showToast({
title: '导出错误:'+JSON.stringify(e),
});
}
}else{
uni.showLoading({
title: '导出中'
});
exportPrintPriceTagData({
data:JSON.stringify(this.goodsList),
}).then(res => {
uni.hideLoading();
if (res.code == 0) {
window.open(this.$util.img(res.data.path));
}else{
this.$util.showToast({
title: res.message
});
}
});
}
},
backFn() {
this.$util.redirectTo('/pages/goods/goodslist');
},
isPos(){
return (window.POS_ || window.ipcRenderer);
},
}
};

View File

@@ -0,0 +1,488 @@
<template>
<page-meta :root-font-size="rootSize"></page-meta>
<view class="uni-flex uni-row height-all" :style="themeColor">
<view class="container common-wrap" style="-webkit-flex: 1;flex: 1;" v-if="shiftsData">
<view class="title">{{ info.username }}</view>
<view class="time-title">
班次:
<text>{{ shiftsData.start_time > 0 ? $util.timeFormat(shiftsData.start_time) : '初始化' }}</text>
<text class="separate">-</text>
<text class="curr-time">{{ shiftsData.end_time | timeFormat }}</text>
</view>
<view class="title-box">
<view class="box">
<view class="name-box">
<text class="title-name"></text>
<text class="name">总销售</text>
</view>
<view class="money-box">
<text class="money">{{ shiftsData.total_sale | moneyFormat }}{{ shiftsData.total_sale_count }}</text>
</view>
</view>
<view class="box">
<view class="name-box">
<text class="title-name"></text>
<text class="name">会员充值</text>
</view>
<view class="money-box">
<text class="money">{{ shiftsData.recharge_money | moneyFormat }}{{ shiftsData.recharge_count }}</text>
</view>
</view>
<view class="box">
<view class="name-box">
<text class="title-name"></text>
<text class="name">应收金额</text>
</view>
<view class="money-box">
<text class="money">{{ shiftsData.total_money | moneyFormat }}{{ shiftsData.total_count }}</text>
</view>
</view>
<view class="box">
<view class="name-box">
<text class="title-name"></text>
<text class="name">支付统计</text>
</view>
<view class="money-box">
<text class="money">{{ shiftsData.total_pay_money | moneyFormat }}{{ shiftsData.total_pay_count }}</text>
</view>
</view>
<view class="box">
<view class="name-box">
<text class="title-name"></text>
<text class="name">商品销售</text>
</view>
<view class="money-box">
<text class="money">{{ shiftsData.sale_goods_count.class_num }}{{ shiftsData.sale_goods_count.num }}</text>
</view>
</view>
</view>
<view class="basic">
<text @click="detail()">
查看详情
<text class="iconqianhou2 iconfont"></text>
</text>
</view>
<view class="common-btn-wrap">
<button type="default" class="default-btn cancel-btn" @click="cancel">取消</button>
<button type="default" class="primary-btn shiftss-btn" @click="changeShiftsFn">交班并登出</button>
</view>
<uni-popup ref="shiftslistPop">
<view class="pop-box shiftsslistPop">
<view class="pop-header">
<view class="pop-header-text">交班详情</view>
<view class="pop-header-close" @click="$refs.shiftslistPop.close()">
<text class="iconguanbi1 iconfont"></text>
</view>
</view>
<view class="pop-content common-scrollbar">
<view class="pop-content-item">
<view class="pop-content-text">总销售{{ shiftsData.total_sale | moneyFormat }} {{ shiftsData.total_sale_count }}</view>
<view class="pop-contents-text">开单销售{{ shiftsData.billing_money | moneyFormat }} {{ shiftsData.billing_count }}</view>
<view class="pop-contents-text">售卡销售{{ shiftsData.buycard_money | moneyFormat }} {{ shiftsData.buycard_count }}</view>
</view>
<view class="pop-content-item">
<view class="pop-content-text">会员充值{{ shiftsData.recharge_money | moneyFormat }} {{ shiftsData.recharge_count }}</view>
</view>
<view class="pop-content-item">
<view class="pop-content-text">应收金额{{ shiftsData.total_money | moneyFormat }} {{ shiftsData.total_count }}</view>
<view class="pop-contents-text">开单销售{{ shiftsData.billing_money | moneyFormat }} {{ shiftsData.billing_count }}</view>
<view class="pop-contents-text">售卡销售{{ shiftsData.buycard_money | moneyFormat }} {{ shiftsData.buycard_count }}</view>
<view class="pop-contents-text">会员充值{{ shiftsData.recharge_money | moneyFormat }} {{ shiftsData.recharge_count }}</view>
<view class="pop-contents-text">订单退款{{ shiftsData.refund_money | moneyFormat }} {{ shiftsData.refund_count }}</view>
</view>
<view class="pop-content-item">
<view class="pop-content-text">支付统计{{ shiftsData.total_pay_money | moneyFormat }} {{ shiftsData.total_pay_count }}</view>
<view class="pop-contents-text" v-if="shiftsData.cash > 0">现金收款{{ shiftsData.cash | moneyFormat }} {{ shiftsData.cash_count }}</view>
<view class="pop-contents-text" v-if="shiftsData.wechatpay > 0">微信收款{{ shiftsData.wechatpay | moneyFormat }} {{ shiftsData.wechatpay_count }}</view>
<view class="pop-contents-text" v-if="shiftsData.alipay > 0">支付宝收款{{ shiftsData.alipay | moneyFormat }} {{ shiftsData.alipay_count }}</view>
<view class="pop-contents-text" v-if="shiftsData.own_wechatpay > 0">个人微信收款{{ shiftsData.own_wechatpay | moneyFormat }} {{ shiftsData.own_wechatpay_count }}</view>
<view class="pop-contents-text" v-if="shiftsData.own_alipay > 0">个人支付宝收款{{ shiftsData.own_alipay | moneyFormat }} {{ shiftsData.own_alipay_count }}</view>
<view class="pop-contents-text" v-if="shiftsData.own_pos > 0">个人POS收款{{ shiftsData.own_pos | moneyFormat }} {{ shiftsData.own_pos_count }}</view>
</view>
<view class="pop-content-item">
<view class="pop-content-text">商品销售{{ shiftsData.sale_goods_count.class_num }}{{ shiftsData.sale_goods_count.num }}</view>
<view class="pop-contents-text">线上销售{{ shiftsData.sale_goods_count.online_class_num }} {{ shiftsData.sale_goods_count.online_num }}</view>
<view class="pop-contents-text">线下销售{{ shiftsData.sale_goods_count.offline_class_num }} {{ shiftsData.sale_goods_count.offline_num }}</view>
</view>
</view>
<view class="pop-content-footer">
<button class="primary-btn" @click="printTicketFn">打印小票</button>
</view>
</view>
</uni-popup>
</view>
<ns-loading ref="loading"></ns-loading>
</view>
</template>
<script>
import dataTable from '@/components/uni-data-table/uni-data-table.vue';
import uniPopup from '@/components/uni-popup/uni-popup.vue';
import { getShiftsData, changeShifts } from '@/api/shifts.js';
import { printTicket } from '@/api/printer.js';
export default {
components: {
dataTable,
uniPopup
},
data() {
return {
shiftsData: null,
info: null,
isSub: false
};
},
onShow() {
this.loadThemeColor();
this.getShiftsInfoFn();
},
methods: {
detail() {
this.$refs.shiftslistPop.open('center');
},
getShiftsInfoFn() {
getShiftsData().then(res => {
if (res.code == 0 && res.data) {
let shiftsData = res.data.shifts_data;
shiftsData.total_sale = parseFloat(shiftsData.billing_money) + parseFloat(shiftsData.buycard_money);
shiftsData.total_sale_count = parseInt(shiftsData.billing_count) + parseInt(shiftsData.buycard_count);
shiftsData.total_count = shiftsData.total_sale_count + parseInt(shiftsData.recharge_count) + parseInt(shiftsData.refund_count);
shiftsData.total_money = shiftsData.total_sale + parseFloat(shiftsData.recharge_money) - parseFloat(shiftsData.refund_money);
shiftsData.total_pay_money =
parseFloat(shiftsData.cash) +
parseFloat(shiftsData.alipay) +
parseFloat(shiftsData.wechatpay) +
parseFloat(shiftsData.own_wechatpay) +
parseFloat(shiftsData.own_alipay) +
parseFloat(shiftsData.own_pos);
shiftsData.total_pay_count =
parseInt(shiftsData.cash_count) +
parseInt(shiftsData.alipay_count) +
parseInt(shiftsData.wechatpay_count) +
parseInt(shiftsData.own_wechatpay_count) +
parseInt(shiftsData.own_alipay_count) +
parseInt(shiftsData.own_pos_count);
this.shiftsData = shiftsData;
this.info = res.data.userinfo;
this.$refs.loading.hide();
} else {
this.$util.showToast({
title: res.message
});
}
})
},
cancel() {
uni.navigateBack();
},
// 交班
changeShiftsFn() {
if (this.isSub) return;
this.isSub = true;
uni.showLoading({
title: ''
});
changeShifts().then(res => {
uni.hideLoading();
if (res.code == 0 && res.data) {
uni.removeStorage({
key: 'cashierToken',
success: () => {
this.$util.clearStoreData();
this.$util.redirectTo('/pages/login/login', {}, 'reLaunch');
}
});
} else {
this.isSub = false;
this.$util.showToast({
title: res.message
});
}
})
},
/**
* 打印小票
*/
printTicketFn() {
printTicket().then(res => {
if (res.code == 0) {
if (Object.values(res.data).length) {
let data = Object.values(res.data);
try {
let print = {
printer: []
};
data.forEach((item) => {
print.printer.push({
printer_type: item.printer_info.printer_type,
host: item.printer_info.host,
ip: item.printer_info.ip,
port: item.printer_info.port,
content: item.content,
print_width: item.printer_info.print_width
})
});
this.$pos.send('Print', JSON.stringify(print));
} catch (e) {
console.log('err', e, res.data)
}
} else {
this.$util.showToast({
title: '未开启交接班小票打印'
})
}
} else {
this.$util.showToast({
title: res.message ? res.message : '小票打印失败'
})
}
})
}
}
}
/**
* 打印回调
* @param {Object} text
*/
window.POS_PRINT_CALLBACK = function (text) {
uni.showToast({
title: text,
icon: 'none'
})
}
</script>
<style lang="scss" scoped>
.height-all {
height: 100vh;
}
.pop-box {
background: #ffffff;
width: 4rem;
height: 60vh;
display: flex;
flex-direction: column;
.pop-header {
width: 100%;
padding: 0 0.15rem 0 0.2rem;
height: 0.5rem;
// width: 3.5rem;
margin: 0 auto;
line-height: 0.5rem;
border-bottom: 0.01rem solid #f0f0f0;
font-size: 0.14rem;
color: #333;
overflow: hidden;
border-radius: 0.02rem 0.2rem 0 0;
box-sizing: border-box;
display: flex;
justify-content: space-between;
.pop-header-text {
font-weight: 900;
}
.pop-header-close {
cursor: pointer;
text {
font-size: 0.18rem;
}
}
}
.pop-content {
flex: 1;
height: 0;
padding: 0.1rem 0.2rem;
box-sizing: border-box;
font-weight: 900;
overflow-y: scroll;
}
.pop-contents {
margin-top: 0.3rem;
width: 3rem;
height: 0.8rem;
padding: 0.1rem 0.2rem;
box-sizing: border-box;
font-weight: 900;
display: flex;
flex-direction: column;
flex-wrap: wrap;
justify-content: space-between;
}
.pop-content-item {
margin-left: 0.3rem;
}
.pop-content-items {
margin-left: 0.3rem;
}
.pop-content-text {
padding: 0.1rem;
}
.pop-contents-text {
margin-left: 0.4rem;
font-weight: normal;
padding: 0.1rem;
}
.pop-content-footer {
display: flex;
padding: .15rem;
justify-content: flex-end;
button {
width: 1rem;
margin: 0;
}
}
}
.container {
display: flex;
align-items: center;
flex-direction: column;
padding: 0.2rem;
}
.title {
font-size: 0.16rem;
margin-top: 0.45rem;
font-weight: 900;
color: rgb(86, 116, 133);
}
.time-title {
padding: 0.1rem;
line-height: 0.2rem;
border-radius: 5px;
background-color: var(--primary-color-light-8);
color: $primary-color;
font-size: 0.14rem;
margin-top: 0.2rem;
text {
margin: 0 0.05rem;
}
.curr-time {
font-weight: bold;
}
}
.title-box {
width: 5rem;
display: flex;
flex-direction: column;
align-content: space-around;
justify-content: flex-start;
align-items: center;
margin-top: 0.3rem;
}
.box {
width: 5.4rem;
height: 0.6rem;
background: #f9fbfb;
border: 1px solid rgb(225, 225, 225);
margin-top: 0.1rem;
display: flex;
flex-direction: row;
justify-content: space-between;
align-content: space-around;
flex-wrap: wrap;
padding: 0 0.23rem 0 0.23rem;
box-sizing: border-box;
}
.title-name {
display: inline-block;
width: 0.3rem;
height: 0.3rem;
border-radius: 15%;
text-align: center;
line-height: 0.3rem;
background: $primary-color;
color: #fff;
font-weight: 900;
font-size: 0.16rem;
}
.name-box {
height: 0.3rem;
}
.money-box {
line-height: 0.3rem;
}
.name {
font-size: 0.16rem;
line-height: 0.3rem;
margin-left: 0.2rem;
font-weight: 900;
color: rgb(86, 116, 133);
}
.money {
margin-left: 0.25rem;
color: rgb(86, 116, 133);
}
.basic {
text-align: center;
margin-top: 0.33rem;
text {
height: 0.15rem;
color: $primary-color;
font-size: 0.14rem;
cursor: pointer;
}
}
.iconqianhou2 {
margin-left: 0.05rem;
font-size: 1px;
color: $primary-color;
}
.cancel-btn {
width: 1.7rem;
height: 0.5rem;
line-height: 0.5rem;
}
.shiftss-btn {
width: 1.7rem;
height: 0.5rem;
line-height: 0.5rem;
background-color: $primary-color;
color: #fff !important;
margin-left: 0.21rem;
}
.common-btn-wrap {
margin-top: 1.14rem;
z-index: 2;
height: 0.6rem;
padding-bottom: 0.05rem;
display: flex;
align-items: center;
}
</style>

View File

@@ -0,0 +1,413 @@
<template>
<base-page>
<view class="manage">
<view class="screen-warp common-form">
<uni-datetime-picker v-model="screen.start_time" type="datetime" placeholder="请选择开始时间" :clearIcon="false" />
<uni-datetime-picker v-model="screen.end_time" type="datetime" placeholder="请选择结束时间" :clearIcon="false" />
<view>
<select-lay :zindex="10" :value="screen.uid" name="names" placeholder="请选择员工" :options="userList" @selectitem="selectUser"/>
</view>
<view class="common-form-item">
<view class="form-inline common-btn-wrap">
<button class="screen-btn" @click="search">搜索</button>
<button type="default" @click="reset()">重置</button>
</view>
</view>
</view>
<uni-data-table url="/cashier/storeapi/cashier/changeShiftsRecord" :option="screen" :cols="cols" ref="table">
<template v-slot:action="data">
<view class="common-table-action"><text @click="detail(data)">查看详情</text></view>
<view class="common-table-action"><text @click="saleGoods(data)">商品销售</text></view>
</template>
</uni-data-table>
</view>
<uni-popup ref="shiftslistPop">
<view class="pop-box shiftsslistPop">
<view class="pop-header">
<view class="pop-header-text">交班详情</view>
<view class="pop-header-close" @click="$refs.shiftslistPop.close()">
<text class="iconguanbi1 iconfont"></text>
</view>
</view>
<view class="pop-content common-scrollbar" v-if="shiftsData">
<view class="pop-content-item">
<view class="pop-content-text">总销售{{ shiftsData.total_sale | moneyFormat }} {{ shiftsData.total_sale_count }}</view>
<view class="pop-contents-text">开单销售{{ shiftsData.billing_money | moneyFormat }} {{ shiftsData.billing_count }}</view>
<view class="pop-contents-text">售卡销售{{ shiftsData.buycard_money | moneyFormat }} {{ shiftsData.buycard_count }}</view>
</view>
<view class="pop-content-item">
<view class="pop-content-text">会员充值{{ shiftsData.recharge_money | moneyFormat }} {{ shiftsData.recharge_count }}</view>
</view>
<view class="pop-content-item">
<view class="pop-content-text">应收金额{{ shiftsData.total_money | moneyFormat }} {{ shiftsData.total_count }}</view>
<view class="pop-contents-text">开单销售{{ shiftsData.billing_money | moneyFormat }} {{ shiftsData.billing_count }}</view>
<view class="pop-contents-text">售卡销售{{ shiftsData.buycard_money | moneyFormat }} {{ shiftsData.buycard_count }}</view>
<view class="pop-contents-text">会员充值{{ shiftsData.recharge_money | moneyFormat }} {{ shiftsData.recharge_count }}</view>
<view class="pop-contents-text">订单退款{{ shiftsData.refund_money | moneyFormat }} {{ shiftsData.refund_count }}</view>
</view>
<view class="pop-content-item">
<view class="pop-content-text">支付统计{{ shiftsData.total_pay_money | moneyFormat }} {{ shiftsData.total_pay_count }}</view>
<view class="pop-contents-text" v-if="shiftsData.cash > 0">现金收款{{ shiftsData.cash | moneyFormat }} {{ shiftsData.cash_count }}</view>
<view class="pop-contents-text" v-if="shiftsData.wechatpay > 0">微信收款{{ shiftsData.wechatpay | moneyFormat }} {{ shiftsData.wechatpay_count }}</view>
<view class="pop-contents-text" v-if="shiftsData.alipay > 0">支付宝收款{{ shiftsData.alipay | moneyFormat }} {{ shiftsData.alipay_count }}</view>
<view class="pop-contents-text" v-if="shiftsData.own_wechatpay > 0">个人微信收款{{ shiftsData.own_wechatpay | moneyFormat }} {{ shiftsData.own_wechatpay_count }}</view>
<view class="pop-contents-text" v-if="shiftsData.own_alipay > 0">个人支付宝收款{{ shiftsData.own_alipay | moneyFormat }} {{ shiftsData.own_alipay_count }}</view>
<view class="pop-contents-text" v-if="shiftsData.own_pos > 0">个人POS收款{{ shiftsData.own_pos | moneyFormat }} {{ shiftsData.own_pos_count }}</view>
</view>
<view class="pop-content-item">
<view class="pop-content-text">商品销售{{ shiftsData.sale_goods_count.class_num }} {{ shiftsData.sale_goods_count.num }}</view>
<view class="pop-contents-text" >线上销售{{ shiftsData.sale_goods_count.online_class_num }} {{ shiftsData.sale_goods_count.online_num }}</view>
<view class="pop-contents-text" >线下销售{{ shiftsData.sale_goods_count.offline_class_num }} {{ shiftsData.sale_goods_count.offline_num }}</view>
</view>
</view>
<view class="pop-content-footer">
<button class="primary-btn" @click="printTicketFn">打印小票</button>
</view>
</view>
</uni-popup>
</base-page>
</template>
<script>
import { printTicket } from '@/api/printer.js'
import { getUserList } from '@/api/user.js'
export default {
data() {
return {
shiftsData: null,
screen: {
page: 1,
start_time: '',
end_time: '',
uid: 0
},
userList: [],
cols: [{
width: 20,
title: '员工',
field: 'username',
align: 'left'
}, {
width: 20,
title: '开始时间',
align: 'center',
return: data => {
return data.start_time ? this.$util.timeFormat(data.start_time) : '';
}
}, {
width: 20,
title: '结束时间',
align: 'center',
return: data => {
return this.$util.timeFormat(data.end_time);
}
}, {
width: 15,
title: '总销售',
align: 'right',
return: data => {
return this.$util.moneyFormat(parseFloat(data.billing_money) + parseFloat(data.buycard_money));
}
}, {
width: 15,
title: '会员充值',
align: 'right',
return: data => {
return this.$util.moneyFormat(data.recharge_money);
}
}, {
width: 15,
title: '应收金额',
align: 'right',
return: data => {
return this.$util.moneyFormat(
parseFloat(data.billing_money) + parseFloat(data.buycard_money) + parseFloat(data.recharge_money) - parseFloat(data.refund_money)
);
}
}, {
width: 15,
title: '支付统计',
align: 'right',
return: data => {
return this.$util.moneyFormat(
parseFloat(data.cash) +
parseFloat(data.alipay) +
parseFloat(data.wechatpay) +
parseFloat(data.own_wechatpay) +
parseFloat(data.own_alipay) +
parseFloat(data.own_pos)
);
}
}, {
width: 16,
title: '商品销售',
align: 'right',
return: data => {
return data.sale_goods_count.class_num + '种 ' + data.sale_goods_count.num + '件';
}
}, {
width: 15,
title: '操作',
action: true, // 表格操作列
align: 'right'
}]
};
},
onLoad() {
this.getUserListFn();
},
methods: {
switchStoreAfter() {
this.screen = {
page: 1,
start_time: '',
end_time: '',
uid: 0
};
this.$refs.table.load();
this.getUserListFn();
},
saleGoods(data){
this.$util.redirectTo('/pages/index/change_shiftssalelist',{ id : data.value.id });
},
detail(data) {
let shiftsData = this.$util.deepClone(data.value);
shiftsData.total_sale = parseFloat(shiftsData.billing_money) + parseFloat(shiftsData.buycard_money);
shiftsData.total_sale_count = parseInt(shiftsData.billing_count) + parseInt(shiftsData.buycard_count);
shiftsData.total_count = shiftsData.total_sale_count + parseInt(shiftsData.recharge_count) + parseInt(shiftsData.refund_count);
shiftsData.total_money = shiftsData.total_sale + parseFloat(shiftsData.recharge_money) - parseFloat(shiftsData.refund_money);
shiftsData.total_pay_money =
parseFloat(shiftsData.cash) +
parseFloat(shiftsData.alipay) +
parseFloat(shiftsData.wechatpay) +
parseFloat(shiftsData.own_wechatpay) +
parseFloat(shiftsData.own_alipay) +
parseFloat(shiftsData.own_pos);
shiftsData.total_pay_count =
parseInt(shiftsData.cash_count) +
parseInt(shiftsData.alipay_count) +
parseInt(shiftsData.wechatpay_count) +
parseInt(shiftsData.own_wechatpay_count) +
parseInt(shiftsData.own_alipay_count) +
parseInt(shiftsData.own_pos_count);
this.shiftsData = shiftsData;
this.$refs.shiftslistPop.open('center');
},
getUserListFn() {
let data = {
page: 1,
page_size: 0
};
getUserList(data).then(res => {
if (res.code >= 0 && res.data.list.length != 0) {
this.userList = res.data.list.map(item => {
return {
label: item.username,
value: item.uid
};
});
}
})
},
reset() {
this.screen = {
page: 1,
start_time: '',
end_time: '',
uid: 0
};
this.$refs.table.load(this.screen);
},
selectUser(index, item) {
if (index >= 0) {
this.screen.uid = parseInt(item.value);
} else {
this.screen.uid = 0;
}
},
search() {
this.$refs.table.load(this.screen);
},
/**
* 打印小票
*/
printTicketFn() {
let data = {
record_id: this.shiftsData.id
};
printTicket(data).then(res => {
if (res.code == 0) {
if (Object.values(res.data).length) {
let data = Object.values(res.data);
try {
let print = {
printer: []
};
data.forEach((item) => {
print.printer.push({
printer_type: item.printer_info.printer_type,
host: item.printer_info.host,
ip: item.printer_info.ip,
port: item.printer_info.port,
content: item.content,
print_width: item.printer_info.print_width
});
});
this.$pos.send('Print', JSON.stringify(print));
} catch (e) {
console.log('err', e, res.data)
}
} else {
this.$util.showToast({
title: '未开启交接班小票打印'
})
}
} else {
this.$util.showToast({
title: res.message ? res.message : '小票打印失败'
})
}
})
}
}
};
/**
* 打印回调
* @param {Object} text
*/
window.POS_PRINT_CALLBACK = function (text) {
uni.showToast({
title: text,
icon: 'none'
})
}
</script>
<style lang="scss" scoped>
.manage {
position: relative;
background-color: #fff;
padding: 0.15rem;
height: 100vh;
box-sizing: border-box;
}
// 筛选面板
.screen-warp {
padding: 0.15rem;
background-color: #f2f3f5;
margin-bottom: 0.15rem;
display: flex;
justify-content: start;
/deep/ .uni-date-x {
height: 0.35rem;
}
/deep/ .uni-select-lay {
background: #fff;
.uni-select-lay-select {
height: 0.37rem;
}
}
.primary-btn {
margin-left: 0;
}
&>* {
margin-right: 0.15rem;
}
.common-btn-wrap{
margin-left: 0;
}
}
// pop弹框
.pop-box {
background: #ffffff;
width: 4rem;
height: 60vh;
display: flex;
flex-direction: column;
.pop-header {
width: 100%;
padding: 0 0.15rem 0 0.2rem;
height: 0.5rem;
margin: 0 auto;
line-height: 0.5rem;
border-bottom: 0.01rem solid #f0f0f0;
font-size: 0.14rem;
color: #333;
overflow: hidden;
border-radius: 0.02rem 0.2rem 0 0;
box-sizing: border-box;
display: flex;
justify-content: space-between;
.pop-header-close {
cursor: pointer;
text {
font-size: 0.18rem;
}
}
}
.pop-content {
flex: 1;
height: 0;
padding: 0.1rem 0.2rem;
box-sizing: border-box;
font-weight: 900;
overflow-y: scroll;
}
.pop-contents {
margin-top: 0.3rem;
width: 3rem;
height: 0.8rem;
padding: 0.1rem 0.2rem;
box-sizing: border-box;
font-weight: 900;
display: flex;
flex-direction: column;
flex-wrap: wrap;
justify-content: space-between;
}
.pop-content-item {
margin-left: 0.3rem;
}
.pop-content-items {
margin-left: 0.3rem;
}
.pop-content-text {
padding: 0.1rem;
}
.pop-contents-text {
margin-left: 0.4rem;
font-weight: normal;
padding: 0.1rem;
}
.pop-content-footer {
display: flex;
padding: 0.1rem 0.2rem;
border-top: 0.01rem solid #e6e6e6;
justify-content: center;
button {
width: 1rem;
margin: 0;
}
}
}
</style>

View File

@@ -0,0 +1,56 @@
<template>
<base-page>
<view class="goods-list">
<view class="title-back flex items-center cursor-pointer" @click="backFn">
<text class="iconfont iconqianhou1"></text>
<text class="left">返回</text>
<text class="content">|</text>
<text>商品销售</text>
</view>
<view class="screen-warp common-form">
<view class="common-form-item">
<view class="form-inline">
<label class="form-label">销售渠道</label>
<view class="form-input-inline">
<select-lay :zindex="10" :value="option.sale_channel" name="sale_channel" placeholder="请选择销售渠道" :options="sale_channel_list" @selectitem="selectChannel"/>
</view>
</view>
<view class="form-inline">
<label class="form-label">规格名称</label>
<view class="form-input-inline">
<input type="text" v-model="option.sku_name" placeholder="请输入规格名称" class="form-input" />
</view>
</view>
<view class="form-inline common-btn-wrap">
<button type="default" class="screen-btn" @click="searchFn()">筛选</button>
<button type="default" @click="resetFn()">重置</button>
<button type="default" class="screen-btn" @click="exportSalelist()">导出</button>
</view>
</view>
</view>
<uniDataTable url="/cashier/storeapi/cashier/changeShiftsSaleGoodsList" :option="option" :cols="cols" ref="saleListTable">
</uniDataTable>
</view>
</base-page>
</template>
<script>
import uniDataTable from '@/components/uni-data-table/uni-data-table.vue';
import saleList from './public/js/sale_list.js';
export default {
components: {
uniDataTable
},
mixins: [saleList]
}
</script>
<style scoped lang="scss">
@import './../goods/public/css/goods_list.scss';
</style>
<style scoped>
.common-btn-wrap button{
margin-right: 0.1rem;
}
</style>

View File

@@ -0,0 +1,33 @@
<template>
<page-meta :root-font-size="rootSize"></page-meta>
<view class="container" :style="themeColor">
<image src="@/static/cashier/start_logo.png" mode="heightFix" />
</view>
</template>
<script>
export default {
data() {
return {};
},
onShow() {
this.loadThemeColor();
},
};
</script>
<style lang="scss" scoped>
.container {
width: 100vw;
height: 100vh;
background: #fff;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
image {
height: 80%;
}
}
</style>

View File

@@ -0,0 +1,36 @@
<template>
<base-page>
<view class="uni-flex uni-row height-all">
<view class="container common-wrap" style="-webkit-flex: 1;flex: 1;">
<view class="msg">对不起您没有权限访问该页面</view>
</view>
</view>
</base-page>
</template>
<script>
export default {
data() {
return {};
},
onLoad() {
uni.hideTabBar({});
},
methods: {}
};
</script>
<style lang="scss" scoped>
.container {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
background: #fff;
.msg {
color: #333;
font-size: 0.16rem;
}
}
</style>

View File

@@ -0,0 +1,106 @@
import {
saleGoodsExport
} from '@/api/shifts.js';
export default {
data() {
return {
page: 1, // 初始是请求第几页
page_size: 20, // 每次返回数据数
option: {
sale_channel:'all',
sku_name:'',
record_id:''
},
sale_channel_list: [{
value: 'online',
label: '线上'
}, {
value: 'offline',
label: '线下'
}],
cols: [{
field: 'account_data',
width: 25,
title: '商品信息',
align: 'left',
templet: data => {
let img = data.goods_class != 'recharge' ? this.$util.img(data.sku_image,{size:'small'}) : this.$util.img(data.sku_image);
let html = `
<view class="goods-content">
<image class="goods-img" src="${img}" mode="aspectFit"/>
<view class="infos">
<text class="goods-name multi-hidden">${data.goods_name}</text>
<text class="spec-name multi-hidden">${data.spec_name}</text>
</view>
</view>
`;
return html;
}
}, {
width: 15,
title: '总数量',
align: 'center',
field: 'num'
}, {
width: 15,
title: '平均销售价',
align: 'center',
field: 'price'
}, {
width: 15,
title: '销售总额',
align: 'center',
field: 'goods_money'
}, {
width: 15,
title: '线下销售',
align: 'center',
field: 'offline_num'
}, {
width: 15,
title: '线上销售',
align: 'center',
field: 'online_num'
}],
};
},
onLoad(option) {
this.option.record_id = option.id || '';
},
computed: {},
methods: {
exportSalelist(){
saleGoodsExport(this.option).then(res => {
if (res.code == 0) {
window.open(this.$util.img(res.data.path));
}else{
this.$util.showToast({
title: res.message
});
}
});
},
selectChannel(index){
this.option.sale_channel = index == -1 ? '' : this.sale_channel_list[index].value.toString();
},
searchFn(){
this.$refs.saleListTable.load({
page: 1
});
},
resetFn(){
this.option.sale_channel = '';
this.option.sku_name = '';
},
backFn() {
this.$util.redirectTo('/pages/index/change_shiftsrecord');
},
detail(data){
if(window.location.origin.indexOf('localhost') != -1){
window.open(window.location.origin+'/cashregister/pages/order/orderlist?order_no='+data.value.order_no,'_blank');
}else{
window.open(this.$config.baseUrl+'/cashregister/pages/order/orderlist?order_no='+data.value.order_no);
}
},
}
}

View File

@@ -0,0 +1,149 @@
<template>
<base-page>
<view class="collect-money-config">
<view class="common-wrap common-form fixd common-scrollbar">
<view class="common-title">本机设置</view>
<view class="common-form-item">
<label class="form-label">打印机选择</label>
<view class="form-inline">
<radio-group @change="printerSelectTypeChange" class="form-radio-group">
<label class="radio form-radio-item">
<radio value="all" :checked="printerSelectType == 'all'" />
全部
</label>
<label class="radio form-radio-item">
<radio value="part" :checked="printerSelectType == 'part'" />
部分
</label>
</radio-group>
</view>
<text class="form-word-aux-line" v-if="printerSelectType == 'all'">{{printerTips}}</text>
</view>
<view class="common-form-item" v-if="printerSelectType == 'part'">
<label class="form-label"></label>
<view class="form-inline">
<checkbox-group class="form-checkbox-group" @change="printerSelectIdsChange">
<label class="form-checkbox-item" v-for="(item, index) in printerList">
<checkbox :value="item.printer_id" :checked="printerSelectIds.indexOf(item.printer_id) > -1"/>
{{item.printer_name}}
</label>
</checkbox-group>
</view>
<text class="form-word-aux-line">{{printerTips}}</text>
</view>
<view class="common-btn-wrap">
<button type="default" class="screen-btn" @click="saveFn">保存</button>
</view>
</view>
</view>
</base-page>
</template>
<script>
import {
getPrinterList,
} from '@/api/printer.js'
export default {
data() {
return {
isRepeat: false,
printerList:[],
printerSelectType:'all',
printerSelectIds:[],
printerTips:'如果一个门店有多个收银机,请为每个收银机设备选择要调用的打印机硬件',
};
},
onLoad() {
this.initData();
this.getPrinterList();
},
onShow() { },
methods: {
initData(){
var local_config = this.$util.getLocalConfig();
this.printerSelectType = local_config.printerSelectType;
this.printerSelectIds = local_config.printerSelectIds;
},
getPrinterList() {
getPrinterList({
page: 1,
page_size: 0
}).then(res => {
if (res.code >= 0) {
this.printerList = res.data.list;
this.printerList.forEach((item, index)=>{
item.printer_id = item.printer_id.toString();
})
}
});
},
printerSelectTypeChange(e) {
this.printerSelectType = e.detail.value;
},
printerSelectIdsChange(e) {
this.printerSelectIds = e.detail.value;
},
saveFn() {
this.$util.setLocalConfig({
printerSelectType:this.printerSelectType,
printerSelectIds:this.printerSelectIds,
})
this.$util.showToast({
title: '设置成功'
});
}
}
};
</script>
<style lang="scss" scoped>
.collect-money-config {
position: relative;
.common-btn-wrap {
position: absolute;
left: 0;
bottom: 0;
right: 0;
padding: 0.24rem 0.2rem;
.screen-btn {
margin: 0;
}
}
.common-wrap.fixd {
padding: 30rpx;
height: calc(100vh - 0.4rem);
overflow-y: auto;
// padding-bottom: 1rem !important;
box-sizing: border-box;
}
.form-input {
font-size: 0.16rem;
}
.form-input-inline.btn {
height: 0.37rem;
line-height: 0.35rem;
box-sizing: border-box;
border: 0.01rem solid #e6e6e6;
text-align: center;
cursor: pointer;
}
.common-title {
font-size: 0.18rem;
margin-bottom: 0.2rem;
}
.common-form .common-form-item .form-label {
width: 1.5rem;
}
.common-form .common-form-item .form-word-aux-line {
margin-left: 1.5rem;
}
}
</style>

View File

@@ -0,0 +1,275 @@
<template>
<page-meta :root-font-size="rootSize"></page-meta>
<view class="container" :style="themeColor">
<view class="login-wrap">
<view class="header">
<view class="title">智慧零售平台登录</view>
</view>
<view class="form-wrap">
<view class="input-wrap">
<text class="iconfont icona-xingzhuang2"></text>
<input type="text" @confirm="loginFn" v-model="formData.username" placeholder="请输入用户名" placeholder-class="placeholder" />
</view>
<view class="input-wrap">
<text class="iconfont iconmima"></text>
<input type="text" @confirm="loginFn" v-model="formData.password" placeholder="请输入密码" placeholder-class="placeholder" v-show="passShow" />
<input type="password" @confirm="loginFn" v-model="formData.password" placeholder="请输入密码" placeholder-class="placeholder" v-show="!passShow" />
<view class="iconfont pass-show" :class="{ iconyanjing5: passShow, iconinvisible: !passShow }" @click="passShow = !passShow"></view>
</view>
<view class="input-wrap">
<text class="iconfont iconyanzhengma"></text>
<input type="number" @confirm="loginFn" v-model="formData.vercode" placeholder="请输入验证码" placeholder-class="placeholder" maxlength="4" />
<image :src="captcha.img" class="captcha" @click="getCaptchaFn" />
</view>
<button type="default" class="login-btn primary-btn" @click="loginFn">登录</button>
</view>
</view>
</view>
</template>
<script>
import validate from 'common/js/validate.js';
import { getCaptcha, login } from '@/api/login.js'
export default {
data() {
return {
passShow: false,
formData: {
username: '',
password: '',
vercode: '',
dynacode: '',
key: ''
},
captcha: {
id: '',
img: ''
},
isSub: false
};
},
onLoad() {
this.loadThemeColor();
this.getCaptchaFn();
},
methods: {
/**
* 获取验证码
*/
getCaptchaFn() {
getCaptcha(this.captcha.id).then(res => {
if (res.code >= 0) {
this.captcha = res.data;
this.captcha.img = this.captcha.img.replace(/\r\n/g, '');
}
})
},
loginFn() {
var data = {
username: this.formData.username,
password: this.formData.password
};
if (this.captcha.id != '') {
data.captcha_id = this.captcha.id;
data.captcha_code = this.formData.vercode;
}
if (this.verify(data)) {
if (this.isSub) return;
this.isSub = true;
uni.showLoading({});
login(data).then(res => {
uni.hideLoading();
if (res.code >= 0) {
uni.setStorageSync('siteId', res.data.site_id);
this.$store.commit('app/setGlobalStoreId', res.data.store_id);
uni.setStorage({
key: 'cashierToken',
data: res.data.token,
success: () => {
this.$store.dispatch('app/getStoreInfoFn');
this.$store.dispatch('app/getUserInfoFn');
this.$store.dispatch('app/getUserGroupFn');
}
});
} else {
this.isSub = false;
this.getCaptchaFn();
this.$util.showToast({
title: res.message
});
}
})
}
},
verify(data) {
var rule = [{
name: 'username',
checkType: 'required',
errorMsg: '请输入用户名'
}, {
name: 'password',
checkType: 'required',
errorMsg: '请输入密码'
}, {
name: 'captcha_code',
checkType: 'required',
errorMsg: '请输入验证码'
}];
var checkRes = validate.check(data, rule);
if (checkRes) {
return true;
} else {
this.$util.showToast({
title: validate.error
});
return false;
}
}
},
watch: {
menu: function(menu) {
if (menu && menu.length) {
if (menu[0].path) this.$util.redirectTo(menu[0].path, {}, 'redirectTo');
else this.$util.redirectTo('/pages/stat/index', {}, 'redirectTo');
}
}
}
};
</script>
<style lang="scss" scoped>
page {
width: 100vw;
height: 100vh;
background: #f7f8fa;
}
.container {
position: absolute;
left: 0;
top: 0;
bottom: 0;
right: 0;
background-size: cover;
background-repeat: no-repeat;
background-position: center;
display: flex;
align-items: center;
justify-content: center;
background-image:url(@/static/login_bg.png);
.login-bg {
margin-right: 1.5rem;
width: 5.9rem;
height: 4.3rem;
image {
width: 5.9rem;
height: 4.3rem;
}
}
}
.login-wrap {
padding: 0.3rem 0;
width: 3.48rem;
background-color: #fff;
box-shadow: 0 0.01rem 0.09rem 0 rgba(15, 92, 251, 0.12);
border-radius: 0.05rem;
.header {
text-align: center;
image {
width: 2.13rem;
height: 0.78rem;
}
.title {
font-weight: bold;
font-size: 0.25rem;
margin-top: 0.1rem;
color: #222222;
}
.desc {
font-size: 0.16rem;
color: #969799;
margin-top: 0.1rem;
}
}
}
.form-wrap {
display: flex;
flex-direction: column;
align-items: center;
margin: 0.2rem 0;
.input-wrap {
width: 2.85rem;
padding: 0 0.1rem;
border-bottom: 0.01rem solid #e6e6e6;
margin-top: 0.25rem;
display: flex;
align-items: center;
box-sizing: border-box;
border-radius: 0.05rem;
.iconfont {
margin-right: .1rem;
font-size: .2rem;
color: #46586E;
}
input {
flex: 1;
height: 0.4rem;
line-height: 0.4rem;
font-size: $uni-font-size-base;
}
.placeholder {
font-size: $uni-font-size-base;
color: #999999;
font-weight: 500;
}
.send-code {
color: $primary-color;
cursor: pointer;
&.disabled {
cursor: not-allowed;
color: #999;
}
}
.captcha {
width: 0.8rem;
height: 0.3rem;
cursor: pointer;
}
.pass-show {
font-size: 0.14rem;
cursor: pointer;
color: #333;
}
}
.login-btn {
width: 2.85rem;
margin-top: 0.3rem;
height: 0.4rem;
line-height: 0.4rem;
border-radius: 0.05rem;
}
}
</style>

View File

@@ -0,0 +1,126 @@
<template>
<base-page>
<view class="coupons-detail">
<view class="common-wrap common-form fixd common-scrollbar" v-if="!loading">
<view class="title-back flex items-center cursor-pointer" @click="backFn">
<text class="iconfont iconqianhou1"></text>
<text class="left">返回</text>
<text class="content">|</text>
<text>优惠券详情</text>
</view>
<view class="common-title">基本信息</view>
<view class="flex flex-wrap">
<view class="common-form-item">
<label class="form-label">优惠券名称</label>
<view class="form-input-inline">{{ couponsData.coupon_name }}</view>
</view>
<view class="common-form-item">
<label class="form-label">优惠券类型</label>
<view class="form-input-inline">{{ couponsData.type == 'reward' ? '满减' : '折扣' }}</view>
</view>
<view class="common-form-item" v-if="couponsData.type == 'reward'">
<label class="form-label">优惠面额</label>
<view class="form-input-inline">{{ couponsData.money }}</view>
</view>
<view class="common-form-item" v-else>
<label class="form-label">优惠券折扣</label>
<view class="form-input-inline">{{ couponsData.discount }}</view>
</view>
<view class="common-form-item" v-if="couponsData.type == 'discount' && couponsData.discount_limit != 0">
<label class="form-label">最多优惠</label>
<view class="form-input-inline">{{ couponsData.discount_limit }}</view>
</view>
<view class="common-form-item">
<label class="form-label">使用门槛 </label>
<view class="form-input-inline">{{ couponsData.at_least }}</view>
</view>
<view class="common-form-item">
<label class="form-label">是否允许直接领取</label>
<view class="form-input-inline">{{ couponsData.is_show === 1 ? '是' : '否' }}</view>
</view>
<view class="common-form-item">
<label class="form-label">发放数量</label>
<view class="form-input-inline">{{ (couponsData.is_show == 0 || couponsData.count == -1) ? '无限制' : couponsData.count + '张' }}</view>
</view>
<view class="common-form-item">
<label class="form-label">最大领取数量</label>
<view class="form-input-inline" v-if="couponsData.is_show == 0 || couponsData.max_fetch == 0">无领取限制</view>
<view class="form-input-inline" v-else>{{ couponsData.max_fetch }}/</view>
</view>
<view class="common-form-item">
<label class="form-label">有效期</label>
<view class="form-input-inline radio-list" v-if="couponsData.validity_type == 0">{{ couponsData.end_time }}</view>
<view class="form-input-inline radio-list" v-else-if="couponsData.validity_type == 1">领取后 {{ couponsData.fixed_term }} 有效</view>
<view class="form-input-inline radio-list" v-else>长期有效</view>
</view>
<view class="common-form-item">
<label class="form-label">使用渠道</label>
<view class="form-input-inline">
{{ couponsData.use_channel === 'all' ? '线上线下使用' :couponsData.use_channel === 'online' ?'线上使用':'线下使用' }}
</view>
</view>
<view v-if="couponsData.use_channel != 'online'" class="common-form-item">
<label class="form-label">适用门店</label>
<view class="form-input-inline truncate">
<text v-if="couponsData.use_store === 'all'">全部门店</text>
<text v-else :title="couponsData.use_store_list.map(v=>{return v.store_name}).join('、')">{{ couponsData.use_store_list.map(v=>{return v.store_name}).join('、') }}</text>
</view>
</view>
<view class="common-form-item">
<label class="form-label">活动商品</label>
<view class="form-input-inline radio-list">
{{couponsData.goods_type == 1 ? '全部商品参与' : couponsData.goods_type == 2 ? '指定商品参与' : '指定不参与商品' }}
</view>
</view>
<view class="common-form-item coupons-img">
<label class="form-label">优惠券图片</label>
<view class="form-input-inline upload-box">
<view class="upload">
<image :src="$util.img(couponsData.image)" mode="heightFix" />
</view>
</view>
</view>
</view>
<view class="common-title">数据统计</view>
<view class="data flex flex-wrap">
<view class="data-item">
<view class="title">发放数</view>
<view class="content">{{ couponsData.count||0 }}</view>
</view>
<view class="data-item">
<view class="title">领取数</view>
<view class="content">{{ couponsData.lead_count||0 }}</view>
</view>
<view class="data-item">
<view class="title">使用数</view>
<view class="content">{{ couponsData.used_count||0 }}</view>
</view>
</view>
<view class="common-title mt-20">领取记录</view>
<view class="record flex">
<block v-for="item in statusList">
<view :class="{'active':item.value==option.state}" type="default" @click="queryRecord(item.value)">{{ item.label }}</view>
</block>
</view>
<uniDataTable url="/coupon/storeapi/membercoupon/getReceiveCouponPageList" :option="option" :cols="cols" ref="couponListTable" />
<block v-if="couponsData.goods_type!=1">
<view class="common-title mt-20">{{couponsData.goods_type==2?'指定商品参与':'指定不参与商品'}}</view>
<uniDataTable :cols="goodsListCols" :data="couponsData.goods_list" classType />
</block>
</view>
</view>
</base-page>
</template>
<script>
import couponDetail from './public/js/coupon_detail.js';
import uniDataTable from '@/components/uni-data-table/uni-data-table.vue';
export default {
components:{
uniDataTable
},
mixins: [couponDetail]
};
</script>
<style lang="scss" scoped>
@import './public/css/coupon_detail.scss';
</style>

View File

@@ -0,0 +1,102 @@
<template>
<base-page>
<view class="coupons-list">
<view class="add-coupons">
<button type="default" class="screen-btn" @click="add">添加优惠券</button>
</view>
<view class="screen-warp common-form">
<view class="common-form-item">
<view class="form-inline">
<label class="form-label">优惠券名称</label>
<view class="form-input-inline">
<input type="text" v-model="option.coupon_name" placeholder="请输入优惠券名称" class="form-input" />
</view>
</view>
<view class="form-inline">
<label class="form-label">优惠券类型</label>
<view class="form-input-inline border-0">
<select-lay :zindex="10" :value="option.type" name="type" placeholder="请选择优惠券类型" :options="typeList" @selectitem="selectCouponsType"/>
</view>
</view>
<view class="form-inline">
<label class="form-label">优惠券状态</label>
<view class="form-input-inline border-0">
<select-lay :zindex="9" :value="option.status" name="status" placeholder="请选择优惠券状态" :options="statusList" @selectitem="selectStatus"/>
</view>
</view>
<view class="form-inline">
<label class="form-label">适用场景</label>
<view class="form-input-inline border-0">
<select-lay :zindex="9" :value="option.use_channel" name="status" placeholder="请选择优惠券状态" :options="useChannelList" @selectitem="selectUseChannel"/>
</view>
</view>
<!-- <view class="form-inline">
<label class="form-label">有效期限</label>
<view class="form-input-inline border-0">
<select-lay :zindex="9" :value="option.validity_type" name="validity_type" placeholder="请选择有效期限" :options="validityTypeList" @selectitem="selectValidityType"/>
</view>
</view> -->
<view class="form-inline common-btn-wrap">
<button type="default" class="screen-btn" @click="searchFn()">筛选</button>
<button type="default" @click="resetFn()">重置</button>
</view>
</view>
</view>
<uniDataTable url="/coupon/storeapi/coupon/lists" :option="option" :cols="cols" ref="couponListTable">
<template v-slot:action="dataTable">
<view class="action-btn-wrap">
<text v-if="dataTable.value.status=='1'" class="action-item" @click="promotion(dataTable.value.coupon_type_id)">推广</text>
<text v-if="dataTable.value.status=='1' && globalStoreInfo.store_id===dataTable.value.store_id" class="action-item" @click="edit(dataTable.value.coupon_type_id)">编辑</text>
<text class="action-item" @click="detail(dataTable.value.coupon_type_id)">详情</text>
<text v-if="dataTable.value.status=='1' && globalStoreInfo.store_id===dataTable.value.store_id" class="action-item" @click="closeOpen(dataTable.value.coupon_type_id)">关闭</text>
<text v-if="dataTable.value.status!='1' && globalStoreInfo.store_id===dataTable.value.store_id" class="action-item" @click="deleteOpen(dataTable.value.coupon_type_id)">删除</text>
</view>
</template>
</uniDataTable>
</view>
<!-- 推广 -->
<ns-promotion-popup ref="promotionPop" />
<!-- 关闭 -->
<unipopup ref="closeCouponsPop" type="center">
<view class="confirm-pop">
<view class="title">确定要关闭该优惠券吗</view>
<view class="btn">
<button type="primary" class="default-btn btn save" @click="$refs.closeCouponsPop.close()">取消</button>
<button type="primary" class="primary-btn btn" @click="close">确定</button>
</view>
</view>
</unipopup>
<!-- 删除 -->
<unipopup ref="deleteCouponsPop" type="center">
<view class="confirm-pop">
<view class="title">确定要删除该优惠券吗</view>
<view class="btn">
<button type="primary" class="default-btn btn save" @click="$refs.deleteCouponsPop.close()">取消</button>
<button type="primary" class="primary-btn btn" @click="del">确定</button>
</view>
</view>
</unipopup>
</base-page>
</template>
<script>
import uniDataTable from '@/components/uni-data-table/uni-data-table.vue';
import nsPromotionPopup from '@/components/ns-promotion-popup/ns-promotion-popup.vue';
import unipopup from '@/components/uni-popup/uni-popup.vue';
import couponList from './public/js/coupon_list.js';
export default {
components: {
unipopup,
uniDataTable,
nsPromotionPopup
},
mixins: [couponList]
};
</script>
<style scoped lang="scss">
@import './public/css/coupon_list.scss';
</style>

View File

@@ -0,0 +1,167 @@
<template>
<base-page>
<view class="coupons-form">
<view class="common-wrap common-form fixd common-scrollbar">
<view class="common-title">{{ couponsData.coupon_type_id ? '编辑优惠券' : '添加优惠券' }}</view>
<view class="common-form-item">
<label class="form-label"><text class="required">*</text>优惠券名称</label>
<view class="form-input-inline">
<input type="text" v-model="couponsData.coupon_name" class="form-input" maxlength="15" />
</view>
</view>
<view class="common-form-item">
<label class="form-label"><text class="required">*</text>优惠券类型</label>
<view class="form-input-inline border-0">
<uni-data-checkbox v-model="couponsData.type" :localdata="typeList"/>
</view>
</view>
<view class="common-form-item" v-if="couponsData.type == 'reward'">
<label class="form-label"><text class="required">*</text>优惠券面额</label>
<view class="form-input-inline">
<input type="number" v-model="couponsData.money" class="form-input" />
</view>
<text class="form-word-aux"></text>
<text class="form-word-aux-line">价格不能小于等于0可保留两位小数</text>
</view>
<view class="common-form-item" v-else>
<label class="form-label"><text class="required">*</text>优惠券折扣</label>
<view class="form-input-inline">
<input type="number" v-model="couponsData.discount" class="form-input" />
</view>
<text class="form-word-aux"></text>
<text class="form-word-aux-line">优惠券折扣不能小于1折且不可大于9.9可保留两位小数</text>
</view>
<view class="common-form-item" v-if="couponsData.type == 'discount'">
<label class="form-label">最多优惠</label>
<view class="form-input-inline"><input type="number" v-model="couponsData.discount_limit" class="form-input" /></view>
<text class="form-word-aux"></text>
</view>
<view class="common-form-item">
<label class="form-label"><text class="required">*</text>满多少元可以使用</label>
<view class="form-input-inline">
<input type="number" v-model="couponsData.at_least" class="form-input" />
</view>
<text class="form-word-aux"></text>
<text class="form-word-aux-line">价格不能小于0无门槛请设为0</text>
</view>
<view class="common-form-item">
<label class="form-label">是否允许直接领取</label>
<view class="form-input-inline border-0">
<switch :checked="couponsData.is_show === 1" style="transform:scale(0.7)" @change="checkIsShow" />
</view>
</view>
<block v-if="couponsData.is_show === 1">
<view class="common-form-item">
<label class="form-label"><text class="required">*</text>发放数量</label>
<view class="form-input-inline">
<input type="number" v-model="couponsData.count" class="form-input" />
</view>
<text class="form-word-aux"></text>
<text class="form-word-aux-line">优惠券发放数量没有之后不能领取或发放-1为不限制发放数量,发放数量只能增加不能减少</text>
</view>
<view class="common-form-item">
<label class="form-label"><text class="required">*</text>最大领取数量</label>
<view class="form-input-inline">
<input type="number" v-model="couponsData.max_fetch" class="form-input" />
</view>
<text class="form-word-aux"></text>
<text class="form-word-aux-line">数量不能小于0且必须为整数设置为0时可无限领取</text>
</view>
</block>
<view class="common-form-item coupons-img">
<label class="form-label">优惠券图片</label>
<view class="form-input-inline upload-box" @click="addImg">
<view class="upload" v-if="couponsData.image">
<image :src="$util.img(couponsData.image)" mode="heightFix" />
</view>
<view class="upload" v-else>
<text class="iconfont iconyunshangchuan"></text>
<view>点击上传</view>
</view>
</view>
<text class="form-word-aux-line">建议尺寸325*95像素图片上传默认不限制大小</text>
</view>
<view class="common-form-item">
<label class="form-label">有效期类型</label>
<view class="form-input-inline border-0 radio-list">
<uni-data-checkbox v-model="couponsData.validity_type" :localdata="validityTypeList"/>
</view>
<view class="form-word-aux-line top" v-if="couponsData.validity_type === 0">
<view class="w-250">
<uni-datetime-picker v-model="couponsData.end_time" type="timestamp" :clearIcon="false" @change="changeTime" />
</view>
</view>
</view>
<view class="common-form-item" v-if="couponsData.validity_type === 1">
<label class="form-label"><text class="required">*</text>领取后几天有效</label>
<view class="form-input-inline">
<input type="number" v-model="couponsData.fixed_term" class="form-input" />
</view>
<text class="form-word-aux"></text>
<text class="form-word-aux-line">不能小于等于0且必须为整数</text>
</view>
<view class="common-form-item">
<label class="form-label">活动商品</label>
<view class="form-input-inline border-0 radio-list">
<uni-data-checkbox v-model="couponsData.goods_type" :localdata="goodsTypeList" @change="goodsType"/>
</view>
<view class="form-word-aux-line top" v-if="couponsData.goods_type==2||couponsData.goods_type===3">
<view class="table-wrap">
<view class="table-head">
<view class="table-tr">
<view class="table-th" style="flex: 5;">商品名称</view>
<view class="table-th" style="flex: 1;">价格</view>
<view class="table-th" style="flex: 1;">库存</view>
<view class="table-th" style="flex: 1;">操作</view>
</view>
</view>
<view class="table-body">
<block v-for="(item, index) in couponsData.goods_list" :key="index">
<view class="table-tr">
<view class="table-td goods-name" style="flex: 5;">{{ item.goods_name }}</view>
<view class="table-td" style="flex: 1;">{{ item.price || '0.00' }}</view>
<view class="table-td" style="flex: 1;">{{ item.goods_stock || 0 }}</view>
<view class="table-td" style="flex: 1;">
<button type="default" class="delete" @click="delGoods(item.sku_id)">删除</button>
</view>
</view>
</block>
<view class="table-tr table-empty" v-if="!couponsData.goods_list.length">暂无数据请选择商品数据</view>
</view>
</view>
<button type="default" class="gooods_select" @click="dialogVisible = true">选择商品</button>
</view>
<view class="form-word-aux-line top" v-if="couponsData.goods_type==4||couponsData.goods_type===5">
<view class="flex items-center">
<button type="default" class="gooods_select" @click="$refs.couponCategoryPop.open(couponsData.goods_ids_real?couponsData.goods_ids_real.split(','):[])">选择商品分类</button>
<text class="goods_names">{{couponsData.goods_names}}</text>
</view>
</view>
</view>
<view class="common-form-item">
<label class="form-label">适用场景</label>
<view class="form-input-inline border-0 radio-list">
<uni-data-checkbox v-model="couponsData.use_channel" :localdata="useChannelList"/>
</view>
<text class="form-word-aux-line">在小程序和pc端商城下单为线上使用在收银台下单为线下使用</text>
</view>
<view class="common-btn-wrap">
<button type="default" class="screen-btn" @click="saveFn">保存</button>
<button type="default" @click="backFn">返回</button>
</view>
</view>
</view>
<stock-goods-dialog v-model="dialogVisible" apiType="spu" @selectGoods="selectGoods" />
<coupon-category-popup ref="couponCategoryPop" @confirm="goodsCategoryConfirm"/>
</base-page>
</template>
<script>
import editCoupon from './public/js/edit_coupon.js';
import couponCategoryPopup from '@/components/coupon-category-popup/coupon-category-popup.vue'
export default {
mixins: [editCoupon]
};
</script>
<style lang="scss" scoped>
@import './public/css/edit_coupon.scss';
</style>

View File

@@ -0,0 +1,121 @@
.coupons-detail {
position: relative;
height: calc(100vh - 0.4rem);
background-color: #fff;
.common-wrap.fixd {
padding: 30rpx;
height: 100%;
overflow-y: auto;
padding-bottom: 0.85rem !important;
box-sizing: border-box;
.form-label {
width: 1.7rem !important;
height: 0.3rem !important;
line-height: 0.3rem !important;
padding: 0 0.15rem;
}
.common-form-item{
width: 33.333%;
height: 0.3rem;
margin-bottom: 0;
.form-input-inline{
border-width: 0 !important;
width: calc(100% - 1.8rem);
}
&.coupons-img{
-webkit-box-align: start;
-ms-flex-align: start;
-webkit-align-items: flex-start;
align-items: flex-start;
width: 100% !important;
height: auto;
.upload-box {
border: 0.01rem dashed #e6e6e6 !important;
width: 2.5rem !important;
height: 1.2rem !important;
display: flex;
align-items: center;
justify-content: center;
.upload {
text-align: center;
color: #5a5a5a;
.iconfont {
font-size: 0.3rem;
}
image {
max-width: 100%;
height: 1.2rem !important;
}
}
}
}
}
}
.common-title {
font-size: 0.18rem;
margin-bottom: 0.2rem;
&.mt-20{
margin-top: 0.2rem;
}
}
.data{
margin-top: 0.1rem;
.data-item{
width: 33.333%;
text-align: center;
.title{
color: #909399;
margin-bottom: 0.2rem;
}
.content{
font-size: 0.26rem;
color: #303133;
}
}
}
/deep/ .member-img{
width: 0.6rem;
height: 0.6rem;
margin-right: 0.1rem;
-ms-flex-negative: 0;
-webkit-flex-shrink: 0;
flex-shrink: 0;
}
/deep/ .member-nickname{
width: 2.3rem;
}
/deep/ .member-mobile{
width: 2.3rem;
}
.record{
margin-bottom: 0.2rem;
view {
width: 1rem;
height: 0.35rem;
line-height: 0.35rem;
text-align: center;
font-size: 0.14rem;
border: 0.01rem solid #e6e6e6;
border-left-width: 0;
transition: all 0.3s;
cursor: pointer;
&:hover,
&.active {
border-color: $primary-color;
color: $primary-color;
background-color: var(--primary-color-light-9);
box-shadow: -0.01rem 0 0 0 $primary-color;
}
&:first-child {
border-left-width: 0.01rem;
box-shadow: none;
}
}
}
}

View File

@@ -0,0 +1,124 @@
view {
color: #303133;
}
/deep/ .uni-scroll-view::-webkit-scrollbar {
width: 0.05rem;
height: 0.3rem;
}
/deep/ .uni-scroll-view::-webkit-scrollbar-thumb {
border-radius: 0.1rem;
box-shadow: inset 0 0 0.05rem rgba(0, 0, 0, 0.2);
background: rgba(193, 193, 193, 1);
}
.cart-empty {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 2.1rem;
}
.record-body {
width: 10rem;
min-height: 7rem;
}
.add-coupons{
margin-bottom: 0.1rem;
button{
background-color: $primary-color;
color: #fff;
display: inline-block;
padding: 0 0.2rem;
height: 0.36rem;
line-height: .36rem;
font-size: 0.14rem;
&::after{
border-width: 0;
}
}
}
// 筛选面板
.screen-warp {
padding: 0.15rem 0.15rem 0;
background-color: #f2f3f5;
margin-bottom: 0.15rem;
.common-form-item .form-label {
width: 1.2rem;
}
.common-btn-wrap {
margin-left: 1.2rem;
}
.coupons-category .form-input-inline {
width: 2.8rem;
}
.form-inline {
margin-bottom: 0.15rem;
}
.common-form-item {
margin-bottom: 0;
}
.input-append {
position: relative;
.form-input {
padding-right: 0.3rem;
}
.unit {
position: absolute;
top: 0;
right: 0.1rem;
height: 0.35rem;
line-height: 0.35rem;
}
}
.form-input-inline.split-wrap {
width: initial;
background: none;
border: none;
}
}
.coupons-list {
display: block;
width: 100%;
@extend %body-overhide;
padding: 0.15rem 0.15rem 0;
background-color: #fff;
/deep/ .coupons-content {
display: flex;
}
.action-btn-wrap {
.action-item {
margin-left: 0.1rem;
color: $primary-color;
&:first-of-type {
margin-left: 0;
}
}
}
/deep/ .batch-action {
.batch-item {
margin-right: 0.15rem;
border: 0.01rem solid rgba(0, 0, 0, 0.2);
padding: 0.05rem;
border-radius: 0.03rem;
}
}
}

View File

@@ -0,0 +1,199 @@
.coupons-form {
position: relative;
.common-wrap.fixd {
padding: 30rpx;
height: calc(100vh - 0.4rem);
overflow-y: auto;
box-sizing: border-box;
.form-label {
width: 1.7rem !important;
}
.form-input-inline /deep/ .uni-select {
border: none;
}
.common-btn-wrap {
position: absolute;
left: 0;
bottom: 0;
right: 0;
padding: 0.24rem 0.2rem;
}
.form-word-aux-line {
margin-left: 1.7rem !important;
.gooods_select{
margin: 0;
}
.goods_names{
margin-left: 0.15rem;
}
}
}
.upload-box {
border: 0.01rem dashed #e6e6e6 !important;
width: 2.5rem !important;
height: 1.2rem !important;
display: flex;
align-items: center;
justify-content: center;
.upload {
text-align: center;
color: #5a5a5a;
.iconfont {
font-size: 0.3rem;
}
image {
max-width: 100%;
height: 1.2rem !important;
}
}
}
.coupons-img {
align-items: flex-start !important;
}
.map-box {
width: 6.5rem;
height: 5rem;
position: relative;
.map-icon {
position: absolute;
top: calc(50% - 0.36rem);
left: calc(50% - 0.18rem);
width: 0.36rem;
height: 0.36rem;
z-index: 100;
}
}
.form-input {
font-size: 0.16rem;
}
.form-input-inline.btn {
height: 0.37rem;
line-height: 0.35rem;
box-sizing: border-box;
border: 0.01rem solid #e6e6e6;
text-align: center;
cursor: pointer;
}
.common-title {
font-size: 0.18rem;
margin-bottom: 0.2rem;
}
/deep/ .uni-select-lay-select{
height: 0.37rem;
width: 2.52rem;
margin: 0;
}
.radio-list{
width: 7rem !important;
}
.radio-item{
margin-right: 0.1rem;
}
/deep/ .uni-date-x{
height: 0.37rem;
}
.top{
margin-top: 0.1rem;
}
.w-250{
width: 2.5rem;
}
.form-input-inline{
width: 2.5rem;
}
.required{
color: red;
}
.table-wrap {
position: relative;
border: 1rpx solid #ccc;
color: #333;
.table-head {
background-color: #f7f7f7;
}
.table-body {
.table-tr {
&:last-of-type .table-td {
border-bottom: 0;
}
}
}
.table-tr {
display: flex;
}
.table-th,
.table-td {
display: flex;
align-items: center;
justify-content: center;
padding: 0.07rem 0.3rem;
border-bottom: 0.01rem solid #ccc;
border-right: 0.01rem solid #ccc;
text-align: center;
&:last-of-type {
border-right: 0;
justify-content: flex-end;
}
&.goods-name {
-webkit-box-pack: start;
-ms-flex-pack: start;
-webkit-justify-content: flex-start;
justify-content: flex-start;
}
}
.delete {
margin: 0;
font-size: $uni-font-size-base;
background-color: $primary-color;
color: #fff;
line-height: 0.32rem;
height: 0.32rem;
&::after{
border-width: 0;
}
}
.table-empty {
justify-content: center;
padding: 0.3rem;
color: #999;
}
}
.gooods_select{
background-color: $primary-color;
color: #fff;
display: inline-block;
padding: 0 0.2rem;
height: 0.36rem;
line-height: .36rem;
font-size: 0.14rem;
border-radius: 3px;
margin-top: 0.1rem;
&::after{
border-width: 0;
}
}
}

View File

@@ -0,0 +1,169 @@
import {getCouponDetail } from '@/api/marketing.js'
export default {
data() {
return {
couponsData: {
coupon_type_id:'',
coupon_name: "",
type: "reward",
money: "",
discount: "",
discount_limit: "",
at_least: "",
is_show: 1,
count: "",
max_fetch: "",
image: "",
validity_type: 0,
end_time: this.$util.timeFormat(Date.parse(new Date()) / 1000),
fixed_term: 0,
goods_type:1,
lead_count:0,
used_count:0,
use_channel:'',
use_store:'',
use_store_list:[],
goods_list:[]
},
loading:false,
cols: [{
field: 'account_data',
width: 20,
title: '会员信息',
align: 'left',
templet: data => {
let img = this.$util.img(data.headimg);
let html = `
<view class="member-content flex">
<image class="member-img" src="${img}" mode="aspectFit"/>
<view class="flex flex-col justify-between">
<text class="member-nickname multi-hidden">${data.nickname}</text>
<text class="member-mobile multi-hidden">${data.mobile}</text>
</view>
</view>
`;
return html;
}
}, {
field: 'coupon_name',
width: 15,
title: '优惠券',
align: 'left',
},{
title: '类型',
width: 10,
unresize: 'false',
templet: data=> {
return data.type == 'reward' ? '满减券' : '折扣券';
}
},{
field: 'get_type_name',
width: 15,
title: '获取方式',
align: 'left',
},{
title: '状态',
width: 10,
unresize: 'false',
templet: data=> {
var str = '';
switch (data.state) {
case 1:
str = '已领取';
break;
case 2:
str = '已使用';
break;
case 3:
str = '已过期';
break;
}
return str;
}
},{
title: '领取时间',
width: 15,
unresize: 'false',
templet: data=> {
return this.$util.timeFormat(Date.parse(new Date(data.fetch_time)));
}
}, {
title: '使用时间',
width: 15,
templet: data=> {
return data.use_time ? this.$util.timeFormat(Date.parse(new Date(data.use_time))) : '';
}
},],
statusList: [{
value: '',
label: '全部'
},{
value: '1',
label: '已领取'
}, {
value: '2',
label: '已使用'
},
{
value: '3',
label: '已过期'
}],
option:{
page_size: 9,
coupon_type_id:'',
state: '',
},
goodsListCols:[{
field: 'goods_name',
width: 60,
title: '商品名称',
align: 'left',
},{
title: '价格',
width: 20,
unresize: 'false',
templet: data=> {
return data.price || '0.00';
}
},{
title: '库存',
width: 20,
unresize: 'false',
templet: data=> {
return data.goods_stock || 0;
}
},]
}
},
onLoad(option) {
if(option.coupon_type_id){
this.couponsData.coupon_type_id = option.coupon_type_id
this.option.coupon_type_id = option.coupon_type_id
this.getData(option.coupon_type_id)
}
},
methods: {
getData(coupon_type_id) {
this.loading = true
getCouponDetail(coupon_type_id).then(res=>{
let data = res.data;
if(res.code>=0 && data) {
Object.keys(this.couponsData).forEach(key => {
this.couponsData[key] = data.info[key]
if (key == 'end_time') this.couponsData[key] = this.couponsData.end_time = this.$util.timeFormat(Date.parse(new Date(data.info[key])))
})
}
this.loading = false
})
},
queryRecord(val){
this.option.state = val
this.$refs.couponListTable.load({
page: 1
});
},
backFn() {
this.$util.redirectTo('/pages/marketing/coupon_list');
},
}
}

View File

@@ -0,0 +1,221 @@
import {closeCoupon, deleteCoupon} from '@/api/marketing.js';
export default {
data() {
return {
option: {
page_size: 10,
coupon_name: '',
type: '',
status: '',
use_channel: '',
},
coupon_type_id: "",
flag: false,
typeList: [{
value: 'reward',
label: '满减'
}, {
value: 'discount',
label: '折扣'
},],
statusList: [{
value: '1',
label: '进行中'
}, {
value: '2',
label: '已结束'
}, {
value: '-1',
label: '已关闭'
}],
// validityTypeList:[{
// value: '0',
// label: '固定时间'
// }, {
// value: '1',
// label: '相对时间'
// },
// {
// value: '2',
// label: '长期有效'
// }],
useChannelList:[
{
value: 'all',
label: '线上线下使用'
},
{
value: 'online',
label: '线上使用'
},
{
value: 'offline',
label: '线下使用'
},
],
cols: [{
field: 'coupon_name',
width: 15,
title: '优惠券名称',
align: 'left',
}, {
field: 'reward',
title: '优惠券类型',
align: 'left',
width: 10,
templet: function (data) {
if (data.type == 'reward') {
return '满减';
} else {
return '折扣';
}
}
}, {
title: '优惠金额/折扣',
width: 10,
align: 'left',
templet: function (data) {
if (data.type == 'reward') {
return `<span style="padding-right: 15px;">¥${data.money}</span>`;
} else {
return `<span style="padding-right: 15px;">${data.discount}折</span>`;
}
}
}, {
field: 'count',
title: '发放数量',
width: 10,
templet: function (data) {
return data.is_show == 0 || data.count == -1 ? '无限制' : data.count;
}
}, {
title: '剩余数量',
width: 10,
templet: function (data) {
return data.is_show == 0 || data.count == -1 ? '无限制' : data.count - data.lead_count;
}
}, {
title: '领取上限',
width: 10,
templet: function (data) {
return data.is_show == 0 || data.max_fetch == 0 ? '无领取限制' : data.max_fetch + '张/人';
}
}, {
title: '有效期限',
unresize: 'false',
width: 15,
templet: (data) => {
if (data.validity_type == 0) {
return `失效期:${this.$util.timeFormat(data.end_time)}`
} else if (data.validity_type == 1) {
return `领取后,${data.fixed_term}天有效`
} else {
return '长期有效'
}
}
},{
field: 'use_channel_name',
title: '适用场景',
unresize: 'false',
width: 10
}, {
field: 'status_name',
title: '状态',
width: 10
}, {
width: 10,
title: '操作',
align: 'right',
action: true
}],
};
},
onLoad() {
},
methods: {
switchStoreAfter() {
this.searchFn();
},
selectCouponsType(index) {
this.option.type = index == -1 ? '' : this.typeList[index].value;
},
selectStatus(index) {
this.option.status = index == -1 ? '' : this.statusList[index].value;
},
selectUseChannel(index) {
this.option.use_channel = index == -1 ? '' : this.useChannelList[index].value;
},
// selectValidityType(index){
// this.option.validity_type = index == -1 ? '' : this.validityTypeList[index].value;
// },
// 搜索商品
searchFn() {
this.$refs.couponListTable.load({
page: 1
});
},
resetFn() {
this.option = {
page_size: 10,
coupon_name: '',
type: '',
status: '',
}
this.$refs.couponListTable.load({
page: 1,
coupon_name: '',
type: '',
status: '',
});
},
add() {
this.$util.redirectTo('/pages/marketing/edit_coupon');
},
detail(coupon_type_id) {
this.$util.redirectTo('/pages/marketing/coupon_detail', {
coupon_type_id
});
},
edit(coupon_type_id) {
this.$util.redirectTo('/pages/marketing/edit_coupon', {
coupon_type_id
});
},
closeOpen(coupon_type_id) {
this.coupon_type_id = coupon_type_id
this.$refs.closeCouponsPop.open()
},
close() {
if (this.flag) return false;
this.flag = true;
this.$refs.closeCouponsPop.close()
closeCoupon(this.coupon_type_id).then(res => {
if (res.code >= 0) {
this.flag = false;
this.$refs.couponListTable.load();
}
})
},
deleteOpen(coupon_type_id) {
this.coupon_type_id = coupon_type_id
this.$refs.deleteCouponsPop.open()
},
del() {
if (this.flag) return false;
this.flag = true;
this.$refs.deleteCouponsPop.close()
deleteCoupon(this.coupon_type_id).then(res => {
if (res.code >= 0) {
this.flag = false;
this.$refs.couponListTable.load();
}
})
},
promotion(coupon_type_id){
this.$refs.promotionPop.open({coupon_type_id})
}
}
}

View File

@@ -0,0 +1,382 @@
import {
getCouponDetail,
addCoupon,
editCoupon,
} from '@/api/marketing.js'
export default {
data() {
return {
couponsData: {
coupon_type_id: '',
coupon_name: "",
type: "reward",
money: "",
discount: "",
discount_limit: "",
at_least: "",
is_show: 1,
count: "",
max_fetch: "",
image: "",
validity_type: 0,
end_time: this.$util.timeFormat((Date.parse(new Date()) / 1000) + (10 * 24 * 60 * 60)),
fixed_term: 0,
goods_type: 1,
goods_ids: '',
goods_ids_real:'',
goods_list: [],
goods_names:'',
use_channel:'all',
},
flag: false,
goods_ids: [],
typeList: [{
value: 'reward',
text: '满减'
}, {
value: 'discount',
text: '折扣'
},],
validityTypeList: [{
value: 0,
text: '固定时间'
}, {
value: 1,
text: '领取之日起'
}, {
value: 2,
text: '长期有效'
}],
goodsTypeList: [{
value: 1,
text: '全部商品参与'
}, {
value: 2,
text: '指定商品参与'
}, {
value: 3,
text: '指定商品不参与'
}, {
value: 4,
text: '指定分类参与'
}, {
value: 5,
text: '指定分类不参与'
}],
useChannelList: [{
value: 'all',
text: '线上线下使用'
}, {
value: 'online',
text: '线上使用'
}, {
value: 'offline',
text: '线下使用'
}],
dialogVisible: false
};
},
onLoad(option) {
if (option.coupon_type_id) {
this.couponsData.coupon_type_id = option.coupon_type_id
this.getData(option.coupon_type_id)
}
},
watch: {
'couponsData.validity_type'(newValue) {
if (newValue === 0) this.couponsData.end_time = this.$util.timeFormat((Date.parse(new Date()) / 1000) + (10 * 24 * 60 * 60))
}
},
methods: {
getData(coupon_type_id) {
getCouponDetail(coupon_type_id).then(res => {
let data = res.data;
if (res.code >= 0 && data) {
Object.keys(this.couponsData).forEach(key => {
this.couponsData[key] = data.info[key]
if (key == 'end_time') this.couponsData[key] = this.couponsData.end_time = this.$util.timeFormat(Date.parse(new Date(data.info[key])))
})
}
this.goods_ids = this.couponsData.goods_list.map(v => v.goods_id)
this.couponsData.goods_ids = this.goods_ids.join()
})
},
addImg() {
this.$util.upload(1, {
path: 'image'
}, res => {
if (res.length > 0) {
this.couponsData.image = res[0];
this.$forceUpdate();
}
});
},
checkIsShow(e) {
this.couponsData.is_show = e.detail.value ? 1 : 0
},
changeTime(data) {
this.couponsData.end_time = data;
},
selectGoods(data) { //选择数据
data.forEach(el => {
if (!this.goods_ids.includes(el.goods_id)) {
this.goods_ids.push(el.goods_id)
this.couponsData.goods_list.push(el)
}
})
},
delGoods(id) {//删除已选择的商品
this.couponsData.goods_list.splice(this.goods_ids.indexOf(id), 1);
this.goods_ids.splice(this.goods_ids.indexOf(id), 1);
},
checkData() {
let _this = this
let verify = {
days: function (value) {
if (_this.couponsData.validity_type == 1) {
if (value % 1 != 0) {
return '请输入整数';
}
if (value <= 0) {
return '有效天数不能小于等于0';
}
return ''
}
return ''
},
number: function (value) {
if (value < 0) {
return '请输入不小于0的数!'
}
return ''
},
coupon_money: function (value) {
if (parseFloat(value) > 10000) {
return '优惠券面额不能大于10000'
}
if (parseFloat(value) <= 0) {
return '优惠券面额不能小于0'
}
return ''
},
int: function (value) {
if (value % 1 != 0) {
return '最多优惠,请输入整数!'
}
if (value < 0) {
return '最多优惠,请输入大于0的数!'
}
return ''
},
money: function (value) {
if (value < 0) {
return '金额不能小于0'
}
var arrMen = value.split(".");
var val = 0;
if (arrMen.length == 2) {
val = arrMen[1];
}
if (val.length > 2) {
return '保留小数点后两位'
}
return ''
},
time: function (value) {
if (_this.couponsData.validity_type == 0) {
var now_time = (new Date()).getTime();
var end_time = (new Date(value)).getTime();
if (now_time > end_time) {
return '结束时间不能小于当前时间!'
}
return ''
}
return ''
},
max: function (value) {
if (!/[\S]+/.test(value)) {
return '请输入最大领取数量';
}
if (_this.couponsData.count != -1 && parseFloat(value) > parseFloat(_this.couponsData.count)) {
return '最大领取数量不能超过发放数量!';
}
return ''
},
fl: function (value, str) {
str = str.substring(0, str.length - 1);
if (value < 1) {
return str + "不能小于1折";
}
if (value > 9.9) {
return str + "不能大于9.9折";
}
var arrMen = value.split(".");
var val = 0;
if (arrMen.length == 2) {
val = arrMen[1];
}
if (val.length > 2) {
return str + "最多可保留两位小数";
}
return ''
},
count: function (value) {
if (!/[\S]+/.test(value)) {
return '请输入发放数量';
}
if (value % 1 != 0) {
return '请输入整数';
}
if (value == 0) {
return '发放数量不能为0';
}
if (value != -1 && parseInt(value) < parseInt('{$coupon_type_info.count}')) {
return '发放数量不能小于原发放数量!';
}
return ''
}
};
if (!this.couponsData.coupon_name) {
this.$util.showToast({
title: "请输入优惠券名称"
});
return false
}
if (!this.couponsData.type) {
this.$util.showToast({
title: "请选择优惠券类型"
});
return false
}
if (this.couponsData.type === 'reward') {
if (!this.couponsData.money) {
this.$util.showToast({
title: "请输入优惠券面额"
});
return false
}
if (verify.number(this.couponsData.money) || verify.money(this.couponsData.money) || verify.coupon_money(this.couponsData.money)) {
this.$util.showToast({
title: verify.number(this.couponsData.money) || verify.money(this.couponsData.money) || verify.coupon_money(this.couponsData.money)
});
return false
}
} else {
if (!this.couponsData.discount) {
this.$util.showToast({
title: "请输入优惠券折扣"
});
return false
}
if (verify.fl(this.couponsData.discount, '优惠券折扣')) {
this.$util.showToast({
title: verify.fl(this.couponsData.discount, '优惠券折扣')
});
return false
}
}
if (this.couponsData.discount_limit) {
if (verify.number(this.couponsData.discount_limit) || verify.int(this.couponsData.discount_limit)) {
this.$util.showToast({
title: verify.number(this.couponsData.discount_limit) || verify.int(this.couponsData.discount_limit)
});
return false
}
}
if (!this.couponsData.at_least) {
this.$util.showToast({
title: "请输入满多少元可以使用"
});
return false
}
if (verify.number(this.couponsData.at_least) || verify.money(this.couponsData.at_least)) {
this.$util.showToast({
title: verify.number(this.couponsData.at_least) || verify.money(this.couponsData.at_least)
});
return false
}
if (this.couponsData.is_show === 1) {
if (verify.count(this.couponsData.count)) {
this.$util.showToast({
title: verify.count(this.couponsData.count)
});
return false
}
if (verify.max(this.couponsData.max_fetch)) {
this.$util.showToast({
title: verify.max(this.couponsData.max_fetch)
});
return false
}
}
if (verify.time(this.couponsData.end_time)) {
this.$util.showToast({
title: verify.time(this.couponsData.end_time)
});
return false
}
if (verify.days(this.couponsData.fixed_term)) {
this.$util.showToast({
title: verify.days(this.couponsData.fixed_term)
});
return false
}
if (this.couponsData.goods_type == 2||this.couponsData.goods_type == 3) {
if (!this.goods_ids.length) {
this.$util.showToast({
title: '请选择活动商品'
});
return false
}
}
if (this.couponsData.goods_type == 4||this.couponsData.goods_type == 5) {
if (!this.goods_ids.length) {
this.$util.showToast({
title: '请选择商品分类'
});
return false
}
}
return true
},
goodsType(){
this.couponsData.goods_ids = ''
this.couponsData.goods_ids_real = ''
this.goods_ids = []
this.couponsData.goods_names = ''
},
goodsCategoryConfirm(obj){
this.goods_ids = obj.id_arr;
this.couponsData.goods_names = obj.name_arr.join('、');
},
saveFn() {
if (this.checkData(this.couponsData)) {
if (this.flag) return false;
this.flag = true;
if (this.couponsData.goods_type != 1) this.couponsData.goods_ids = this.goods_ids.join();
let save = this.couponsData.coupon_type_id ? editCoupon : addCoupon;
save(this.couponsData).then(res => {
this.flag = false;
this.$util.showToast({
title: res.message
});
if (res.code >= 0) {
setTimeout(() => {
this.backFn();
}, 500);
}
});
}
},
backFn() {
this.$util.redirectTo('/pages/marketing/coupon_list');
},
}
};

View File

@@ -0,0 +1,139 @@
<template>
<base-page>
<view class="uni-flex uni-row height-all page-height member-list-wrap">
<view class="common-wrap">
<view class="left-wrap">
<view class="left-wrap-head">
<view class="head-text">会员列表</view>
</view>
<view class="left-wrap-content">
<view class="wrap-search-box">
<view class="wrap-search">
<input placeholder="请输入会员账号 昵称 手机号" v-model="searchMobile" @blur="searchMember()" placeholder-style="font-size:0.14rem" />
<text class="iconfont icon31sousuo" @click="searchMember()"></text>
</view>
</view>
<scroll-view :scroll-top="scrollTop" @scroll="scroll" @scrolltolower="getMemberListFn()" scroll-y="true" class="common-scrollbar content-list" v-show="!one_judge">
<view class="content-item" :class="{ active: memberId == item.member_id }" v-for="(item, index) in memberList" :key="index" @click="selectMember(item.member_id)">
<view class="item-img">
<image mode="aspectFill" v-if="item.headimg" :src="$util.img(item.headimg)" @error="headError(item)"/>
<image mode="aspectFill" v-else :src="$util.img(defaultImg.head)"/>
</view>
<view class="item-content">
<view class="item-title">
<view class="item-title-text">{{ item.nickname }}</view>
<view class="item-label">{{ item.member_level_name && item.member_level ? item.member_level_name : '非会员' }}</view>
</view>
<view class="item-desc">
<view>{{ item.mobile }}</view>
<view>
余额
<text>{{ parseFloat(parseFloat(item.balance) + parseFloat(item.balance_money)).toFixed(2) }}</text>
</view>
</view>
</view>
</view>
<view v-if="memberList.length == 0" class="empty">
<image src="@/static/member/member-empty.png" mode="widthFix" />
<view class="tips">暂无会员</view>
</view>
</scroll-view>
<view class="add-member">
<button type="default" class="primary-btn" @click="$refs.addMemberPop.open()">添加会员</button>
</view>
</view>
</view>
<view class="right-wrap">
<view class="right-wrap-head">
<view class="head-text">会员详情</view>
</view>
<ns-member-detail v-if="!one_judge && memberId" ref="memberDetail" :member-id="memberId"/>
<view class="empty" v-else-if="!one_judge && !memberId">
<image src="@/static/member/member-empty.png" mode="widthFix"/>
<view class="tips">暂无会员</view>
</view>
</view>
</view>
</view>
<!-- 添加会员 -->
<uni-popup ref="addMemberPop">
<view class="pop-box add-member-pop-box">
<view class="pop-header">
<view class="pop-header-text">添加会员</view>
<view class="pop-header-close" @click="$refs.addMemberPop.close()">
<text class="iconguanbi1 iconfont"></text>
</view>
</view>
<view class="common-scrollbar pop-content">
<view class="form-content">
<view class="form-item">
<view class="form-label">
<text class="required">*</text>
手机号
</view>
<view class="form-inline search-wrap">
<input type="number" class="form-input" v-model="addMemberData.mobile" placeholder="请输入会员手机号" />
</view>
</view>
<view class="form-item">
<view class="form-label">
<text class="required"></text>
会员昵称
</view>
<view class="form-inline search-wrap">
<input type="text" class="form-input" v-model="addMemberData.nickname" placeholder="请输入会员昵称" />
</view>
</view>
<view class="form-item">
<view class="form-label">
<text class="required"></text>
性别
</view>
<view class="form-inline search-wrap">
<uni-data-checkbox v-model="addMemberData.sex" :localdata="sex"></uni-data-checkbox>
</view>
</view>
<view class="form-item">
<view class="form-label">
<text class="required"></text>
生日
</view>
<view class="form-inline">
<uni-datetime-picker :end="endTime" v-model="addMemberData.birthday" type="date" :clearIcon="false" />
</view>
</view>
</view>
</view>
<view class="pop-bottom">
<button class="primary-btn" @click="addMemberFn">确定</button>
</view>
</view>
</uni-popup>
</base-page>
</template>
<script>
import dataTable from '@/components/uni-data-table/uni-data-table.vue';
import nsMemberDetail from '@/components/ns-member-detail/ns-member-detail.vue';
import list from './public/js/list.js';
export default {
components: { dataTable, nsMemberDetail },
mixins: [list]
};
</script>
<style>
.member-list-wrap .right-wrap >>> .member-head {
display: none;
}
</style>
<style lang="scss" scoped>
@import './public/css/member.scss';
</style>

View File

@@ -0,0 +1,343 @@
.page-height {
height: 100%;
}
.common-wrap {
display: flex;
-webkit-flex: 1;
flex: 1;
}
.left-wrap {
position: relative;
width: 5rem;
border-right: 0.01rem solid #e6e6e6;
.left-wrap-head {
height: 0.6rem;
box-sizing: border-box;
line-height: 0.6rem;
display: flex;
position: relative;
text-align: center;
justify-content: center;
border-bottom: 0.01rem solid #e6e6e6;
.head-icon {
position: absolute;
right: 0.15rem;
font-size: 0.26rem;
cursor: pointer;
}
.head-text {
font-size: 0.18rem;
font-weight: 500;
}
}
.left-wrap-content {
height: calc(100% - 0.6rem);
.wrap-search-box {
height: 0.35rem;
padding: 0.1rem 0.2rem;
border-bottom: 0.01rem solid #e6e6e6;
.wrap-search {
background: #f5f5f5;
display: flex;
position: relative;
padding: 0.05rem 0.15rem 0.05rem 0.4rem;
input {
width: 100%;
}
.iconfont {
position: absolute;
left: 0.15rem;
top: 0.08rem;
cursor: pointer;
}
}
}
.content-list {
height: calc(100% - 1.23rem);
.content-item {
padding: 0.15rem;
display: flex;
align-items: center;
cursor: pointer;
border-bottom: 0.01rem solid #e6e6e6;
&.active {
background: var(--primary-color-light-9);
}
.item-img {
width: 0.45rem;
height: 0.45rem;
border-radius: 50%;
image {
width: 100%;
height: 100%;
border-radius: 50%;
}
}
.item-content {
padding-left: 0.15rem;
width: calc(100% - 0.45rem);
box-sizing: border-box;
.item-title {
width: 100%;
font-size: 0.16rem;
align-items: center;
display: flex;
justify-content: space-between;
.item-label {
border: 0.01rem solid $primary-color;
color: $primary-color;
background-color: #fff;
border-radius: 0.02rem;
width: fit-content;
padding: 0.01rem 0.05rem;
margin-left: 0.15rem;
}
.item-title-text {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 50%;
font-size: 0.15rem;
}
}
.item-desc {
margin-top: 0.15rem;
font-size: 0.14rem;
display: flex;
justify-content: space-between;
text {
color: #fe2278;
font-size: 0.18rem;
}
}
}
}
}
.add-member {
position: absolute;
bottom: 0;
left: 0;
right: 0;
padding: 0.24rem 0.2rem;
background: #fff;
}
}
}
.right-wrap {
width: calc(100% - 5rem);
border-left: 0;
.right-wrap-head {
height: 0.6rem;
box-sizing: border-box;
line-height: 0.6rem;
display: flex;
position: relative;
text-align: center;
justify-content: center;
border-bottom: 0.01rem solid #e6e6e6;
.head-text {
font-size: 0.18rem;
font-weight: 500;
}
}
}
.empty {
text-align: center;
padding-top: 1.2rem;
image {
width: 2rem;
}
.tips {
color: #999;
margin-top: 0.15rem;
}
}
/deep/ .uni-scroll-view {
&::-webkit-scrollbar {
width: 0.06rem;
height: 0.06rem;
background-color: rgba($color: #000000, $alpha: 0);
}
&::-webkit-scrollbar-button {
display: none;
}
&::-webkit-scrollbar-thumb {
border-radius: 0.06rem;
box-shadow: inset 0 0 0.06rem rgba(45, 43, 43, 0.45);
background-color: #ddd;
display: none;
}
&:hover::-webkit-scrollbar-thumb {
display: block;
}
&::-webkit-scrollbar-track {
background-color: transparent;
}
}
// pop弹框
.pop-box {
background: #ffffff;
width: 8rem;
height: 7rem;
.pop-header {
padding: 0 0.15rem 0 0.2rem;
height: 0.5rem;
line-height: 0.5rem;
border-bottom: 0.01rem solid #f0f0f0;
font-size: 0.14rem;
color: #333;
overflow: hidden;
border-radius: 0.02rem 0.2rem 0 0;
box-sizing: border-box;
display: flex;
justify-content: space-between;
.pop-header-text {
}
.pop-header-close {
cursor: pointer;
text {
font-size: 0.18rem;
}
}
}
.pop-content {
height: calc(100% - 1.05rem);
overflow-y: scroll;
padding: 0.2rem;
box-sizing: border-box;
}
.pop-bottom {
padding: 0.1rem;
height: 0.65rem;
border-top: 0.01rem solid #eee;
button {
width: 1rem;
}
}
}
//表单
.form-content {
.form-item {
margin-bottom: 0.1rem;
display: flex;
.form-label {
width: 1.3rem;
text-align: right;
padding-right: 0.1rem;
box-sizing: border-box;
height: 0.32rem;
line-height: 0.32rem;
.required {
color: red;
margin-right: 0.03rem;
}
}
.form-inline {
width: 2.5rem;
line-height: 0.32rem;
box-sizing: border-box;
.form-input {
border-width: 0.01rem;
border-style: solid;
background-color: #fff;
color: rgba(0, 0, 0, 0.85);
border-radius: 0.02rem;
padding-left: 0.1rem;
height: 0.32rem;
line-height: 0.32rem;
font-size: 0.14rem;
border-color: #e6e6e6;
}
}
.search-wrap {
position: relative;
text {
position: absolute;
top: 50%;
right: 0.1rem;
transform: translateY(-50%);
border-left: 0.01rem solid #e6e6e6;
line-height: 0.3rem;
padding-left: 0.1rem;
cursor: pointer;
}
}
}
}
.add-member-pop-box {
width: 3.8rem;
height: 3.38rem;
.pop-content {
overflow-y: inherit;
}
.form-content {
display: flex;
flex-direction: column;
align-items: center;
.form-label {
width: 0.9rem;
}
}
.pop-bottom {
height: auto;
button {
width: 95%;
}
}
}

View File

@@ -0,0 +1,159 @@
import {getMemberList, getMemberInfoById, addMember} from '@/api/member.js'
let _self;
export default {
data() {
return {
memberList: [],
page: 1,
pageSize: 20,
searchMobile: '',
memberId: 0,
currentMemberInfo: null,
endTime: '',
sex: [{
text: '未知',
value: 0
}, {
text: '男',
value: 1
}, {
text: '女',
value: 2
}],
addMemberData: {
mobile: '',
nickname: '',
sex: 0,
birthday: ''
},
// 第一次请求列表、详情渲染判断
one_judge: true,
//无限滚动请求锁
memberListLock: true,
scrollTop: 0,
};
},
onLoad(data) {
_self = this;
this.getMemberListFn(data.member_id || 0);
let date = new Date();
var y = date.getFullYear();
var m = date.getMonth() + 1;
var d = date.getDate();
this.endTime = y + '-' + m + '-' + d;
},
methods: {
// 查询客户列表
getMemberListFn(member_id = 0) {
if (!this.memberListLock) return false;
let data = {
page: this.page,
page_size: this.pageSize,
search_text: this.searchMobile,
};
getMemberList(data).then(res => {
if (res.code >= 0) {
if (this.page == 1) this.memberList = [];
this.memberList = this.memberList.concat(res.data.list);
this.memberList.forEach((item) => {
if (item.mobile) {
if (this.userInfo && this.userInfo.is_admin == 0) {
// 非管理员,不能查看会员手机号
item.mobile = item.mobile.substring(0, 4 - 1) + '****' + item.mobile.substring(6 + 1);
}
} else {
item.mobile = '';
}
});
if (this.page == 1 && this.memberList.length > 0) {
// 订单页面跳转过来查看 会员详情
this.memberId = member_id || this.memberList[0]['member_id'];
this.one_judge = false;
}else if(this.page == 1){
this.one_judge = false;
this.memberId = 0
} else {
this.one_judge = false;
}
if (this.page == 1) {
this.scrollTop = 0
}
if (res.data.list.length < data.page_size) {
this.memberListLock = false
} else {
this.page++;
}
}
})
},
scroll(e) {
this.scrollTop = e.detail.scrollTop
},
searchMember() {
this.page = 1;
this.one_judge = true;
this.memberListLock = true;
this.getMemberListFn();
},
selectMember(member_id) {
this.memberId = member_id;
},
getMemberInfo() {
getMemberInfoById(this.memberId).then(res => {
if (res.code >= 0) {
this.currentMemberInfo = res.data;
this.currentMemberInfo.birthday = res.data.birthday > 0 ? this.$util.timeFormat(res.data.birthday, 'Y-m-d') : '';
this.one_judge = false;
}
})
},
verify() {
if (!this.addMemberData.mobile) {
this.$util.showToast({
title: '请输入会员手机号'
});
return false;
}
if (!this.$util.verifyMobile(this.addMemberData.mobile)) {
this.$util.showToast({
title: '请输入正确的手机号码'
});
return false;
}
return true;
},
// 添加客户
addMemberFn() {
if (this.verify()) {
if (this.flag) return;
this.flag = true;
addMember(this.addMemberData).then(res => {
if (res.code == 0 && res.data) {
this.addMemberData = {
mobile: '',
nickname: '',
sex: 0,
birthday: ''
};
this.page = 1;
this.one_judge = true;
this.memberListLock = true;
this.getMemberListFn();
this.$refs.addMemberPop.close();
} else {
this.$util.showToast({
title: '该手机号已注册为客户'
});
}
this.flag = false;
})
}
},
headError(item) {
item.headimg = this.defaultImg.head;
}
}
}

View File

@@ -0,0 +1,686 @@
<template>
<base-page>
<view class="goodslist">
<view class="goodslist-box">
<view class="goodslist-left">
<view class="goods-title">
订单管理
<view class="screen-btn" @click="showScreen = !showScreen">{{showScreen ? '关闭':'筛选'}}
</view>
</view>
<view class="screen-content" v-if="showScreen">
<scroll-view scroll-y="true" class="screen-box">
<view class="screen-item">
<view class="tit">创建时间</view>
<view class="values">
<view class="value" :class="(!conditions.start_time_val && !conditions.end_time_val ) && conditions.time_type == '' ? 'active' : ''" @click="changeCondition('time_type','')">全部</view>
<view class="value" :class="(!conditions.start_time_val && !conditions.end_time_val ) && conditions.time_type == '7' ? 'active' : ''" @click="changeCondition('time_type','7')">近7天</view>
<view class="value" :class="(!conditions.start_time_val && !conditions.end_time_val ) && conditions.time_type == '30' ? 'active' : ''" @click="changeCondition('time_type','30')">近30天</view>
<view class="time-range">
<uni-datetime-picker class="time-value" :inputDisabled="false" v-model="conditions.start_time_val" type="datetime" placeholder="开始时间" />
<view class="line">-</view>
<uni-datetime-picker class="time-value" :inputDisabled="false" v-model="conditions.end_time_val" type="datetime" placeholder="结束时间" />
</view>
</view>
</view>
<view v-if="currOrderList == 'online'">
<view class="screen-item">
<view class="tit">订单类型</view>
<view class="values">
<view class="value" :class="conditions.order_type == vItem.type ? 'active' : ''" v-for="(vItem,vIndex) in orderConditionList.order_type_list" :key="vIndex" @click="changeCondition('order_type',vItem.type)">{{vItem.name}}</view>
</view>
</view>
<view class="screen-item">
<view class="tit">订单状态</view>
<view class="values">
<view class="value" :class="conditions.order_status == '' ? 'active' : ''" @click="changeCondition('order_status','')">全部</view>
<view class="value" :class="conditions.order_status == vItem.type ? 'active' : ''" v-for="(vItem,vIndex) in orderConditionList.order_status_list" :key="vIndex" @click="changeCondition('order_status',vItem.type)">{{vItem.name}}</view>
</view>
</view>
<view class="screen-item">
<view class="tit">付款方式</view>
<view class="values">
<view class="value" :class="conditions.pay_type == '' ? 'active' : ''" @click="changeCondition('pay_type','')">全部</view>
<view class="value" :class="conditions.pay_type == vItem.type ? 'active' : ''" v-for="(vItem,vIndex) in orderConditionList.pay_type_list" :key="vIndex" @click="changeCondition('pay_type',vItem.type)">{{vItem.name}}</view>
</view>
</view>
<view class="screen-item">
<view class="tit">订单来源</view>
<view class="values">
<view class="value" :class="conditions.order_from == '' ? 'active' : ''" @click="changeCondition('order_from','')">全部</view>
<view class="value" :class="conditions.order_from == vItem.type ? 'active' : ''" v-for="(vItem,vIndex) in orderConditionList.order_from_list" :key="vIndex" @click="changeCondition('order_from',vItem.type)">{{vItem.name}}</view>
</view>
</view>
</view>
<view v-else>
<view class="screen-item">
<view class="tit">订单类型</view>
<view class="values">
<view class="value" :class="conditions.order_type == 'all' ? 'active' : ''" @click="changeCondition('order_type','all')">全部</view>
<view class="value" :class="conditions.order_type == vItem.type ? 'active' : ''" v-for="(vItem,vIndex) in orderConditionList.cashier_order_type_list" :key="vIndex" @click="changeCondition('order_type',vItem.type)">{{vItem.name}}</view>
</view>
</view>
<view class="screen-item">
<view class="tit">订单状态</view>
<view class="values">
<view class="value" :class="conditions.order_status == '' ? 'active' : ''" @click="changeCondition('order_status','')">全部</view>
<view class="value" :class="conditions.order_status == vItem.type ? 'active' : ''" v-for="(vItem,vIndex) in orderConditionList.cashier_order_status_list" :key="vIndex" @click="changeCondition('order_status',vItem.type)">{{vItem.name}}</view>
</view>
</view>
<view class="screen-item">
<view class="tit">付款方式</view>
<view class="values">
<view class="value" :class="conditions.pay_type == '' ? 'active' : ''" @click="changeCondition('pay_type','')">全部</view>
<view class="value" :class="conditions.pay_type == vItem.type ? 'active' : ''" v-for="(vItem,vIndex) in orderConditionList.cashier_pay_type_list" :key="vIndex" @click="changeCondition('pay_type',vItem.type)">{{vItem.name}}</view>
</view>
</view>
</view>
</scroll-view>
<view class="search-btn">
<view class="btn" @click="resetCondition()">重置</view>
<view class="btn" @click="searchOrder()">确定</view>
</view>
</view>
<view v-if="!showScreen" class="goods-search">
<view class="search">
<text class="iconfont icon31sousuo" @click="search('')"></text>
<input type="text" v-model="search_text" @keydown.enter="search('enter')" placeholder="输入订单号/商品名称/收货人姓名/手机号/留言/备注" />
</view>
</view>
<view v-if="!showScreen" class="order-type-list">
<view class="class-item" :class="{ active: currOrderList == 'cashier' }" @click="selectOrderList('cashier')">收银订单</view>
<view class="class-item" :class="{ active: currOrderList == 'online' }" @click="selectOrderList('online')">商城订单</view>
</view>
<block v-if="!showScreen && !one_judge && order_list.length > 0">
<scroll-view :scroll-top="scrollTop" @scroll="scroll" scroll-y="true" class="goods-list-scroll" :show-scrollbar="false" @scrolltolower="getOrderListFn">
<view class="item" @click="getOrderDetailFn(item.order_id, index)" v-for="(item, index) in order_list" :key="index" :class="index == selectGoodsKeys ? 'itemhover' : ''">
<view class="title">
<view>订单编号{{ item.order_no }}</view>
<view v-if="item.order_type == 5">{{ item.cashier_order_type_name }}</view>
<view v-else="item.order_type != 5">{{ item.order_type_name }}</view>
</view>
<view class="total-money-num">
<view class="flex-shrink-0">{{ item.order_status_name }}</view>
<view class="member-info">
<view>买家</view>
<view class="member-info-name" :title="item.nickname" v-if="item.member_id">{{ item.nickname }}</view>
<view class="member-info-name" v-else>散客</view>
</view>
<view class="box">
<view>实付金额</view>
<view>{{ item.pay_money }}</view>
</view>
<view class="refund-state flex-shrink-0" v-if="parseFloat(item.refund_money) > 0">退款</view>
</view>
</view>
</scroll-view>
</block>
<view class="notYet" v-else-if="!showScreen && !one_judge && order_list.length == 0">暂无数据</view>
</view>
<view class="goodslist-right" v-show="type == 'detail'">
<view class="goods-title">订单详情</view>
<view class="order-information tab-wrap" v-show="!one_judge">
<view class="tab-head">
<text v-for="(item, index) in tabObj.list" :key="index" :class="{ active: tabObj.index == item.value }" @click="tabObj.index = item.value" v-if="(item.value == 3 && order_detail.order_log && order_detail.order_log.length > 0) || item.value != 3">
{{ item.name }}
</text>
</view>
<view class="tab-content" v-if="JSON.stringify(order_detail) != '{}'">
<view class="other-information" v-if="tabObj.index == 1">
<view class="item-info">
<view class="info-tit">收货信息</view>
<view class="infos">
<view class="info">收货人{{order_detail.name}}</view>
<view class="info">收货电话{{order_detail.mobile}}</view>
<view class="info">收货地址{{order_detail.full_address}}{{ order_detail.address}}</view>
</view>
</view>
<view class="item-info">
<view class="info-tit">用户信息</view>
<view class="infos">
<view class="info" v-if="order_detail.member_id">
用户昵称{{ order_detail.nickname }}
<text class="look" @click="viewMember()">查看会员</text>
</view>
<view class="info" v-else>用户昵称散客</view>
</view>
</view>
<view class="item-info">
<view class="info-tit">订单信息</view>
<view class="infos">
<view class="info">订单类型{{ order_detail.order_type_name }}</view>
<view class="info">订单状态{{ order_detail.order_status_name }}</view>
<view class="info">{{ order_detail.order_type == 2 || order_detail.order_type == 3 ? ( order_detail.order_type == 2 ? '买家预计上门时间:' : '买家要求送达时间:' ) : ''}}{{ ( order_detail.order_type == 2 || order_detail.order_type == 3 ) ? order_detail.buyer_ask_delivery_time : '' }}</view>
<view class="info">订单编号{{order_detail.order_no}}</view>
<view class="info">外部交易号{{order_detail.out_trade_no}}</view>
<view class="info">订单来源{{order_detail.order_from_name}}</view>
<view class="info">创建时间{{$util.timeFormat(order_detail.create_time)}}</view>
<view class="info">支付时间{{$util.timeFormat(order_detail.pay_time)}}</view>
<view class="info">支付方式{{order_detail.pay_type_name}}</view>
<view class="info">商品总价{{order_detail.goods_money}}</view>
<view class="info">店铺优惠-{{order_detail.promotion_money}}</view>
<view class="info">订单减免-{{order_detail.reduction}}</view>
<view class="info">优惠券-{{order_detail.coupon_money}}</view>
<view class="info">积分抵扣-{{order_detail.point_money}}</view>
<view class="info" v-show="order_detail.online_money > 0">线上支付{{ order_detail.online_money | moneyFormat }}</view>
<view class="info" v-show="order_detail.cash > 0">现金支付{{ order_detail.cash | moneyFormat }}</view>
<view class="info" v-show="order_detail.cash_change > 0">找零-{{ order_detail.cash_change | moneyFormat }}</view>
<view class="info" v-show="parseFloat(order_detail.balance_money) > 0">余额抵扣{{ $util.moneyFormat(order_detail.balance_money) }}</view>
<view class="info" v-show="order_detail.own_wechatpay > 0">个人微信收款{{ order_detail.own_wechatpay | moneyFormat }}</view>
<view class="info" v-show="order_detail.own_alipay > 0">个人支付宝收款{{ order_detail.own_alipay | moneyFormat }}</view>
<view class="info" v-show="order_detail.own_pos > 0">个人POS收款{{ order_detail.own_pos | moneyFormat }}</view>
<view class="info" >实付金额{{ order_detail.pay_money }}</view>
<view class="info" v-if="parseFloat(order_detail.refund_money) > 0">退款金额{{ order_detail.refund_money }}</view>
</view>
</view>
<view class="item-info">
<view class="info-tit">订单备注</view>
<view class="infos remark">
<view class="info">买家留言{{order_detail.buyer_message}}</view>
<view class="info">商家备注{{ order_detail.remark }}</view>
</view>
</view>
</view>
<view class="goods-info" v-if="tabObj.index == 2">
<view class="table">
<view class="table-th table-all">
<view class="table-td" style="width:55%">商品</view>
<view class="table-td" style="width:15%">价格</view>
<view class="table-td" style="width:10%">数量</view>
<view class="table-td" style="width:15%;justify-content: flex-end;">小计</view>
</view>
<view class="table-tr table-all" v-for="(item, index) in order_detail.order_goods" :key="index">
<view class="table-td" style="width:55%">
<image v-if="item.sku_image == '@/static/goods/goods.png'" src="@/static/goods/goods.png" mode="widthFix"/>
<image v-else :src="$util.img(item.sku_image, { size: 'small' })" @error="item.sku_image = '@/static/goods/goods.png'" mode="widthFix"/>
<view class="content-text">
<view>
<text v-if="item.is_gift" class="gift-tag">赠品</text>
{{ item.goods_name }}
</view>
<view class="text-color-gray">
{{ item.spec_name }}
</view>
<view v-if="item.refund_status != 0">
<text class="refun-status">{{ item.refund_status_name }}</text>
</view>
</view>
</view>
<view class="table-td" style="width:15%">{{ item.price }}</view>
<view class="table-td" style="width:10%">{{ item.num }}</view>
<view class="table-td uni-column" style="width:15%;align-items: flex-end;">
<view>{{ item.goods_money }}</view>
<view class="refund-success" v-if="item.refund_status == 'refund_complete'">退款成功</view>
</view>
</view>
</view>
</view>
<view class="other-information journal" v-if="order_detail.order_log && order_detail.order_log.length > 0 && tabObj.index == 3">
<ns-order-log :list="order_detail.order_log"></ns-order-log>
</view>
</view>
<view class="notYet" v-if="JSON.stringify(order_detail) == '{}'">暂无数据</view>
<ns-loading ref="detailLoading"></ns-loading>
</view>
<view class="remarks-box" v-if="JSON.stringify(order_detail) != '{}'">
<button type="primary" class="default-btn comp-btn remarks" @click="printTicket">打印小票</button>
<button type="primary" class="default-btn comp-btn remarks" @click="type = 'refund'" v-if="order_detail.is_enable_refund">退款</button>
<button type="primary" class="default-btn comp-btn remarks" @click="open('remark')">备注</button>
<!-- <button type="primary" class="default-btn comp-btn remarks">调整价格</button> -->
<block v-if="order_detail.order_status_action.action">
<block v-for="(item, index) in order_detail.order_status_action.action" :key="index">
<button type="primary" class="primary-btn btn remarks" @click="open(item['action'])" v-if="item['action'] == 'orderLocalDelivery' || item['action'] == 'orderDelivery' || item['action'] == 'orderClose'||item['action'] == 'orderAdjustMoney'">{{ item.title }}</button>
</block>
</block>
<button v-if="order_detail.order_type == 2 && order_detail.order_status == 2" type="primary" class="primary-btn btn remarks" @click="open('storeOrderTakeDelivery')">提货</button>
<button v-for="(item, index) in order_detail.order_action" :key="index" type="primary" class="primary-btn btn remarks" @click="open(item['action'])">{{ item.title }}</button>
</view>
</view>
<!-- 订单退款 -->
<view class="goodslist-right refund-wrap" v-show="type == 'refund'">
<view class="goods-title">退款</view>
<view class="content common-scrollbar">
<view v-show="refundStep == 0">
<block v-for="(item, index) in order_detail.order_goods" :key="index">
<view class="goods-item" v-if="item.refund_status == 0">
<view class="iconfont" :class="refundGoods.indexOf(item.order_goods_id) == -1 ? 'iconyuan_checkbox' : 'iconyuan_checked'" @click="selectOrderGoods(item)"></view>
<view class="image">
<image v-if="item.sku_image == '@/static/goods/goods.png'" src="@/static/goods/goods.png" mode="widthFix"/>
<image v-else :src="$util.img(item.sku_image, { size: 'small' })" @error="item.sku_image = '@/static/goods/goods.png'" mode="widthFix"/>
</view>
<view class="info">
<view class="content-text">{{ item.goods_name }}</view>
</view>
<view>
<view class="price">{{ item.price }}</view>
<view class="num">x {{ item.num }}</view>
</view>
</view>
</block>
</view>
<block v-if="refundDetail">
<view class="bg-grey" v-show="refundStep == 1">
<block v-for="(refundItem, refundIndex) in refundDetail.refund_list" :key="refundIndex">
<view class="refund-goods-item">
<view class="row">
<view class="title">退款商品</view>
<view class="cont">
<view class="goods-item">
<view class="image">
<image v-if="refundItem.order_goods_info.sku_image == '@/static/goods/goods.png'" src="@/static/goods/goods.png" mode="widthFix"/>
<image v-else :src="$util.img(refundItem.order_goods_info.sku_image, { size: 'small' })" @error="refundItem.order_goods_info.sku_image = '@/static/goods/goods.png'" mode="widthFix"/>
</view>
<view class="info">
<view class="content-text">{{ refundItem.order_goods_info.sku_name }}</view>
</view>
</view>
</view>
</view>
<view class="row">
<view class="title">退款金额</view>
<view class="cont">
<view class="money-box">
<input type="number" v-model="refundApply.refund_array[refundItem.order_goods_info.order_goods_id].refund_money" />
</view>
<view class="refund-money">
可退金额
<text>{{ refundItem.order_goods_info.refund_apply_money | moneyFormat }}</text>
</view>
</view>
</view>
<view class="row" style="margin-top:8px;">
<view class="title">是否返还库存</view>
<view class="cont">
<radio-group @change="changeIsRefundStock(refundItem,$event)" class="form-radio-group">
<label class="radio form-radio-item">
<radio value="1" :checked="refundApply.refund_array[refundItem.order_goods_info.order_goods_id].is_refund_stock == 1" />
</label>
<label class="radio form-radio-item">
<radio value="0" :checked="refundApply.refund_array[refundItem.order_goods_info.order_goods_id].is_refund_stock == 0" />
</label>
</radio-group>
</view>
</view>
<view class="row" v-if="refundApply.refund_array[refundItem.order_goods_info.order_goods_id].is_refund_stock == 1" style="margin-top:8px;">
<view class="title">退还数量</view>
<view class="cont">
<view class="money-box">
<input type="number" :max="Number(refundItem.order_goods_info.num)" v-model="refundApply.refund_array[refundItem.order_goods_info.order_goods_id].refund_stock_num" />
</view>
</view>
</view>
<view class="row" style="margin-top:8px;">
<view class="title">完成状态</view>
<view class="cont">
<radio-group @change="refundApply.refund_array[refundItem.order_goods_info.order_goods_id].refund_status = $event.detail.value" class="form-radio-group">
<label class="radio form-radio-item">
<radio value="PARTIAL_REFUND" :checked="refundApply.refund_array[refundItem.order_goods_info.order_goods_id].refund_status == 'PARTIAL_REFUND'" />
部分退款状态
</label>
<label class="radio form-radio-item">
<radio value="REFUND_COMPLETE" :checked="refundApply.refund_array[refundItem.order_goods_info.order_goods_id].refund_status == 'REFUND_COMPLETE'" />
退款完成状态
</label>
</radio-group>
</view>
</view>
<view class="row">
<view class="title"></view>
<view class="cont tips">
<view>1如果是退部分金额退款后可以是部分退款状态或退款完成状态</view>
<view>2如果是退全部金额则退款后一定是退款完成状态</view>
<view>3退款完成才会执行相关业务如核销码失效卡包失效等操作</view>
</view>
</view>
</view>
</block>
<view class="refund-goods-item">
<view class="row">
<view class="title">退款说明</view>
<view class="cont">
<textarea placeholder="请输入退款说明" v-model="refundApply.refund_remark" />
</view>
</view>
</view>
</view>
<view v-show="refundStep == 2">
<view class="refund-type" :class="{ active: refundApply.refund_transfer_type == index }" @click="refundApply.refund_transfer_type = index" v-for="(item, index) in refundDetail.refund_transfer_type" :key="index">
<view class="title">{{ item.name }}</view>
<view class="desc">{{ item.desc }}</view>
</view>
</view>
</block>
</view>
<view class="remarks-box">
<button type="primary" class="default-btn comp-btn remarks" @click="type = 'detail'">取消</button>
<button type="primary" class="primary-btn comp-btn remarks" v-show="refundStep > 0" @click="refundStep -= 1">上一步</button>
<button type="primary" class="primary-btn comp-btn remarks" @click="refundNext">{{ refundStep == 2 ? '确认退款' : '下一步' }}</button>
</view>
</view>
</view>
<!-- 留言 -->
<unipopup ref="remark" type="center">
<view class="message">
<view class="title">
备注
<text class="iconfont iconguanbi1" @click="$refs.remark.close()"></text>
</view>
<view class="textarea-box">
<textarea v-model="order_detail.remark" class="textarea" maxlength="200" placeholder="输入请不多于200字"/>
</view>
<button @click="saveRemark" type="primary" class="primary-btn btn save">保存</button>
</view>
</unipopup>
<!-- 订单关闭 -->
<unipopup ref="orderClose" type="center">
<view class="order-close">
<view class="title">是否要关闭订单</view>
<view class="btn">
<button type="primary" class="default-btn btn save" @click="orderOperation('close')">取消</button>
<button type="primary" class="primary-btn btn" @click="orderOperation('save')">确定</button>
</view>
</view>
</unipopup>
<!-- 门店提货 -->
<unipopup ref="storeOrderTakeDelivery" type="center">
<view class="order-close">
<view class="title">确定要直接提货吗</view>
<view class="btn">
<button type="primary" class="default-btn btn save" @click="$refs.storeOrderTakeDelivery.close()">取消</button>
<button type="primary" class="primary-btn btn" @click="storeOrderTakeDelivery()">确定</button>
</view>
</view>
</unipopup>
<unipopup ref="orderLocalDelivery" type="center">
<view class="order-delivery local">
<view class="title">订单发货</view>
<view class="content">
<view class="content-item">
<view class="title">收货地址</view>
<view class="info">
<text>{{ order_detail.name }}</text>
<text>{{ order_detail.mobile }}</text>
<text>{{ order_detail.full_address }}{{ order_detail.address }}</text>
</view>
</view>
<view class="content-item">
<view class="title">配送员</view>
<view class="info">
<view class="select">
<select-lay :zindex="10" :value="localDelivery.deliverer" name="names" placeholder="请选择配送员" :options="deliverer" @selectitem="selectDeliverer"/>
</view>
</view>
</view>
<view class="content-item">
<view class="title">配送员手机号</view>
<view class="info">
<input type="text" class="input" v-model="localDelivery.deliverer_mobile" />
</view>
</view>
</view>
<view class="btn">
<button type="primary" class="default-btn btn save" @click="$refs.orderLocalDelivery.close()">取消</button>
<button type="primary" class="primary-btn btn" @click="orderLocalDeliveryFn()">确定</button>
</view>
</view>
</unipopup>
<unipopup ref="orderDelivery" type="center">
<view class="order-delivery express">
<view class="title">订单发货</view>
<view class="content">
<view class="content-item">
<view class="title">收货地址</view>
<view class="info">
<text>{{ order_detail.name }}</text>
<text>{{ order_detail.mobile }}</text>
<text>{{ order_detail.full_address }}{{ order_detail.address }}</text>
</view>
</view>
<view class="content-item">
<view class="title">发货方式</view>
<view class="info">
<radio-group @change="expresDelivery.delivery_type = $event.detail.value" class="form-radio-group">
<label class="radio form-radio-item">
<radio value="1" :checked="expresDelivery.delivery_type == 1" />物流发货
</label>
<label class="radio form-radio-item">
<radio value="0" :checked="expresDelivery.delivery_type == 0" />无需物流
</label>
</radio-group>
</view>
</view>
<view v-show="expresDelivery.delivery_type == 1">
<view class="content-item">
<view class="title">物流公司</view>
<view class="info">
<view class="select">
<select-lay :zindex="10" :value="expresDelivery.express_company_id" name="names" placeholder="请选择物流公司" :options="expressCompany" @selectitem="selectExpressCompany"/>
</view>
</view>
</view>
<view class="content-item">
<view class="title">快递单号</view>
<view class="info">
<input type="text" class="input" v-model="expresDelivery.delivery_no" />
</view>
</view>
</view>
<view class="content-item">
<view class="info goods-info common-scrollbar">
<view class="table">
<checkbox-group @change="expresDelivery.order_goods_ids = $event.detail.value">
<view class="table-th table-all">
<view class="table-td" style="width:5%"></view>
<view class="table-td" style="width:45%">商品</view>
<view class="table-td" style="width:10%">数量</view>
<view class="table-td" style="width:20%;justify-content: flex-end;">物流单号</view>
<view class="table-td" style="width:20%;justify-content: flex-end;">物流状态</view>
</view>
<view class="table-tr table-all" v-for="(item, index) in order_detail.order_goods" :key="index">
<view class="table-td" style="width:5%">
<checkbox :value="String(item.order_goods_id)" :disabled="item.delivery_status != 0" />
</view>
<view class="table-td" style="width:45%">
<image v-if="item.sku_image == '@/static/goods/goods.png'" src="@/static/goods/goods.png" mode="widthFix"/>
<image v-else :src="$util.img(item.sku_image, { size: 'small' })" @error="item.sku_image = '@/static/goods/goods.png'" mode="widthFix"/>
<view class="content-text">
<view>{{ item.goods_name }} {{ item.spec_name }}</view>
</view>
</view>
<view class="table-td" style="width:10%">{{ item.num }}</view>
<view class="table-td uni-column" style="width:20%;align-items: flex-end;">{{ item.delivery_no }}</view>
<view class="table-td uni-column" style="width:20%;align-items: flex-end;">{{ item.delivery_status_name }}</view>
</view>
</checkbox-group>
</view>
</view>
</view>
</view>
<view class="btn">
<button type="primary" class="default-btn btn save" @click="$refs.orderDelivery.close()">取消</button>
<button type="primary" class="primary-btn btn" @click="orderDelivery()">确定</button>
</view>
</view>
</unipopup>
<!-- 调整价格 -->
<unipopup ref="orderAdjustMoney" type="center">
<view class="order-adjust-money">
<view class="title">
<text>调整价格</text>
<text class="iconfont iconguanbi1" @click="clear"></text>
</view>
<view class="tip">注意 : 只有订单未付款时才支持改价,改价后请联系买家刷新订单核实订单金额后再支付</view>
<view class="table">
<view class="table-th table-all">
<view class="table-td" style="width:10%;padding: 0 0.07rem;">商品信息</view>
<view class="table-td" style="width:5%;padding: 0 0.07rem;">单价</view>
<view class="table-td" style="width:5%;padding: 0 0.07rem;">数量</view>
<view class="table-td" style="width:5%;padding: 0 0.07rem;">小计</view>
<view class="table-td" style="width:9%;padding: 0 0.07rem;">商品总额</view>
<view class="table-td" style="width:5%;padding: 0 0.07rem;">优惠</view>
<view class="table-td" style="width:8%;padding: 0 0.07rem;">优惠券</view>
<view class="table-td" style="width:8%;padding: 0 0.07rem;">积分抵现</view>
<view class="table-td" style="width:9%;padding: 0 0.07rem;">发票费用</view>
<view class="table-td" style="width:10%;padding: 0 0.07rem;">发票邮寄费用</view>
<view class="table-td" style="width:10%;padding: 0 0.07rem;">调整金额</view>
<view class="table-td" style="width:10%;padding: 0 0.07rem;">运费</view>
<view class="table-td" style="width:6%;padding: 0 0.07rem;">总计</view>
</view>
<view class="table-tr table-all">
<view class="table-td" style="width:25%">
<view class="table-tr table-all" v-for="(item, index) in order_detail.order_goods" :key="index">
<view class="table-td" style="width:40%;padding: 0 0.07rem;">{{ item.sku_name }} </view>
<view class="table-td" style="width:20%;padding: 0 0.07rem;">{{ item.price }} </view>
<view class="table-td" style="width:20%;padding: 0 0.07rem;">{{ item.num }} </view>
<view class="table-td" style="width:20%;padding: 0 0.07rem;">{{ item.goods_money }} </view>
</view>
</view>
<view class="table-td left" style="width:9%;padding: 0 0.07rem;">{{order_detail.goods_money}}</view>
<view class="table-td" style="width:5%;padding: 0 0.07rem;">{{ order_detail.promotion_money }}</view>
<view class="table-td" style="width:8%;padding: 0 0.07rem;">{{ order_detail.coupon_money }}</view>
<view class="table-td" style="width:8%;padding: 0 0.07rem;">{{ order_detail.point_money }}</view>
<view class="table-td" style="width:9%;padding: 0 0.07rem;">{{order_detail.invoice_money}}</view>
<view class="table-td" style="width:10%;padding: 0 0.07rem;">{{order_detail.invoice_delivery_money}}</view>
<view class="table-td" style="width:10%;padding: 0 0.07rem;"><input type="number" v-model="adjustParams.adjust_money" /></view>
<view class="table-td" style="width:10%;padding: 0 0.07rem;"><input type="number" min="0" v-model="adjustParams.delivery_money" /></view>
<view class="table-td" style="width:6%;padding: 0 0.07rem;">{{parseFloat(parseFloat(order_detail.goods_money)-parseFloat(order_detail.promotion_money||0)-parseFloat(order_detail.coupon_money||0) -parseFloat(order_detail.point_money||0)+ parseFloat(adjustParams.adjust_money||0) + parseFloat(adjustParams.delivery_money||0)).toFixed(2)}}</view>
</view>
</view>
<view class="tip m-0"><text class="Highlight">{{'实际商品金额 '}}</text>= 商品总额 - 优惠金额 - 优惠券金额 - 积分抵现 + 调价</view>
<view class="tip m-0"><text class="Highlight">{{'发票费用 '}}</text>= 实际商品金额 * 发票比率</view>
<view class="tip m-0">订单总额 =<text class="Highlight">{{' 实际商品金额 '}}</text>+ <text class="Highlight">{{'发票费用 '}}</text>+ 运费 + 发票邮寄费用</view>
<view class="footer">
<button type="primary" class="primary-btn btn remarks" @click="adjustSave">确定</button>
<button class="default-btn comp-btn remarks clear" @click="clear">取消</button>
</view>
</view>
</unipopup>
</view>
</base-page>
</template>
<script>
import nsOrderLog from '@/components/ns-order-log/ns-order-log.vue';
import nsLoading from '@/components/ns-loading/ns-loading.vue';
import unipopup from '@/components/uni-popup/uni-popup.vue';
import orderList from './public/js/order_list.js';
export default {
components: {
nsOrderLog,
nsLoading,
unipopup,
},
mixins: [orderList]
};
/**
* 打印回调
* @param {Object} text
*/
window.POS_PRINT_CALLBACK = function(text) {
uni.showToast({
title: text,
icon: 'none'
})
}
</script>
<style scoped lang="scss">
@import './public/css/orderlist.scss';
.tab-wrap {
padding: 0 !important;
background-color: #fff !important;
.tab-head {
display: flex;
background-color: #f8f8f8;
text {
width: 1.15rem;
height: 0.55rem;
line-height: 0.55rem;
text-align: center;
font-size: $uni-font-size-lg;
&.active {
background-color: #fff;
}
}
}
}
.item-box {
padding: 0.1rem;
}
.form-radio-item {
margin-right: .1rem;
display: inline-flex;
align-items: center;
}
.message {
width: 5.2rem;
min-height: 3.2rem;
border-radius: 0.06rem;
background: #ffffff;
padding-bottom: 0.15rem;
.title {
width: 100%;
height: 0.5rem;
border-bottom: 0.01rem solid #e6e6e6;
text-align: center;
line-height: 0.5rem;
font-size: 0.16rem;
font-weight: bold;
position: relative;
.iconguanbi1 {
position: absolute;
top: 50%;
transform: translateY(-50%);
right: 0.15rem;
font-size: 0.18rem;
}
}
.textarea-box {
margin: 0.15rem;
height: 2.2rem;
border: 0.01rem solid #e6e6e6;
border-radius: 0.06rem;
padding: 0.15rem;
box-sizing: border-box;
.textarea {
width: 100%;
height: 100%;
}
}
.save {
width: auto !important;
float: right;
margin-right: 0.15rem;
}
}
.message:after {
overflow: hidden;
display: block;
content: '';
height: 0;
clear: both;
}
</style>

View File

@@ -0,0 +1,413 @@
<template>
<base-page>
<view class="goodslist">
<view class="goodslist-box">
<view class="goodslist-left">
<view class="goods-title">
退款维权
<text class="iconfont icongengduo1"></text>
</view>
<view class="goods-search">
<view class="search">
<text class="iconfont icon31sousuo"></text>
<input type="text" v-model="search_text" @input="search" placeholder="搜索订单号/商品名称" />
</view>
</view>
<block v-if="!one_judge && order_list.length > 0">
<scroll-view :scroll-top="scrollTop" @scroll="scroll" scroll-y="true" class="goods-list-scroll" :show-scrollbar="false" @scrolltolower="getOrderList">
<view class="item" @click="getOrderDetail(item.order_goods_id, index)" v-for="(item, index) in order_list" :key="index" :class="index == selectGoodsKeys ? 'itemhover' : ''">
<view class="title">
<view>退款编号{{ item.order_no }}</view>
<view>{{ item.order_type_name }}</view>
</view>
<view class="total-money-num">
<view class="box">
<view>订单金额</view>
<view>{{ item.real_goods_money }}</view>
</view>
<view class="box">
<view>退款金额</view>
<view>{{ item.refund_apply_money }}</view>
</view>
</view>
<view class="total-money-num">
<view class="member-info">
<view>退款状态</view>
<view>{{ item.refund_status_name }}({{ item.refund_type == 1 ? '仅退款' : '退款退货' }})</view>
</view>
</view>
</view>
</scroll-view>
</block>
<view class="notYet" v-else-if="!one_judge && order_list.length == 0">暂无数据</view>
</view>
<view class="goodslist-right">
<view class="goods-title">订单详情</view>
<view class="order-information tab-wrap" v-if="Object.keys(order_detail).length">
<view class="tab-head">
<text v-for="(item, index) in tabObj.list" :key="index" :class="{ active: tabObj.index == item.value }" @click="tabObj.index = item.value">{{ item.name }}</text>
</view>
<view class="tab-content">
<view class="other-information" v-if="tabObj.index == 1">
<view class="item-box">
<view class="item">
<view>买家</view>
<view v-if="order_detail.nickname">{{ order_detail.nickname }}</view>
<view v-else>散客</view>
</view>
<view class="item">
<view>退款编号</view>
<view>{{ order_detail.refund_no }}</view>
</view>
<view class="item">
<view>申请时间</view>
<view>{{ $util.timeFormat(order_detail.refund_action_time) }}</view>
</view>
<view class="item">
<view>维权类型</view>
<view>{{ order_detail.refund_mode > 1 ? '售后' : '退款' }}</view>
</view>
<view class="item">
<view>退款方式</view>
<view>
{{ order_detail.shop_active_refund == 1 ? '主动退款' : order_detail.refund_type == 1 ? '仅退款' : '退货退款' }}
({{ (order_detail.refund_type == 1 && '原路退款') || (order_detail.refund_type == 2 && '线下退款') || '退款到余额' }})
</view>
</view>
<view class="item">
<view>退款金额</view>
<view>{{ order_detail.refund_status == 3 ? order_detail.refund_real_money : order_detail.refund_apply_money }}</view>
</view>
<view class="item">
<view>退款原因</view>
<view>{{ order_detail.refund_reason || '--' }}</view>
</view>
<view class="item">
<view>退款说明</view>
<view>{{ order_detail.refund_remark || '--' }}</view>
</view>
<view class="item">
<view>商家退款说明</view>
<view>{{ order_detail.shop_refund_remark || '--' }}</view>
</view>
<view class="item">
<view>退款状态</view>
<view>{{ order_detail.refund_status_name }}</view>
</view>
<view class="item" v-if="order_detail.refund_refuse_reason">
<view>拒绝理由</view>
<view>{{ order_detail.refund_refuse_reason }}</view>
</view>
</view>
</view>
<view class="goods-info" v-if="tabObj.index == 2">
<view class="table">
<view class="table-th table-all">
<view class="table-td" style="width:45%">商品</view>
<view class="table-td" style="width:15%">价格</view>
<view class="table-td" style="width:10%">数量</view>
<view class="table-td" style="width:15%;">小计</view>
<view class="table-td" style="width:15%;justify-content: flex-end;">状态</view>
</view>
<view class="table-tr table-all">
<view class="table-td" style="width:45%">{{ order_detail.sku_name }}</view>
<view class="table-td" style="width:15%">{{ order_detail.price }}</view>
<view class="table-td" style="width:10%">{{ order_detail.num }}</view>
<view class="table-td" style="width:15%">{{ order_detail.goods_money }}</view>
<view class="table-td uni-column" style="width:15%;align-items: flex-end;">{{ order_detail.refund_status_name }}</view>
</view>
</view>
</view>
<view class="other-information journal" v-if="tabObj.index == 3">
<ns-order-log :list="order_detail.refund_log_list"></ns-order-log>
</view>
<view class="remarks-box" v-if="order_detail.refund_action.length">
<block v-for="(item, index) in order_detail.refund_action" :key="index">
<button type="primary" class="primary-btn btn remarks" @click="open(item['event'])">{{ item.title }}</button>
</block>
</view>
</view>
</view>
<block v-else-if="!one_judge && !Object.keys(order_detail).length" >
<image class="cart-empty" src="@/static/cashier/cart_empty.png" mode="widthFix" />
</block>
</view>
</view>
<!-- 同意退款 -->
<unipopup ref="orderRefundAgree" type="center">
<view class="order-refund-agree">
<view class="title">售后维权处理</view>
<view class="content">
<view class="content-item">
<view class="title">注意</view>
<view class="info">
<text v-if="order_detail.pay_type == 'OFFLINE_PAY'">该笔订单通过线下支付商家同意后退款将通过线下原路退回</text>
<text v-else>该笔订单通过在线付款商家同意后退款将自动原路退回买家付款账户</text>
</view>
</view>
<view class="content-item">
<view class="title">退款方式</view>
<view class="info">
<text>{{ order_detail.refund_type == 1 ? '仅退款' : '退货退款' }}</text>
</view>
</view>
<view class="content-item">
<view class="title">退款金额</view>
<view class="info">
<text>{{ order_detail.refund_apply_money }}</text>
</view>
</view>
</view>
<view class="btn">
<button type="primary" class="default-btn btn save" @click="$refs.orderRefundAgree.close()">取消</button>
<button type="primary" class="primary-btn btn" @click="orderRefundAgree()">确认退款</button>
</view>
</view>
</unipopup>
<!-- 拒绝退款 -->
<unipopup ref="orderRefundRefuse" type="center">
<view class="order-refund-agree">
<view class="title">售后维权处理</view>
<view class="content">
<view class="tips">注意建议你与买家协商后再确定是否拒绝退款如你拒绝退款后买家可修改退款申请协议重新发起退款</view>
<view class="content-item">
<view class="title">退款方式</view>
<view class="info">
<text>{{ order_detail.refund_type == 1 ? '仅退款' : '退货退款' }}</text>
</view>
</view>
<view class="content-item">
<view class="title">退款金额</view>
<view class="info">
<text>{{ order_detail.refund_apply_money }}</text>
</view>
</view>
<view class="content-item textarea-wrap">
<view class="title">拒绝理由</view>
<view class="info textarea-box">
<textarea v-model="refundRefuseReason" class="textarea" maxlength="200" placeholder="请输入拒绝理由最多不超过200字"></textarea>
</view>
</view>
</view>
<view class="btn">
<button type="primary" class="default-btn btn save" @click="$refs.orderRefundRefuse.close()">取消</button>
<button type="primary" class="primary-btn btn" @click="orderRefundRefuse()">确认退款</button>
</view>
</view>
</unipopup>
<!-- 关闭维权 -->
<unipopup ref="orderRefundClose" type="center">
<view class="order-close">
<view class="title">确定要关闭本次维权吗</view>
<view class="btn">
<button type="primary" class="default-btn btn save" @click="$refs.orderRefundClose.close()">取消</button>
<button type="primary" class="primary-btn btn" @click="orderRefundClose()">确定</button>
</view>
</view>
</unipopup>
<!-- 转账 -->
<unipopup ref="orderRefundTransfer" type="center">
<view class="order-refund-agree">
<view class="title">售后维权处理</view>
<view class="content">
<view class="content-item">
<view class="title">申请退款金额</view>
<view class="info">
<text>{{ order_detail.refund_apply_money }}</text>
</view>
</view>
<view class="content-item">
<view class="title">实际退款金额</view>
<view class="info">
<view class="money-box">
<input type="number" v-model="refundTransfer.refund_real_money" />
</view>
</view>
</view>
<view class="content-item" v-if="order_detail.use_point>0">
<view class="title">退还积分</view>
<view class="info">
<text>{{ order_detail.use_point }}</text>
</view>
</view>
<view class="content-item" v-if="order_detail.coupon_info && order_detail.coupon_info.length>0">
<view class="title">退还优惠券</view>
<view class="info">
<text>{{ order_detail.coupon_info.coupon_name }}</text>
<text v-if="order_detail.coupon_info.money>0">{{order_detail.coupon_info.money}}</text>
<text v-else>{{order_detail.coupon_info.discount}}</text>
</view>
</view>
<view class="content-item">
<view class="title">退款方式</view>
<view class="info">
<radio-group @change="refundTransfer.refund_money_type = $event.detail.value" class="form-radio-group">
<label class="radio form-radio-item">
<radio value="1" :checked="refundTransfer.refund_money_type == 1" />
原路退款
</label>
<label class="radio form-radio-item">
<radio value="2" :checked="refundTransfer.refund_money_type == 2" />
线下退款
</label>
<label class="radio form-radio-item">
<radio value="3" :checked="refundTransfer.refund_money_type == 3" />
退款到余额
</label>
</radio-group>
</view>
</view>
<view class="content-item textarea-wrap">
<view class="title">退款说明</view>
<view class="info textarea-box">
<textarea v-model="refundTransfer.shop_refund_remark" class="textarea" maxlength="200" placeholder="请输入拒绝理由最多不超过200字"></textarea>
</view>
</view>
</view>
<view class="btn">
<button type="primary" class="default-btn btn save" @click="$refs.orderRefundTransfer.close()">取消</button>
<button type="primary" class="primary-btn btn" @click="orderRefundTransfer()">确认退款</button>
</view>
</view>
</unipopup>
<!-- 买家退货接收维权收货 -->
<unipopup ref="orderRefundTakeDelivery" type="center">
<view class="order-refund-agree">
<view class="title">售后维权处理</view>
<view class="content">
<view class="tips">注意需你同意退款申请买家才能退货给你买家退货后你需再次确认收货后退款将自动原路退回至买家付款账户</view>
<view class="content-item">
<view class="title">退款方式</view>
<view class="info">
<text>{{ order_detail.refund_type == 1 ? '仅退款' : '退货退款' }}</text>
</view>
</view>
<view class="content-item">
<view class="title">退款金额</view>
<view class="info">
<text>{{ order_detail.refund_apply_money }}</text>
</view>
</view>
<view class="content-item">
<view class="title">退货地址</view>
<view class="info">
<text>{{ order_detail.refund_address }}</text>
</view>
</view>
<view class="content-item textarea-wrap">
<view class="title">是否入库</view>
<view class="info">
<radio-group @change="isRefundStock = $event.detail.value" class="form-radio-group">
<label class="radio form-radio-item">
<radio value="0" :checked="isRefundStock == 0" />
</label>
<label class="radio form-radio-item">
<radio value="1" :checked="isRefundStock == 1" />
</label>
</radio-group>
</view>
</view>
</view>
<view class="btn">
<button type="primary" class="default-btn btn save" @click="$refs.orderRefundTakeDelivery.close()">取消</button>
<button type="primary" class="primary-btn btn" @click="orderRefundTakeDelivery()">确认收到退货</button>
</view>
</view>
</unipopup>
</view>
</base-page>
</template>
<script>
import orderRefund from './public/js/order_refund'
import nsOrderLog from '@/components/ns-order-log/ns-order-log.vue';
import unipopup from '@/components/uni-popup/uni-popup.vue';
export default {
components: {
nsOrderLog,
unipopup
},
mixins: [orderRefund]
};
</script>
<style scoped lang="scss">
@import './public/css/orderlist.scss';
.total-money-num .box {
margin-top: 0;
}
.goodslist {
.goodslist-right {
.other-information {
.title {
margin-bottom: 0.1rem !important;
}
.item-box {
margin-bottom: 0.15rem;
.item {
&:nth-child(1),
&:nth-child(2) {
margin-top: 0 !important;
}
view:nth-child(1) {
width: 1rem !important;
}
}
}
}
}
}
.tab-wrap {
padding: 0 !important;
background-color: #fff !important;
.tab-head {
display: flex;
background-color: #f8f8f8;
text {
width: 1.15rem;
height: 0.55rem;
line-height: 0.55rem;
text-align: center;
font-size: $uni-font-size-lg;
&.active {
background-color: #fff;
}
}
}
}
.item-box {
padding: 0.1rem;
}
/deep/ .goods-list-scroll {
width: 100%;
height: calc(100% - 1.44rem) !important;
}
</style>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,888 @@
import {
getOrderList,
getOrderDetail,
orderRemark,
orderClose,
orderStoreDelivery,
orderLocalDelivery,
orderPrintTicket,
getExpressCompanyList,
orderExpressDelivery,
getOrderDeliverList,
orderAdjustPrice,
getorderCondition
} from '@/api/order.js'
import {getRefundApplyData, orderRefund} from '@/api/order_refund.js'
export default {
data() {
return {
selectGoodsKeys: 0,
otherInfoValue: {
order_no: {
title: '订单编号:',
value: ''
},
out_trade_no: {
title: '订单交易号:',
value: ''
},
create_time: {
title: '消费时间:',
value: ''
},
pay_status: {
title: '支付状态:',
value: ''
},
order_status: {
title: '订单状态:',
value: ''
},
pay_type: {
title: '付款方式:',
value: ''
},
operator_name: {
title: '收银员:',
value: ''
},
pay_time: {
title: '付款时间:',
value: ''
}
},
// 订购日志所需列表数据
list: [],
//获取订单的页数
page: 1,
//每次获取订单的条数
page_size: 8,
// 订单搜索是用到的数据
search_text: '',
conditions: {
order_status: '',
time_type: '',
start_time: '',
end_time: '',
start_time_val: '',
end_time_val: '',
order_type: 'all',
order_from: '',
pay_type: '',
},
//订单列表类型
currOrderList: 'cashier',
//订单类型
trade_type: '',
//初始时加载详情数据判断
one_judge: true,
//无限滚动请求锁
listLock: false,
scrollTop: 0,
// 订单列表数据
order_list: [],
//订单详情数据
order_detail: {},
type: 'detail',
refundStep: 0,
refundGoods: [],
refundDetail: null,
refundRepeat: false,
refundApply: {
refund_remark: '',
refund_transfer_type: ''
},
localDelivery: {
deliverer_mobile: '',
deliverer: ''
},
expresDelivery: {
delivery_type: 1,
express_company_id: 0,
delivery_no: '',
order_goods_ids: []
},
expressCompany: [],
deliverer: [],
tabObj: {
list: [{
value: 1,
name: '基础信息'
}, {
value: 2,
name: '商品信息'
}, {
value: 3,
name: '订单日志'
}],
index: 1
},
isLogisticsRepeat: false,
//调价
adjustParams:{
order_id:null,
adjust_money:0,
delivery_money:0
},
currGlobalStoreId:'',
showScreen: false,
orderConditionList: [],
};
},
onLoad(option) {
this.search_text = option.order_no || '';
this.currOrderList = option.order_from == 'online' ? 'online' : 'cashier';
if(uni.getStorageSync('globalStoreId')) this.currGlobalStoreId = uni.getStorageSync('globalStoreId');
// 获取订单列表数据
this.getOrderListFn();
this.getExpressCompany();
this.getDeliver();
this.getOrderCondition()
},
watch: {
type: function (nval, oval) {
if (oval == 'refund') {
this.refundStep = 0;
this.refundGoods = [];
this.refundDetail = null;
this.refundRepeat = false;
this.refundApply = {
refund_remark: '',
refund_transfer_type: ''
};
}
}
},
methods: {
changeIsRefundStock(refundItem,e) {
this.refundApply.refund_array[refundItem.order_goods_info.order_goods_id].is_refund_stock = e.detail.value;
this.$forceUpdate()
},
searchOrder() {
if(this.conditions.start_time_val || this.conditions.end_time_val){
if(new Date(this.conditions.end_time_val).getTime() <= new Date(this.conditions.start_time_val).getTime()){
this.$util.showToast({title:'结束时间不能早于开始时间'})
return;
}
}
this.page = 1;
this.order_list = [];
this.one_judge = true;
this.listLock = false;
this.showScreen = false;
this.getOrderListFn();
},
initCondition() {
this.conditions.order_status = '';
this.conditions.time_type = '';
this.conditions.start_time = '';
this.conditions.end_time = '';
this.conditions.start_time_val = '';
this.conditions.end_time_val = '';
this.conditions.order_type = 'all';
this.conditions.order_from = '';
this.conditions.pay_type = '';
},
resetCondition() {
this.page = 1;
this.order_list = [];
this.one_judge = true;
this.listLock = false;
this.initCondition();
this.showScreen = false;
this.getOrderListFn();
},
changeCondition(mode,type) {
this.conditions[mode] = type;
if(mode == 'order_type'){
if(this.currOrderList == 'online'){
this.orderConditionList.order_type_list.forEach((item,index) => {
if(item.type == type) this.orderConditionList.order_status_list = item.status;
})
this.conditions.order_status = '';
}
}
if(mode == 'time_type'){
this.conditions.start_time_val = '';
this.conditions.end_time_val = '';
switch (type){
case '':
this.conditions.start_time = '';
this.conditions.end_time = '';
break;
case '7':
this.conditions.start_time = this.getDay(type);
this.conditions.end_time = this.getNowDate();
break;
case '30':
this.conditions.start_time = this.getDay(type);
this.conditions.end_time = this.getNowDate();
break;
default:
break;
}
}
},
getDay(p_count) {
var dd = new Date();
dd.setDate(dd.getDate() - p_count); //获取p_count天后的日期
var y = dd.getFullYear();
var m = dd.getMonth() + 1; //获取当前月份的日期
if (m < 10) {
m = '0' + m;
}
var d = dd.getDate();
if (d < 10) {
d = '0' + d;
}
return y + '-' + m + '-' + d +' 00:00:00';
},
getNowDate() {
var date = new Date();
var y = date.getFullYear();
var m = date.getMonth() + 1; //获取当前月份的日期
if (m < 10) {
m = '0' + m;
}
var d = date.getDate();
if (d < 10) {
d = '0' + d;
}
return y + '-' + m + '-' + d +' 23:59:59';
},
getOrderCondition() {
getorderCondition()
.then((res)=>{
if(res.code>=0){
var data = res.data;
for (var index in data) {
var arr = [];
if (index != 'order_label_list' && index != 'order_status_list' && index != 'pay_type_list' && index != 'cashier_pay_type_list' && index != 'cashier_order_type_list') {
for (var index_c in data[index]) {
var obj = {
type: index_c
};
obj = Object.assign(obj, data[index][index_c]);
arr.push(obj);
}
} else {
for (var index_c in data[index]) {
var obj = {
type: index_c,
name: data[index][index_c]
};
arr.push(obj);
}
}
data[index] = arr;
}
this.orderConditionList = data;
this.orderConditionList.order_type_list.forEach((item,index)=>{
var arr = [];
for (var index_c in item.status) {
var obj = {
type: index_c,
name: item.status[index_c]
};
arr.push(obj);
}
item.status = arr;
if(item.type == 'all'){
this.orderConditionList.order_status_list = item.status;
}
})
}
})
},
switchStoreAfter() {
if(this.currGlobalStoreId == uni.getStorageSync('globalStoreId')) return;
this.currGlobalStoreId = uni.getStorageSync('globalStoreId');
this.page = 1;
this.order_list = [];
this.one_judge = true;
this.listLock = false;
this.getOrderListFn();
this.getDeliver()
},
// 搜索
search(type) {
this.page = 1;
this.order_list = [];
this.one_judge = true;
this.listLock = false;
if (type == 'enter') {
document.onkeydown = e => {
if (e.keyCode === 13) {
//回车后执行搜索方法
this.getOrderListFn();
}
}
} else {
this.getOrderListFn();
}
},
selectOrderList(order_type) {
this.currOrderList = order_type;
this.page = 1;
this.order_list = [];
this.one_judge = true;
this.listLock = false;
this.initCondition();
this.selectGoodsKeys = 0;
this.getOrderListFn();
},
/**
* 获取订单列表
*/
getOrderListFn() {
if (this.listLock) return false;
this.listLock = true;
getOrderList({
page: this.page,
page_size: this.page_size,
search_text: this.search_text,
order_scene: this.currOrderList,
order_status: this.conditions.order_status,
start_time: this.conditions.start_time_val ? this.conditions.start_time_val : this.conditions.start_time,
end_time: this.conditions.end_time_val ? this.conditions.end_time_val : this.conditions.end_time,
order_type: this.conditions.order_type,
order_from: this.conditions.order_from,
pay_type: this.conditions.pay_type,
}).then((res) => {
if (res.data.list.length == 0 && this.one_judge) {
this.order_detail = {};
this.one_judge = false;
if (this.$refs.detailLoading) this.$refs.detailLoading.hide()
}
if (res.code >= 0 && res.data.list.length != 0) {
if (this.order_list.length == 0) {
this.order_list = res.data.list;
} else {
this.order_list = this.order_list.concat(res.data.list);
}
//初始时加载一遍详情数据
if (this.one_judge) {
this.getOrderDetailFn(this.order_list[0].order_id);
}
}
if (this.page == 1) {
this.scrollTop = 0
}
if (res.data.list.length >= this.page_size) {
this.page++
this.listLock = false
}
});
},
scroll(e) {
this.scrollTop = e.detail.scrollTop
},
/**
* 获取订单详情数据
*/
getOrderDetailFn(order_id, keys = 0, callback) {
// 清空数据
this.localDelivery = {
deliverer_mobile: '',
deliverer: ''
};
this.selectGoodsKeys = keys;
this.type = 'detail';
this.$refs.detailLoading.show();
getOrderDetail({
order_id
}).then((res) => {
if (res.code >= 0) {
this.order_detail = res.data;
this.order_detail.order_status_action = JSON.parse(res.data.order_status_action)
this.otherInfoValue.order_no.value = res.data.order_no;
this.otherInfoValue.out_trade_no.value = res.data.out_trade_no;
this.otherInfoValue.create_time.value = this.$util.timeFormat(res.data.create_time);
this.otherInfoValue.operator_name.value = res.data.operator_name;
this.otherInfoValue.pay_type.value = res.data.pay_type_name;
this.otherInfoValue.order_status.value = res.data.order_status_name;
if (res.data.pay_status == 1) {
this.otherInfoValue.pay_status.value = '已支付';
this.otherInfoValue.pay_time.value = this.$util.timeFormat(res.data.pay_time);
} else {
this.otherInfoValue.pay_status.value = '待支付';
this.otherInfoValue.pay_time.value = '';
}
if (typeof callback == 'function') {
callback();
}
Object.keys(this.adjustParams).forEach(key=>{
this.adjustParams[key] = parseFloat(this.order_detail[key])
})
this.$forceUpdate();
this.one_judge = false;
if (this.$refs.detailLoading) this.$refs.detailLoading.hide()
}
});
},
/**
* 打开弹出框
* @param action
*/
open(action) {
this.$refs[action].open();
},
/**
* 关闭弹出框
* @param name
*/
close(name) {
this.$refs[name].close();
},
/**
* 调价提交
*/
adjustSave(){
if(parseFloat(this.adjustParams.delivery_money+0)<0){
this.$util.showToast({
title: '运费不可小于0'
});
return false
}else if(!parseFloat(this.adjustParams.delivery_money+0)){
this.adjustParams.delivery_money = 0
}
if(parseFloat(parseFloat(this.order_detail.goods_money)-parseFloat(this.order_detail.promotion_money||0)-parseFloat(this.order_detail.coupon_money||0) -parseFloat(this.order_detail.point_money||0)+ parseFloat(this.adjustParams.adjust_money||0) + parseFloat(this.adjustParams.delivery_money||0)).toFixed(2)<0){
this.$util.showToast({
title: '真实商品价格不可小于0'
});
return false
}
orderAdjustPrice(this.adjustParams).then((res)=>{
this.$util.showToast({
title: res.message
});
if (res.code >= 0) {
this.getOrderDetailFn(this.order_list[this.selectGoodsKeys].order_id);
this.$refs.orderAdjustMoney.close()
}
})
},
/**
* 关闭调价弹框
*/
clear(){
Object.keys(this.adjustParams).forEach(key=>{
this.adjustParams[key] = this.adjustParams[key] = parseFloat(this.order_detail[key])
})
this.$refs.orderAdjustMoney.close()
},
/**
* 留言数据保存
*/
saveRemark() {
orderRemark({
order_id: this.order_detail.order_id,
remark: this.order_detail.remark
}).then((res) => {
this.$util.showToast({
title: res.message
});
if (res.code >= 0) {
this.getOrderDetailFn(this.order_list[this.selectGoodsKeys].order_id);
this.$refs.remark.close();
}
});
},
/**
* 关闭订单
*/
orderCloseFn() {
orderClose({
order_id: this.order_detail.order_id
}).then((res) => {
this.$util.showToast({
title: res.message
});
if (res.code >= 0) {
this.getOrderDetailFn(this.order_list[this.selectGoodsKeys].order_id, this.selectGoodsKeys, () => {
this.order_list[this.selectGoodsKeys] = this.order_detail;
this.$forceUpdate();
});
this.$refs.orderClose.close();
}
});
},
/**
* 订单取消
*/
orderOperation(type) {
switch (type) {
case 'save':
this.orderCloseFn();
break;
case 'close':
this.$refs.orderClose.close();
break;
}
},
selectOrderGoods(data) {
let index = this.refundGoods.indexOf(data.order_goods_id);
if (index == -1) this.refundGoods.push(data.order_goods_id);
else this.refundGoods.splice(index, 1);
},
/**
* 退款下一步
*/
refundNext() {
if (this.refundStep == 0) {
if (!this.refundGoods.length) {
this.$util.showToast({
title: '请选择要退款的商品'
});
return;
}
getRefundApplyData({
refund_array: JSON.stringify(this.refundGoods)
}).then((res) => {
if (res.code == 0) {
this.refundDetail = res.data;
this.refundStep = 1;
let refundData = {};
this.refundDetail.refund_list.forEach(refundItem => {
refundData[refundItem.order_goods_info.order_goods_id] = {
refund_pay_money: this.$util.moneyFormat(refundItem.order_goods_info.refund_apply_money),
refund_money: this.$util.moneyFormat(refundItem.order_goods_info.refund_apply_money),
refund_status:'PARTIAL_REFUND',
is_refund_stock: 1,
refund_stock_num: refundItem.order_goods_info.num
};
});
Object.assign(this.refundApply, {
order_id: this.order_detail.order_id,
refund_array: refundData,
refund_transfer_type: Object.keys(this.refundDetail.refund_transfer_type)[0]
});
} else {
this.$util.showToast({
title: res.message
});
}
});
} else if (this.refundStep == 1) {
if (this.refundVerify()) this.refundStep = 2;
} else if (this.refundStep == 2) {
this.createRefund();
}
},
/**
* 退款验证
*/
refundVerify() {
try {
this.refundDetail.refund_list.forEach(refundItem => {
let data = this.refundApply.refund_array[refundItem.order_goods_info.order_goods_id];
if (isNaN(parseFloat(data.refund_money))) {
this.$util.showToast({
title: '退款金额输入错误'
});
throw new Error('');
}
if (parseFloat(data.refund_money) < 0) {
this.$util.showToast({
title: '退款金额不能小于0'
});
throw new Error('');
}
if (parseFloat(data.refund_money) > parseFloat(data.refund_pay_money)) {
this.$util.showToast({
title: '退款金额超出可退金额'
});
throw new Error('');
}
if(data.is_refund_stock == 1){
if(!Number(data.refund_stock_num)){
this.$util.showToast({
title: '请输入返还数量'
});
throw new Error('');
}
if(data.refund_stock_num <= 0){
this.$util.showToast({
title: '返还数量不能小于0'
});
throw new Error('');
}
if(refundItem.order_goods_info.goods_class != 6 || (refundItem.order_goods_info.goods_class == 6 && refundItem.order_goods_info.pricing_type != 'weight' )){
// 不能为小数
if(String(data.refund_stock_num).indexOf('.') != -1){
this.$util.showToast({
title: '商品'+refundItem.order_goods_info.goods_name+'的返还数量只能是正整数'
});
throw new Error('');
}
}
if(data.refund_stock_num > refundItem.order_goods_info.num){
this.$util.showToast({
title: '商品'+refundItem.order_goods_info.goods_name+'最多返还'+refundItem.order_goods_info.num+'件'
});
throw new Error('');
}
}
});
} catch (e) {
return false;
}
return true;
},
/**
* 退款申请
*/
createRefund() {
if (this.refundRepeat) return;
this.refundRepeat = true;
uni.showLoading({
title: ''
});
let data = this.$util.deepClone(this.refundApply);
data.refund_array = JSON.stringify(data.refund_array);
orderRefund(data).then((res) => {
uni.hideLoading();
if (res.code == 0) {
this.$util.showToast({
title: '退款成功'
});
this.getOrderDetailFn(this.order_detail.order_id);
this.type = 'detail';
} else {
this.refundRepeat = false;
this.$util.showToast({
title: res.message
});
}
});
},
/**
* 提货
*/
storeOrderTakeDelivery() {
if (this.isRepeat) return;
this.isRepeat = true;
uni.showLoading({
title: ''
});
orderStoreDelivery(this.order_detail.order_id).then(res => {
uni.hideLoading();
this.isRepeat = false;
if (res.code == 0) {
this.getOrderDetailFn(this.order_detail.order_id);
this.$refs.storeOrderTakeDelivery.close();
} else {
this.$util.showToast({
title: res.message
});
}
})
},
/**
* 本地配送
*/
orderLocalDeliveryFn() {
if (!this.localDelivery.deliverer) {
this.$util.showToast({
title: '请选择配送员'
});
return;
}
if (!this.localDelivery.deliverer_mobile) {
this.$util.showToast({
title: '请输入配送员联系方式'
});
return;
}
if (this.isRepeat) return;
this.isRepeat = true;
uni.showLoading({
title: ''
});
orderLocalDelivery({
order_id: this.order_detail.order_id,
deliverer: this.localDelivery.deliverer,
deliverer_mobile: this.localDelivery.deliverer_mobile
}).then(res => {
uni.hideLoading();
this.isRepeat = false;
if (res.code == 0) {
this.getOrderDetailFn(this.order_detail.order_id);
this.localDelivery = {
deliverer_mobile: '',
deliverer: ''
};
this.$refs.orderLocalDelivery.close();
} else {
this.$util.showToast({
title: res.message
});
}
})
},
getDeliver() {
getOrderDeliverList().then(res => {
if (res.code == 0 && res.data) {
this.deliverer = res.data.map(item => {
return {
label: item.deliver_name,
value: item.deliver_name, // 废弃deliver_id
mobile: item.deliver_mobile
};
});
}
})
},
selectDeliverer(index, item) {
if (index >= 0) {
this.localDelivery.deliverer_mobile = this.deliverer[index].mobile; // 配送员手机号
this.localDelivery.deliverer = item.value; // 配送员
} else {
this.localDelivery.deliverer_mobile = '';
this.localDelivery.deliverer = '';
}
},
viewMember() {
this.$util.redirectTo('/pages/member/list', {member_id: this.order_detail.member_id});
},
/**
* 打印小票
*/
printTicket() {
orderPrintTicket(this.order_detail.order_id).then(res => {
if (res.code == 0) {
if (Object.values(res.data).length) {
let data = Object.values(res.data);
try {
let print = {
printer: []
};
data.forEach((item) => {
print.printer.push({
printer_type: item.printer_info.printer_type,
host: item.printer_info.host,
ip: item.printer_info.ip,
port: item.printer_info.port,
content: item.content,
print_width: item.printer_info.print_width
})
});
this.$pos.send('Print', JSON.stringify(print));
} catch (e) {
console.log('err', e, res.data)
}
} else {
this.$util.showToast({
title: '未开启订单小票打印'
})
}
} else {
this.$util.showToast({
title: res.message ? res.message : '小票打印失败'
})
}
})
},
getExpressCompany() {
getExpressCompanyList().then(res => {
if (res.code == 0 && res.data) {
this.expressCompany = res.data.map(item => {
return {
label: item.company_name,
value: item.company_id
};
});
}
})
},
selectExpressCompany(index, item) {
if (index >= 0) {
this.expresDelivery.express_company_id = parseInt(item.value)
} else {
this.expresDelivery.express_company_id = 0
}
},
/**
* 物流配送订单发货
*/
orderDelivery() {
if (this.expresDelivery.delivery_type == 1) {
if (!this.expresDelivery.express_company_id) {
this.$util.showToast({
title: '请选择物流公司'
});
return;
}
if (!this.expresDelivery.delivery_no) {
this.$util.showToast({
title: '请输入物流单号'
});
return;
}
}
if (!this.expresDelivery.order_goods_ids.length) {
this.$util.showToast({
title: '请选择要发货的商品'
});
return;
}
if (this.isLogisticsRepeat) return;
this.isLogisticsRepeat = true;
uni.showLoading({
title: ''
});
orderExpressDelivery({
order_id: this.order_detail.order_id,
delivery_type: this.expresDelivery.delivery_type,
express_company_id: this.expresDelivery.express_company_id,
delivery_no: this.expresDelivery.delivery_no,
order_goods_ids: this.expresDelivery.order_goods_ids.toString()
}).then(res => {
uni.hideLoading();
if (res.code == 0) {
this.isLogisticsRepeat = false;
this.getOrderDetailFn(this.order_detail.order_id);
this.expresDelivery = {
delivery_type: 1,
express_company_id: 0,
delivery_no: '',
order_goods_ids: []
};
this.$refs.orderDelivery.close();
} else {
this.isLogisticsRepeat = false;
this.$util.showToast({
title: res.message
});
}
})
}
}
}

View File

@@ -0,0 +1,251 @@
import {
orderRefundComplete,
getOrderRefundLists,
getOrderRefundDetail,
orderRefundAgree,
orderRefundClose,
orderRefundRefuse,
orderRefundReceive
} from '@/api/order_refund.js'
export default {
data() {
return {
selectGoodsKeys: 0,
//获取订单的页数
page: 1,
//每次获取订单的条数
page_size: 8,
// 订单搜索是用到的数据
search_text: '',
//初始时加载详情数据判断
one_judge: true,
//无限滚动请求锁
listLock: true,
scrollTop: 0,
// 订单列表数据
order_list: [],
//订单详情数据
order_detail: {},
tabObj: {
list: [{
value: 1,
name: '基础信息'
}, {
value: 2,
name: '商品信息'
}, {
value: 3,
name: '订单日志'
}],
index: 1
},
isRepeat: false,
refundRefuseReason: '', // 拒绝理由
refundTransfer: {
refund_real_money: 0,
refund_money_type: 1,
shop_refund_remark: ''
},
isRefundStock: 0
};
},
onLoad(option) {
this.getOrderList();
},
methods: {
// 搜索
search() {
this.page = 1;
this.order_list = [];
this.one_judge = true;
this.listLock = true;
this.getOrderList();
},
/**
* 获取订单列表
*/
getOrderList() {
if (!this.listLock) return false;
getOrderRefundLists({
page: this.page,
page_size: this.page_size,
search: this.search_text
}).then(res => {
if (res.data.list.length == 0) {
this.order_detail = {};
this.one_judge = false;
}
if (res.code >= 0) {
if (this.order_list.length == 0) {
this.order_list = res.data.list;
} else {
this.order_list = this.order_list.concat(res.data.list);
}
//初始时加载一遍详情数据
if (this.one_judge) {
this.getOrderDetail(this.order_list[0].order_goods_id);
}
}
if (this.page == 1) {
this.scrollTop = 0
}
if (res.data.list.length < this.page_size) {
this.listLock = false
} else {
this.page++
}
})
},
scroll(e) {
this.scrollTop = e.detail.scrollTop
},
/**
* 获取订单详情数据
*/
getOrderDetail(order_goods_id, keys = 0, callback) {
this.selectGoodsKeys = keys;
getOrderRefundDetail({order_goods_id}).then(res => {
if (res.code >= 0) {
this.order_detail = res.data;
if (typeof callback == 'function') {
callback();
}
this.$forceUpdate();
this.one_judge = false;
}
});
},
/**
* 打开弹出框
*/
open(action) {
if (action == 'orderRefundTransfer') {
this.refundTransfer.order_goods_id = this.order_detail.order_goods_id;
this.refundTransfer.refund_real_money = this.order_detail.refund_apply_money;
this.refundTransfer.refund_money_type = 1;
this.refundTransfer.shop_refund_remark = '';
}
this.$refs[action].open();
},
/**
* 关闭弹出框
*/
close(name) {
this.$refs[name].close();
},
// 同意维权
orderRefundAgree() {
if (this.isRepeat) return;
this.isRepeat = true;
orderRefundAgree({order_goods_id: this.order_detail.order_goods_id}).then(res => {
this.$util.showToast({
title: res.message
});
if (res.code >= 0) {
this.getOrderDetail(this.order_detail.order_goods_id);
this.$refs.orderRefundAgree.close();
}
this.isRepeat = false;
});
},
// 拒绝维权
orderRefundRefuse() {
if (!this.refundRefuseReason) {
this.$util.showToast({
title: '请输入拒绝理由'
});
return;
}
if (this.isRepeat) return;
this.isRepeat = true;
orderRefundRefuse({
order_goods_id: this.order_detail.order_goods_id,
refund_refuse_reason: this.refundRefuseReason
}).then(res => {
this.$util.showToast({
title: res.message
});
if (res.code >= 0) {
this.getOrderDetail(this.order_detail.order_goods_id);
this.$refs.orderRefundRefuse.close();
}
this.isRepeat = false;
});
},
// 关闭维权
orderRefundClose() {
if (this.isRepeat) return;
this.isRepeat = true;
orderRefundClose({
order_goods_id: this.order_detail.order_goods_id
}).then(res => {
this.$util.showToast({
title: res.message
});
if (res.code >= 0) {
this.getOrderDetail(this.order_detail.order_goods_id);
this.$refs.orderRefundClose.close();
}
this.isRepeat = false;
});
},
// 转账
orderRefundTransfer() {
if (!this.refundTransfer.refund_real_money) {
this.$util.showToast({
title: '请输入退款金额'
});
return;
}
var money = parseFloat(this.refundTransfer.refund_real_money);
if (isNaN(money)) {
this.$util.showToast({
title: '请输入正确的退款金额'
});
return;
}
if (money < 0) {
this.$util.showToast({
title: '退款金额不能为负数'
});
return;
}
if (this.isRepeat) return;
this.isRepeat = true;
orderRefundComplete(this.refundTransfer).then(res => {
this.$util.showToast({
title: res.message
});
if (res.code >= 0) {
this.getOrderDetail(this.order_detail.order_goods_id);
this.$refs.orderRefundTransfer.close();
}
this.isRepeat = false;
})
},
// 买家退货接收,维权收货
orderRefundTakeDelivery() {
if (this.isRepeat) return;
this.isRepeat = true;
orderRefundReceive({
order_goods_id: this.order_detail.order_goods_id,
is_refund_stock: this.isRefundStock
}).then(res => {
this.$util.showToast({
title: res.message
});
if (res.code >= 0) {
this.getOrderDetail(this.order_detail.order_goods_id);
this.$refs.orderRefundTakeDelivery.close();
}
this.isRepeat = false;
});
}
}
};

View File

@@ -0,0 +1,96 @@
import {getOrderRechargeDetail, getOrderRechargeList} from '@/api/recharge.js';
export default {
data() {
return {
selectGoodsKeys: 0,
// 订购日志所需列表数据
list: [],
//获取订单的页数
page: 1,
//每次获取订单的条数
page_size: 8,
// 订单搜索是用到的数据
search_text: '',
//订单类型
trade_type: '',
//初始时加载详情数据判断
one_judge: true,
//无限滚动请求锁
listLock: true,
scrollTop: 0,
// 订单列表数据
order_list: [],
//订单详情数据
order_detail: {}
};
},
onLoad(option) {
this.getOrderList();
},
methods: {
// 搜索
search() {
this.page = 1;
this.order_list = [];
this.one_judge = true;
this.listLock = true;
this.getOrderList();
},
/**
* 获取订单列表
*/
getOrderList() {
if (!this.listLock) return false;
getOrderRechargeList({
page: this.page,
page_size: this.page_size,
search_text: this.search_text
}).then(res => {
if (res.data.list.length == 0 && this.one_judge) {
this.order_detail = {};
this.one_judge = false;
}
if (res.code >= 0 && res.data.list.length != 0) {
if (this.order_list.length == 0) {
this.order_list = res.data.list;
} else {
this.order_list = this.order_list.concat(res.data.list);
}
//初始时加载一遍详情数据
if (this.one_judge) {
this.getOrderDetail(this.order_list[0].order_id);
}
}
if (this.page == 1) {
this.scrollTop = 0
}
if (res.data.list.length < this.page_size) {
this.listLock = false
} else {
this.page++
}
})
},
scroll(e) {
this.scrollTop = e.detail.scrollTop
},
/**
* 获取订单详情数据
*/
getOrderDetail(order_id, keys = 0, callback) {
this.selectGoodsKeys = keys;
getOrderRechargeDetail({order_id}).then(res => {
if (res.code >= 0) {
this.order_detail = res.data;
if (typeof callback == 'function') {
callback();
}
this.$forceUpdate();
this.one_judge = false;
}
})
},
}
};

View File

@@ -0,0 +1,174 @@
<template>
<base-page>
<view class="goodslist">
<view class="goodslist-box">
<view class="goodslist-left">
<view class="goods-title">
充值订单
<text class="iconfont icongengduo1"></text>
</view>
<view class="goods-search">
<view class="search">
<text class="iconfont icon31sousuo"></text>
<input type="text" v-model="search_text" @input="search" placeholder="搜索订单号/流水号/买家" />
</view>
</view>
<block v-if="!one_judge && order_list.length > 0">
<scroll-view :scroll-top="scrollTop" @scroll="scroll" scroll-y="true" class="goods-list-scroll" :show-scrollbar="false" @scrolltolower="getOrderList">
<view class="item" @click="getOrderDetail(item.order_id, index)" v-for="(item, index) in order_list" :key="index" :class="index == selectGoodsKeys ? 'itemhover' : ''">
<view class="title">
<view>订单编号{{ item.order_no }}</view>
<view>充值订单</view>
</view>
<view class="total-money-num">
<view class="member-info">
<view>买家</view>
<view v-if="item.member_id">{{ item.nickname }}</view>
<view v-else>散客</view>
</view>
<view class="box">
<view>充值金额</view>
<view>{{ item.face_value }}</view>
</view>
<view class="box">
<view>实付金额</view>
<view>{{ item.price }}</view>
</view>
</view>
</view>
</scroll-view>
</block>
<view class="notYet" v-else-if="!one_judge && order_list.length == 0">暂无数据</view>
</view>
<view class="goodslist-right">
<view class="goods-title">订单详情</view>
<view class="order-information" v-show="!one_judge">
<block v-if="JSON.stringify(order_detail) != '{}'">
<view class="order-status">充值订单</view>
<view class="order-types">
<view class="type type1">
<view>订单编号</view>
<view>{{ order_detail.order_no }}</view>
</view>
<view class="type type1">
<view>订单流水号</view>
<view>{{ order_detail.out_trade_no }}</view>
</view>
<view class="type type1">
<view>买家</view>
<view v-if="order_detail.member_id">
{{ order_detail.nickname }}
<text class="look" @click="$util.redirectTo('/pages/member/list', { member_id: order_detail.member_id })">查看</text>
</view>
<view v-else>散客</view>
</view>
<view class="type type1">
<view>实付金额</view>
<view>{{ order_detail.price }}</view>
</view>
<view class="type type1">
<view>实付方式</view>
<view>{{ order_detail.pay_type_name }}</view>
</view>
<view class="type type1">
<view>状态</view>
<view>{{ order_detail.status == 2 ? '已支付' : '未支付' }}</view>
</view>
<view class="type type1">
<view>支付时间</view>
<view>{{ order_detail.pay_time > 0 ? $util.timeFormat(order_detail.pay_time) : '' }}
</view>
</view>
<view class="type type1">
<view>订单来源</view>
<view>{{ order_detail.order_from_name }}</view>
</view>
</view>
<view class="other-information">
<view class="title">其他信息</view>
<view class="item-box">
<view class="item">
<view>套餐名称</view>
<view>{{ order_detail.recharge_name }}</view>
</view>
<view class="item">
<view>充值面值</view>
<view>{{ order_detail.face_value }}</view>
</view>
<view class="item">
<view>售价</view>
<view>{{ order_detail.buy_price }}</view>
</view>
<view class="item" v-if="order_detail.point > 0">
<view>赠送积分</view>
<view>{{ order_detail.point }}</view>
</view>
<view class="item" v-if="order_detail.growth > 0">
<view>赠送成长值</view>
<view>{{ order_detail.growth }}</view>
</view>
</view>
<view class="goods-info" v-if="order_detail.coupon_list && order_detail.coupon_list['data'].length > 0">
<view class="title">赠送优惠券</view>
<view class="table">
<view class="table-th table-all">
<view class="table-td" style="width:25%">优惠券名称</view>
<view class="table-td" style="width:15%">类型</view>
<view class="table-td" style="width:35%">优惠金额</view>
<view class="table-td" style="width:25%;justify-content: flex-end;">有效期</view>
</view>
<block v-for="(item, index) in order_detail.coupon_list['data']" :key="index">
<view class="table-tr table-all">
<view class="table-td" style="width:25%">{{ item.coupon_name }}</view>
<view class="table-td" style="width:15%">{{ item.type == 'reward' ? '满减券' : '折扣券' }}</view>
<view class="table-td" style="width:40%" v-if="item.type == 'reward'">{{ item.at_least }}元减{{ item.money }}</view>
<view class="table-td" style="width:35%" v-if="item.type == 'discount'">
{{ item.at_least }}元打{{ item.discount }}
<block v-if="item.discount_limit">最多抵扣{{ item.discount_limit }}</block>
</view>
<view class="table-td uni-column" style="width:25%;text-align: right;align-items: flex-end;">
<view v-if="item.end_time">{{ $util.timeFormat(item.end_time) }}</view>
<view v-else>长期有效</view>
</view>
</view>
</block>
</view>
</view>
</view>
</block>
<block v-else>
<image class="cart-empty" src="@/static/cashier/cart_empty.png" mode="widthFix" />
</block>
</view>
</view>
</view>
</view>
</base-page>
</template>
<script>
import unipopup from '@/components/uni-popup/uni-popup.vue';
import rechargeOrder from './public/js/recharge_order';
export default {
components: {
unipopup
},
mixins: [rechargeOrder]
};
</script>
<style scoped lang="scss">
@import './public/css/orderlist.scss';
.goodslist .goodslist-box .goodslist-right .order-information .goods-info {
padding: 0.2rem 0;
}
/deep/ .goods-list-scroll {
width: 100%;
height: calc(100% - 1.71rem) !important;
}</style>

View File

@@ -0,0 +1,746 @@
<template>
<base-page>
<view class="printer ">
<view class="common-wrap common-form body-overhide">
<view class="common-title">打印机设置</view>
<view class="common-form-item">
<label class="form-label">
<text class="required">*</text>
打印机名称
</label>
<view class="form-input-inline">
<input type="text" v-model="savedata.printer_name" class="form-input" />
</view>
<text class="form-word-aux"></text>
</view>
<view class="common-form-item">
<label class="form-label">
<text class="required">*</text>
打印机类型
</label>
<view class="form-inline">
<radio-group @change="printerTypeChange" class="form-radio-group">
<label class="radio form-radio-item">
<radio value="cloud" :checked="savedata.printer_type == 'cloud'" />
云打印机
</label>
<label class="radio form-radio-item">
<radio value="local" :checked="savedata.printer_type == 'local'" />
本地打印机
</label>
<label class="radio form-radio-item">
<radio value="network" :checked="savedata.printer_type == 'network'" />
网络打印机
</label>
</radio-group>
</view>
</view>
<view v-show="savedata.printer_type == 'cloud'">
<view class="common-form-item">
<label class="form-label">
<text class="required">*</text>
打印机品牌
</label>
<view class="form-input-inline">
<view class="form-input">易联云</view>
</view>
<text class="form-word-aux"></text>
</view>
<view class="common-form-item">
<label class="form-label">
<text class="required">*</text>
打印机编号
</label>
<view class="form-input-inline">
<input type="text" v-model="savedata.printer_code" class="form-input" />
</view>
<text class="form-word-aux"></text>
</view>
<view class="common-form-item">
<label class="form-label">
<text class="required">*</text>
打印机密钥
</label>
<view class="form-input-inline">
<input type="text" v-model="savedata.printer_key" class="form-input" />
</view>
<text class="form-word-aux"></text>
</view>
<view class="common-form-item">
<label class="form-label">
<text class="required">*</text>
应用id
</label>
<view class="form-input-inline">
<input type="text" v-model="savedata.open_id" class="form-input" />
</view>
<text class="form-word-aux-line">应用id易联云-开发者中心后台应用中心里获取</text>
</view>
<view class="common-form-item">
<label class="form-label">
<text class="required">*</text>
apiKey
</label>
<view class="form-input-inline">
<input type="text" v-model="savedata.apikey" class="form-input" />
</view>
<text class="form-word-aux-line">apiKey易联云-开发者中心后台应用中心里获取</text>
</view>
</view>
<view v-show="savedata.printer_type == 'local'">
<view class="common-form-item">
<label class="form-label">
<text class="required">*</text>
打印机端口
</label>
<view class="form-input-inline">
<view class="form-input">
<input type="text" v-model="savedata.host" class="form-input" /></view>
</view>
<text class="form-word-aux">打印机端口 (可以填写打印机端口号如LPT1 本地网络共享打印机\\192.168.1.100\POS_NAME)</text>
</view>
</view>
<view v-show="savedata.printer_type == 'network'">
<view class="common-form-item">
<label class="form-label">
<text class="required">*</text>
打印机IP
</label>
<view class="form-input-inline">
<view class="form-input">
<input type="text" v-model="savedata.ip" class="form-input" /></view>
</view>
<text class="form-word-aux"></text>
</view>
<view class="common-form-item">
<label class="form-label">
<text class="required">*</text>
打印机端口
</label>
<view class="form-input-inline">
<view class="form-input">
<input type="text" v-model="savedata.port" class="form-input" /></view>
</view>
<text class="form-word-aux"></text>
</view>
</view>
<view v-show="savedata.printer_type == 'local' || savedata.printer_type == 'network'">
<view class="common-form-item">
<label class="form-label">
<text class="required">*</text>
打印宽度
</label>
<view class="form-inline">
<radio-group @change="printWidthChange" class="form-radio-group">
<label class="radio form-radio-item">
<radio value="58mm" :checked="savedata.print_width == '58mm'" />
58mm
</label>
<label class="radio form-radio-item">
<radio value="80mm" :checked="savedata.print_width == '80mm'" />
80mm
</label>
</radio-group>
</view>
</view>
</view>
<view class="common-title">支付打印</view>
<view class="common-form-item">
<label class="form-label">支付打印</label>
<view class="form-inline">
<radio-group @change="orderPayChange" class="form-radio-group">
<label class="radio form-radio-item">
<radio value="1" :checked="savedata.order_pay_open == 1" />
开启
</label>
<label class="radio form-radio-item">
<radio value="0" :checked="savedata.order_pay_open == 0" />
关闭
</label>
</radio-group>
</view>
</view>
<view class="common-form-item" v-if="savedata.order_pay_open == 1">
<label class="form-label">打印模板</label>
<view class="form-input-inline " v-if="template.goodsorder && template.goodsorder.length">
<uni-data-select v-model="orderPayTempIndex" :localdata="template.goodsorder"></uni-data-select>
</view>
</view>
<view class="common-form-item" v-if="savedata.order_pay_open == 1">
<label class="form-label">打印联数</label>
<view class="form-inline">
<radio-group @change="orderPayNumChange" class="form-radio-group">
<label class="radio form-radio-item">
<radio value="1" :checked="savedata.order_pay_print_num == 1" />
1
</label>
<label class="radio form-radio-item">
<radio value="2" :checked="savedata.order_pay_print_num == 2" />
2
</label>
<label class="radio form-radio-item">
<radio value="3" :checked="savedata.order_pay_print_num == 3" />
3
</label>
<label class="radio form-radio-item">
<radio value="4" :checked="savedata.order_pay_print_num == 4" />
4
</label>
</radio-group>
</view>
</view>
<view class="common-form-item" v-if="savedata.order_pay_open == 1">
<label class="form-label">订单类型</label>
<view class="form-block">
<checkbox-group class="form-checkbox-group" @change="orderPayTypeChange">
<label class="form-checkbox-item" v-for="(item, index) in orderType">
<checkbox :value="item.type.toString()" :checked="savedata.order_pay_order_type.includes(item.type.toString()) || savedata.order_pay_order_type.includes(parseInt(item.type))" />
{{ item.name }}
</label>
</checkbox-group>
</view>
</view>
<view class="common-title">收货打印</view>
<view class="common-form-item">
<label class="form-label">收货打印</label>
<view class="form-inline">
<radio-group @change="takeDeliveryChange" class="form-radio-group">
<label class="radio form-radio-item">
<radio value="1" :checked="savedata.take_delivery_open == 1" />
开启
</label>
<label class="radio form-radio-item">
<radio value="0" :checked="savedata.take_delivery_open == 0" />
关闭
</label>
</radio-group>
</view>
</view>
<view class="common-form-item" v-if="savedata.take_delivery_open == 1">
<label class="form-label">打印模板</label>
<view class="form-input-inline" v-if="template.goodsorder && template.goodsorder.length">
<uni-data-select v-model="takeDeliveryTempIndex" :localdata="template.goodsorder"></uni-data-select>
</view>
</view>
<view class="common-form-item" v-if="savedata.take_delivery_open == 1">
<label class="form-label">打印联数</label>
<view class="form-inline">
<radio-group @change="takeDeliveryNumChange" class="form-radio-group">
<label class="radio form-radio-item">
<radio value="1" :checked="savedata.take_delivery_print_num == 1" />
1
</label>
<label class="radio form-radio-item">
<radio value="2" :checked="savedata.take_delivery_print_num == 2" />
2
</label>
<label class="radio form-radio-item">
<radio value="3" :checked="savedata.take_delivery_print_num == 3" />
3
</label>
<label class="radio form-radio-item">
<radio value="4" :checked="savedata.take_delivery_print_num == 4" />
4
</label>
</radio-group>
</view>
</view>
<view class="common-form-item" v-if="savedata.take_delivery_open == 1">
<label class="form-label">订单类型</label>
<view class="form-block">
<checkbox-group class="form-checkbox-group" @change="takeDeliveryTypeChange">
<label class="form-checkbox-item" v-for="(item, index) in orderType">
<checkbox :value="item.type.toString()" :checked="savedata.take_delivery_order_type.includes(item.type.toString()) || savedata.take_delivery_order_type.includes(parseInt(item.type))" />
{{ item.name }}
</label>
</checkbox-group>
</view>
</view>
<view class="common-title">手动打印</view>
<view class="common-form-item">
<label class="form-label">手动打印</label>
<view class="form-inline">
<radio-group @change="manualChange" class="form-radio-group">
<label class="radio form-radio-item">
<radio value="1" :checked="savedata.manual_open == 1" />
开启
</label>
<label class="radio form-radio-item">
<radio value="0" :checked="savedata.manual_open == 0" />
关闭
</label>
</radio-group>
</view>
</view>
<view class="common-form-item" v-if="savedata.manual_open == 1">
<label class="form-label">打印模板</label>
<view class="form-input-inline" v-if="template.goodsorder && template.goodsorder.length">
<uni-data-select v-model="manualTempIndex" :localdata="template.goodsorder"></uni-data-select>
</view>
</view>
<view class="common-form-item" v-if="savedata.manual_open == 1">
<label class="form-label">打印联数</label>
<view class="form-inline">
<radio-group @change="manualNumChange" class="form-radio-group">
<label class="radio form-radio-item">
<radio value="1" :checked="savedata.print_num == 1" />
1
</label>
<label class="radio form-radio-item">
<radio value="2" :checked="savedata.print_num == 2" />
2
</label>
<label class="radio form-radio-item">
<radio value="3" :checked="savedata.print_num == 3" />
3
</label>
<label class="radio form-radio-item">
<radio value="4" :checked="savedata.print_num == 4" />
4
</label>
</radio-group>
</view>
</view>
<view class="common-title">充值打印</view>
<view class="common-form-item">
<label class="form-label">充值打印</label>
<view class="form-inline">
<radio-group @change="rechargeChange" class="form-radio-group">
<label class="radio form-radio-item">
<radio value="1" :checked="savedata.recharge_open == 1" />
开启
</label>
<label class="radio form-radio-item">
<radio value="0" :checked="savedata.recharge_open == 0" />
关闭
</label>
</radio-group>
</view>
</view>
<view class="common-form-item" v-if="savedata.recharge_open == 1">
<label class="form-label">打印模板</label>
<view class="form-input-inline" v-if="template.recharge && template.recharge.length">
<uni-data-select v-model="rechargeTempIndex" :localdata="template.recharge"></uni-data-select>
</view>
</view>
<view class="common-form-item" v-if="savedata.recharge_open == 1">
<label class="form-label">打印联数</label>
<view class="form-inline">
<radio-group @change="rechargeNumChange" class="form-radio-group">
<label class="radio form-radio-item">
<radio value="1" :checked="savedata.recharge_print_num == 1" />
1
</label>
<label class="radio form-radio-item">
<radio value="2" :checked="savedata.recharge_print_num == 2" />
2
</label>
<label class="radio form-radio-item">
<radio value="3" :checked="savedata.recharge_print_num == 3" />
3
</label>
<label class="radio form-radio-item">
<radio value="4" :checked="savedata.recharge_print_num == 4" />
4
</label>
</radio-group>
</view>
</view>
<view class="common-title">收银交班打印</view>
<view class="common-form-item">
<label class="form-label">收银交班打印</label>
<view class="form-inline">
<radio-group @change="changeShiftsChange" class="form-radio-group">
<label class="radio form-radio-item">
<radio value="1" :checked="savedata.change_shifts_open == 1" />
开启
</label>
<label class="radio form-radio-item">
<radio value="0" :checked="savedata.change_shifts_open == 0" />
关闭
</label>
</radio-group>
</view>
</view>
<view class="common-form-item" v-if="savedata.change_shifts_open == 1">
<label class="form-label">打印模板</label>
<view class="form-input-inline" v-if="template.change_shifts && template.change_shifts.length">
<uni-data-select v-model="changeShiftsTempIndex" :localdata="template.change_shifts"></uni-data-select>
</view>
</view>
<view class="common-form-item" v-if="savedata.change_shifts_open == 1">
<label class="form-label">打印联数</label>
<view class="form-inline">
<radio-group @change="changeShiftsNumChange" class="form-radio-group">
<label class="radio form-radio-item">
<radio value="1" :checked="savedata.change_shifts_print_num == 1" />
1
</label>
<label class="radio form-radio-item">
<radio value="2" :checked="savedata.change_shifts_print_num == 2" />
2
</label>
<label class="radio form-radio-item">
<radio value="3" :checked="savedata.change_shifts_print_num == 3" />
3
</label>
<label class="radio form-radio-item">
<radio value="4" :checked="savedata.change_shifts_print_num == 4" />
4
</label>
</radio-group>
</view>
</view>
</view>
<view class="common-btn-wrap">
<button type="default" class="primary-btn" @click="saveFn">保存</button>
<button type="default" class="default-btn" @click="back">返回</button>
</view>
</view>
</base-page>
</template>
<script>
import uniDataSelect from '@/components/uni-data-select/uni-data-select.vue';
import {
getPrinterInfo,
getTemplate,
getOrderType,
editPrinter,
addPrinter
} from '@/api/printer.js'
export default {
components: {
uniDataSelect
},
data() {
return {
printer_id: 0,
savedata: {
printer_name: '',
brand: 'yilianyun',
printer_code: '',
printer_key: '',
open_id: '',
apikey: '',
printer_type: 'cloud',
order_pay_open: 0,
order_pay_template_id: 0,
order_pay_print_num: 1,
order_pay_order_type: [],
take_delivery_open: 0,
take_delivery_template_id: 0,
take_delivery_print_num: 1,
take_delivery_order_type: [],
manual_open: 0,
template_id: 0,
print_num: 1,
recharge_open: 0,
recharge_template_id: 0,
recharge_print_num: 1,
change_shifts_open: 0,
change_shifts_template_id: 0,
change_shifts_print_num: 1,
host: '',
ip: '',
port: '',
print_width: '58mm'
},
time: {
start: '08:30',
end: '23:30'
},
interval: 30,
advance: '',
max: '',
week: [],
flag: false,
template: {},
orderPayTempIndex: 0,
takeDeliveryTempIndex: 0,
manualTempIndex: 0,
rechargeTempIndex: 0,
changeShiftsTempIndex: 0,
orderType: []
};
},
onLoad(option) {
if (option.printer_id) {
this.printer_id = option.printer_id;
}
},
onShow() {
uni.setLocale('zh-Hans');
this.getTemplate();
this.getOrderTypeFn();
},
methods: {
getData() {
getPrinterInfo(this.printer_id).then(res => {
if (res.code >= 0) {
this.savedata = res.data;
this.orderPayTempIndex = this.savedata.order_pay_template_id;
this.takeDeliveryTempIndex = this.savedata.take_delivery_template_id;
this.manualTempIndex = this.savedata.template_id;
this.rechargeTempIndex = this.savedata.recharge_template_id;
this.changeShiftsTempIndex = this.savedata.change_shifts_template_id;
} else {
this.$util.showToast({
title: res.message
});
}
})
},
back() {
this.$util.redirectTo('/pages/printer/list');
},
getTemplate() {
getTemplate().then(res => {
if (res.code == 0) {
let template = {};
res.data.map((item, index) => {
if (!template[item.type]) template[item.type] = [];
var obj = {};
obj.text = item.template_name;
obj.value = item.template_id;
template[item.type].push(obj);
});
this.template = template;
if (this.printer_id) {
this.getData();
}
}
})
},
getOrderTypeFn() {
getOrderType().then(res => {
if (res.code == 0) {
this.orderType = res.data;
}
});
},
printerTypeChange(e) {
this.savedata.printer_type = e.detail.value;
},
printWidthChange(e) {
this.savedata.print_width = e.detail.value;
},
orderPayChange(e) {
this.savedata.order_pay_open = e.detail.value;
},
orderPayNumChange(e) {
this.savedata.order_pay_print_num = e.detail.value;
},
orderPayTypeChange(e) {
this.savedata.order_pay_order_type = e.detail.value;
},
takeDeliveryChange(e) {
this.savedata.take_delivery_open = e.detail.value;
},
takeDeliveryNumChange(e) {
this.savedata.take_delivery_print_num = e.detail.value;
},
takeDeliveryTypeChange(e) {
this.savedata.take_delivery_order_type = e.detail.value;
},
manualChange(e) {
this.savedata.manual_open = e.detail.value;
},
manualNumChange(e) {
this.savedata.print_num = e.detail.value;
},
rechargeChange(e) {
this.savedata.recharge_open = e.detail.value;
},
rechargeNumChange(e) {
this.savedata.recharge_print_num = e.detail.value;
},
changeShiftsChange(e) {
this.savedata.change_shifts_open = e.detail.value;
},
changeShiftsNumChange(e) {
this.savedata.change_shifts_print_num = e.detail.value;
},
check() {
let data = Object.assign({}, this.savedata);
if (!data.printer_name) {
this.$util.showToast({
title: '请输入打印机名称'
});
return false;
}
if (data.printer_type == 'cloud') {
if (!data.printer_code) {
this.$util.showToast({
title: '请输入打印机编号'
});
return false;
}
if (!data.printer_key) {
this.$util.showToast({
title: '请输入打印机密钥'
});
return false;
}
if (!data.open_id) {
this.$util.showToast({
title: '请输入应用id'
});
return false;
}
if (!data.apikey) {
this.$util.showToast({
title: '请输入apikey'
});
return false;
}
}
if (data.printer_type == 'local') {
if (!data.host) {
this.$util.showToast({
title: '请输入打印机打印机端口'
});
return false;
}
}
if (data.printer_type == 'network') {
if (!data.ip) {
this.$util.showToast({
title: '请输入打印机打印机地址'
});
return false;
}
if (!data.port) {
this.$util.showToast({
title: '请输入打印机打印机端口'
});
return false;
}
}
return true;
},
saveFn() {
if (this.check()) {
let data = this.savedata;
data.take_delivery_order_type = data.take_delivery_order_type.toString();
data.order_pay_order_type = data.order_pay_order_type.toString();
data.order_pay_template_id = this.orderPayTempIndex;
data.take_delivery_template_id = this.takeDeliveryTempIndex;
data.template_id = this.manualTempIndex;
data.recharge_template_id = this.rechargeTempIndex;
data.change_shifts_template_id = this.changeShiftsTempIndex;
let action = '';
if (this.printer_id > 0) {
data.printer_id = this.printer_id;
action = editPrinter(data)
} else {
action = addPrinter(data)
}
if (this.flag) return false;
this.flag = true;
action.then(res => {
this.flag = false;
this.$util.showToast({
title: res.message
});
if (res.code >= 0) {
setTimeout(() => {
this.$util.redirectTo('/pages/printer/list');
}, 1500);
}
});
}
},
timeTurnTimeStamp(time) {
let data = time.split(':');
return data[0] * 3600 + data[1] * 60;
},
timeFormat(time) {
let h = time / 3600;
let i = (time % 3600) / 60;
h = h < 10 ? '0' + h : h;
i = i < 10 ? '0' + i : i;
return h + ':' + i;
}
}
};
</script>
<style lang="scss" scoped>
.common-title {
font-size: 0.18rem;
margin-bottom: 0.2rem;
}
/deep/ .uni-select{
border-width: 0;
border-radius: 0;
}
.printer{
position: relative;
height: 100%;
.common-wrap {
background-color: #fff;
@extend %body-overhide;
padding: 0.2rem 0.2rem 0.88rem 0.2rem;
}
.common-btn-wrap{
width: 100%;
position: absolute;
left: 0;
bottom: 0;
padding: 0.24rem 0.2rem;
display: flex;
justify-content: space-between;
margin: 0;
box-sizing: border-box;
background-color: #fff;
button{
line-height: 0.4rem;
height: 0.4rem;
margin: 0;
flex: 1;
&.primary-btn{
margin-right: 0.1rem;
}
}
}
}
</style>

View File

@@ -0,0 +1,367 @@
<template>
<base-page>
<view class="printerlist">
<view class="printerlist-box">
<view class="printerlist-left">
<view class="printer-title">
打印机
<text class="iconfont icongengduo1"></text>
</view>
<view class="printer-list-wrap">
<block v-if="list.length > 0">
<scroll-view scroll-y="true" class="printer-list-scroll all-scroll" @scrolltolower="getPrinterListFn">
<view class="item" @click="printerSelect(item, index)" v-for="(item, index) in list" :key="index" :class="index == selectprinterKeys ? 'itemhover' : ''">
<view class="item-right">
<view class="printer-name">{{ item.printer_name }}</view>
<view class="printer-money">{{ printerType(item.printer_type) }}</view>
</view>
</view>
</scroll-view>
</block>
<view class="notYet" v-else-if="!one_judge && list.length == 0">暂无打印机</view>
</view>
<view class="add-printer">
<button type="default" class="primary-btn" @click="addprinter">添加打印机</button>
</view>
</view>
<view class="printerlist-right" v-show="!one_judge">
<view class="printer-title">打印机详情</view>
<view class="printer-information">
<block v-if="JSON.stringify(detail) != '{}'">
<view class="title">基本信息</view>
<view class="information-box">
<view class="box-left">
<view class="information">
<view>名称</view>
<view>{{ detail.printer_name }}</view>
</view>
<view class="information">
<view>打印机类型</view>
<view>{{ printerType(detail.printer_type) }}</view>
</view>
<block v-if="detail.printer_type == 'cloud'">
<view class="information">
<view>品牌</view>
<view>{{ brandList[detail.brand] }}</view>
</view>
<view class="information">
<view>打印机编号</view>
<view>{{ detail.printer_code }}</view>
</view>
<view class="information">
<view>打印机秘钥</view>
<view>{{ detail.printer_key }}</view>
</view>
<view class="information">
<view>应用id</view>
<view>{{ detail.open_id }}</view>
</view>
<view class="information">
<view>apiKey</view>
<view>{{ detail.apikey }}</view>
</view>
</block>
<block v-if="detail.printer_type == 'local'">
<view class="information">
<view>打印机端口</view>
<view>{{ detail.host }}</view>
</view>
</block>
<block v-if="detail.printer_type == 'network'">
<view class="information">
<view>打印机地址</view>
<view>{{ detail.ip }}</view>
</view>
<view class="information">
<view>打印机端口</view>
<view>{{ detail.host }}</view>
</view>
</block>
<view class="information">
<view>添加时间</view>
<view>{{ detail.create_time ? $util.timeFormat(detail.create_time) : '--' }}</view>
</view>
</view>
</view>
<view class="title">支付打印</view>
<view class="information-box">
<view class="box-left">
<view class="information">
<view>支付打印</view>
<view>{{ detail.order_pay_open ? '开启' : '关闭' }}</view>
</view>
<view class="information" v-if="detail.order_pay_open">
<view>打印模板</view>
<view>
{{ template[detail.order_pay_template_id] ? template[detail.order_pay_template_id].template_name : '--' }}
</view>
</view>
<view class="information" v-if="detail.order_pay_open">
<view>打印联数</view>
<view>{{ detail.order_pay_print_num }}</view>
</view>
<view class="information" v-if="detail.order_pay_open">
<view>订单类型</view>
<view>
<block v-for="(item, index) in detail.order_pay_order_type" :key="index">
<text v-if="item" class="order-type">{{ detail['order_type_list'][item]['name'] }}</text>
</block>
</view>
</view>
</view>
</view>
<view class="title">收货打印</view>
<view class="information-box">
<view class="box-left">
<view class="information">
<view>收货打印</view>
<view>{{ detail.take_delivery_open ? '开启' : '关闭' }}</view>
</view>
<view class="information" v-if="detail.take_delivery_open">
<view>打印模板</view>
<view>
{{ template[detail.take_delivery_template_id] ? template[detail.take_delivery_template_id].template_name : '--' }}
</view>
</view>
<view class="information" v-if="detail.take_delivery_open">
<view>打印联数</view>
<view>{{ detail.take_delivery_print_num }}</view>
</view>
<view class="information" v-if="detail.take_delivery_open">
<view>订单类型</view>
<view>
<block v-for="(item, index) in detail.take_delivery_order_type" :key="index">
<text v-if="item" class="order-type">{{ detail['order_type_list'][item]['name'] }}</text>
</block>
</view>
</view>
</view>
</view>
<view class="title">手动打印</view>
<view class="information-box">
<view class="box-left">
<view class="information">
<view>手动打印</view>
<view>{{ detail.manual_open ? '开启' : '关闭' }}</view>
</view>
<view class="information" v-if="detail.manual_open">
<view>打印模板</view>
<view>
{{ template[detail.template_id] ? template[detail.template_id].template_name : '--' }}
</view>
</view>
<view class="information" v-if="detail.manual_open">
<view>打印联数</view>
<view>{{ detail.print_num }}</view>
</view>
</view>
</view>
<view class="title">充值打印</view>
<view class="information-box">
<view class="box-left">
<view class="information">
<view>充值打印</view>
<view>{{ detail.recharge_open ? '开启' : '关闭' }}</view>
</view>
<view class="information" v-if="detail.recharge_open">
<view>打印模板</view>
<view>
{{ template[detail.recharge_template_id] ? template[detail.recharge_template_id].template_name : '--' }}
</view>
</view>
<view class="information" v-if="detail.recharge_open">
<view>打印联数</view>
<view>{{ detail.recharge_print_num }}</view>
</view>
</view>
</view>
<view class="title">收银交班打印</view>
<view class="information-box">
<view class="box-left">
<view class="information">
<view>收银交班打印</view>
<view>{{ detail.change_shifts_open ? '开启' : '关闭' }}</view>
</view>
<view class="information" v-if="detail.change_shifts_open">
<view>打印模板</view>
<view>
{{ template[detail.change_shifts_template_id] ? template[detail.change_shifts_template_id].template_name : '--' }}
</view>
</view>
<view class="information" v-if="detail.change_shifts_open">
<view>打印联数</view>
<view>{{ detail.change_shifts_print_num }}</view>
</view>
</view>
</view>
</block>
<block v-else>
<image class="cart-empty" src="@/static/cashier/cart_empty.png" mode="widthFix" />
</block>
</view>
<view class="button-box" v-if="JSON.stringify(detail) != '{}'">
<button class="default-btn" @click="$refs.deletePop.open()">删除</button>
<button class="default-btn" @click="editprinter(detail.printer_id)">修改</button>
</view>
</view>
</view>
</view>
<!-- 删除 -->
<uni-popup ref="deletePop" type="center">
<view class="confirm-pop">
<view class="title">确定要删除吗</view>
<view class="btn">
<button type="primary" class="default-btn btn save" @click="$refs.deletePop.close()">取消</button>
<button type="primary" class="primary-btn btn" @click="deletePrinterFn(detail.printer_id)">确定</button>
</view>
</view>
</uni-popup>
</base-page>
</template>
<script>
import {
getPrinterList,
getTemplate,
getPrinterInfo,
deletePrinter
} from '@/api/printer.js'
export default {
data() {
return {
selectprinterKeys: 0,
search_text: '',
page: 1,
// 每次返回数据数
page_size: 8,
// 第一次请求列表做详情渲染判断
one_judge: true,
//详情数据
detail: {},
brandList: {
yilianyun: '易联云',
'365': '365'
},
template: {},
list: [],
repeatFlag: false,
};
},
onLoad() {
// 初始化请求打印机列表数据
this.getTemplateFn();
},
methods: {
printerType(printerType) {
var str = '';
switch (printerType) {
case 'cloud':
str = '云打印机';
break;
case 'local':
str = '本地打印机';
break;
case 'network':
str = '网络打印机';
break;
}
return str;
},
switchStoreAfter() {
this.search()
},
printerSelect(item, keys) {
this.selectprinterKeys = keys;
this.getPrinterDetail(item.printer_id);
},
// 搜索员工
search() {
this.page = 1;
this.list = [];
this.one_judge = true;
this.getPrinterListFn();
},
addprinter() {
this.$util.redirectTo('/pages/printer/add');
},
editprinter(printer_id) {
this.$util.redirectTo('/pages/printer/add', {
printer_id: printer_id
});
},
/**
* 请求的列表数据
*/
getPrinterListFn() {
getPrinterList({
page: this.page,
page_size: this.page_size
}).then(res => {
if (res.data.list.length == 0 && this.one_judge) {
this.detail = {};
this.one_judge = false;
}
if (res.code >= 0 && res.data.list.length != 0) {
this.page += 1;
if (this.list.length == 0) {
this.list = res.data.list;
} else {
this.list = this.list.concat(res.data.list);
}
//初始时加载一遍详情数据
if (this.one_judge) {
this.getPrinterDetail(this.list[0].printer_id);
}
}
})
},
getTemplateFn() {
getTemplate().then(res => {
if (res.code == 0) {
let template = {};
res.data.forEach(item => {
template[item.template_id] = item;
})
this.template = template;
this.getPrinterListFn();
}
})
},
getPrinterDetail(printer_id) {
getPrinterInfo(printer_id).then(res => {
if (res.code == 0) {
this.detail = res.data;
this.one_judge = false;
}
})
},
deletePrinterFn(printer_id) {
if (this.repeatFlag) return;
this.repeatFlag = true;
deletePrinter(printer_id).then(res => {
this.repeatFlag = false;
if (res.code >= 0) {
this.page = 1;
this.list = [];
this.one_judge = true;
this.$refs.deletePop.close()
this.getPrinterListFn();
} else {
this.$util.showToast({
title: res.message
});
}
})
}
}
};
</script>
<style scoped lang="scss">
@import './public/css/printer.scss';
</style>

View File

@@ -0,0 +1,280 @@
.printerlist {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: space-between;
box-sizing: border-box;
.printerlist-box {
width: 100%;
height: 100%;
background: #ffffff;
display: flex;
.printerlist-left {
width: 5rem;
height: 100%;
border-right: 0.01rem solid #e6e6e6;
box-sizing: border-box;
display: flex;
flex-direction: column;
.notYet {
color: #e6e6e6;
font-size: 0.4rem;
margin-top: 3rem;
text-align: center;
}
.add-printer {
padding: 0.24rem 0.2rem;
background: #fff;
button {
height: .4rem;
line-height: .4rem;
}
}
.printer-title {
text-align: center;
line-height: 0.6rem;
font-size: 0.18rem;
font-weight: 500;
height: 0.6rem;
border-bottom: 0.01rem solid #e6e6e6;
box-sizing: border-box;
position: relative;
.icongengduo1 {
position: absolute;
top: 50%;
right: 0.2rem;
transform: translateY(-50%);
font-size: 0.3rem;
color: $primary-color;
}
}
.printer-list-wrap {
flex: 1;
height: 0;
}
.printer-list-scroll {
width: 100%;
height: 100%;
.itemhover {
background: var(--primary-color-light-9);
}
.item {
width: 100%;
display: flex;
align-items: center;
padding: 0.2rem;
box-sizing: border-box;
border-bottom: 0.01rem solid #e6e6e6;
image {
width: 0.7rem;
height: 0.7rem;
margin-right: 0.1rem;
}
.item-right {
display: flex;
flex-direction: column;
justify-content: space-between;
height: 0.6rem;
.printer-name {
font-size: 0.16rem;
}
.printer-money {
font-size: 0.14rem;
}
}
}
}
}
.printerlist-right {
width: 0;
flex: 1;
height: 100%;
box-sizing: border-box;
position: relative;
.printer-title {
text-align: center;
line-height: 0.6rem;
font-size: 0.18rem;
font-weight: 500;
height: 0.6rem;
border-bottom: 0.01rem solid #e6e6e6;
box-sizing: border-box;
position: relative;
.icongengduo1,.iconguanbi1 {
position: absolute;
top: 50%;
right: 0.2rem;
transform: translateY(-50%);
font-size: 0.3rem;
color: $primary-color;
cursor: pointer;
}
}
.printer-information {
width: 100%;
padding: 0.2rem 0.2rem 0.88rem 0.2rem;
box-sizing: border-box;
height: calc(100% - 0.6rem);
overflow: auto;
position: relative;
.title {
font-size: 0.18rem;
margin-bottom: 0.32rem;
}
.title2 {
margin-bottom: 0.35rem;
}
.information-box {
display: flex;
justify-content: space-between;
.box-left {
width: 5rem;
.information {
width: 100%;
padding-left: 0.1rem;
box-sizing: border-box;
display: flex;
align-items: center;
margin-bottom: 0.15rem;
view {
color: #303133;
font-size: 0.14rem;
}
view:nth-child(1) {
width: 1.3rem;
margin-right: 0.16rem;
text-align: right;
}
view:nth-child(2) {
width: 74%;
margin-right: 0.23rem;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
}
.information:last-child {
margin-bottom: 0.35rem;
}
}
.printer-img {
width: 1.5rem;
height: 1.5rem;
}
}
.table {
width: 100%;
height: 2.6rem;
box-sizing: border-box;
.table-all {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 0.38rem;
box-sizing: border-box;
.table-td {
font-size: 0.14rem;
text-align: left;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
}
.table-th {
height: 0.56rem;
background: #f7f8fa;
}
.table-tb {
width: 100%;
height: calc(100% - 0.56rem);
.table-tr {
height: 0.7rem;
border-bottom: 0.01rem solid #e6e6e6;
box-sizing: border-box;
.table-td {
image {
width: 0.5rem;
height: 0.5rem;
}
text-overflow: -o-ellipsis-lastline;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
line-clamp: 2;
-webkit-box-orient: vertical;
}
}
}
}
}
}
}
}
view {
color: #303133;
}
/deep/ .uni-scroll-view::-webkit-scrollbar {
width: 0.05rem;
height: 0.3rem;
}
/deep/ .uni-scroll-view::-webkit-scrollbar-thumb {
border-radius: 0.1rem;
box-shadow: inset 0 0 0.05rem rgba(0, 0, 0, 0.2);
background: rgba(193, 193, 193, 1);
}
.printer-information::-webkit-scrollbar {
width: 0.05rem;
height: 0.3rem;
}
.printer-information::-webkit-scrollbar-thumb {
border-radius: 0.1rem;
box-shadow: inset 0 0 0.05rem rgba(0, 0, 0, 0.2);
background: rgba(193, 193, 193, 1);
}
.button-box {
position: absolute;
width: 100%;
right: 0;
bottom: 0;
background-color: #fff;
display: flex;
align-items: center;
justify-content: flex-end;
padding: 0.24rem 0.2rem;
box-sizing: border-box;
button {
width: 1rem;
height: 0.4rem;
line-height: 0.4rem;
margin: 0;
margin-left: 0.1rem;
}
}
.button-box:after {
overflow: hidden;
content: '';
height: 0;
display: block;
clear: both;
}
.cart-empty {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 2.1rem;
}
.order-type{
margin-right: 0.1rem;
}

View File

@@ -0,0 +1,216 @@
<template>
<base-page>
<view class="uni-flex uni-row page-height recharge-wrap">
<view class="common-wrap left-wrap">
<view class="cashregister-header-box">
<view class="order-time">
<view class="title">消费时间</view>
<uni-datetime-picker v-model="create_time" type="datetime" :clearIcon="false" />
</view>
<view class="header" v-if="globalMemberInfo">
<view class="headimg">
<image class="header-image" :src="globalMemberInfo.headimg ? $util.img(globalMemberInfo.headimg) : $util.img(defaultImg.head)" @error="globalMemberInfo.headimg = defaultImg.head"/>
<view v-if="globalMemberInfo.member_level" class="member-nameplate">
{{ globalMemberInfo.member_level_name }}
</view>
</view>
<view class="head-info">
<view class="head-info-top">
<view class="name">
<block v-if="globalMemberInfo.mobile">
<view class="mobile">{{ globalMemberInfo.mobile }}</view>
<view class="text">
<text></text>
<text class="nickname">{{globalMemberInfo.nickname }}</text>
<text></text>
</view>
</block>
<text v-else>{{ globalMemberInfo.nickname }}</text>
</view>
</view>
<view class="head-info-bottom point">积分{{ globalMemberInfo.point }}</view>
<view class="head-info-bottom balance">余额{{ (parseFloat(globalMemberInfo.balance_money) + parseFloat(globalMemberInfo.balance)) | moneyFormat}}</view>
</view>
<button class="switch primary-btn member-open">更换会员</button>
<button class="switch primary-btn replace-member">散客</button>
</view>
<view class="header" v-else>
<view class="headimg">
<image class="header-image" :src="$util.img(defaultImg.head)" />
</view>
<view class="head-info">
<view class="name">散客</view>
</view>
<button class="switch primary-btn">查询会员</button>
</view>
</view>
<view class="content">
<view class="content-list common-scrollbar">
<view class="empty">
<image src="@/static/cashier/cart_empty.png" mode="widthFix"/>
<view class="tips">点击右侧商品选择商品进行结账</view>
</view>
</view>
</view>
<view class="bottom">
<view class="bottom-info">
<view class="bottom-left"> 0 </view>
<view class="bottom-right">
<text class="pay-money">0.00</text>
</view>
</view>
<view class="bottom-btn">
<button class="primary-btn btn-right">结账</button>
</view>
</view>
<view class="pay-shade"></view>
</view>
<view class="uni-flex uni-row common-wrap right-wrap">
<scroll-view scroll-y="true" class="info-wrap" v-show="type == 'member'">
<view class="header">会员充值</view>
<view class="headimg-content" v-if="globalMemberInfo">
<view class="headimg">
<image v-if="globalMemberInfo.headimg" :src="globalMemberInfo.headimg ? $util.img(globalMemberInfo.headimg) : $util.img(defaultImg.head)"/>
<image v-else mode="aspectFill" src="@/static/member/head.png" />
</view>
<view class="header-info" @click="showMember">
<view class="name">
<text>{{ globalMemberInfo.nickname }}</text>
<text v-if="globalMemberInfo.member_level" class="level-name">{{ globalMemberInfo.member_level_name }}</text>
<button type="default" @click.stop="openMember()" class="primary-btn">切换会员</button>
</view>
<view class="header-info-item">
<view>手机号{{ globalMemberInfo.mobile || '--' }}</view>
</view>
</view>
</view>
<view class="headimg-content" v-else>
<view class="headimg">
<image mode="aspectFill" src="@/static/member/head.png" />
</view>
<view class="header-info">
<view class="name">
<text>散客</text>
<button type="default" @click="openMember()" class="primary-btn">登录会员</button>
</view>
<view class="header-info-item">
<view>手机号--</view>
</view>
</view>
</view>
<view class="form-box">
<view class="form-content">
<view class="form-item">
<view class="form-label">
<text class="required"></text>
充值方式
</view>
<view class="form-inline">
<uni-data-checkbox v-model="rechargeType" :localdata="rechargeTypeList" />
</view>
</view>
<view class="form-item" v-if="rechargeType == 2">
<view class="form-label">
<text class="required">*</text>
充值金额
</view>
<view class="form-inline">
<input type="number" class="form-input" v-model="rechargeMoney" />
</view>
</view>
<view class="form-item" v-if="rechargeType == 1">
<view class="form-label">
<text class="required">*</text>
充值金额
</view>
<view class="form-inline ">
<view class="label-list">
<view class="form-label" :class="{ active: rechargeIndex == index }" @click="rechargeIndex = index" v-for="(item, index) in memberRecharge" :key="index">
<view class="price">{{ item.buy_price }}</view>
<view class="balance">到账{{ item.face_value }}</view>
</view>
</view>
</view>
</view>
<view class="form-item" v-if="reward">
<view class="form-label">
<text class="required">*</text>
充值优惠
</view>
<view class="form-inline">
<view class="content-box">
<view class="content-gift" v-if="memberRecharge[rechargeIndex].growth">
<text class="iconfont iconchengchangzhi"></text>
<text>赠送{{ memberRecharge[rechargeIndex].growth }}成长值</text>
</view>
<view class="content-gift" v-if="memberRecharge[rechargeIndex].point">
<text class="iconfont iconjifen"></text>
<text>赠送{{ memberRecharge[rechargeIndex].point }}积分</text>
</view>
<view class="content-gift" v-if="memberRecharge[rechargeIndex].coupon_id">
<text class="iconfont iconyouhuiquan1"></text>
<text>赠送优惠券 X{{ memberRecharge[rechargeIndex].coupon_id.split(',').length }}</text>
</view>
</view>
</view>
</view>
<view class="gift-remark" v-if="rechargeType == 1 && memberRecharge.length > 0 && memberRecharge[rechargeIndex] && memberRecharge[rechargeIndex].goods_data != undefined">
备注赠送的产品需线下提货赠送的项目可在线下进行使用
</view>
<view class="action-btn">
<button type="primary" class="primary-btn" @click="pay()">充值</button>
</view>
</view>
</view>
</scroll-view>
<view class="info-wrap" v-show="type == 'pay'">
<ns-payment ref="payment" storeRoute="recharge" @cancel="cancelPayment" @success="paySuccess" :outTradeNo="outTradeNo"/>
</view>
</view>
</view>
<ns-select-member ref="selectMember"/>
<!-- 会员详情弹出框 -->
<ns-member-detail-popup ref="memberDetailPopup" />
</base-page>
</template>
<script>
import recharge from './public/js/recharge.js';
import nsSelectMember from '@/components/ns-select-member/ns-select-member.vue';
export default {
components: {
nsSelectMember
},
mixins: [recharge],
};
</script>
<style>
.recharge-wrap .cashregister-header-box>>>.uni-select-lay-select {
padding-right: 0.1rem !important;
}
.recharge-wrap .cashregister-header-box>>>.uni-select-lay-icon {
display: none !important;
}
.recharge-wrap .cashregister-header-box>>>.uni-select-lay-input-close {
display: none !important;
}
.recharge-wrap >>> .member-head .iconfont {
display: none;
}
</style>
<style lang="scss" scoped>
@import './public/css/index.scss';
</style>

View File

@@ -0,0 +1,442 @@
.left-wrap {
position: relative;
max-width: 4rem;
display: flex;
flex-direction: column;
margin-right: 0.2rem;
flex: 1;
.pay-shade {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
background-color: rgba($color: #fff, $alpha: 0.6);
z-index: 10;
cursor: no-drop;
}
.content {
padding: 0.15rem;
color: #303133;
flex: 1;
height: 0;
display: flex;
flex-direction: column;
.title {
font-size: 0.14rem;
display: flex;
justify-content: space-between;
}
.clear {
display: flex;
align-items: center;
text {
&:nth-child(1) {
font-size: 0.18rem;
}
&:nth-child(2) {
margin-left: 0.03rem;
font-size: 0.14rem;
}
}
}
.content-list {
margin-top: 0.1rem;
flex: 1;
height: 0;
overflow-y: scroll;
.content-item {
.flex {
display: flex;
align-items: center;
}
display: flex;
align-items: center;
justify-content: space-between;
border-bottom: 0.01rem solid #e6e6e6;
padding: 0.1rem 0;
.item-img {
width: 0.5rem;
height: 0.5rem;
display: flex;
align-items: center;
image {
width: 100%;
}
}
.item-info {
flex: 1;
margin-left: 0.1rem;
width: 0;
min-width: 0;
.item-name {
font-size: 0.14rem;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
width: 2rem;
}
.del {
margin-right: -0.8rem;
margin-top: -0.2rem;
color: $primary-color;
font-size: 0.14rem;
float: right;
}
.item-spe {
font-size: 0.1rem;
color: #999;
margin-top: 0.05rem;
}
.item-price {
font-size: 0.14rem;
margin-top: 0.05rem;
margin-left: -0.03rem;
}
}
.item-num {
display: flex;
align-items: center;
margin-left: 0.1rem;
margin-top: 0.3rem;
.num-dec {
width: 0.25rem;
height: 0.25rem;
background: #e6e6e6;
border: 0.01rem solid #e6e6e6;
border-radius: 30%;
text-align: center;
line-height: 0.23rem;
font-size: 0.25rem;
margin-right: 0.1rem;
cursor: pointer;
transition: 0.3s;
}
.num-inc {
width: 0.25rem;
height: 0.25rem;
background: $primary-color;
border: 0.01rem solid #e6e6e6;
border-radius: 30%;
text-align: center;
line-height: 0.23rem;
font-size: 0.25rem;
margin-left: 0.1rem;
cursor: pointer;
transition: 0.3s;
color: #fff;
}
}
}
}
.empty {
text-align: center;
image {
width: 60%;
margin-top: 0.4rem;
}
.tips {
color: #999;
margin-top: 0.15rem;
}
}
}
.bottom {
width: 100%;
padding:0.2rem 0.2rem 0.24rem 0.2rem;
box-sizing: border-box;
background-color: #ffffff;
.bottom-info {
display: flex;
align-items: center;
justify-content: space-between;
.bottom-left {
font-size: 0.14rem;
}
.bottom-right {
font-size: 0.14rem;
.pay-money {
font-size: 0.27rem;
height: 0.22rem;
font-weight: 600;
font-family: AlibabaPuHuiTiM;
color: $primary-color;
line-height: 0.22rem;
}
}
}
.bottom-btn {
display: flex;
align-items: center;
justify-content: flex-end;
margin-top: 0.2rem;
.btn-right {
width: 1.4rem;
height: 0.4rem;
line-height: 0.4rem;
border: 0 !important;
margin: 0;
}
}
}
}
.page-height {
height: 100%;
}
.common-wrap {
height: 100%;
}
.right-wrap {
border: 0.01rem solid #e6e6e6;
border-radius: 0.02rem;
height: 100%;
border-left: 0;
padding: 0 0.2rem;
box-sizing: border-box;
flex: 1;
.header {
height: 0.66rem;
line-height: 0.66rem;
text-align: left;
border-bottom: 0.01rem solid #e6e6e6;
color: #303133;
font-size: 0.14rem;
}
.info-wrap {
position: relative;
height: 100%;
flex: 1;
.headimg-content {
display: flex;
align-items: center;
margin-top: 0.2rem;
.headimg {
width: 0.7rem;
height: 0.7rem;
border-radius: 50%;
overflow: hidden;
image {
width: 100%;
height: 100%;
}
}
.header-info {
margin-left: 0.15rem;
flex: 1;
.name {
display: flex;
align-items: center;
font-size: 0.16rem;
color: #303133;
.level-name {
background: #ffffff;
border: 0.01rem solid $primary-color;
border-radius: 0.02rem;
font-size: 0.12rem;
color: $primary-color;
margin-left: 0.15rem;
min-width: 0.65rem;
height: 0.22rem;
text-align: center;
line-height: 0.22rem;
padding: 0 0.04rem;
}
.primary-btn {
padding: 0 0.1rem;
width: 1rem;
font-size: $uni-font-size-sm;
margin: 0;
height: 0.24rem;
line-height: 0.24rem;
margin-left: 0.1rem;
}
}
.header-info-item {
display: flex;
align-items: center;
margin-top: 0.1rem;
justify-content: space-between;
view {
text-align: left;
font-size: 0.14rem;
color: #303133;
opacity: 0.9;
}
}
}
}
}
.form-box {
.form-content {
margin-top: 0.2rem;
.gift-remark {
margin-left: 1.3rem;
color: #999;
margin-bottom: 0.15rem;
}
.form-item {
margin-bottom: 0.1rem;
display: flex;
.form-label {
width: 1.3rem;
text-align: right;
padding-right: 0.1rem;
box-sizing: border-box;
height: 0.32rem;
line-height: 0.32rem;
.required {
color: red;
margin-right: 0.03rem;
}
}
.form-inline {
flex: 1;
width: 0;
line-height: 0.32rem;
margin-right: 0.1rem;
box-sizing: border-box;
.form-input {
width: 2.3rem;
border-width: 0.01rem;
border-style: solid;
background-color: #fff;
color: rgba(0, 0, 0, 0.85);
border-radius: 0.02rem;
padding-left: 0.1rem;
height: 0.32rem;
line-height: 0.32rem;
font-size: 0.14rem;
border-color: #e6e6e6;
}
button {
display: inline-block;
margin-right: 0.1rem;
&:nth-child(2) {
margin-right: 0;
}
}
.label-list {
display: flex;
flex-wrap: wrap;
.form-label {
padding: 0.05rem 0.15rem;
border: 0.01rem solid #e6e6e6;
display: flex;
align-items: center;
text-align: center;
margin: 0 0.1rem 0.1rem 0;
cursor: pointer;
flex-direction: column;
width: unset;
height: unset;
white-space: nowrap;
.balance {
color: #999;
}
.price {
font-size: 0.17rem;
font-weight: 600;
}
&.active {
border-color: $primary-color;
color: $primary-color;
background-color: var(--primary-color-light-9);
.balance {
color: $primary-color;
}
}
}
}
.content-gift {
background-color: #f8f8f8;
padding: 0.04rem 0.1rem;
margin-bottom: 0.15rem;
font-size: 0.13rem;
.iconfont {
color: $primary-color;
margin-right: 0.05rem;
}
text {
color: $primary-color;
}
}
}
}
.action-btn {
position: absolute;
left: 0;
right: 0;
bottom: 0.24rem;
button {
height: 0.4rem;
line-height: 0.4rem;
}
}
}
}
}

View File

@@ -0,0 +1,239 @@
import {getRechargeConfig, addRecharge} from '@/api/recharge'
import {getMemberInfoById} from '@/api/member'
import {mapGetters} from 'vuex';
export default {
data() {
return {
type: 'member',
//充值卡相关
memberRecharge: [],
rechargeMoney: 0,
rechargeType: 1,
rechargeIndex: 0,
rechargeTypeList: [{
text: '充值套餐',
value: 1
}, {
text: '自定义金额',
value: 2
}],
outTradeNo: '',
isRepeat: false
};
},
computed: {
reward() {
if (this.rechargeType == 1 && this.memberRecharge.length > 0 && this.memberRecharge[this.rechargeIndex]) {
let data = this.memberRecharge[this.rechargeIndex];
if (data.point || data.growth || data.coupon) return true;
}
return false;
},
...mapGetters(['rechargeActive','memberSearchWayConfig'])
},
onLoad() {
uni.hideTabBar();
},
onShow() {
this.create_time = this.$util.timeFormat(parseInt(new Date().getTime() / 1000));
this.addKeyDownEvent();
// 添加组件的键盘监听事件
if (this.$refs.payment) this.$refs.payment.addKeyDownEvent();
this.getMemberRecharge();
},
onHide() {
this.removeKeyDownEvent();
// 移除组件的键盘监听事件
if (this.$refs.payment) this.$refs.payment.removeKeyDownEvent();
},
methods: {
//充值卡相关
getMemberRecharge() {
getRechargeConfig().then(res => {
if (res.code == 0 && res.data) {
this.memberRecharge = res.data;
if (this.memberRecharge.length > 0) {
for (let i in this.memberRecharge) this.memberRecharge[i]['money'] = this.memberRecharge[i]['price'];
} else {
this.rechargeType = 2;
this.rechargeTypeList[0].disable = true;
}
}
});
},
getMemberInfo() {
getMemberInfoById(this.globalMemberInfo.member_id).then(res => {
if (res.code == 0 && res.data) {
this.$store.commit('app/setGlobalMemberInfo', res.data);
} else {
this.$util.showToast({
title: '未获取到会员信息'
});
}
});
},
openMember() {
if (this.$refs.selectMember) {
this.$store.commit('recharge/setActive', 'ShowMember');
this.$refs.selectMember.open(() => {
this.$store.commit('recharge/setActive', 'ShowMemberAfter');
});
setTimeout(() => {
this.$refs.selectMember.inputFocus = true;
}, 200);
}
},
showMember() {
this.$store.commit('recharge/setActive', 'ShowMember');
if (!this.globalMemberInfo) {
if (this.$refs.selectMember) this.$refs.selectMember.open(() => {
this.$store.commit('recharge/setActive', 'ShowMemberAfter');
});
} else {
// 打开会员信息弹出框
this.$store.commit('recharge/setActive', 'ShowMemberAfter');
this.$refs.memberDetailPopup.open();
}
},
pay() {
if (!this.globalMemberInfo || (this.globalMemberInfo && !this.globalMemberInfo.member_id)) {
this.type = 'member';
this.openMember();
return false;
}
if (this.rechargeType == 1 && !this.memberRecharge[this.rechargeIndex]) {
this.$util.showToast({
title: '请选择充值套餐'
});
return;
}
var isValid = /^-?\d+(\.\d{1,2})?$/;
if (this.rechargeType == 2 && !isValid.test(this.rechargeMoney)) {
this.$util.showToast({
title: '请输入正确的充值金额'
});
return;
}
let data = {
member_id: this.globalMemberInfo.member_id
};
if (this.rechargeType == 1) {
data.sku_array = [{
recharge_id: this.memberRecharge[this.rechargeIndex].recharge_id
}];
} else {
data.sku_array = [{
money: this.rechargeMoney
}];
}
data.sku_array = JSON.stringify(data.sku_array);
this.$store.commit('recharge/setActive', 'OrderCreate');
if (this.isRepeat) return;
this.isRepeat = true;
addRecharge(data).then(res => {
this.isRepeat = false;
if (res.code == 0) {
this.outTradeNo = res.data.out_trade_no;
this.type = 'pay';
} else {
this.$util.showToast({
title: res.message
});
}
});
},
cancelPayment() {
this.type = 'member';
},
paySuccess() {
this.type = 'member';
this.outTradeNo = '';
this.getMemberInfo();
this.$store.commit('recharge/setActive', '');
this.isRepeat = false;
},
/**
* 添加键盘监听事件
*/
addKeyDownEvent() {
// #ifdef H5
// 绑定监听事件
window.addEventListener("keydown", this.listenerKeyDown, true);
// 监听F1~F12BACKSPACE
window.POS_HOTKEY_CALLBACK = (control, code) => {
this.posHotKeyCallback(code);
};
// #endif
},
/**
* 移除键盘监听事件
*/
removeKeyDownEvent() {
// #ifdef H5
window.removeEventListener("keydown", this.listenerKeyDown, true);
delete window.POS_HOTKEY_CALLBACK;
// #endif
},
listenerKeyDown(e) {
var code = e.code;
// console.log('KeyDown', this.type, code, this.rechargeActive, e);
if (this.rechargeActive == '' && code == 'KeyM') {
// 选择会员键盘快捷键【M】
this.openMember();
} else if(this.rechargeActive == 'ShowMember' && this.memberSearchWayConfig.way == 'list'){
// 按照会员列表进行搜索
if (code == 'Enter' || code == 'NumpadEnter') {
if(this.$refs.selectMember.searchFinish && this.$refs.selectMember.memberId){
this.$refs.selectMember.getMemberInfo(this.$refs.selectMember.memberId);
}
}
} else if (this.rechargeActive == 'ShowMemberAfter' || (this.type == 'member' && this.rechargeActive == '')) {
// 活跃窗口:设置会员后,选择充值金额
if (code == 'Enter' || code == 'NumpadEnter') {
this.pay();
}
}
},
/**
* 监听键盘事件回调
* @param {Object} code
*/
posHotKeyCallback(code) {
if (code == 'BACKSPACE') {
// 退格键
if (this.rechargeActive == 'OrderCreate') {
if (this.$refs.payment) {
if (this.$refs.payment.active == 'openMoneyPopup') {
this.$refs.payment.deleteCode();
}
}
}
} else {
// 触发左侧菜单按键回调
this.menuTriggerKeyCodeCallBack(code);
}
}
}
}

View File

@@ -0,0 +1,182 @@
<template>
<base-page>
<view class="goodslist">
<view class="goodslist-box">
<view class="goodslist-left">
<view class="goods-title">
退款记录
<text class="iconfont icongengduo1"></text>
</view>
<view class="goods-search">
<view class="search">
<text class="iconfont icon31sousuo"></text>
<input type="text" v-model="search_text" @input="search" placeholder="搜索退款编号/订单号/客户手机号" />
</view>
</view>
<block v-if="refund_list.length > 0">
<scroll-view scroll-y="true" class="goods-list-scroll" :show-scrollbar="false" @scrolltolower="getRefundList">
<view class="item" @click="getRefundDetail(item.refund_id, index)" v-for="(item, index) in refund_list" :key="index" :class="index == refundIndex ? 'itemhover' : ''">
<view class="title">
<view>退款编号{{ item.refund_no }}</view>
<view>{{ item.refund_status_name }}</view>
</view>
<view class="total-money-num">
<view class="member-info">
<view>客户</view>
<view v-if="item.member_id">{{ item.nickname }}</view>
<view v-else>散客</view>
</view>
<view class="box">
<view>退款金额</view>
<view>{{ item.refund_money }}</view>
</view>
</view>
</view>
</scroll-view>
</block>
<view class="notYet" v-else-if="refund_list.length == 0">暂无数据</view>
</view>
<view class="goodslist-right">
<view class="goods-title">退款详情</view>
<block v-if="refund_detail">
<view class="order-information">
<view class="order-status">{{ refund_detail.refund_status_name }}</view>
<view class="goods-info">
<block v-for="(item, index) in refund_detail.item_list" :key="index">
<view class="goods-item">
<view class="image">
<image :src="$util.img(item.img, { size: 'small' })" mode="widthFix" />
</view>
<view class="info">
<view class="content-text">{{ item.name }}</view>
</view>
<view>
<view class="price">
<text class="title">退款金额</text>
{{ item.refund_pay_money }}
</view>
</view>
</view>
</block>
</view>
<view class="goods-info refund-info">
<view class="info-item">
<view class="title">退款类型</view>
<view class="content">{{ refund_detail.refund_trade_type_name }}</view>
</view>
<view class="info-item">
<view class="title">退款编号</view>
<view class="content">{{ refund_detail.refund_no }}</view>
</view>
<view class="info-item">
<view class="title">退款时间</view>
<view class="content">{{ refund_detail.create_time | timeFormat }}</view>
</view>
<view class="info-item">
<view class="title">退款方式</view>
<view class="content">{{ refund_detail.refund_transfer_type_name }}</view>
</view>
<view class="info-item">
<view class="title">退款说明</view>
<view class="content">{{ refund_detail.refund_goods_remark }}</view>
</view>
<view class="info-item">
<view class="title">退款金额</view>
<view class="content">{{ refund_detail.refund_pay_money }}</view>
</view>
<view class="info-item">
<view class="title">退还积分</view>
<view class="content">{{ refund_detail.refund_point }}积分</view>
</view>
<view class="info-item">
<view class="title">退还余额</view>
<view class="content">{{ (parseFloat(refund_detail.refund_balance_money) + parseFloat(refund_detail.refund_balance)) | moneyFormat }}</view>
</view>
</view>
</view>
</block>
<block v-else>
<image class="cart-empty" src="@/static/cashier/cart_empty.png" mode="widthFix" />
</block>
</view>
</view>
</view>
</base-page>
</template>
<script>
import { getOrderRefundLists, getOrderRefundDetail } from '@/api/order_refund.js'
export default {
data() {
return {
refundIndex: 0,
// 订购日志所需列表数据
list: [],
//获取订单的页数
page: 1,
//每次获取订单的条数
page_size: 8,
// 订单搜索是用到的数据
search_text: '',
// 订单列表数据
refund_list: [],
//订单详情数据
refund_detail: null
};
},
onLoad(option) {
this.getRefundList();
},
methods: {
// 搜索
search() {
this.page = 1;
this.refund_list = [];
this.getRefundList();
},
/**
* 获取订单列表
*/
getRefundList() {
getOrderRefundLists({
page: this.page,
page_size: this.page_size,
search_text: this.search_text
}).then(res=>{
if (res.data.list.length == 0) {
this.refund_detail = null;
}
if (res.code >= 0 && res.data.list.length != 0) {
if (this.refund_list.length == 0) {
this.refund_list = res.data.list;
} else {
this.refund_list = this.refund_list.concat(res.data.list);
}
//初始时加载一遍详情数据
if (this.page == 1) {
this.getRefundDetail(this.refund_list[0].refund_id);
}
this.page += 1;
}
})
},
/**
* 获取订单详情数据
*/
getRefundDetail(refund_id, index = 0) {
this.refundIndex = index;
getOrderRefundDetail({refund_id}).then(res=>{
if (res.code >= 0) {
this.refund_detail = res.data;
}
})
}
}
};
</script>
<style scoped lang="scss">
@import './public/css/list.scss';
</style>

View File

@@ -0,0 +1,303 @@
.goodslist {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: space-between;
box-sizing: border-box;
.goodslist-box {
width: 100%;
height: 100%;
background: #ffffff;
display: flex;
.goodslist-left {
width: 5rem;
height: 100%;
border-right: 0.01rem solid #e6e6e6;
box-sizing: border-box;
overflow: hidden;
position: relative;
.notYet {
color: #e6e6e6;
font-size: 0.4rem;
margin-top: 3rem;
text-align: center;
}
.goods-title {
text-align: center;
line-height: 0.6rem;
font-size: 0.18rem;
font-weight: 500;
height: 0.6rem;
border-bottom: 0.01rem solid #e6e6e6;
box-sizing: border-box;
position: relative;
.icongengduo1 {
position: absolute;
top: 50%;
right: 0.2rem;
transform: translateY(-50%);
font-size: 0.3rem;
color: $primary-color;
}
}
.goods-search {
width: 100%;
height: 0.6rem;
border-bottom: 0.01rem solid #e6e6e6;
display: flex;
align-items: center;
justify-content: center;
padding: 0 0.2rem;
box-sizing: border-box;
.search {
width: 5.6rem;
height: 0.4rem;
border-radius: 0.04rem;
background: #f5f5f5;
display: flex;
align-items: center;
padding: 0 0.2rem;
box-sizing: border-box;
.iconfont {
font-size: 0.16rem;
color: #909399;
margin-right: 0.11rem;
}
input {
width: 80%;
height: 60%;
border: none;
font-size: 0.14rem;
}
}
}
.goods-list-scroll {
width: 100%;
height: calc(100% - 1.2rem);
.itemhover {
background: var(--primary-color-light-9);
}
.item {
padding: 0.2rem;
.title {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 0.2rem;
view {
font-size: 0.16rem;
}
view:nth-child(2) {
color: $primary-color;
}
}
}
}
}
.goodslist-right {
flex: 1;
width: 0;
height: 100%;
border-right: 0.01rem solid #e6e6e6;
box-sizing: border-box;
position: relative;
padding-bottom: 0.8rem;
overflow: hidden;
.goods-title {
text-align: center;
line-height: 0.6rem;
font-size: 0.18rem;
font-weight: 500;
height: 0.6rem;
border-bottom: 0.01rem solid #e6e6e6;
box-sizing: border-box;
position: relative;
}
.cart-empty {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 2.1rem;
}
.order-information {
width: 100%;
height: calc(100% - 0.6rem);
background: #f8f8f8;
padding: 0.2rem;
box-sizing: border-box;
overflow: scroll;
// position: relative;
.order-status {
font-size: 0.24rem;
font-weight: bold;
margin-bottom: 0.24rem;
}
.goods-info {
background: #ffffff;
padding: 0.2rem;
box-sizing: border-box;
.goods-item {
padding: 0.15rem 0;
border-bottom: 0.01rem solid #e6e6e6;
display: flex;
&:last-child {
border-bottom: 0;
}
.iconfont {
font-size: 0.2rem;
cursor: pointer;
display: flex;
align-items: center;
}
.iconyuan_checked {
color: $primary-color;
}
.image {
width: 0.8rem;
height: 0.8rem;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
margin-right: 0.15rem;
image {
width: inherit;
}
}
.info {
flex: 1;
margin-right: 0.15rem;
}
.price {
text-align: right;
font-weight: bolder;
.title {
font-weight: normal;
font-size: .12rem;
color: #999;
}
}
.num {
text-align: right;
}
}
}
.refund-info {
margin-top: .15rem;
.info-item {
display: flex;
line-height: .3rem;
.content {
flex: 1;
text-align: right;
margin-left: .1rem;
width: 0;
}
}
}
}
}
}
}
.total-money-num {
.member-info {
display: flex;
align-items: center;
float: left;
-ms-flex-negative: 0;
-webkit-flex-shrink: 0;
flex-shrink: 0;
}
.box {
display: flex;
align-items: center;
float: right;
view {
font-size: 0.14rem;
}
view:nth-child(1) {
// transform: translateY(-.01rem);
}
view:nth-child(2) {
color: #fe2278;
font-size: 0.18rem;
}
}
}
.total-money-num:after {
overflow: hidden;
content: '';
height: 0;
display: block;
clear: both;
}
view {
color: #303133;
}
/deep/ .uni-scroll-view::-webkit-scrollbar {
width: 0.05rem;
height: 0.3rem;
}
/deep/ .uni-scroll-view::-webkit-scrollbar-thumb {
border-radius: 0.1rem;
box-shadow: inset 0 0 0.05rem rgba(0, 0, 0, 0.2);
background: rgba(193, 193, 193, 1);
}
.order-information::-webkit-scrollbar {
width: 0.05rem;
height: 0.3rem;
}
.order-information::-webkit-scrollbar-thumb {
border-radius: 0.1rem;
box-shadow: inset 0 0 0.05rem rgba(0, 0, 0, 0.2);
background: rgba(193, 193, 193, 1);
}

View File

@@ -0,0 +1,224 @@
<template>
<base-page>
<view class="common-wrap common-form">
<view class="common-title">预约设置</view>
<view class="common-form-item">
<label class="form-label">预约时间</label>
<view class="form-block">
<checkbox-group class="form-checkbox-group" @change="checkboxChange">
<label class="form-checkbox-item">
<checkbox value="1" :checked="week.includes('1') || week.includes(1)" />
周一
</label>
<label class="form-checkbox-item">
<checkbox value="2" :checked="week.includes('2') || week.includes(2)" />
周二
</label>
<label class="form-checkbox-item">
<checkbox value="3" :checked="week.includes('3') || week.includes(3)" />
周三
</label>
<label class="form-checkbox-item">
<checkbox value="4" :checked="week.includes('4') || week.includes(4)" />
周四
</label>
<label class="form-checkbox-item">
<checkbox value="5" :checked="week.includes('5') || week.includes(5)" />
周五
</label>
<label class="form-checkbox-item">
<checkbox value="6" :checked="week.includes('6') || week.includes(6)" />
周六
</label>
<label class="form-checkbox-item">
<checkbox value="0" :checked="week.includes('0') || week.includes(0)" />
周日
</label>
</checkbox-group>
</view>
</view>
<view class="common-form-item">
<label class="form-label"></label>
<view class="form-inline">
<view class="form-input-inline">
<picker mode="time" class="form-input" :value="time.start" @change="bindStartTimeChange">
<view class="uni-input">{{ time.start }}</view>
</picker>
</view>
<text class="form-mid">-</text>
<view class="form-input-inline">
<picker mode="time" class="form-input" :value="time.end" @change="bindEndTimeChange">
<view class="uni-input">{{ time.end }}</view>
</picker>
</view>
</view>
</view>
<view class="common-form-item">
<label class="form-label">预约时间间隔</label>
<view class="form-inline">
<radio-group @change="radioChange" class="form-radio-group">
<label class="radio form-radio-item">
<radio value="30" :checked="interval == 30" />
30分钟
</label>
<label class="radio form-radio-item">
<radio value="60" :checked="interval == 60" />
1个小时
</label>
<label class="radio form-radio-item">
<radio value="90" :checked="interval == 90" />
90分钟
</label>
<label class="radio form-radio-item">
<radio value="120" :checked="interval == 120" />
2小时
</label>
</radio-group>
</view>
</view>
<view class="common-form-item">
<label class="form-label">预约提前</label>
<view class="form-input-inline"><input type="number" v-model="advance" class="form-input" /></view>
<text class="form-word-aux">小时</text>
</view>
<view class="common-form-item">
<label class="form-label">每时段可预约</label>
<view class="form-input-inline"><input type="number" v-model="max" class="form-input" /></view>
<text class="form-word-aux"></text>
</view>
<view class="common-btn-wrap"><button type="default" class="screen-btn" @click="saveFn">保存</button></view>
<ns-loading :layer-background="{ background: 'rgba(255,255,255,.8)' }" ref="loading"></ns-loading>
</view>
</base-page>
</template>
<script>
import {
getReserveConfig,
setReserveConfig
} from '@/api/reserve'
export default {
data() {
return {
time: {
start: '08:30',
end: '23:30'
},
interval: 30,
advance: '',
max: '',
week: [],
flag: false
};
},
onLoad() {},
onShow() {
this.getData();
uni.setLocale('zh-Hans');
},
methods: {
getData() {
getReserveConfig().then(res => {
if (res.code >= 0) {
({
start: this.time.start,
end: this.time.end,
interval: this.interval,
advance: this.advance,
max: this.max,
week: this.week
} = res.data);
this.time.start = this.timeFormat(this.time.start);
this.time.end = this.timeFormat(this.time.end);
this.$refs.loading.hide();
} else {
this.$util.showToast({
title: res.message
});
}
});
},
bindStartTimeChange(e) {
this.time.start = e.detail.value;
},
bindEndTimeChange(e) {
this.time.end = e.detail.value;
},
radioChange(e) {
this.interval = e.detail.value;
},
checkboxChange(e) {
this.week = e.detail.value;
},
getSaveData() {
let data = {};
data.start = this.timeTurnTimeStamp(this.time.start);
data.end = this.timeTurnTimeStamp(this.time.end);
data.interval = this.interval;
data.advance = this.advance;
data.max = this.max;
data.week = this.week.toString();
return data;
},
saveFn() {
if (this.flag) return false;
this.flag = true;
setReserveConfig(this.getSaveData()).then(res => {
this.flag = false;
this.$util.showToast({
title: res.message
});
if (res.code >= 0) {
this.$refs.loading.show();
this.getData();
}
});
},
timeTurnTimeStamp(time) {
let data = time.split(':');
return data[0] * 3600 + data[1] * 60;
},
timeFormat(time) {
let h = time / 3600;
let i = (time % 3600) / 60;
h = h < 10 ? '0' + h : h;
i = i < 10 ? '0' + i : i;
return h + ':' + i;
}
}
};
</script>
<style lang="scss" scoped>
.common-wrap {
position: relative;
padding: 30rpx;
height: calc(100vh - 51px);
.form-label {
width: 1.5rem !important;
}
.common-btn-wrap {
position: absolute;
left: 0;
right: 0;
bottom: 0;
padding: 0.24rem 0.2rem;
margin-left: 0;
text-align: center;
height: 0.4rem;
button {
width: 100%;
height: 0.4rem;
line-height: 0.4rem;
}
}
}
.common-title {
font-size: 0.18rem;
margin-bottom: 0.2rem;
}
</style>

View File

@@ -0,0 +1,468 @@
<template>
<base-page>
<view class="uni-flex uni-row height-all">
<view class="common-wrap uni-flex uni-column" style="-webkit-flex: 1;flex: 1;">
<view class="common-tab-wrap" id="tab">
<view class="tab-item" :class="{ 'active-bar': active == 0 }" @click="switchTab(0)">
<text class="text">预约看板</text>
</view>
<view class="tab-item" :class="{ 'active-bar': active == 1 }" @click="switchTab(1)">
<text class="text">预约列表</text>
</view>
<view class="active" :style="activeStyle"></view>
</view>
<swiper :interval="3000" :duration="300" :current="active" @change="swiperChange">
<!-- 预约看板 -->
<swiper-item>
<view class="swiper-item common-scrollbar">
<view class="uni-flex panel-head">
<button type="default" class="primary-btn" @click="addYuyue()">添加预约</button>
<view class="status uni-flex">
<block v-for="(item, index) in status" :key="index">
<view class="color" :class="item.state"></view>
<view>{{ item.name }}</view>
</block>
</view>
</view>
<view class="panel-body">
<view class="head-time uni-flex">
<view @click="prevWeek()" class="item">
<view class="iconfont iconqianhou1"></view>
</view>
<view class="time-box">{{ weekDate.start }} - {{ weekDate.end }}</view>
<view @click="nextWeek()" class="item">
<view class="iconfont iconqianhou2"></view>
</view>
<!-- <view class="head-time-switch">
<view :class="yuYueDateType == 'week' ? 'active' : ''" @click="yuYueDateType = 'week'"></view>
<view :class="yuYueDateType == 'month' ? 'active' : ''" @click="yuYueDateType = 'month'"></view>
</view> -->
</view>
<block v-if="yuYueDateType == 'week'">
<view class="head uni-flex">
<view v-for="(item, index) in weeks" class="item" :key="index">
<button type="default" class="default-btn" :class="{ active: item.currday }">
{{ item.week }}
<text>{{ item.date }}</text>
</button>
</view>
</view>
<view class="body uni-flex">
<scroll-view scroll-y="true" @scrolltolower="getReserve(index)" class="common-scrollbar item" v-for="(item, index) in weeks" :key="index">
<block v-if="item.data">
<view class="panel-item" :class="reserve_item.reserve_state" v-for="(reserve_item, reserve_index) in item.data.list" :key="reserve_index">
<view class="username">{{ reserve_item.nickname }}</view>
<view class="time" :class="reserve_item.reserve_state">{{ $util.timeFormat(reserve_item.reserve_time, 'm-d H:i') }}</view>
<view class="service" v-for="(server_item, server_index) in reserve_item.item" :key="server_index" @click="yuyueEvent('info', reserve_item)">{{ server_item.goods_name }}</view>
<uni-dropdown>
<view class="action" slot="dropdown-link">
<text class="iconfont icongengduo"></text>
</view>
<view slot="dropdown">
<view class="dropdown-menu">
<view class="menu-item" @click="yuyueEvent('info', reserve_item)">详情</view>
<view class="menu-item" v-for="(menu_item, menu_index) in operation[reserve_item.reserve_state]" :key="menu_index" @click="yuyueEvent(menu_item.event, reserve_item)">
{{ menu_item.title }}
</view>
<view class="arrow"></view>
</view>
</view>
</uni-dropdown>
</view>
<view style="height: 1.5rem;"></view>
</block>
</scroll-view>
</view>
</block>
<block v-if="yuYueDateType == 'month'">
<view class="head uni-flex">
<view v-for="(item, index) in week" class="item" :key="index">
<button type="default" class="default-btn">{{ item }}</button>
</view>
</view>
</block>
</view>
</view>
</swiper-item>
<!-- 预约列表 -->
<swiper-item>
<view class="yuyuelist">
<view class="yuyuelist-box">
<view class="yuyuelist-left">
<view class="yuyue-title">预约客户</view>
<view class="yuyue-search">
<view class="search">
<text class="iconfont icon31sousuo" @click="searchYuyueList()"></text>
<input type="text" v-model="yuyueSearchText" placeholder="请输入会员手机号" />
</view>
</view>
<scroll-view @scrolltolower="getYuyueList()" scroll-y="true" class="yuyue-list-scroll all-scroll">
<view class="item" v-for="(item, index) in yuyueList" :key="index" @click="selectYuyue(item.reserve_id)" :class="{ active: item.reserve_id == reserveId }">
<view class="item-head">
<image mode="aspectFill" v-if="item.headimg" :src="$util.img(item.headimg)" @error="item.headimg = defaultImg.head"/>
<image mode="aspectFill" v-else :src="$util.img(defaultImg.head)"/>
<view class="item-right">
<view class="yuyue-name" v-if="item.nickname">{{ item.nickname }}</view>
<view class="yuyue-desc">{{ item.mobile }}</view>
</view>
<text>{{ item.reserve_state_name }}</text>
</view>
<view class="item-common">预约时间{{ $util.timeFormat(item.create_time) }}
</view>
<view class="item-common yuyue-project">
预约项目
<block v-for="(sItem, sIndex) in item.item" :key="sIndex">
{{ sItem.goods_name }}{{ sIndex != item.item.length - 1 ? '' : '' }}
</block>
</view>
</view>
<view v-if="yuyueList.length == 0" class="empty">
<image src="@/static/member/member-empty.png" mode="widthFix"/>
<view class="tips">暂无预约客户</view>
</view>
</scroll-view>
</view>
<view class="yuyuelist-right" v-if="yuyueInfo">
<view class="yuyue-title">预约详情</view>
<view class="yuyue-information common-scrollbar">
<view class="title">预约信息</view>
<view class="information-box">
<view class="box-left">
<view class="information">
<view>预约客户</view>
<view>{{ yuyueInfo.nickname }}</view>
</view>
<view class="information">
<view>客户手机号</view>
<view>{{ yuyueInfo.mobile }}</view>
</view>
<view class="information">
<view>预约门店</view>
<view>{{ yuyueInfo.store_name }}</view>
</view>
<view class="information">
<view>预约状态</view>
<view>{{ yuyueInfo.reserve_state_name }}</view>
</view>
<view class="information">
<view>预约到店时间</view>
<view>{{ $util.timeFormat(yuyueInfo.reserve_time, 'Y-m-d H:i') }}
</view>
</view>
<view class="information">
<view>预约时间</view>
<view>{{ $util.timeFormat(yuyueInfo.create_time) }}</view>
</view>
<view class="information">
<view>备注</view>
<view>{{ yuyueInfo.desc ? yuyueInfo.desc : '--' }}</view>
</view>
</view>
</view>
<view class="title title2">预约内容</view>
<view class="table" v-if="yuyueInfo">
<view class="table-th table-all">
<view class="table-td" style="width:50%">项目</view>
<view class="table-td" style="width:50%">员工</view>
</view>
<scroll-view class="table-tb" scroll-y="true">
<view class="table-tr table-all" v-for="(item, index) in yuyueInfo.item" :key="index">
<view class="table-td" style="width:50%">{{ item.goods_name }}
</view>
<view class="table-td" style="width:50%">
{{ item.uid ? item.username : '--' }}
</view>
</view>
</scroll-view>
</view>
<view class="button-box flex items-center justify-end" v-if="yuyueInfo && operation[yuyueInfo.reserve_state]">
<button class="default-btn" v-for="(menu_item, menu_index) in operation[yuyueInfo.reserve_state]" :key="menu_index" @click="yuyueEvent(menu_item.event, yuyueInfo)">{{ menu_item.title }}</button>
</view>
</view>
</view>
<view class="yuyuelist-right empty" v-else>
<image src="@/static/cashier/cart_empty.png" mode="widthFix"/>
<view class="tips">暂无预约信息</view>
</view>
</view>
</view>
</swiper-item>
</swiper>
</view>
</view>
<!-- 添加/修改预约 -->
<uni-popup ref="addYuyuePop" :maskClick="false">
<view class="pop-box">
<view class="pop-header">
<view class="pop-header-text">{{ yuYueData.reserve_id ? '修改' : '添加' }}预约</view>
<view class="pop-header-close" @click="closeYuyuePop">
<text class="iconguanbi1 iconfont"></text>
</view>
</view>
<scroll-view scroll-y="true" class="common-scrollbar pop-content">
<view class="form-content">
<view class="form-item" v-if="!yuYueData.reserve_id">
<view class="form-label">
<text class="required">*</text>
手机号
</view>
<view class="form-inline search-wrap">
<input type="number" class="form-input" v-model="searchMobile" placeholder="请输入客户手机号" />
<text class="iconfont icon31sousuo" @click="searchMember"></text>
</view>
</view>
<view class="form-item">
<view class="form-label">
<text class="required">*</text>
客户
</view>
<view class="form-inline">
<view class="member-info" v-if="yuYueData.member_id">
<image :src="$util.img(yuYueData.member.headimg, { size: 'small' })" mode="widthFix" />
<view class="info">
<view class="name">{{ yuYueData.member.nickname }}</view>
<view>
<text>手机号{{ yuYueData.member.mobile }}</text>
</view>
</view>
</view>
</view>
</view>
<view class="form-item">
<view class="form-label">
<text class="required">*</text>
到店时间
</view>
<view class="form-inline">
<uni-datetime-picker :start="toDay" v-model="yuYueData.date" type="date" :clearIcon="false" @change="changeYuyueTime" />
</view>
<view class="form-inline">
<select-lay :zindex="10" :value="yuYueData.time" name="names" placeholder="请选择到店时间" :options="yuYueTime" @selectitem="selectYuYueTime"/>
</view>
</view>
<view class="form-item">
<view class="form-label">
<text class="required">*</text>
预约门店
</view>
<view class="form-inline">{{ globalStoreInfo.store_name }}</view>
</view>
<view class="form-item">
<view class="form-label">
<text class="required">*</text>
项目
</view>
<view>
<view class="table">
<view class="table-tr table-head">
<view class="table-th">预约项目</view>
<view class="table-th">员工</view>
<view class="table-th">操作</view>
</view>
<view class="table-content table-tr" v-for="(goods_item, goods_index) in yuYueData.goods" :key="goods_index">
<view class="table-td">
<uni-dropdown>
<view class="action" slot="dropdown-link">
<view class="service-item">
<view class="info" v-if="goods_item.goods_id">
<view class="title">{{ goods_item.goods_name }}</view>
<view class="desc">项目时长{{ goods_item.service_length }}分钟 {{ goods_item.price }}</view>
</view>
<view class="info" v-else>请选择项目</view>
<text class="iconfont iconsanjiao_xia"></text>
</view>
</view>
<view slot="dropdown">
<view class="dropdown-content-box">
<view class="select-service">
<div class="service-wrap">
<div class="flex-wrap">
<div class="item" v-for="(item, index) in goodsList" :key="index" @click="selectGoods(item, goods_index)">
<div class="title">{{ item.goods_name }}</div>
<div class="desc">项目时长{{ item.service_length }}分钟 {{ item.price }}</div>
</div>
</div>
</div>
</view>
<view class="arrow"></view>
</view>
</view>
</uni-dropdown>
</view>
<view class="table-td">
<uni-dropdown>
<view class="action" slot="dropdown-link">
<view class="service-item" @click="loadServicer(goods_index)">
<view class="info">
<view class="title" v-if="goods_item.uid && goods_item.uid > 0">
{{ goods_item.username }}
</view>
<view class="title" v-else>不选择员工</view>
</view>
<text class="iconfont iconsanjiao_xia"></text>
</view>
</view>
<view slot="dropdown">
<view class="dropdown-content-box">
<div class="select-servicer">
<div class="select-item">
<div class="title" @click="selectServicer({ uid: 0, username: '' }, goods_index)">不选择员工</div>
</div>
<div class="select-item" v-for="(item, index) in servicerList" :key="index" @click="selectServicer(item, goods_index)">
<div class="title">{{ item.username }}</div>
</div>
</div>
<view class="arrow"></view>
</view>
</view>
</uni-dropdown>
</view>
<view class="table-td">
<view class="action-btn" @click="deleteService(goods_index)">删除</view>
</view>
</view>
</view>
<button class="primary-btn select-btn" @click="addService">添加项目</button>
</view>
</view>
<view class="form-item">
<view class="form-label">
<text class="required"></text>
备注
</view>
<view class="form-inline">
<textarea class="form-textarea" v-model="yuYueData.desc"></textarea>
</view>
</view>
</view>
</scroll-view>
<view class="pop-bottom">
<button class="primary-btn" @click="yuYueSubmit">确定</button>
</view>
</view>
</uni-popup>
<!-- 预约详情 -->
<uni-popup ref="yuyuePop">
<view class="pop-box yuyue-info">
<view class="pop-header">
<view class="pop-header-text">预约详情</view>
<view class="pop-header-close" @click="$refs.yuyuePop.close()">
<text class="iconguanbi1 iconfont"></text>
</view>
</view>
<scroll-view scroll-y="true" class="common-scrollbar pop-content">
<view class="yuyue-pop form-content" v-if="yuYueDetail">
<view class="form-item">
<view class="form-label">预约客户</view>
<view class="form-inline search-wrap">
<text>{{ yuYueDetail.member.nickname }}</text>
</view>
</view>
<view class="form-item">
<view class="form-label">客户手机号</view>
<view class="form-inline search-wrap">
<text>{{ yuYueDetail.member.mobile }}</text>
</view>
</view>
<view class="form-item">
<view class="form-label">预约门店</view>
<view class="form-inline search-wrap">{{ yuYueDetail.store_name }}</view>
</view>
<view class="form-item">
<view class="form-label">预约状态</view>
<view class="form-inline search-wrap">{{ yuYueDetail.reserve_state_name }}</view>
</view>
<view class="form-item">
<view class="form-label">预约到店时间</view>
<view class="form-inline search-wrap">
{{ $util.timeFormat(yuYueDetail.reserve_time, 'Y-m-d H:i') }}
</view>
</view>
<view class="form-item">
<view class="form-label">创建时间</view>
<view class="form-inline search-wrap">
{{ $util.timeFormat(yuYueDetail.create_time, 'Y-m-d H:i:s') }}
</view>
</view>
<view class="form-item">
<view class="form-label">预约项目</view>
<scroll-view scroll-y="true" class="form-inline search-wrap make-server">
<view class="table-container">
<view class="thead">
<view class="th">
<view class="content">项目</view>
<view class="content">员工</view>
<view class="content">时长</view>
</view>
</view>
<view class="tbody">
<view class="tr" v-for="(item, index) in yuYueDetail.item" :key="index">
<view class="td">
<view class="content">{{ item.goods_name }}</view>
<view class="content">{{ item.username ? item.username : '--' }}</view>
<view class="content">{{ item.service_length }}分钟</view>
</view>
</view>
</view>
</view>
</scroll-view>
</view>
<view class="form-item">
<view class="form-label">备注</view>
<view class="form-inline search-wrap">{{ yuYueDetail.remark ? yuYueDetail.remark : '--' }}
</view>
</view>
</view>
</scroll-view>
<view class="pop-bottom"><button class="primary-btn" @click="$refs.yuyuePop.close()">确定</button></view>
</view>
</uni-popup>
<ns-loading :layer-background="{ background: 'rgba(255,255,255,.6)' }" :default-show="false" ref="loading"></ns-loading>
<!-- #ifdef APP-PLUS -->
<ns-update></ns-update>
<!-- #endif -->
</base-page>
</template>
<script>
import uniDatetimePicker from '@/components/uni-datetime-picker/uni-datetime-picker.vue';
import selectLay from '@/components/select-lay/select-lay.vue';
import index from './public/js/index.js';
export default {
components: {
uniDatetimePicker,
selectLay
},
mixins: [index]
};
</script>
<style scoped>
.table-content>>>.tr .td .content.action {
overflow: unset;
}
.form-inline>>>.uni-icons {
height: 0.3rem;
}
</style>
<style lang="scss" scoped>
@import './public/css/index.scss';
</style>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,603 @@
import {
getReserveStatus,
getReserveConfig,
getReserveWeekday,
getReserveLists,
getAppointmentProjectList,
getEmployeeList,
editReserve,
addReserve,
cancelReserve,
getReserveDetail,
reserveToStore,
reserveConfirm,
reserveComplete
} from '@/api/reserve'
import {
getMemberInfoBySearchMember
} from '@/api/member'
export default {
data() {
return {
activeStyle: {},
active: 0,
weeks: [],
status: [],
length: 0, //周
//预约记录操作
operation: {
arrived_store: [{
title: '确认完成',
event: 'complet'
}],
wait_confirm: [{
title: '确认预约',
event: 'confirm'
}, {
title: '更改预约',
event: 'update'
}, {
title: '取消预约',
event: 'cancel'
}],
wait_to_store: [{
title: '确认到店',
event: 'tostore'
}, {
title: '取消预约',
event: 'cancel'
}]
},
yuYueTime: [], //预约时间段
yuYueConfig: {},
yuYueData: {
time: '', //时间
date: '', //日期
member_id: '',
member: {},
goods: [],
desc: '',
reserve_id: 0
},
searchMobile: '',
flag: false,
yuYueDetail: null,
weekDate: {
start: '-',
end: '-'
},
week: ['周日', '周一', '周二', '周三', '周四', '周五', '周六'],
current: '',
yuYueDateType: 'week',
goodsList: [],
allServicerList: [], //所有的员工
servicerList: [], //所有的员工
yuyueList: [],
yuyuePage: 1,
yuyueSearchText: '',
reserveId: 0,
yuyueInfo: null,
toDay: '', // 今天日期
};
},
onLoad() {
uni.hideTabBar();
this.init();
},
onReady() {
this.tabActive('tab');
},
methods: {
init() {
this.weeks = [];
this.getReserveStatusFn(); // 预约状态
this.getReserveConfigFn(); // 预约配置
this.getAppointmentProjectListFn(); // 预约项目列表
this.getEmployeeListFn(); // 员工列表
this.getWeekReserve(); // 预约看板/周
this.getYuyueList(); // 预约记录列表
let date = new Date();
var y = date.getFullYear();
var m = date.getMonth() + 1;
var d = date.getDate();
this.toDay = y + '-' + m + '-' + d;
},
tabActive(id) {
const query = uni.createSelectorQuery().in(this);
var tab;
query.select('#' + id).boundingClientRect(data => {
tab = data;
});
query.select('#' + id + ' .active-bar .text').boundingClientRect(data => {
this.activeStyle = {
width: data.width + 'px',
transform: 'translateX(' + (data.left - tab.left) + 'px)'
};
}).exec();
},
switchTab(value) {
this.active = value;
this.$nextTick(() => {
this.tabActive('tab');
});
},
swiperChange(e) {
this.active = e.detail.current;
this.$nextTick(() => {
this.tabActive('tab');
});
},
// 预约状态
getReserveStatusFn() {
getReserveStatus().then(res => {
if (res.code >= 0) {
this.status = res.data;
}
});
},
// 预约配置
getReserveConfigFn() {
getReserveConfig().then(res => {
if (res.code >= 0) {
this.yuYueConfig = res.data;
}
});
},
// ******************** 预约看板 ********************
// 查询预约记录(每周)
getWeekReserve() {
if (this.flag) return;
this.flag = true;
getReserveWeekday({
length: this.length
}).then(res => {
if (res.code >= 0) {
this.weeks = res.data;
this.$refs.loading.hide();
this.weekDate.start = this.$util.timeFormat(this.weeks[0].start, 'Y-m-d');
this.weekDate.end = this.$util.timeFormat(this.weeks[this.weeks.length - 1].end, 'Y-m-d');
for (let i in this.weeks) {
this.getReserve(i);
if (i == this.weeks.length - 1) {
setTimeout(() => {
this.flag = false;
}, 500);
}
}
}
this.flag = false;
});
},
//获取预约分页数据
getReserve(index) {
let currentWeek = this.weeks[index];
if (!currentWeek.page) currentWeek.page = 1;
getReserveLists({
page: currentWeek.page,
start: currentWeek.start,
end: currentWeek.end
}).then(res => {
if (res.code >= 0) {
let data = res.data;
if (currentWeek.page == 1) {
currentWeek.data = {
list: [],
page_count: data.page_count,
count: data.count
};
currentWeek.data['list'] = data.list;
} else {
currentWeek.data['list'] = currentWeek.data['list'].concat(data.list);
}
if (data.page_count >= currentWeek.page) currentWeek.page++;
this.$forceUpdate();
}
});
},
//上一周
prevWeek() {
this.$refs.loading.show();
--this.length;
this.getWeekReserve();
},
//下一周
nextWeek() {
this.$refs.loading.show();
++this.length;
this.getWeekReserve();
},
// ******************** 添加/编辑预约 ********************
// 查询预约项目列表
getAppointmentProjectListFn() {
getAppointmentProjectList({
page: 1,
page_size: 0
}).then(res => {
if (res.code >= 0) {
this.goodsList = res.data.list;
}
});
},
// 查询员工列表
getEmployeeListFn() {
getEmployeeList().then(res => {
if (res.code >= 0) {
this.allServicerList = res.data;
}
});
},
//添加预约
addYuyue() {
this.yuYueData = {
reserve_id: 0,
member_id: '',
member: {},
time: '', //时间
date: this.toDay, //日期
goods: [{}],
desc: '',
};
this.reserveId = 0;
this.handleYuyueDate();
this.$refs.addYuyuePop.open();
},
closeYuyuePop() {
this.yuYueData = {
time: '', //时间
date: '', //日期
member_id: '',
member: {},
goods: [{}],
desc: '',
reserve_id: 0
};
this.$refs.addYuyuePop.close();
},
// 查询会员信息
searchMember() {
if (this.searchMobile.length == 0) {
this.$util.showToast({
title: '请输入客户手机号'
});
return;
}
if (!this.$util.verifyMobile(this.searchMobile)) {
this.$util.showToast({
title: '手机号格式不正确'
});
return;
}
getMemberInfoBySearchMember({
search_text: this.searchMobile
}).then(res => {
if (res.data) {
this.yuYueData.member_id = res.data.member_id;
this.yuYueData.member = res.data;
} else {
this.yuYueData.member_id = '';
this.yuYueData.member = {};
this.$util.showToast({
title: '客户未找到'
});
}
});
},
//处理预约时间段
handleYuyueDate() {
let time_list = [];
let start = this.yuYueConfig.start / 60;
let end = this.yuYueConfig.end / 60;
let date = new Date();
var y = date.getFullYear();
var m = date.getMonth() + 1;
var d = date.getDate();
let time = date.getHours() * 60 + date.getMinutes();
let yuyue_time_stamp = this.$util.timeTurnTimeStamp(this.yuYueData.date);
let time_stamp = this.$util.timeTurnTimeStamp(y + '-' + m + '-' + d);
// if(time > start) start = time;
for (let i = start; i < end; i++) {
if (i % this.yuYueConfig.interval == 0) {
let data = {
label: (Math.floor(i / 60) < 10 ? '0' + Math.floor(i / 60) : Math.floor(i / 60)) + ':' + (i % 60 == '0' ? '00' : i % 60),
value: (Math.floor(i / 60) < 10 ? '0' + Math.floor(i / 60) : Math.floor(i / 60)) + ':' + (i % 60 == '0' ? '00' : i % 60),
disabled: false
};
if (yuyue_time_stamp < time_stamp) data.disabled = true;
if (yuyue_time_stamp == time_stamp && time > i) data.disabled = true;
let week = new Date(this.yuYueData.date).getDay();
let yuyue_week = this.yuYueConfig.week;
let config_week = [];
for (let i in yuyue_week) config_week.push(parseInt(yuyue_week[i]));
if (config_week.indexOf(week) === -1) data.disabled = true;
time_list.push(data);
}
}
this.yuYueTime = time_list;
},
// 监听预约时间
changeYuyueTime(time) {
this.yuYueData.date = time;
this.handleYuyueDate();
},
// 选择预约时间·
selectYuYueTime(index, item) {
if (index >= 0) {
this.yuYueData.time = item.value;
} else {
this.yuYueData.time = '';
}
},
// 设置项目
selectGoods(data, index) {
this.yuYueData.goods[index] = Object.assign(this.yuYueData.goods[index], JSON.parse(JSON.stringify(data)));
this.$forceUpdate();
},
// 加载员工列表
loadServicer(index) {
this.servicerList = this.allServicerList;
},
// 设置员工
selectServicer(data, index) {
this.yuYueData.goods[index].uid = data.uid;
this.yuYueData.goods[index].username = data.username;
this.$forceUpdate();
},
// 添加项目
addService() {
this.yuYueData.goods.push({});
},
// 删除项目
deleteService(index) {
if (this.yuYueData.goods.length == 1) {
this.$util.showToast({
title: '至少需要有一项项目'
});
} else {
this.yuYueData.goods.splice(index, 1);
}
},
// 预约验证
verify() {
if (!this.yuYueData.member_id) {
this.$util.showToast({
title: '请选择会员'
});
return false;
}
if (!this.yuYueData.date || !this.yuYueData.time) {
this.$util.showToast({
title: '请设置到店时间'
});
return false;
}
if (!this.yuYueData.goods.length) {
this.$util.showToast({
title: '请选择预约项目'
});
return false;
}
for (let i in this.yuYueData.goods) {
if (!this.yuYueData.goods[i]['goods_id']) {
this.$util.showToast({
title: '请选择预约项目'
});
return false;
}
}
return true;
},
// 添加/编辑预约
yuYueSubmit() {
if (this.verify()) {
if (this.flag) return;
this.flag = true;
let data = Object.assign({}, this.yuYueData);
data.goods = JSON.stringify(data.goods);
data.member = JSON.stringify(data.member);
let save = data.reserve_id ? editReserve : addReserve;
save(data).then(res => {
this.$util.showToast({
title: res.message
});
this.flag = false;
if (res.code >= 0) {
this.getWeekReserve();
if (this.reserveId) this.getYuyueInfo();
this.closeYuyuePop();
this.yuyuePage = 1;
this.getYuyueList();
}
});
}
},
//操作
yuyueEvent(event, data) {
this.reserveId = data.reserve_id;
switch (event) {
case 'info':
this.getYuYueDetail(data.reserve_id);
break;
case 'tostore':
this.tostore(data.reserve_id);
break;
case 'cancel':
this.cancel(data.reserve_id);
break;
case 'confirm':
this.confirm(data.reserve_id);
break;
case 'update': // 修改预约
this.$refs.loading.show();
this.yuYueInfo(data.reserve_id);
break;
case 'complet':
this.complet(data.reserve_id);
break;
}
},
//修改预约
yuYueInfo(reserve_id) {
if (this.flag) return;
this.flag = true;
getReserveDetail(reserve_id).then(res => {
if (res.code >= 0) {
this.yuYueData = {
reserve_id: res.data.reserve_id,
member_id: res.data.member_id,
member: res.data.member,
time: this.$util.timeFormat(res.data.reserve_time, 'H:i'),
date: this.$util.timeFormat(res.data.reserve_time, 'Y-m-d'),
goods: res.data.item,
desc: res.data.remark
};
this.handleYuyueDate();
this.$refs.addYuyuePop.open();
} else {
this.$util.showToast({
title: res.message
});
}
this.flag = false;
this.$refs.loading.hide();
});
},
// 预约详情
getYuYueDetail(reserve_id) {
if (this.flag) return;
this.flag = true;
getReserveDetail(reserve_id).then(res => {
if (res.code >= 0) {
this.yuYueDetail = res.data;
this.$refs.yuyuePop.open();
}
this.flag = false;
});
},
//预约确认
confirm(reserve_id) {
if (this.flag) return;
this.flag = true;
reserveConfirm(reserve_id).then(res => {
this.flag = false;
if (res.code >= 0) {
this.getWeekReserve();
this.getYuyueInfo();
}
this.$util.showToast({
title: res.message
});
});
},
//完成
complet(reserve_id) {
if (this.flag) return;
this.flag = true;
reserveComplete(reserve_id).then(res => {
this.flag = false;
if (res.code >= 0) {
this.getWeekReserve();
this.getYuyueInfo();
}
this.$util.showToast({
title: res.message
});
});
},
//取消预约
cancel(reserve_id) {
if (this.flag) return;
this.flag = true;
cancelReserve(reserve_id).then(res => {
this.flag = false;
if (res.code >= 0) {
this.getWeekReserve();
this.getYuyueInfo();
}
this.$util.showToast({
title: res.message
});
});
},
//确认到店
tostore(reserve_id) {
reserveToStore(reserve_id).then(res => {
this.flag = false;
if (res.code >= 0) {
this.getWeekReserve();
this.getYuyueInfo();
}
this.$util.showToast({
title: res.message
});
});
},
// ******************** 预约列表 ********************
// 获取预约分页数据
getYuyueList() {
getReserveLists({
page: this.yuyuePage,
search_text: this.yuyueSearchText
}).then(res => {
if (res.code >= 0) {
if (this.yuyuePage == 1) this.yuyueList = [];
this.yuyueList = this.yuyueList.concat(res.data.list);
if (this.yuyuePage == 1 && this.yuyueList.length > 0) {
this.reserveId = this.yuyueList[0]['reserve_id'];
this.getYuyueInfo();
}
if (res.data.page_count >= this.yuyuePage) this.yuyuePage++;
}
});
},
// 搜索预约客户
searchYuyueList() {
this.yuyuePage = 1;
this.getYuyueList();
},
selectYuyue(id) {
this.reserveId = id;
this.getYuyueInfo();
},
getYuyueInfo() {
getReserveDetail(this.reserveId).then(res => {
if (res.code >= 0) {
this.yuyueInfo = res.data;
} else {
this.yuyueInfo = null;
}
this.refreshStatus();
this.$forceUpdate();
});
},
refreshStatus() {
if (this.yuyueList && this.yuyueInfo) {
Object.keys(this.yuyueList).forEach(key => {
let data = this.yuyueList[key];
if (data.reserve_id == this.yuyueInfo['reserve_id']) {
this.yuyueList[key]['reserve_state'] = this.yuyueInfo['reserve_state'];
this.yuyueList[key]['reserve_state_name'] = this.yuyueInfo['reserve_state_name'];
}
})
}
}
}
};

View File

@@ -0,0 +1,379 @@
<template>
<base-page>
<view class="common-wrap common-form body-overhide">
<view class="common-title">电子秤设置</view>
<view class="common-form-item">
<label class="form-label">
<text class="required">*</text>
电子秤名称
</label>
<view class="form-input-inline"><input type="text" v-model="formData.name" class="form-input" /></view>
<text class="form-word-aux"></text>
</view>
<view class="common-form-item">
<label class="form-label">
<text class="required">*</text>
秤类型
</label>
<view class="form-input-inline border-none">
<view class="scale-type">
<view :class="{ active: formData.type == 'barcode' }" @click="formData.type = 'barcode'">条码秤</view>
<view :class="{ active: formData.type == 'cashier' }" @click="formData.type = 'cashier'">收银秤</view>
</view>
</view>
</view>
<view class="common-form-item">
<label class="form-label">
<text class="required">*</text>
电子秤品牌
</label>
<view class="form-input-inline border-none">
<uni-data-select v-model="formData.brand" :localdata="brandList" label=""></uni-data-select>
</view>
</view>
<view class="common-form-item">
<label class="form-label">
<text class="required">*</text>
电子秤型号
</label>
<view class="form-input-inline border-none">
<uni-data-select v-model="formData.model" :localdata="modelList"></uni-data-select>
</view>
</view>
<view class="common-form-item">
<label class="form-label">通讯方式</label>
<view class="form-inline">
<radio-group @change="networkTypeChange" class="form-radio-group">
<label class="radio form-radio-item">
<radio value="tcp" :checked="formData.network_type == 'tcp'" />
TCP
</label>
<label class="radio form-radio-item">
<radio value="serialport" :checked="formData.network_type == 'serialport'" />
串口
</label>
</radio-group>
</view>
</view>
<view class="scale-tips" v-if="formData.brand == 'dahua' && formData.model == 'TM'">
<view>使用大华电子秤前需先配置一下电子秤条码格式配置方式为</view>
<view>
使用大华电子秤厂官方提供的大华电子秤上位机软件TMA4.0连接到设备后打开基础设置 -> 系统参数设置条码格式为 FFWWWWWNNNNNC
FFWWWWWNNNNNEEEEEC设置好之后点击下载下载成功之后即配置完成
</view>
</view>
<view class="scale-tips" v-if="formData.brand == 'aclas' && formData.model == 'LS'">
<view>使用顶尖电子秤需将电子秤默认条码类型配置为7 或者 87</view>
</view>
<view v-show="formData.network_type == 'tcp'">
<view class="common-form-item">
<label class="form-label">
<text class="required">*</text>
设备ip地址
</label>
<view class="form-input-inline">
<input type="text" v-model="formData.config.ip" class="form-input" />
</view>
<text class="form-word-aux"></text>
</view>
<view class="common-form-item">
<label class="form-label">
<text class="required">*</text>
设备端口号
</label>
<view class="form-input-inline">
<input type="text" v-model="formData.config.port" class="form-input" />
</view>
<text class="form-word-aux"></text>
</view>
</view>
<view v-show="formData.network_type == 'serialport'">
<view class="common-form-item">
<label class="form-label">
<text class="required">*</text>
串口名称
</label>
<view class="form-input-inline">
<input type="text" v-model="formData.config.serialport" class="form-input" />
</view>
<text class="form-word-aux"></text>
</view>
<view class="common-form-item">
<label class="form-label">
<text class="required">*</text>
串口波特率
</label>
<view class="form-input-inline">
<input type="text" v-model="formData.config.baudrate" class="form-input" />
</view>
<text class="form-word-aux"></text>
</view>
</view>
<view class="common-btn-wrap">
<button type="primary" class="screen-btn" @click="saveFn">保存</button>
<button type="default" class="screen-btn" @click="back">返回</button>
</view>
</view>
</base-page>
</template>
<script>
import uniDataSelect from '@/components/uni-data-select/uni-data-select.vue';
import {
getScaleDetail,
getScaleBrand,
addScale,
editScale
} from '@/api/scale.js'
export default {
components: {
uniDataSelect
},
data() {
return {
brandList: [],
modelList: [],
formData: {
type: 'barcode',
name: "",
brand: "",
model: "",
config: {
ip: '',
port: '',
serialport: '',
baudrate: ''
},
network_type: 'tcp'
},
flag: false,
scaleId: 0,
scaleBrand: {}
};
},
async onLoad(option) {
await this.getScaleBrandFn();
if (option.scale_id) {
this.scaleId = option.scale_id;
this.getDetailFn();
}
},
onShow() {},
watch: {
'formData.brand': {
handler: function(nval) {
if (nval) {
let modelList = this.scaleBrand[nval].model_list
this.modelList = Object.keys(modelList).map(key => {
return {
value: key,
text: modelList[key].model_name
}
})
if (this.formData.model && !Object.keys(modelList).includes(this.formData.model)) this.formData
.model = '';
} else {
this.formData.model = '';
this.modelList = []
}
},
immediate: true
}
},
methods: {
async getScaleBrandFn() {
if (!this.addon.includes('scale')) {
this.$util.showToast({
title: '未安装电子秤插件'
});
return;
}
let res = await getScaleBrand()
if (res.code == 0) {
this.scaleBrand = res.data
let brandList = [];
Object.keys(this.scaleBrand).forEach(key => {
brandList.push({
text: this.scaleBrand[key].brand_name,
value: key
})
})
this.brandList = brandList
}
},
bradnChange(e) {
this.formData.model = e.detail.value;
},
selectBrand(e) {
this.formData.brand = e;
},
saveFn() {
if (!this.addon.includes('scale')) {
this.$util.showToast({
title: '未安装电子秤插件'
});
return;
}
if (this.check()) {
if (this.flag) return false;
this.flag = true;
let data = this.$util.deepClone(this.formData)
data.config = JSON.stringify(this.formData.config)
data.scale_id = this.scaleId
let action = '';
if (this.scaleId) {
action = editScale(data)
} else {
action = addScale(data)
}
action.then(res => {
this.flag = false;
this.$util.showToast({
title: res.message
});
if (res.code >= 0) {
setTimeout(() => {
this.$util.redirectTo('/pages/scale/list');
}, 1500);
}
});
}
},
back() {
this.$util.redirectTo('/pages/scale/list');
},
check() {
if (!this.formData.name) {
this.$util.showToast({
title: '请输入电子秤名称'
});
return false;
}
if (!this.formData.model) {
this.$util.showToast({
title: '请选择电子秤型号'
});
return false;
}
if (this.formData.network_type == 'tcp') {
if (!this.formData.config.ip) {
this.$util.showToast({
title: '请输入设备IP地址'
});
return false;
}
if (!this.formData.config.port) {
this.$util.showToast({
title: '请输入设备端口号'
});
return false;
}
}
if (this.formData.network_type == 'serialport') {
if (!this.formData.config.serialport) {
this.$util.showToast({
title: '请输入串口名称'
});
return false;
}
if (!this.formData.config.baudrate) {
this.$util.showToast({
title: '请输入串口波特率'
});
return false;
}
}
return true;
},
getDetailFn() {
if (!this.addon.includes('scale')) {
this.$util.showToast({
title: '未安装电子秤插件'
});
return;
}
getScaleDetail({
"scale_id": this.scaleId
}).then(res => {
if (res.code >= 0) {
if (res.data) {
this.formData = res.data
}
}
})
},
networkTypeChange(e) {
this.formData.network_type = e.detail.value
}
}
};
</script>
<style lang="scss" scoped>
.common-wrap {
padding: 30rpx;
background-color: #fff;
@extend %body-overhide;
}
.common-title {
font-size: 0.18rem;
margin-bottom: 0.2rem;
}
.scale-type {
display: flex;
align-items: center;
view {
width: 1rem;
height: 0.35rem;
line-height: 0.35rem;
text-align: center;
font-size: 0.14rem;
border: 0.01rem solid #e6e6e6;
border-left-width: 0;
transition: all 0.3s;
cursor: pointer;
&:hover,
&.active {
border-color: $primary-color;
color: $primary-color;
background-color: var(--primary-color-light-9);
box-shadow: -0.01rem 0 0 0 $primary-color;
}
&:first-child {
border-left-width: 0.01rem;
box-shadow: none;
}
}
}
.border-none {
border: none !important;
}
/deep/ .uni-select {
border-radius: 0;
}
.scale-tips {
display: inline-block;
padding: .1rem;
border-radius: .05rem;
color: $primary-color !important;
border: .01rem solid $primary-color !important;
background-color: var(--primary-color-light-9) !important;
margin-left: 1.1rem;
margin-bottom: 0.1rem;
}
</style>

View File

@@ -0,0 +1,239 @@
<template>
<base-page>
<view class="scalelist">
<view class="scalelist-box">
<view class="scalelist-left">
<view class="scale-title">
电子秤
<text class="iconfont icongengduo1"></text>
</view>
<view class="scale-list-wrap">
<block v-if="list.length > 0">
<scroll-view scroll-y="true" class="scale-list-scroll all-scroll" @scrolltolower="getList">
<view class="item" @click="scaleSelect(item, index)" v-for="(item, index) in list" :key="index" :class="index == selectScaleKeys ? 'itemhover' : ''">
<view class="item-right w-full">
<view class="flex justify-between w-full">
<view class="scale-name">{{ item.name }}<text class="scale-type-tag">{{ item.type == 'cashier' ? '收银秤': '条码秤' }}</text></view>
<view class="flex items-center" v-if="item.connect_status">
<text class="status-icon success"></text>已连接
</view>
<view class="flex items-center" v-else>
<text class="status-icon fail"></text>未连接
</view>
</view>
<view class="scale-money">{{ item.brand_name }}-{{ item.model_name }}</view>
</view>
</view>
</scroll-view>
</block>
<view class="notYet" v-else-if="!one_judge && list.length == 0">暂无电子秤</view>
</view>
<view class="add-printer">
<button type="default" class="primary-btn" @click="addScale">添加电子秤</button>
</view>
</view>
<view class="scalelist-right" v-show="!one_judge">
<view class="scale-title">电子秤详情</view>
<view class="scale-information">
<block v-if="JSON.stringify(detail) != '{}'">
<view class="title">基本信息</view>
<view class="information-box">
<view class="box-left">
<view class="information">
<view>电子秤名称</view>
<view>{{ detail.name }}</view>
</view>
<view class="information">
<view>电子秤类型</view>
<view>{{ detail.type == 'cashier' ? '收银秤' : '条码秤' }}</view>
</view>
<view class="information">
<view>电子秤品牌</view>
<view>{{ detail.brand_name }}</view>
</view>
<view class="information">
<view>电子秤型号</view>
<view>{{ detail.model_name }}</view>
</view>
</view>
</view>
</block>
<block v-else>
<image class="cart-empty" src="@/static/cashier/cart_empty.png" mode="widthFix"/>
</block>
</view>
<view class="button-box" v-if="JSON.stringify(detail) != '{}'">
<button class="default-btn" @click="$refs.deletePop.open()">删除</button>
<button class="default-btn" @click="editScale(detail.scale_id)">修改</button>
</view>
</view>
</view>
</view>
<!-- 删除 -->
<uni-popup ref="deletePop" type="center">
<view class="confirm-pop">
<view class="title">确定要删除吗</view>
<view class="btn">
<button type="primary" class="default-btn btn save" @click="$refs.deletePop.close()">取消</button>
<button type="primary" class="primary-btn btn" @click="deleteScaleFn(detail.scale_id)">确定</button>
</view>
</view>
</uni-popup>
</base-page>
</template>
<script>
import {
getScaleList,
getScaleDetail,
deleteScale
} from '@/api/scale.js'
var self;
export default {
data() {
return {
selectScaleKeys: 0,
search_text: '',
page: 1,
// 每次返回数据数
page_size: 8,
// 第一次请求列表做详情渲染判断
one_judge: true,
//详情数据
detail: {},
brandList: {
yilianyun: '易联云',
'365': '365'
},
flag: false,
template: {},
list: [],
connectSuccess: []
};
},
onLoad() {
// 初始化请求打印机列表数据
this.getList();
self = this;
},
methods: {
switchStoreAfter() {
this.page = 1;
this.list = [];
this.detail = {};
this.one_judge = false;
this.getList()
},
getList() {
if (!this.addon.includes('scale')) {
this.$util.showToast({
title: '未安装电子秤插件'
});
return;
}
getScaleList({
page: this.page,
page_size: this.page_size,
}).then(res => {
if (res.data.list.length == 0 && this.one_judge) {
this.detail = {};
this.one_judge = false;
}
if (res.code >= 0 && res.data.list.length != 0) {
this.page += 1;
if (this.list.length == 0) {
this.list = res.data.list;
} else {
this.list = this.list.concat(res.data.list);
}
// 检测设备是否连接
this.checkConnect();
//初始时加载一遍详情数据
if (this.one_judge) {
this.getDetailFn(this.list[0].scale_id);
}
}
})
},
scaleSelect(item, keys) {
this.selectScaleKeys = keys;
this.getDetailFn(item.scale_id);
},
addScale() {
this.$util.redirectTo('/pages/scale/add');
},
editScale(scale_id) {
this.$util.redirectTo('/pages/scale/add', {
scale_id: scale_id
});
},
getDetailFn(scale_id) {
getScaleDetail({
scale_id
}).then(res => {
if (res.code == 0) {
this.detail = res.data;
this.one_judge = false;
}
})
},
deleteScaleFn(scale_id) {
if (this.flag) return;
this.flag = true;
deleteScale({scale_id}).then(res => {
this.flag = false;
if (res.code >= 0) {
this.page = 1;
this.list = [];
this.one_judge = true;
this.$refs.deletePop.close()
this.getList();
} else {
this.$util.showToast({
title: res.message
});
}
})
},
checkConnect() {
if (typeof window.POS_DATA_CALLBACK == 'function') delete window.POS_DATA_CALLBACK;
/**
* 商品同步数据回调
* @param {Object} text
*/
window.POS_DATA_CALLBACK = function (text) {
let data = text.split(':');
let index = parseInt(data[0]);
switch (data[1]) {
case 'PingWeigher':
self.$set(self.list[index], 'connect_status', parseInt(data[3]));
break;
}
};
try {
let weigher = this.list.map(item => {
item.config = typeof item.config == 'string' ? JSON.parse(item.config) : scale.config;
return item
});
this.$pos.send('PingWeigher', JSON.stringify({
weigher
}));
} catch (e) {
}
}
}
};
</script>
<style scoped lang="scss">
@import './public/css/scale.scss';
</style>

View File

@@ -0,0 +1,356 @@
.scalelist {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: space-between;
box-sizing: border-box;
.scalelist-box {
width: 100%;
height: 100%;
background: #ffffff;
display: flex;
.scalelist-left {
width: 5rem;
height: 100%;
border-right: 0.01rem solid #e6e6e6;
box-sizing: border-box;
display: flex;
flex-direction: column;
.notYet {
color: #e6e6e6;
font-size: 0.4rem;
margin-top: 3rem;
text-align: center;
}
.add-printer {
padding: 0.24rem 0.2rem;
background: #fff;
button {
height: .4rem;
line-height: .4rem;
}
}
.scale-title {
text-align: center;
line-height: 0.6rem;
font-size: 0.18rem;
font-weight: 500;
height: 0.6rem;
border-bottom: 0.01rem solid #e6e6e6;
box-sizing: border-box;
position: relative;
.icongengduo1 {
position: absolute;
top: 50%;
right: 0.2rem;
transform: translateY(-50%);
font-size: 0.3rem;
color: $primary-color;
}
}
.scale-list-wrap {
flex: 1;
height: 0;
}
.scale-list-scroll {
width: 100%;
height: 100%;
.itemhover {
background: var(--primary-color-light-9);
}
.item {
width: 100%;
display: flex;
align-items: center;
padding: 0.2rem;
box-sizing: border-box;
border-bottom: 0.01rem solid #e6e6e6;
image {
width: 0.7rem;
height: 0.7rem;
margin-right: 0.1rem;
}
.item-right {
display: flex;
flex-direction: column;
justify-content: space-between;
height: 0.6rem;
.scale-name {
font-size: 0.16rem;
}
.scale-money {
font-size: 0.14rem;
}
}
}
}
}
.scalelist-right {
width: 0;
flex: 1;
height: 100%;
border-right: 0.01rem solid #e6e6e6;
box-sizing: border-box;
position: relative;
.scale-title {
text-align: center;
line-height: 0.6rem;
font-size: 0.18rem;
font-weight: 500;
height: 0.6rem;
border-bottom: 0.01rem solid #e6e6e6;
box-sizing: border-box;
position: relative;
.icongengduo1,.iconguanbi1 {
position: absolute;
top: 50%;
right: 0.2rem;
transform: translateY(-50%);
font-size: 0.3rem;
color: $primary-color;
cursor: pointer;
}
}
.scale-information {
width: 100%;
padding: 0.2rem 0.2rem 0.88rem 0.2rem;
box-sizing: border-box;
height: calc(100% - 0.6rem);
overflow: auto;
position: relative;
.title {
font-size: 0.18rem;
margin-bottom: 0.32rem;
}
.title2 {
margin-bottom: 0.35rem;
}
.information-box {
display: flex;
justify-content: space-between;
.box-left {
width: 5rem;
.information {
width: 100%;
padding-left: 0.1rem;
box-sizing: border-box;
display: flex;
align-items: center;
margin-bottom: 0.15rem;
view {
color: #303133;
font-size: 0.14rem;
}
view:nth-child(1) {
width: 1.3rem;
margin-right: 0.16rem;
text-align: right;
}
view:nth-child(2) {
width: 74%;
margin-right: 0.23rem;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
}
.information:last-child {
margin-bottom: 0.35rem;
}
}
.scale-img {
width: 1.5rem;
height: 1.5rem;
}
}
.table {
width: 100%;
height: 2.6rem;
box-sizing: border-box;
.table-all {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 0.38rem;
box-sizing: border-box;
.table-td {
font-size: 0.14rem;
text-align: left;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
}
.table-th {
height: 0.56rem;
background: #f7f8fa;
}
.table-tb {
width: 100%;
height: calc(100% - 0.56rem);
.table-tr {
height: 0.7rem;
border-bottom: 0.01rem solid #e6e6e6;
box-sizing: border-box;
.table-td {
image {
width: 0.5rem;
height: 0.5rem;
}
text-overflow: -o-ellipsis-lastline;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
line-clamp: 2;
-webkit-box-orient: vertical;
}
}
}
}
}
}
}
}
view {
color: #303133;
}
/deep/ .uni-scroll-view::-webkit-scrollbar {
width: 0.05rem;
height: 0.3rem;
}
/deep/ .uni-scroll-view::-webkit-scrollbar-thumb {
border-radius: 0.1rem;
box-shadow: inset 0 0 0.05rem rgba(0, 0, 0, 0.2);
background: rgba(193, 193, 193, 1);
}
.scale-information::-webkit-scrollbar {
width: 0.05rem;
height: 0.3rem;
}
.scale-information::-webkit-scrollbar-thumb {
border-radius: 0.1rem;
box-shadow: inset 0 0 0.05rem rgba(0, 0, 0, 0.2);
background: rgba(193, 193, 193, 1);
}
.button-box {
position: absolute;
width: 100%;
right: 0;
bottom: 0;
background-color: #fff;
display: flex;
align-items: center;
justify-content: flex-end;
padding: 0.24rem 0.2rem;
box-sizing: border-box;
button {
min-width: 0.9rem;
height: 0.4rem;
line-height: 0.4rem;
margin: 0;
margin-left: 0.1rem;
}
}
.cart-empty {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 2.1rem;
}
.form-content {
margin-top: 0.2rem;
.form-item {
margin-bottom: 0.1rem;
display: flex;
.form-label {
width: 1.3rem;
text-align: right;
padding-right: 0.1rem;
box-sizing: border-box;
height: 0.32rem;
line-height: 0.32rem;
.required {
color: red;
margin-right: 0.03rem;
}
}
.form-inline {
width: 2.4rem;
line-height: 0.32rem;
margin-right: 0.1rem;
box-sizing: border-box;
.form-input {
border-width: 0.01rem;
border-style: solid;
background-color: #fff;
color: rgba(0, 0, 0, 0.85);
border-radius: 0.02rem;
padding-left: 0.1rem;
height: 0.32rem;
line-height: 0.32rem;
font-size: 0.14rem;
border-color: #e6e6e6;
}
.form-textarea {
border-width: 0.01rem;
border-style: solid;
background-color: #fff;
color: rgba(0, 0, 0, 0.85);
border-radius: 0.02rem;
padding-left: 0.1rem;
line-height: 0.32rem;
font-size: 0.14rem;
border-color: #e6e6e6;
height: 1rem;
}
button {
width: calc(50% - 0.05rem);
display: inline-block;
margin-right: 0.1rem;
&:nth-child(2) {
margin-right: 0;
}
}
}
}
}
.order-type{
margin-right: 0.1rem;
}
.status-icon {
width: .05rem;
height: .05rem;
border-radius: 50%;
margin-right: .05rem;
&.success {
background: limegreen;
}
&.fail {
background: red;
}
}
.scale-type-tag {
border: 0.01rem solid $primary-color;
color: $primary-color;
background-color: #fff;
border-radius: 0.02rem;
width: -webkit-fit-content;
width: fit-content;
padding: 0.01rem 0.05rem;
margin-left: 0.10rem
}

View File

@@ -0,0 +1,608 @@
<template>
<base-page>
<view class="common-wrap">
<view class="title">营业数据</view>
<view class="choice-day">
<view class="date-btn" :class="dateType == 'today' ? 'select' : ''" @click="switchDateType('today')" value="today">今日</view>
<view class="date-btn" :class="dateType == 'yesterday' ? 'select' : ''" @click="switchDateType('yesterday')" value="yesterday">昨日</view>
<view class="date-btn" :class="dateType == 'week' ? 'select' : ''" @click="switchDateType('week')" value="week">7日内</view>
<view class="date-btn" :class="dateType == 'month' ? 'select' : ''" @click="switchDateType('month')" value="month">30日内</view>
<view class="date-btn" :class="dateType == 'custom' ? 'select' : ''" @click="switchDateType('custom')" value="custom">自定义</view>
<view class="report text-color">
<text class="move iconfont iconicon-test"></text>
<text></text>
</view>
</view>
<template v-if="businessData">
<view class="title-port">线下收银</view>
<view class="money">
<view class="estimate" :class="statType == 'expected_earnings_total_money' ? 'estimate-active' : ''">
<view class="income">
<text class="income-name">预计收入()</text>
<!-- <uni-dropdown>
<view class="action" slot="dropdown-link"><text class="iconfont iconbangzhu js-prompt-top"></text></view>
<view slot="dropdown">
<view class="dropdown-content-box">
<view class="text">弹框展示内容</view>
<view class="arrow"></view>
</view>
</view>
</uni-dropdown> -->
</view>
<view class="num-money">
<text class="last_income">{{ businessData.expected_earnings_total_money || 0.0 }}</text>
<text class="detail" @click="switchStatType('expected_earnings_total_money')">查看详情</text>
</view>
</view>
<view class="estimate" :class="statType == 'billing_money' ? 'estimate-active' : ''">
<view class="income">
<text class="income-name">开单金额数()</text>
<!-- <uni-dropdown>
<view class="action" slot="dropdown-link"><text class="iconfont iconbangzhu js-prompt-top"></text></view>
<view slot="dropdown">
<view class="dropdown-content-box">
<view class="text">弹框展示内容</view>
<view class="arrow"></view>
</view>
</view>
</uni-dropdown> -->
</view>
<view class="num-money">
<text class="last_income">{{ businessData.billing_money || 0.0 }}</text>
<text class="detail" @click="switchStatType('billing_money')">查看详情</text>
</view>
</view>
<view class="estimate" :class="statType == 'billing_count' ? 'estimate-active' : ''">
<view class="income"><text class="income-name">开单数量</text></view>
<view class="num-money">
<text class="last_income">{{ businessData.billing_count || 0 }}</text>
<text class="detail" @click="switchStatType('billing_count')">查看详情</text>
</view>
</view>
<view class="estimate" :class="statType == 'buycard_money' ? 'estimate-active' : ''">
<view class="income"><text class="income-name">办卡金额数()</text></view>
<view class="num-money">
<text class="last_income">{{ businessData.buycard_money || 0.0 }}</text>
<text class="detail" @click="switchStatType('buycard_money')">查看详情</text>
</view>
</view>
<view class="estimate" :class="statType == 'buycard_count' ? 'estimate-active' : ''">
<view class="income"><text class="income-name">办卡数</text></view>
<view class="num-money">
<text class="last_income">{{ businessData.buycard_count || 0 }}</text>
<text class="detail" @click="switchStatType('buycard_count')">查看详情</text>
</view>
</view>
<view class="estimate" :class="statType == 'recharge_money' ? 'estimate-active' : ''">
<view class="income"><text class="income-name">会员充值金额()</text></view>
<view class="num-money">
<text class="last_income">{{ businessData.recharge_money || 0.0 }}</text>
<text class="detail" @click="switchStatType('recharge_money')">查看详情</text>
</view>
</view>
<view class="estimate" :class="statType == 'recharge_count' ? 'estimate-active' : ''">
<view class="income"><text class="income-name">会员充值数量</text></view>
<view class="num-money">
<text class="last_income">{{ businessData.recharge_count || 0 }}</text>
<text class="detail" @click="switchStatType('recharge_count')">查看详情</text>
</view>
</view>
<view class="estimate" :class="statType == 'refund_money' ? 'estimate-active' : ''">
<view class="income"><text class="income-name">会员退款金额()</text></view>
<view class="num-money">
<text class="last_income">{{ businessData.refund_money || 0.0 }}</text>
<text class="detail" @click="switchStatType('refund_money')">查看详情</text>
</view>
</view>
<view class="estimate" :class="statType == 'refund_count' ? 'estimate-active' : ''">
<view class="income"><text class="income-name">会员退款数量</text></view>
<view class="num-money">
<text class="last_income">{{ businessData.refund_count || 0 }}</text>
<text class="detail" @click="switchStatType('refund_count')">查看详情</text>
</view>
</view>
<view class="estimate" :class="statType == 'order_member_count' ? 'estimate-active' : ''">
<view class="income"><text class="income-name">门店下单会员数</text></view>
<view class="num-money">
<text class="last_income">{{ businessData.order_member_count || 0 }}</text>
<text class="detail" @click="switchStatType('order_member_count')">查看详情</text>
</view>
</view>
<view class="estimate" :class="statType == 'balance_money' ? 'estimate-active' : ''">
<view class="income"><text class="income-name">会员余额消费金额</text></view>
<view class="num-money">
<text class="last_income">{{ businessData.balance_money || 0.0 }}</text>
<text class="detail" @click="switchStatType('balance_money')">查看详情</text>
</view>
</view>
</view>
</template>
<template v-if="businessData">
<view class="title-port">线上商城</view>
<view class="money">
<view class="estimate" :class="statType == 'online_pay_money' ? 'estimate-active' : ''">
<view class="income"><text class="income-name">商城订单()</text></view>
<view class="num-money">
<text class="last_income">{{ businessData.online_pay_money || 0.0 }}</text>
<text class="detail" @click="switchStatType('online_pay_money')">查看详情</text>
</view>
</view>
<view class="estimate" :class="statType == 'online_refund_money' ? 'estimate-active' : ''">
<view class="income"><text class="income-name">退款维权()</text></view>
<view class="num-money">
<text class="last_income">{{ businessData.online_refund_money || 0.0 }}</text>
<text class="detail" @click="switchStatType('online_refund_money')">查看详情</text>
</view>
</view>
</view>
</template>
</view>
<uni-popup ref="customTime">
<view class="pop-box">
<view class="pop-header">
<view class="pop-header-text">自定义时间选择</view>
<view class="pop-header-close" @click="$refs.customTime.close()">
<text class="iconguanbi1 iconfont"></text>
</view>
</view>
<view class="pop-content ">
<uni-datetime-picker v-model="timeObj.custom" @change="changeTime" :end="endDate" :clearIcon="false" type="datetimerange" rangeSeparator="至" />
</view>
<view class="pop-bottom"><button class="primary-btn" @click="getStatData()">确定</button></view>
</view>
</uni-popup>
<uni-popup ref="chartsPop">
<view class="pop-box charts-pop">
<view class="pop-header">
<view class="pop-header-text">运营数据图表展示</view>
<view class="pop-header-close" @click="$refs.chartsPop.close()">
<text class="iconguanbi1 iconfont"></text>
</view>
</view>
<view class="pop-content">
<qiun-data-charts type="line" :chartData="chartData" :eopts="{ seriesTemplate: { smooth: true } }" :ontouch="true" :opts="chartsOpts" />
</view>
<!-- <view class="pop-bottom"><button class="primary-btn" @click="getStatData()">确定</button></view> -->
</view>
</uni-popup>
</base-page>
</template>
<script>
import {
getStatDay,
getStatHour,
getStatTotal
} from '@/api/stat.js';
export default {
data() {
return {
statType: 'expected_earnings_total_money',
statTypeArr: {
expected_earnings_total_money: '预计收入',
billing_money: '开单金额数',
billing_count: '开单数量',
buycard_money: '办卡金额数',
buycard_count: '办卡数',
recharge_money: '会员充值金额',
recharge_count: '会员充值数量',
refund_money: '会员退款金额',
refund_count: '会员退款数量',
order_member_count: '门店下单会员数',
balance_money: '会员余额消费金额',
online_pay_money: '商城订单',
online_refund_money: '退款维权'
},
dateType: 'today',
timeObj: {
today: [],
yesterday: [],
week: [],
month: [],
custom: []
},
chartData: {
categories: [],
series: []
},
businessData: null,
chartsOpts: {
enableScroll: true,
xAxis: {
scrollShow: true,
itemCount: 24,
disableGrid: true
}
}
};
},
onLoad() {
this.setDate();
this.getStatData();
},
onShow() {
let date = new Date();
var y = date.getFullYear();
var m = date.getMonth() + 1;
var d = date.getDate();
this.endDate = y + '-' + m + '-' + d + ' 23:59:59';
},
methods: {
// 重置图表数据
resetChartData() {
this.chartData.categories = [];
this.chartData.series = [];
},
setDate() {
let time = this.$util.timeTurnTimeStamp(this.$util.timeFormat(Date.now() / 1000, 'Y-m-d'));
this.timeObj.today = [time, time + 86399];
this.timeObj.yesterday = [time - 86400, time - 1];
this.timeObj.week = [time - 604800, time];
this.timeObj.month = [time - 2592000, time];
},
switchDateType(type) {
this.dateType = type;
if (type == 'custom') {
this.$refs.customTime.open();
return false;
}
if (type == 'month') this.chartsOpts.xAxis.itemCount = 10;
else this.chartsOpts.xAxis.itemCount = 24;
this.getStatData();
},
switchStatType(type) {
this.statType = type;
this.$refs.chartsPop.open();
this.resetChartData();
this.getStatData();
setTimeout(() => {
this.getChartData();
}, 500);
},
changeTime(e) {
this.timeObj.custom = e;
this.chartsOpts.xAxis.itemCount = 10;
},
getStatData() {
if (this.dateType == 'custom') {
this.$refs.customTime.close();
this.timeObj.custom[0] = this.$util.timeTurnTimeStamp(this.timeObj.custom[0]) *
1000; // 解决自定义数据保存之后再次点击出现的数据错乱
this.timeObj.custom[1] = this.$util.timeTurnTimeStamp(this.timeObj.custom[1]) *
1000; // 解决自定义数据保存之后再次点击出现的数据错乱
}
this.getBusinessData();
},
getChartData() {
let data = {};
data.start_time = this.timeObj[this.dateType][0];
let action = '';
if (this.dateType == 'today' || this.dateType == 'yesterday') {
action = getStatHour(data);
} else {
data.end_time = this.timeObj[this.dateType][1];
action = getStatDay(data);
}
action.then(res => {
if (res.code >= 0) {
this.chartData.series = [];
this.chartData.series.push({
data: res.data[this.statType],
name: this.statTypeArr[this.statType]
});
this.chartData.categories = res.data.time;
}
});
},
getBusinessData() {
let data = {};
data.start_time = this.dateType == 'custom' ? parseInt(this.timeObj[this.dateType][0] / 1000) : parseInt(this.timeObj[this.dateType][0]);
data.end_time = this.dateType == 'custom' ? parseInt(this.timeObj[this.dateType][1] / 1000) : parseInt(this.timeObj[this.dateType][1]);
getStatTotal(data).then(res => {
if (res.code >= 0) {
this.businessData = res.data;
}
});
}
}
};
</script>
<style>
.pop-content>>>.uni-icons {
line-height: 0.32rem;
}
</style>
<style lang="scss" scoped>
.common-wrap {
padding: 0.2rem 0.2rem 0.6rem;
height: 100vh;
box-sizing: border-box;
overflow-y: auto;
}
.title {
display: flex;
margin-bottom: 0.2rem;
font-size: 0.16rem;
font-family: Source Han Sans CN;
font-weight: bold;
line-height: 0.2rem;
}
.title-port {
margin-bottom: 0.2rem;
margin-left: 0.1rem;
font-size: 0.16rem;
font-family: Source Han Sans CN;
font-weight: bold;
line-height: 0.2rem;
}
.choice-day {
display: flex;
margin-bottom: 0.2rem;
}
.choice-time {
margin-top: 0.09rem;
font-size: 0.12rem;
font-family: Source Han Sans CN;
font-weight: 400;
line-height: 0.36rem;
}
.report {
display: flex;
justify-content: flex-end;
margin-right: 0.2rem;
font-size: 0.14rem;
font-family: Source Han Sans CN;
font-weight: 400;
line-height: 0.36rem;
cursor: pointer;
}
.move {
margin-right: 0.06rem;
}
.money {
display: flex;
flex-wrap: wrap;
margin-top: 0.2rem;
.estimate {
width: calc((100% - 0.85rem) / 5);
margin: 0 0.08rem 0.2rem;
padding: 0.2rem;
background: #fff;
border: 0.01rem solid #eee;
border-radius: 0.02rem;
cursor: pointer;
position: relative;
box-sizing: border-box;
.income {
display: flex;
flex-direction: row;
box-sizing: border-box;
line-height: 0.2rem;
.income-name {
font-size: 0.16rem;
}
}
.num-money {
.last_income {
display: block;
margin: 0.15rem 0;
font-size: 0.24rem;
font-weight: 500;
line-height: 0.2rem;
}
.detail {
display: block;
text-align: right;
color: $primary-color;
font-size: $uni-font-size-sm;
position: relative;
bottom: -0.05rem;
}
}
}
.estimate:last-child {
margin-right: 0;
}
}
.yesterday {
display: flex;
flex-wrap: wrap;
font-size: 0.12rem;
}
.top-num {
display: flex;
margin-left: 0.05rem;
font-size: 0.12rem;
font-weight: 400;
}
.date-btn {
height: 0.42rem;
line-height: 0.42rem;
font-size: 0.14rem;
padding: 0 0.3rem;
box-sizing: border-box;
border: 0.01rem solid #d2d2d2;
cursor: pointer;
border-right: none;
border-left: none;
position: relative;
}
.date-btn:nth-child(6)::after {
border-radius: 0 0.02rem 0.02rem 0;
}
.date-btn:first-child::after {
border-radius: 0.02rem 0 0 0.02rem;
}
.date-btn:first-child {
border-radius: 0.02rem 0 0 0.02rem;
}
.date-btn::after {
content: '';
position: absolute;
top: -0.01rem;
left: 0;
bottom: -0.01rem;
right: -0.01rem;
border-right: 0.01rem solid #d2d2d2;
border-left: 0.01rem solid #d2d2d2;
}
.select {
color: #fff;
background-color: $primary-color;
border-color: $primary-color;
}
.select::after {
z-index: 2;
border-color: $primary-color;
}
.select:first-child {
border-radius: 0.02rem 0 0 0.02rem;
}
.seleced:nth-child(6) {
border-radius: 0 0.02rem 0.02rem 0;
}
.c-datepicker-picker {
z-index: 99999999 !important;
}
.yesterday {
display: none;
}
.dropdown-content-box {
padding: 0.05rem 0;
margin-top: 0.05rem;
background-color: #fff;
border: 0.01rem solid #ebeef5;
border-radius: 0.04rem;
box-shadow: 0 0.01rem 0.12rem 0 rgba(0, 0, 0, 0.1);
position: relative;
.arrow {
position: absolute;
top: -0.06rem;
right: 0.06rem;
width: 0;
height: 0;
border-left: 0.06rem solid transparent;
border-right: 0.06rem solid transparent;
border-bottom: 0.06rem solid #fff;
}
.text {
display: flex;
align-items: center;
justify-content: center;
margin: 0;
padding: 0 0.1rem;
transition: all 0.3s;
font-size: 0.12rem;
width: 1.5rem;
box-sizing: border-box;
text-align: left;
line-height: 1.5;
}
}
.js-prompt-top {
color: #c8c9cc;
font-size: 0.14rem;
z-index: 999;
margin-left: 0.05rem;
cursor: pointer;
}
// pop弹框
.pop-box {
background: #ffffff;
width: 6rem;
height: 3.38rem;
.pop-header {
padding: 0 0.15rem 0 0.2rem;
height: 0.5rem;
line-height: 0.5rem;
border-bottom: 0.01rem solid #f0f0f0;
font-size: 0.14rem;
color: #333;
overflow: hidden;
border-radius: 0.02rem 0.2rem 0 0;
box-sizing: border-box;
display: flex;
justify-content: space-between;
.pop-header-text {}
.pop-header-close {
cursor: pointer;
text {
font-size: 0.18rem;
}
}
}
.pop-content {
height: calc(100% - 1.05rem);
// overflow-y: scroll;
padding: 0.2rem;
box-sizing: border-box;
}
.pop-bottom {
padding: 0.1rem 0.2rem;
border-top: 0.01rem solid #eee;
button {
width: 100%;
line-height: 0.35rem;
height: 0.35rem;
}
}
}
.charts-pop {
width: 9.5rem;
height: 5.4rem;
background-color: #fff;
.pop-content {
width: 100%;
height: calc(100% - 1rem);
}
}
</style>

View File

@@ -0,0 +1,398 @@
<template>
<base-page>
<view class="goodslist">
<view class="goodslist-box">
<view class="goodslist-left">
<view class="goods-title">
调拨单查询
<text class="iconfont icongengduo1"></text>
</view>
<view class="goods-search">
<view class="search">
<text class="iconfont icon31sousuo"></text>
<input type="text" v-model="search_text" @input="search" placeholder="搜索调拨单号" />
</view>
</view>
<scroll-view scroll-y="true" class="goods-list-scroll" :show-scrollbar="false" @scrolltolower="getListData">
<view class="item" @click="getDetailData(item.allot_id, index)" v-for="(item, index) in list" :key="index" :class="{ itemhover: selectGoodsKeys == index }">
<view class="title">
<view>{{ item.allot_no }}</view>
<view>{{ item.goods_money }}</view>
</view>
<view class="other-info">
<view>出库门店{{ item.output_store_name }}</view>
<view>入库门店{{ item.input_store_name }}</view>
<view>{{ $util.timeFormat(item.allot_time) }}</view>
</view>
</view>
<view class="notYet" v-if="!one_judge && !list.length">暂无数据</view>
</scroll-view>
<view class="add-wastage">
<button type="default" class="primary-btn" v-if="globalStoreInfo.stock_type == 'store'" @click="add()">添加调拨单</button>
</view>
</view>
<view class="goodslist-right">
<view class="goods-title">调拨单详情</view>
<view class="order-information" v-if="Object.keys(detail).length">
<view class="order-status">基本信息</view>
<view class="order-types">
<view class="type type1">
<view>调拨单号</view>
<view>{{ detail.allot_no }}</view>
</view>
<view class="type type1">
<view>制单人</view>
<view>{{ detail.operater_name || '--' }}</view>
</view>
<view class="type type1">
<view>调拨时间</view>
<view class="message">{{ $util.timeFormat(detail.allot_time) }}</view>
</view>
<view class="type type1">
<view>出库门店</view>
<view class="message">{{ detail.output_store_name }}</view>
</view>
<template v-if="detail.out_info">
<view class="type type1">
<view>出库时间</view>
<view class="message">{{ detail.out_info.create_time }}</view>
</view>
<view class="type type1">
<view>经办人</view>
<view class="message">{{ detail.out_info.operater_name }}</view>
</view>
<view class="type type1">
<view>状态</view>
<view class="message">{{ detail.out_info.status_name }}</view>
</view>
<view class="type type1" v-if="detail.out_info.verifier_name">
<view>审核人</view>
<view class="message">{{ detail.out_info.verifier_name }}</view>
</view>
<view class="type type1" v-if="detail.out_info.audit_time">
<view>审核时间</view>
<view class="message">{{ detail.out_info.audit_time }}</view>
</view>
<view class="type type1" v-if="detail.out_info.status == -1">
<view>拒绝理由</view>
<view class="message">{{ detail.out_info.refuse_reason }}</view>
</view>
</template>
<view class="type type1">
<view>入库门店</view>
<view class="message">{{ detail.input_store_name }}</view>
</view>
<template v-if="detail.input_info">
<view class="type type1">
<view>入库时间</view>
<view class="message">{{ detail.input_info.create_time }}</view>
</view>
<view class="type type1">
<view>经办人</view>
<view class="message">{{ detail.input_info.operater_name }}</view>
</view>
<view class="type type1">
<view>状态</view>
<view class="message">{{ detail.input_info.status_name }}</view>
</view>
<view class="type type1" v-if="detail.input_info.verifier_name">
<view>审核人</view>
<view class="message">{{ detail.input_info.verifier_name }}</view>
</view>
<view class="type type1" v-if="detail.input_info.audit_time">
<view>审核时间</view>
<view class="message">{{ detail.input_info.audit_time }}</view>
</view>
<view class="type type1" v-if="detail.input_info.status == -1">
<view>拒绝理由</view>
<view class="message">{{ detail.input_info.refuse_reason }}</view>
</view>
</template>
<view class="type type1">
<view>备注</view>
<view class="message">{{ detail.remark }}</view>
</view>
</view>
<view class="goods-info">
<view class="title">商品明细</view>
<view class="table">
<view class="table-th table-all">
<view class="table-td" style="width:45%;justify-content: flex-start;">商品名称/规格/条形码</view>
<view class="table-td" style="width:15%">单位</view>
<view class="table-td" style="width:10%">数量</view>
<view class="table-td" style="width:15%">成本价()</view>
<view class="table-td" style="width:15%;justify-content: flex-end;">金额()</view>
</view>
<view class="table-tr table-all" v-for="(item, index) in detail.goods_sku_list_array" :key="index">
<view class="table-td table-goods-name" style="width:45%;justify-content: flex-start;">
<image :src="$util.img(item.goods_img)" mode="aspectFill" />
<text class="multi-hidden">{{ item.goods_sku_name }}</text>
</view>
<view class="table-td" style="width:15%">{{ item.goods_unit || '件' }}</view>
<view class="table-td" style="width:10%">{{ item.goods_num }}</view>
<view class="table-td" style="width:15%">{{ item.goods_price }}</view>
<view class="table-td" style="width:15%;justify-content: flex-end;">{{ parseFloat(item.goods_sum).toFixed(2) }}</view>
</view>
</view>
<view class="total-money-num">
<view class="box">
<view>商品种类</view>
<view class="money">{{ detail.goods_count }}</view>
</view>
<view class="box">
<view>商品数量</view>
<view class="money">{{ detail.goods_price }}{{ detail.goods_unit }}</view>
</view>
<view class="box total">
<view>合计金额</view>
<view class="money">{{ parseFloat(detail.goods_total_price).toFixed(2) }}</view>
</view>
</view>
<view class="action-box">
<!-- 只有经办人才能操作入库单 -->
<template v-if="(detail.status == 1 || detail.status == -1) && detail.operater == detail.uid">
<button type="primary" class="default-btn" @click="open('deleteWastagePop')">删除</button>
<button type="primary" class="default-btn" @click="edit">编辑</button>
</template>
<!-- 只有管理员和拥有单据审核权限的才能审核 -->
<template v-if="detail.status == 1 && detail.is_audit == 0">
<button type="primary" class="default-btn" @click="open('refuseWastagePop')">审核拒绝</button>
<button type="primary" class="primary-btn" @click="open('agreeWastagePop')">审核通过</button>
</template>
</view>
</view>
</view>
<block v-else-if="!one_judge && !Object.keys(detail).length">
<image class="cart-empty" src="@/static/goods/goods_empty.png" mode="widthFix"/>
</block>
</view>
</view>
</view>
<!-- 同意 -->
<unipopup ref="agreeWastagePop" type="center">
<view class="confirm-pop">
<view class="title">确定要通过该单据吗</view>
<view class="btn">
<button type="primary" class="default-btn btn save" @click="close('agreeWastagePop')">取消</button>
<button type="primary" class="primary-btn btn" @click="agree">确定</button>
</view>
</view>
</unipopup>
<!-- 拒绝 -->
<unipopup ref="refuseWastagePop" type="center">
<view class="confirm-pop message">
<view class="title">
拒绝理由
<text class="iconfont iconguanbi1" @click="close('refuseWastagePop')"></text>
</view>
<view class="textarea-box">
<textarea v-model="refuseReason" class="textarea" maxlength="200" placeholder="输入请不多于200字"></textarea>
</view>
<button @click="refuse" type="primary" class="primary-btn btn save">保存</button>
</view>
</unipopup>
<!-- 删除 -->
<unipopup ref="deleteWastagePop" type="center">
<view class="confirm-pop">
<view class="title">确定要删除该单据吗</view>
<view class="btn">
<button type="primary" class="default-btn btn save" @click="close('deleteWastagePop')">取消</button>
<button type="primary" class="primary-btn btn" @click="deleteDocument">确定</button>
</view>
</view>
</unipopup>
</base-page>
</template>
<script>
import {
getAllocateList,
getAllocateDetail,
allocateAgree,
allocateDelete,
allocateRefuse
} from '@/api/stock.js';
import unipopup from '@/components/uni-popup/uni-popup.vue';
export default {
components: {
unipopup
},
data() {
return {
selectGoodsKeys: 0,
//获取订单的页数
page: 1,
//每次获取订单的条数
page_size: 9,
// 订单搜索是用到的数据
search_text: '',
//初始时加载详情数据判断
one_judge: true,
// 订单列表数据
list: [],
//订单详情数据
detail: {},
repeatFlag: false,
refuseReason: ''
};
},
onLoad() {
this.getListData();
},
methods: {
// 搜索
search() {
this.page = 1;
this.list = [];
this.one_judge = true;
this.getListData();
},
/**
* 获取订单列表
*/
getListData() {
getAllocateList({
page: this.page,
page_size: this.page_size,
allot_no: this.search_text
}).then(res => {
if (res.data.list.length == 0 && this.one_judge) {
this.detail = {};
this.one_judge = false;
}
if (res.code >= 0 && res.data.list.length != 0) {
this.page += 1;
if (this.list.length == 0) {
this.list = res.data.list;
} else {
this.list = this.list.concat(res.data.list);
}
//初始时加载一遍详情数据
if (this.one_judge) {
this.getDetailData(this.list[0].allot_id);
}
}
});
},
/**
* 获取单据详情
*/
getDetailData(allot_id, keys = 0) {
this.selectGoodsKeys = keys;
this.type = 'detail';
getAllocateDetail(allot_id).then(res => {
if (res.code >= 0) {
this.detail = res.data;
this.$forceUpdate();
this.one_judge = false;
}
});
},
add() {
this.$util.redirectTo('/pages/stock/edit_allocate');
},
edit() {
this.$util.redirectTo('/pages/stock/edit_allocate', {
allot_id: this.detail.allot_id
});
},
open(action) {
this.$refs[action].open();
},
close(name) {
this.$refs[name].close();
},
/**
* 审核通过
*/
agree() {
if (this.repeatFlag) return;
this.repeatFlag = true;
allocateAgree(this.detail.allot_id).then(res => {
this.$util.showToast({
title: res.message
});
if (res.code >= 0) {
this.search();
this.getDetailData(this.detail.allot_id);
this.close('agreeWastagePop');
}
this.repeatFlag = false;
})
},
/**
* 审核拒绝
*/
refuse() {
if (!this.refuseReason) {
this.$util.showToast({
title: '请输入拒绝理由'
});
return;
}
if (this.repeatFlag) return;
this.repeatFlag = true;
allocateRefuse({
allot_id: this.detail.allot_id,
refuse_reason: this.refuseReason
}).then(res => {
this.$util.showToast({
title: res.message
});
if (res.code >= 0) {
this.search();
this.getDetailData(this.detail.allot_id);
this.close('refuseWastagePop');
}
this.repeatFlag = false;
})
},
/**
* 删除单据
*/
deleteDocument() {
if (this.repeatFlag) return;
this.repeatFlag = true;
allocateDelete(this.detail.allot_id).then(res => {
this.$util.showToast({
title: res.message
});
if (res.code >= 0) {
this.list.splice(this.selectGoodsKeys, 1);
if (this.selectGoodsKeys == 0) {
this.selectGoodsKeys = 0;
} else {
this.selectGoodsKeys -= 1;
}
this.getDetailData(this.list[this.selectGoodsKeys].allot_id, this.selectGoodsKeys);
this.close('deleteWastagePop');
}
this.repeatFlag = false;
});
}
}
};
</script>
<style scoped lang="scss">
@import './public/css/orderlist.scss';
</style>

View File

@@ -0,0 +1,360 @@
<template>
<base-page>
<view class="goodslist">
<view class="goodslist-box">
<view class="goodslist-left">
<view class="goods-title">
盘点单查询
<text class="iconfont icongengduo1"></text>
</view>
<view class="goods-search">
<view class="search">
<text class="iconfont icon31sousuo"></text>
<input type="text" v-model="search_text" @input="search" placeholder="搜索盘点单号" />
</view>
</view>
<scroll-view scroll-y="true" class="goods-list-scroll" :show-scrollbar="false" @scrolltolower="getListData">
<view class="item" @click="getDetailData(item.inventory_id, index)" v-for="(item, index) in list" :key="index" :class="{ itemhover: selectGoodsKeys == index }">
<view class="title">
<view>{{ item.inventory_no }}</view>
</view>
<view class="other-info">
<view>{{ item.operater_name }}</view>
<view>{{ item.status_name }}</view>
<view>{{ $util.timeFormat(item.create_time) }}</view>
</view>
</view>
<view class="notYet" v-if="!one_judge && !list.length">暂无数据</view>
</scroll-view>
<view class="add-wastage">
<button type="default" class="primary-btn" v-if="globalStoreInfo.stock_type == 'store'" @click="add()">添加盘点单</button>
</view>
</view>
<view class="goodslist-right">
<view class="goods-title">盘点单详情</view>
<view class="order-information" v-if="Object.keys(detail).length">
<view class="order-status">基本信息</view>
<view class="order-types">
<view class="type type1">
<view>盘点单号</view>
<view>{{ detail.inventory_no }}</view>
</view>
<view class="type type1">
<view>制单人</view>
<view>{{ detail.operater_name || '--' }}</view>
</view>
<view class="type type1">
<view>制单时间</view>
<view class="message">{{ detail.create_time }}</view>
</view>
<view class="type type1">
<view>盘点时间</view>
<view class="message">{{ detail.action_time }}</view>
</view>
<view class="type type1">
<view>状态</view>
<view class="message">{{ detail.status_name }}</view>
</view>
<view class="type type1" v-if="detail.verifier_name">
<view>审核人</view>
<view class="message">{{ detail.verifier_name }}</view>
</view>
<view class="type type1" v-if="detail.audit_time">
<view>审核时间</view>
<view class="message">{{ detail.audit_time }}</view>
</view>
<view class="type type1" v-if="detail.status == -1">
<view>拒绝理由</view>
<view class="message">{{ detail.refuse_reason }}</view>
</view>
<view class="type type1">
<view>备注</view>
<view class="message">{{ detail.remark }}</view>
</view>
</view>
<view class="goods-info">
<view class="title">商品明细</view>
<view class="table">
<view class="table-th table-all">
<view class="table-td" style="width:25%;justify-content: flex-start;">商品名称/规格/条形码</view>
<!-- <view class="table-td" style="width:5%">单位</view> -->
<view class="table-td" style="width:8%">实物库存</view>
<view class="table-td" style="width:8%">实盘数量</view>
<view class="table-td" style="width:8%">盈亏数量</view>
<view class="table-td" style="width:13%">盈亏成本总额()</view>
</view>
<view class="table-tr table-all" v-for="(item, index) in detail.goods_sku_list_array" :key="index">
<view class="table-td table-goods-name" style="width:25%;justify-content: flex-start;">
<image :src="$util.img(item.goods_img)" mode="aspectFill" />
<text class="multi-hidden">{{ item.goods_sku_name }}</text>
</view>
<!-- <view class="table-td" style="width:5%"></view> -->
<view class="table-td" style="width:8%">{{ item.stock }}</view>
<view class="table-td" style="width:8%">{{ item.inventory_num }}</view>
<view class="table-td" style="width:8%">{{ item.profitloss_num }}</view>
<view class="table-td" style="width:13%">{{ item.inventory_cost_money }}</view>
</view>
</view>
<view class="total-money-num">
<view class="box">
<view>商品种类</view>
<view class="money">{{ detail.goods_count }}</view>
</view>
<view class="box">
<view>实盘种类</view>
<view class="money">{{ detail.kinds_num }}</view>
</view>
<view class="box">
<view>盘盈</view>
<view class="money kinds-profit">{{ detail.kinds_profit_num }}</view>
</view>
<view class="box">
<view>盘亏</view>
<view class="money kinds-loss">{{ detail.kinds_loss_num }}</view>
</view>
<view class="box">
<view>持平种类</view>
<view class="money">{{ detail.kinds_even_num }}</view>
</view>
</view>
</view>
<view class="action-box">
<!-- 只有经办人才能操作入库单 -->
<template v-if="(detail.status == 1 || detail.status == -1) && detail.operater == detail.uid">
<button type="primary" class="default-btn" @click="open('deleteWastagePop')">删除</button>
<button type="primary" class="default-btn" @click="edit">编辑</button>
</template>
<!-- 只有管理员和拥有单据审核权限的才能审核 -->
<template v-if="detail.status == 1 && detail.is_audit == 0">
<button type="primary" class="default-btn" @click="open('refuseWastagePop')">审核拒绝</button>
<button type="primary" class="primary-btn" @click="open('agreeWastagePop')">审核通过</button>
</template>
</view>
</view>
<block v-else-if="!one_judge && !Object.keys(detail).length">
<image class="cart-empty" src="@/static/goods/goods_empty.png" mode="widthFix"/>
</block>
</view>
</view>
</view>
<!-- 同意 -->
<unipopup ref="agreeWastagePop" type="center">
<view class="confirm-pop">
<view class="title">确定要通过该盘点单吗</view>
<view class="btn">
<button type="primary" class="default-btn btn save" @click="close('agreeWastagePop')">取消</button>
<button type="primary" class="primary-btn btn" @click="agree">确定</button>
</view>
</view>
</unipopup>
<!-- 拒绝 -->
<unipopup ref="refuseWastagePop" type="center">
<view class="confirm-pop message">
<view class="title">
拒绝理由
<text class="iconfont iconguanbi1" @click="close('refuseWastagePop')"></text>
</view>
<view class="textarea-box">
<textarea v-model="refuseReason" class="textarea" maxlength="200" placeholder="输入请不多于200字"></textarea>
</view>
<button @click="refuse" type="primary" class="primary-btn btn save">保存</button>
</view>
</unipopup>
<!-- 删除 -->
<unipopup ref="deleteWastagePop" type="center">
<view class="confirm-pop">
<view class="title">确定要删除该盘点单吗</view>
<view class="btn">
<button type="primary" class="default-btn btn save" @click="close('deleteWastagePop')">取消</button>
<button type="primary" class="primary-btn btn" @click="deleteCheck">确定</button>
</view>
</view>
</unipopup>
</base-page>
</template>
<script>
import {
getInventoryList,
getInventoryDetail,
inventoryAgree,
inventoryRefuse,
inventoryDelete
} from '@/api/stock.js';
import unipopup from '@/components/uni-popup/uni-popup.vue';
export default {
components: {
unipopup
},
data() {
return {
selectGoodsKeys: 0,
//获取订单的页数
page: 1,
//每次获取订单的条数
page_size: 9,
// 订单搜索是用到的数据
search_text: '',
//初始时加载详情数据判断
one_judge: true,
// 订单列表数据
list: [],
//订单详情数据
detail: {},
repeatFlag: false,
refuseReason: ''
};
},
onLoad(option) {
this.getListData();
},
methods: {
// 搜索
search() {
this.page = 1;
this.list = [];
this.one_judge = true;
this.getListData();
},
/**
* 获取订单列表
*/
getListData() {
getInventoryList({
page: this.page,
page_size: this.page_size,
inventory_no: this.search_text
}).then(res => {
if (res.data.list.length == 0 && this.one_judge) {
this.detail = {};
this.one_judge = false;
}
if (res.code >= 0 && res.data.list.length != 0) {
this.page += 1;
if (this.list.length == 0) {
this.list = res.data.list;
} else {
this.list = this.list.concat(res.data.list);
}
//初始时加载一遍详情数据
if (this.one_judge) {
this.getDetailData(this.list[0].inventory_id);
}
}
});
},
/**
* 获取订单详情数据
*/
getDetailData(inventory_id, keys = 0) {
this.selectGoodsKeys = keys;
this.type = 'detail';
getInventoryDetail(inventory_id).then(res => {
if (res.code >= 0) {
this.detail = res.data;
this.$forceUpdate();
this.one_judge = false;
}
});
},
add(data) {
this.$util.redirectTo('/pages/stock/edit_check');
},
edit() {
this.$util.redirectTo('/pages/stock/edit_check', {
inventory_id: this.detail.inventory_id
});
},
open(action) {
this.$refs[action].open();
},
close(name) {
this.$refs[name].close();
},
agree() {
if (this.repeatFlag) return;
this.repeatFlag = true;
inventoryAgree(this.detail.inventory_id).then(res => {
this.$util.showToast({
title: res.message
});
if (res.code >= 0) {
this.search();
this.getDetailData(this.detail.inventory_id);
this.close('agreeWastagePop');
}
this.repeatFlag = false;
});
},
refuse() {
if (!this.refuseReason) {
this.$util.showToast({
title: '请输入拒绝理由'
});
return;
}
if (this.repeatFlag) return;
this.repeatFlag = true;
inventoryRefuse({
inventory_id: this.detail.inventory_id,
refuse_reason: this.refuseReason
}).then(res => {
this.$util.showToast({
title: res.message
});
if (res.code >= 0) {
this.search();
this.getDetailData(this.detail.inventory_id);
this.close('refuseWastagePop');
}
this.repeatFlag = false;
});
},
deleteCheck() {
if (this.repeatFlag) return;
this.repeatFlag = true;
inventoryDelete(this.detail.inventory_id).then(res => {
this.$util.showToast({
title: res.message
});
if (res.code >= 0) {
this.list.splice(this.selectGoodsKeys, 1);
if (this.selectGoodsKeys == 0) {
this.selectGoodsKeys = 0;
} else {
this.selectGoodsKeys -= 1;
}
this.getDetailData(this.list[this.selectGoodsKeys].inventory_id, this
.selectGoodsKeys);
this.close('deleteWastagePop');
}
this.repeatFlag = false;
})
}
}
};
</script>
<style scoped lang="scss">
.kinds-loss {
color: red !important;
}
.kinds-profit {
color: #15eb26 !important;
}
@import './public/css/orderlist.scss';
</style>

View File

@@ -0,0 +1,142 @@
<template>
<base-page>
<view class="stock-body">
<view class="content-wrap" @click="goodsShow = false">
<view class="title">{{ screen.allot_id ? '编辑调拨单' : '添加调拨单' }}</view>
<view class="screen-warp form-content">
<view class="form-item">
<label class="form-label">
<text class="required">*</text>
调拨单号
</label>
<view class="form-inline input">
<input type="text" v-model="screen.allot_no" :disabled="screen.allot_id != ''" placeholder="请输入调拨单号" />
</view>
</view>
<view class="form-item">
<label class="form-label">
<text class="required">*</text>
调拨方式
</label>
<view class="form-inline">
<select-lay :zindex="10" :value="type" name="names" placeholder="请选择调拨方式" :options="screen.allocateTypeList" @selectitem="selectAllocateType"/>
</view>
</view>
<view class="form-item store-info">
<view class="form-label">当前门店</view>
<view class="form-inline">{{ globalStoreInfo.store_name }}</view>
</view>
<view class="form-item store-info">
<view class="form-label">当前操作人</view>
<view class="form-inline">{{ userInfo ? userInfo.username : '' }}</view>
</view>
<view class="form-item">
<label class="form-label">
<text class="required">*</text>
{{ storeName }}
</label>
<view class="form-inline">
<select-lay :zindex="10" :value="screen.store_id" name="names" :placeholder="'请选择' + storeName" :options="screen.storeList" @selectitem="selectStore"/>
</view>
</view>
<view class="form-item">
<label class="form-label">
<text class="required">*</text>
调拨时间
</label>
<view class="form-inline">
<uni-datetime-picker :start="screen.startDate" v-model="screen.birthday" type="timestamp" :clearIcon="false" @change="changeTime" />
</view>
</view>
</view>
<view class="table-wrap">
<view class="table-head">
<view class="table-tr">
<view class="table-th" style="flex: 3;">产品名称/规格/编码</view>
<view class="table-th" style="flex: 1;">当前库存</view>
<view class="table-th" style="flex: 1;">单位</view>
<view class="table-th" style="flex: 2;">成本价</view>
<view class="table-th" style="flex: 2;">数量</view>
<view class="table-th" style="flex: 1;">总金额</view>
<view class="table-th" style="flex: 1;">操作</view>
</view>
</view>
<view class="table-body">
<view class="table-tr">
<view class="table-td select-goods-input" style="flex: 3;" @click.stop="goodsShow = true">
<input type="text" @confirm="getGoodsData($event, -1)" placeholder="请输入产品名称/规格/编码" v-model="params.search_text" />
<text class="iconfont icontuodong" @click="getGoodsData({ detail: null }, -1)"></text>
</view>
<view class="table-td" style="flex: 1;"></view>
<view class="table-td" style="flex: 1;"></view>
<view class="table-td" style="flex: 2;"></view>
<view class="table-td" style="flex: 2;"></view>
<view class="table-td" style="flex: 1;"></view>
<view class="table-td" style="flex: 1;"></view>
</view>
<block v-for="(item, index) in goodsList" :key="index">
<view class="table-tr" v-if="goodsIdArr.includes(item.sku_id)">
<view class="table-td goods-name" style="flex: 3;">{{ item.title }}</view>
<view class="table-td" style="flex: 1;">{{ item.real_stock || 0 }}</view>
<view class="table-td" style="flex: 1;">{{ item.unit || '件' }}</view>
<view class="table-td" style="flex: 2;">{{ item.cost_price || 0 }}</view>
<view class="table-td" style="flex: 2;">
<input type="number" v-model="item.goods_num" placeholder="请输入数量" @input="calcTotalData" />
</view>
<view class="table-td" style="flex: 1;">
{{ (item.goods_num * item.cost_price || 0).toFixed(2) }}
</view>
<view class="table-td" style="flex: 1;">
<button type="default" class="delete" @click="delGoods(item.sku_id)">删除</button>
</view>
</view>
</block>
<view class="table-tr table-empty" v-if="!goodsIdArr.length">暂无数据请选择商品数据</view>
</view>
</view>
<stock-goods-dialog v-model="dialogVisible" :params="params" @selectGoods="selectGoods" />
</view>
<view class="action-wrap">
<view class="table-total">
合计{{ totalData.kindsNum }}种产品合计金额{{ totalData.price.toFixed(2) }}
</view>
<view class="btn-wrap">
<button type="default" class="remark default" @click="$refs.remarkPopup.open()">备注</button>
<button type="default" class="stockout-btn" @click="stockOutFn" :loading="isSubmit">确认调拨</button>
<button type="default" class="default" @click="backFn">返回</button>
</view>
</view>
</view>
<uni-popup ref="remarkPopup" type="center">
<view class="remark-wrap">
<view class="header">
<text class="title">备注</text>
<text class="iconfont iconguanbi1" @click="$refs.remarkPopup.close()"></text>
</view>
<view class="body">
<textarea v-model="remark" placeholder="填写备注信息" placeholder-class="placeholder-class" />
</view>
<view class="footer">
<button type="default" class="primary-btn" @click="remarkConfirm">确认</button>
</view>
</view>
</uni-popup>
</base-page>
</template>
<script>
import editAllocate from './public/js/edit_allocate';
import stockGoodsDialog from '@/components/stock-goods-dialog/stock-goods-dialog.vue';
export default {
components: {
stockGoodsDialog
},
mixins: [editAllocate]
};
</script>
<style lang="scss" scoped>
@import './public/css/editStock.scss';
</style>

View File

@@ -0,0 +1,131 @@
<template>
<base-page>
<view class="stock-body">
<view class="content-wrap" @click="goodsShow = false">
<view class="title" v-if="screen.inventory_id != ''">编辑盘点单</view>
<view class="title" v-else>添加盘点单</view>
<view class="screen-warp form-content">
<view class="form-item">
<label class="form-label">
<text class="required">*</text>
盘点单号
</label>
<view class="form-inline input">
<input type="text" v-model="screen.inventory_no" :disabled="screen.inventory_id != ''" placeholder="请输入入库单号" />
</view>
</view>
<view class="form-item">
<label class="form-label">
<text class="required">*</text>
盘点时间
</label>
<view class="form-inline">
<uni-datetime-picker v-model="screen.time" type="timestamp" :clearIcon="false" @change="changeTime" />
</view>
</view>
<view class="form-item store-info">
<view class="form-label">当前门店</view>
<view class="form-inline">{{ globalStoreInfo.store_name }}</view>
</view>
<view class="form-item store-info">
<view class="form-label">当前操作人</view>
<view class="form-inline">{{ userInfo ? userInfo.username : '' }}</view>
</view>
</view>
<view class="tips text-color" v-if="globalStoreInfo.stock_config && globalStoreInfo.stock_config.is_audit == 1">
说明待审核状态下只有经办人允许修改只有变为已审核状态后才会使库存发生变化已审核状态的单据不允许再修改</view>
<view class="table-wrap">
<view class="table-head">
<view class="table-tr">
<view class="table-th" style="flex: 3;">产品名称/规格/编码</view>
<view class="table-th" style="flex: 1;">当前库存</view>
<view class="table-th" style="flex: 1;">销售库存</view>
<view class="table-th" style="flex: 1;">单位</view>
<view class="table-th" style="flex: 2;">实盘数量</view>
<view class="table-th" style="flex: 1;">盈亏数量</view>
<view class="table-th" style="flex: 1;">操作</view>
</view>
</view>
<view class="table-body">
<view class="table-tr">
<view class="table-td select-goods-input" style="flex: 3;" @click.stop="goodsShow = true">
<input type="text" @confirm="getGoodsData($event, -1)" placeholder="请输入产品名称/规格/编码" v-model="params.search_text" />
<text class="iconfont icontuodong" @click="getGoodsData({ detail: null }, -1)"></text>
</view>
<view class="table-td" style="flex: 1;"></view>
<view class="table-td" style="flex: 1;"></view>
<view class="table-td" style="flex: 1;"></view>
<view class="table-td" style="flex: 2;"></view>
<view class="table-td" style="flex: 1;"></view>
<view class="table-td" style="flex: 1;"></view>
</view>
<block v-for="(item, index) in goodsList" :key="index">
<view class="table-tr" v-if="goodsIdArr.includes(item.sku_id)">
<view class="table-td goods-name" style="flex: 3;">{{ item.title }}</view>
<view class="table-td" style="flex: 1;">{{ item.real_stock || 0 }}</view>
<view class="table-td" style="flex: 1;">{{ item.stock || 0 }}</view>
<view class="table-td" style="flex: 1;">{{ item.unit || '件' }}</view>
<view class="table-td" style="flex: 2;">
<input type="number" v-model="item.goods_num" placeholder="请输入数量" @input="calcTotalData" />
</view>
<view class="table-td" style="flex: 1;">{{ parseFloat(item.goods_num - item.stock) || 0 }}</view>
<view class="table-td" style="flex: 1;">
<button type="default" class="delete" @click="delGoods(item.sku_id)">删除</button>
</view>
</view>
</block>
<view class="table-tr table-empty" v-if="!goodsIdArr.length">暂无数据请选择商品数据</view>
</view>
</view>
</view>
<view class="action-wrap">
<view class="table-total">合计{{ totalData.kindsNum }}种商品盘盈{{ totalData.upNum }}盘亏{{ totalData.downNum }}持平{{ totalData.sameNum }}</view>
<view class="btn-wrap">
<button type="default" class="remark default" @click="$refs.remarkPopup.open()">备注</button>
<button type="default" class="stockout-btn" @click="stockOutFn" :loading="isSubmit">盘点</button>
<button type="default" class="default" @click="backFn">返回</button>
</view>
</view>
</view>
<stock-goods-dialog v-model="dialogVisible" :params="params" @selectGoods="selectGoods" />
<unipopup ref="tipsPop" type="center">
<view class="confirm-pop">
<view class="title">单据保存后将处于"待审核"状态只有经办人可以编辑或删除等操作是否确认保存</view>
<view class="btn">
<button type="primary" class="default-btn btn save" @click="$refs.tipsPop.close()">取消</button>
<button type="primary" class="primary-btn btn" @click="save">确定</button>
</view>
</view>
</unipopup>
<uni-popup ref="remarkPopup" type="center">
<view class="remark-wrap">
<view class="header">
<text class="title">备注</text>
<text class="iconfont iconguanbi1" @click="$refs.remarkPopup.close()"></text>
</view>
<view class="body">
<textarea v-model="remark" placeholder="填写备注信息" placeholder-class="placeholder-class" />
</view>
<view class="footer">
<button type="default" class="primary-btn" @click="remarkConfirm">确认</button>
</view>
</view>
</uni-popup>
</base-page>
</template>
<script>
import editInventory from './public/js/edit_inventory'
import unipopup from '@/components/uni-popup/uni-popup.vue';
import stockGoodsDialog from '@/components/stock-goods-dialog/stock-goods-dialog.vue';
export default {
components: {
unipopup,
stockGoodsDialog
},
mixins: [editInventory]
};
</script>
<style lang="scss" scoped>
@import './public/css/editStock.scss';
</style>

View File

@@ -0,0 +1,224 @@
<template>
<base-page>
<view class="manage">
<view class="screen-warp common-form">
<view class="common-form-item">
<view class="form-inline">
<label class="form-label">商品名称/编码</label>
<view class="form-input-inline">
<input type="text" v-model="option.search" placeholder="请输入商品名称/编码" class="form-input" />
</view>
</view>
<view class="form-inline goods-category">
<label class="form-label">商品分类</label>
<view class="form-input-inline">
<uni-data-picker v-model="option.category_id" :localdata="classifyData.data" popup-title="请选择商品分类"></uni-data-picker>
</view>
</view>
<view class="form-inline common-btn-wrap">
<button type="default" class="screen-btn" @click="searchFn()">筛选</button>
<button type="default" @click="resetFn()">重置</button>
</view>
</view>
</view>
<view class="manage-table">
<uniDataTable url="/stock/storeapi/manage/lists" :option="option" :cols="cols" ref="goodsListTable">
<template v-slot:action="dataTable">
<view class="action-btn">
<text @click="toDetail()">查看流水</text>
</view>
</template>
</uniDataTable>
</view>
</view>
</base-page>
</template>
<script>
import {
getGoodsCategory
} from '@/api/goods.js';
import uniDataPicker from '@/components/uni-data-picker/uni-data-picker.vue';
import uniDataTable from '@/components/uni-data-table/uni-data-table.vue';
export default {
components: {
uniDataPicker,
uniDataTable
},
data() {
return {
classifyData: {
data: []
},
table: {
loading: false, //表格加载动画
data: []
},
paging: {
pageSize: 9, // 每页数据量
pageCurrent: 1, // 当前页
total: 0 // 数据总量
},
option: {
search: '',
category_id: '',
page_size: 10
},
cols: [
{
field: 'account_data',
width: 20,
title: '产品名称',
align: 'left',
templet: data => {
let img = this.$util.img(data.sku_image, { size: 'small' });
let html = `
<view class="goods-content">
<image class="goods-img" src="${img}" mode="aspectFill" />
<text class="goods-name multi-hidden">${data.goods_name}</text>
</view>
`;
return html;
}
}, {
width: 19,
title: '规格',
align: 'center',
field: 'spec_name'
}, {
width: 13,
title: '编码',
align: 'center',
field: 'sku_no'
}, {
field: 'real_stock',
width: 10,
title: '库存',
align: 'center'
}, {
field: 'cost_price',
width: 12,
title: '成本',
align: 'center'
}, {
width: 20,
title: '添加时间',
templet: data => {
return this.$util.timeFormat(data.create_time);
}
}, {
width: 15,
title: '操作',
align: 'right',
action: true
}],
};
},
onLoad(option) {
this.getCategory();
},
methods: {
// 搜索商品
searchFn() {
this.$refs.goodsListTable.load({
page: 1
});
},
resetFn() {
this.option.search = '';
this.option.category_id = '';
this.$refs.goodsListTable.load({
page: 1
});
},
getCategory() {
getGoodsCategory({
level: 3
}).then(res => {
let data = res.data;
if (res.code == 0 && data.length) {
this.classifyData.data = this.analyzeCategory(data);
this.$forceUpdate();
} else {
this.$util.showToast({
title: res.message
});
}
})
},
analyzeCategory(data) {
var arr = data.map((item, index) => {
var obj = {};
obj.text = item.category_name;
obj.value = item.category_id;
if (item.child_list && item.child_list.length) {
obj.children = this.analyzeCategory(item.child_list);
}
return obj;
});
return arr;
},
toDetail() {
this.$util.redirectTo('/pages/stock/records');
}
}
};
</script>
<style lang="scss" scoped>
.manage {
position: relative;
background-color: #fff;
padding: 0.15rem;
min-height: 100vh;
box-sizing: border-box;
}
// 筛选面板
.screen-warp {
padding: 0.15rem;
background-color: #f2f3f5;
margin-bottom: 0.15rem;
.common-form-item .form-label {
width: 1.2rem;
}
.common-btn-wrap {
margin-left: 1.2rem;
}
.goods-category .form-input-inline {
width: 2.8rem;
/deep/ .input-value-border{
border-width: 0;
}
}
.common-form-item {
margin-bottom: 0;
}
}
/deep/ .goods-content {
display: flex;
.goods-img {
margin-right: 0.1rem;
width: 0.5rem;
height: 0.5rem;
}
.goods-name {
flex: 1;
white-space: pre-wrap;
align-self: baseline;
}
}
.action-btn {
text {
color: $primary-color;
}
}
</style>

View File

@@ -0,0 +1,271 @@
.form-content {
display: flex;
flex-wrap: wrap;
margin-top: 0.2rem;
.store-info {
.form-inline {
padding-left: 0.05rem;
}
}
.form-item {
margin-bottom: 0.1rem;
display: flex;
.form-label {
width: 1.3rem;
text-align: right;
padding-right: 0.1rem;
box-sizing: border-box;
height: 0.32rem;
line-height: 0.32rem;
.required {
color: red;
margin-right: 0.03rem;
}
}
.form-inline {
width: 2.4rem;
line-height: 0.32rem;
margin-right: 0.1rem;
box-sizing: border-box;
&.input {
input {
padding: 0 0.1rem;
}
}
.form-input {
border-width: 0.01rem;
border-style: solid;
background-color: #fff;
color: rgba(0, 0, 0, 0.85);
border-radius: 0.02rem;
padding-left: 0.1rem;
height: 0.32rem;
line-height: 0.32rem;
font-size: 0.14rem;
border-color: #e6e6e6;
}
}
}
}
.stock-body{
position: relative;
height: 100%;
.content-wrap {
padding: 0.15rem;
background-color: #fff;
@extend %body-overhide;
box-sizing: border-box;
.title {
font-size: 0.18rem;
margin-bottom: 0.2rem;
text-align: center;
}
.table-wrap {
position: relative;
margin-top: 40rpx;
border: 1rpx solid #dcdfe6;
.table-head {
background-color: #f7f7f7;
}
.table-body {
@extend %body-overhide;
max-height: 6rem;
.table-tr {
&:nth-child(1) {
position: absolute;
left: 0;
right: 0;
background: #fff;
z-index: 3;
}
&:nth-child(2) {
margin-top: 0.49rem;
}
&:last-of-type .table-td {
border-bottom: 0;
}
}
}
.table-tr {
display: flex;
}
.table-th,
.table-td {
display: flex;
align-items: center;
justify-content: center;
padding: 0.07rem 0.3rem;
border-bottom: 0.01rem solid #dcdfe6;
border-right: 0.01rem solid #dcdfe6;
text-align: center;
&:last-of-type {
border-right: 0;
justify-content: flex-end;
}
&.goods-name {
justify-content: flex-start;
image {
width: 0.45rem;
height: 0.45rem;
flex-shrink: 0;
}
.name {
margin-left: 0.1rem;
}
}
}
.delete {
margin: 0;
font-size: $uni-font-size-base;
background-color: $primary-color;
color: #fff;
line-height: 0.32rem;
height: 0.32rem;
&::after{
border-width: 0;
}
}
.table-empty {
justify-content: center;
padding: 0.3rem;
color: #999;
}
}
.select-goods-input,
.goods-name {
position: relative;
input {
flex: 1;
padding: 0 0.2rem;
}
.icontuodong {
font-size: 0.16rem;
position: absolute;
top: 0.17rem;
right: 0.34rem;
z-index: 2;
cursor: pointer;
}
}
input {
font-size: $uni-font-size-base !important;
border: 0.01rem solid #e6e6e6 !important;
height: 0.32rem;
}
}
.action-wrap {
position: absolute;
bottom: 0;
left: 0;
right: 0;
display: flex;
justify-content: space-between;
padding: 0.24rem 0.2rem;
align-items: center;
background-color: #fff;
z-index: 10;
.btn-wrap {
display: flex;
align-items: center;
justify-content: center;
button {
margin: 0;
min-width: 2.75rem;
height: 0.4rem;
line-height: 0.4rem;
font-size: $uni-font-size-base;
&.stockout-btn {
margin-right: 0.15rem;
background-color: $primary-color;
color: #fff;
&::after{
border-width: 0;
}
}
&.remark {
margin-right: 0.15rem;
min-width: 1.2rem;
}
}
}
}
}
.remark-wrap {
width: 6rem;
background-color: #fff;
border-radius: 0.04rem;
box-shadow: 0 0.01rem 0.12rem 0 rgba(0, 0, 0, 0.1);
.header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 0.15rem;
height: 0.45rem;
line-height: 0.45rem;
border-bottom: 0.01rem solid #e8eaec;
.iconfont {
font-size: $uni-font-size-lg;
}
}
.body {
padding: 0.15rem 0.15rem 0.1rem;
textarea {
border: 0.01rem solid #e6e6e6;
width: 100%;
padding: 0.1rem;
box-sizing: border-box;
font-size: 0.14rem;
}
.placeholder-class {
font-size: 0.14rem;
}
}
.footer {
height: 0.5rem;
padding-bottom: 0.05rem;
display: flex;
align-items: center;
justify-content: center;
button.default {
width: 95%;
}
}
}

View File

@@ -0,0 +1,356 @@
.goodslist {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: space-between;
box-sizing: border-box;
.goodslist-box {
width: 100%;
height: 100%;
background: #fff;
display: flex;
.goodslist-left {
width: 5rem;
height: 100%;
border-right: 0.01rem solid #e6e6e6;
box-sizing: border-box;
overflow: hidden;
position: relative;
.notYet {
color: #e6e6e6;
font-size: 0.4rem;
padding-top: 3rem;
text-align: center;
}
.goods-title {
text-align: center;
line-height: 0.6rem;
font-size: 0.18rem;
font-weight: 500;
height: 0.6rem;
border-bottom: 0.01rem solid #e6e6e6;
box-sizing: border-box;
position: relative;
.icongengduo1 {
position: absolute;
top: 50%;
right: 0.2rem;
transform: translateY(-50%);
font-size: 0.3rem;
color: $primary-color;
}
}
.goods-search {
width: 100%;
height: 0.6rem;
border-bottom: 0.01rem solid #e6e6e6;
display: flex;
align-items: center;
justify-content: center;
padding: 0 0.2rem;
box-sizing: border-box;
.search {
width: 5.6rem;
height: 0.4rem;
border-radius: 0.04rem;
background: #f5f5f5;
display: flex;
align-items: center;
padding: 0 0.2rem;
box-sizing: border-box;
.iconfont {
font-size: 0.16rem;
color: #909399;
margin-right: 0.11rem;
}
input {
width: 80%;
height: 60%;
border: none;
font-size: 0.14rem;
}
}
}
.goods-list-scroll {
width: 100%;
height: calc(100% - 2.08rem);
.itemhover {
background: var(--primary-color-light-9);
}
.item {
padding: 0.2rem;
.title {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 0.2rem;
view {
font-size: 0.16rem;
}
view:nth-child(2) {
color: $primary-color;
}
}
}
}
.add-wastage {
padding: 0.24rem 0.2rem;
button{
width: 100%;
line-height: 0.4rem;
height: 0.4rem;
}
}
}
.goodslist-right {
flex: 1;
width: 0;
height: 100%;
box-sizing: border-box;
position: relative;
padding-bottom: 0.88rem;
overflow: hidden;
.goods-title {
text-align: center;
line-height: 0.6rem;
font-size: 0.18rem;
font-weight: 500;
height: 0.6rem;
border-bottom: 0.01rem solid #e6e6e6;
box-sizing: border-box;
position: relative;
}
.cart-empty {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 2.1rem;
}
.order-information {
width: 100%;
height: calc(100% - 0.6rem);
padding: 0.2rem;
box-sizing: border-box;
overflow-y: auto;
// position: relative;
.order-status {
font-size: 0.24rem;
font-weight: bold;
margin-bottom: 0.24rem;
}
.order-types {
width: 100%;
min-height: 1rem;
padding: 0.2rem 0.3rem;
display: flex;
flex-direction: column;
justify-content: space-between;
margin-bottom: 0.2rem;
box-sizing: border-box;
.type {
padding-left: 0.1rem;
view {
font-size: 0.14rem;
.look {
color: $primary-color;
margin-left: 0.24rem;
}
}
view:nth-child(1) {
width: 0.9rem;
text-align: right;
margin-right: 0.1rem;
}
.message{
max-width: 10.7rem;
overflow: hidden;
-o-text-overflow: ellipsis;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.type1 {
display: flex;
align-items: center;
height: 0.34rem;
}
}
.goods-info {
min-height: 2.7rem;
background: #ffffff;
padding: 0.2rem 0;
box-sizing: border-box;
.title {
font-size: 0.18rem;
font-weight: 550;
margin-bottom: 0.2rem;
}
.table {
width: 100%;
box-sizing: border-box;
margin-bottom: 0.2rem;
.table-all {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 0.38rem;
box-sizing: border-box;
.table-td {
font-size: 0.14rem;
text-align: left;
display: flex;
align-items: center;
justify-content: center;
image {
margin-right: 0.1rem;
}
}
.table-goods-name {
image {
width: 0.6rem;
height: 0.6rem;
margin-right: 0.1rem;
flex-shrink: 0;
}
}
}
.table-th {
height: 0.56rem;
background: #f7f8fa;
}
.table-tr {
height: 0.7rem;
border-bottom: 0.01rem solid #e6e6e6;
.table-td {
image {
width: 0.5rem;
height: 0.5rem;
}
.content-text {
width: 80%;
height: 0.4rem;
text-overflow: -o-ellipsis-lastline;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
line-clamp: 2;
-webkit-box-orient: vertical;
}
}
}
}
}
}
.total-money-num {
display: flex;
flex-direction: column;
.box {
justify-content: flex-end;
padding: 0.1rem 0 0 0;
color: #333;
}
.money {
text-align: right;
width: 1.2rem;
color: #333;
font-size: 0.14rem;
}
.total {
border-top: 0.01rem solid #e6e6e6;
margin-top: 0.1rem;
.money {
color: #fe2278;
font-size: 0.18rem;
}
}
}
}
}
}
.other-info {
display: flex;
justify-content: space-between;
align-items: center;
}
.total-money-num {
.member-info {
display: flex;
align-items: center;
float: left;
-ms-flex-negative: 0;
-webkit-flex-shrink: 0;
flex-shrink: 0;
}
.box {
display: flex;
align-items: center;
float: right;
view {
font-size: 0.14rem;
}
view:nth-child(1) {
// transform: translateY(-.01rem);
}
view:nth-child(2) {
color: #fe2278;
font-size: 0.18rem;
}
}
}
.total-money-num:after {
overflow: hidden;
content: '';
height: 0;
display: block;
clear: both;
}
/deep/ .uni-scroll-view::-webkit-scrollbar {
width: 0.05rem;
height: 0.3rem;
}
/deep/ .uni-scroll-view::-webkit-scrollbar-thumb {
border-radius: 0.1rem;
box-shadow: inset 0 0 0.05rem rgba(0, 0, 0, 0.2);
background: rgba(193, 193, 193, 1);
}
.order-information::-webkit-scrollbar {
width: 0.05rem;
height: 0.3rem;
}
.order-information::-webkit-scrollbar-thumb {
border-radius: 0.1rem;
box-shadow: inset 0 0 0.05rem rgba(0, 0, 0, 0.2);
background: rgba(193, 193, 193, 1);
}
.action-box {
width: 100%;
position: absolute;
bottom: 0;
right: 0;
background: #ffffff;
padding: 0.24rem 0.2rem;
box-sizing: border-box;
button {
min-width: 0.9rem;
height: 0.4rem;
font-size: 0.18rem;
text-align: center;
line-height: 0.4rem;
float: right;
margin-left: 0.1rem;
}
}

View File

@@ -0,0 +1,294 @@
import {
getAllotNo,
getAllocateDetailInEdit,
getSkuListForStock,
getStoreLists,
editAllocate,
addAllocate
} from '@/api/stock.js';
export default {
data() {
return {
params: {
search_text: '', //产品名称
temp_store_id: ''
},
goodsList: [],
goodsIdArr: [],
goodsShow: false,
totalData: {
kindsNum: 0,
price: 0
},
isSubmit: false,
remark: '',
// 筛选面板的时间
type: 'in',
storeName: '出库门店',
screen: {
store_id: "",
remark: '',
allot_id: "",
allot_no: "",
storeList: [],
startDate: '1998-01-30 00:00:00',
birthday: '',
allocateTypeList: [{
label: '调拨入库',
value: 'in'
},
{
label: '调拨出库',
value: 'out'
}
]
},
dialogVisible: false, //弹框
inputIndex: -1
};
},
onLoad(option) {
this.screen.allot_id = option.allot_id || '';
if (this.screen.allot_id) {
this.getEditData();
} else {
this.getDocumentNo()
}
},
onShow() {
this.screen.birthday = this.$util.timeFormat(Date.parse(new Date()) / 1000);
this.getStoreLists()
},
watch: {
goodsIdArr(data) {
this.calcTotalData();
},
},
methods: {
getDocumentNo() {//获取单据号
getAllotNo().then(res => {
if (res.code >= 0) {
this.screen.allot_no = res.data
} else {
this.$util.showToast({
title: res.message
});
}
});
},
getEditData() {
// 编辑时获取详情
getAllocateDetailInEdit(this.screen.allot_id).then(res => {
if (res.code >= 0 && res.data) {
this.info = res.data;
//当前门店id===入库id则是商品入库门店选择回填为output_store_id出库门店id否则为商品出库门店选择回填为input_store_id入库门店id
this.type = this.globalStoreInfo.store_id == this.info.input_store_id ? 'in' : 'out'
this.screen.store_id = this.type == 'in' ? this.info.output_store_id : this.info.input_store_id
this.screen.allot_no = this.info.allot_no
this.screen.birthday = this.$util.timeFormat(this.info.allot_time)
this.remark = JSON.parse(JSON.stringify(this.info.remark))
this.screen.remark = this.info.remark
for (let sku_id in this.info.goods_list) {
this.info.goods_list[sku_id].title = this.info.goods_list[sku_id].sku_name
this.goodsIdArr.push(parseInt(sku_id));
this.goodsList.push(this.info.goods_list[sku_id]);
}
}
});
},
selectAllocateType(id) {
this.type = id == -1 ? '' : this.screen.allocateTypeList[id].value;
this.storeName = id == -1 || id == 0 ? '出库门店' : '入库门店';
this.params.temp_store_id = this.type == 'in' ? this.screen.store_id : '' //当是入库的时候,需要查出库门店的商品
this.goodsIdArr = []
this.goodsList = []
},
selectStore(id) {
this.screen.store_id = id == -1 ? '' : this.screen.storeList[id].value;
if (this.type == 'in') {
this.goodsIdArr = []
this.goodsList = []
}
},
changeTime(data) {
this.screen.birthday = data;
},
getGoodsData({detail}, index) { //input回车处理
this.inputIndex = index
var data = {
search: detail ? detail.value : '',
}
if (this.type == 'in') data.temp_store_id = this.screen.store_id;
if (detail && detail.value) {
getSkuListForStock(data).then(res => {
if (res.code >= 0 && res.data.length == 1) {
this.selectGoods(res.data)
} else if (res.code >= 0) {
this.params.search_text = detail ? detail.value : ''
this.dialogVisible = true
} else {
this.$util.showToast({
title: res.message
});
}
});
} else {
this.params.search_text = detail ? detail.value : ''
this.dialogVisible = true
}
},
selectGoods(data) { //选择数据
data.forEach((el, index) => {
el.goods_num = 1;
el.goods_price = 0;
el.title = el.sku_name + ''
//点击或回车行为选择商品后当为第一行并且展示列表不存在选择的商品push到展示列表或者不为第一行并且展示列表中不存在时选择的商品除第一条全部push到展示列表
if (!this.goodsIdArr.includes(el.sku_id)) {
console.log(111);
this.goodsIdArr.push(el.sku_id);
this.goodsList.push(el);
} else {//只要展示列表存在直接累加
var elIndex = this.goodsIdArr.indexOf(el.sku_id)
if(this.params.search_text){
this.goodsList[elIndex].goods_num = parseFloat(this.goodsList[elIndex].goods_num) + 1
}
}
})
this.goodsShow = false;
this.params.search_text = '';
this.$forceUpdate();
},
delGoods(id) {//删除已选择的商品
this.goodsList.splice(this.goodsIdArr.indexOf(id), 1);
this.goodsIdArr.splice(this.goodsIdArr.indexOf(id), 1);
},
getStoreLists() {
this.screen.storeList = [];
getStoreLists().then(res => {
if (res.code >= 0) {
let data = res.data;
for (let i = 0; i < data.length; i++) {
if (this.globalStoreId != data[i]['store_id']) {
this.screen.storeList.push({
'label': data[i]['store_name'],
'value': data[i]['store_id'].toString()
});
}
}
if (this.screen.storeList.length > 0) {
this.screen.store_id = this.screen.storeList[0].value;
this.params.temp_store_id = this.screen.store_id
}
}
});
},
stockOutFn() {
if (!this.screen.allot_no) {
this.$util.showToast({
title: "请输入调拨单号"
});
return false;
}
if (!this.type) {
this.$util.showToast({
title: "请选择调拨方式"
});
return false;
}
if (!this.screen.store_id) {
this.$util.showToast({
title: "请选择出库门店"
});
return false;
}
if (!this.screen.birthday) {
this.$util.showToast({
title: "请选择调拨时间"
});
return false;
}
if (!this.goodsIdArr.length) {
this.$util.showToast({
title: "请选择调拨数据"
});
return false;
}
// 检测库存是否填写,且提取数据
let isStock = false;
let saveData = [];
try {
this.goodsList.forEach((item, index) => {
if (this.goodsIdArr.includes(item.sku_id)) {
if (!parseFloat(item.goods_num || 0)) {
isStock = true;
let toast = "请输入" + item.sku_name + "的调拨数量";
this.$util.showToast({
title: toast
});
throw new Error('end');
}
var obj = {};
obj.goods_num = item.goods_num;
obj.goods_price = item.cost_price;
obj.goods_sku_id = item.sku_id;
saveData.push(obj);
}
})
} catch (e) {
if (e.message != "end") throw e;
}
if (isStock) return false;
if (this.isSubmit) return false;
this.isSubmit = true;
let save = this.screen.allot_id ? editAllocate : addAllocate
save({
allot_type: this.type,
allot_id: this.screen.allot_id,
temp_store_id: this.screen.store_id,
allot_time: this.screen.birthday,
remark: this.screen.remark,
allot_no: this.screen.allot_no,
goods_sku_list: JSON.stringify(saveData)
}).then(res => {
this.isSubmit = false;
this.$util.showToast({
title: res.message
});
if (res.code >= 0) {
setTimeout(() => {
this.backFn();
}, 500);
this.resetFn();
}
});
},
backFn() {
this.$util.redirectTo('/pages/stock/allocate');
},
calcTotalData() {//计算商品种类、金额
this.totalData.kindsNum = 0;
this.totalData.price = 0;
this.goodsList.forEach((item, index) => {
if (this.goodsIdArr.includes(item.sku_id)) {
this.totalData.price += parseFloat(item.cost_price || 0) * parseFloat(item.goods_num || 1);
}
})
this.totalData.kindsNum = this.goodsIdArr.length;
},
resetFn() {
this.goodsIdArr = [];
this.goodsShow = false;
this.totalData.kindsNum = 0;
this.totalData.price = 0;
},
remarkConfirm() {
this.screen.remark = JSON.parse(JSON.stringify(this.remark))
this.$refs.remarkPopup.close()
}
}
};

View File

@@ -0,0 +1,235 @@
import {
getInventoryNo,
getInventoryDetailInEdit,
getSkuListForStock,
editInventory,
addInventory
} from '@/api/stock.js';
export default {
data() {
return {
params: {
search_text: '', //产品名称
},
goodsList: [],
goodsIdArr: [],
goodsShow: false,
totalData: {
kindsNum: 0,
upNum: 0,
downNum: 0,
sameNum: 0
},
screen: {
inventory_id: '',
inventory_no: "",
remark: "",
stock_json: "",
time: ""
},
remark: '',
isSubmit: false,
inputIndex: -1,
dialogVisible: false,
info: null
};
},
onLoad(option) {
this.screen.inventory_id = option.inventory_id || '';
this.screen.time = this.$util.timeFormat(Date.parse(new Date()) / 1000);
if (this.screen.inventory_id) {
this.getEditData();
} else {
this.getDocumentNo()
}
},
watch: {
goodsIdArr(data) {
this.calcTotalData();
},
},
methods: {
getDocumentNo() {//获取单据号
getInventoryNo().then(res => {
if (res.code >= 0) {
this.screen.inventory_no = res.data
} else {
this.$util.showToast({
title: res.message
});
}
});
},
getEditData() {
getInventoryDetailInEdit(this.screen.inventory_id).then(res => {
if (res.code >= 0 && res.data) {
this.info = res.data;
this.screen.inventory_no = this.info.inventory_no
this.screen.time = this.$util.timeFormat(this.info.action_time)
this.remark = JSON.parse(JSON.stringify(this.info.remark))
for (let sku_id in this.info.goods_list) {
this.info.goods_list[sku_id].title = this.info.goods_list[sku_id].sku_name
this.goodsIdArr.push(parseInt(sku_id));
this.goodsList.push(this.info.goods_list[sku_id]);
}
}
});
},
getGoodsData({
detail
}, index) { //input回车处理
this.inputIndex = index
if (detail && detail.value) {
getSkuListForStock({
search: detail ? detail.value : ''
}).then(res => {
if (res.code >= 0 && res.data.length == 1) {
this.selectGoods(res.data)
} else if (res.code >= 0) {
this.params.search_text = detail ? detail.value : ''
this.dialogVisible = true
} else {
this.$util.showToast({
title: res.message
});
}
});
} else {
this.params.search_text = detail ? detail.value : ''
this.dialogVisible = true
}
},
selectGoods(data) { //选择数据
data.forEach((el, index) => {
el.goods_num = 1;
el.goods_price = 0;
el.title = el.sku_name + ''
//点击或回车行为选择商品后当为第一行并且展示列表不存在选择的商品push到展示列表或者不为第一行并且展示列表中不存在时选择的商品除第一条全部push到展示列表
if (!this.goodsIdArr.includes(el.sku_id)) {
console.log(111);
this.goodsIdArr.push(el.sku_id);
this.goodsList.push(el);
} else {//只要展示列表存在直接累加
var elIndex = this.goodsIdArr.indexOf(el.sku_id)
if(this.params.search_text){
this.goodsList[elIndex].goods_num = parseFloat(this.goodsList[elIndex].goods_num) + 1
}
}
})
this.goodsShow = false;
this.params.search_text = '';
this.$forceUpdate();
},
delGoods(id) {
this.goodsList.splice(this.goodsIdArr.indexOf(id), 1);
this.goodsIdArr.splice(this.goodsIdArr.indexOf(id), 1);
},
stockOutFn() {
if (!this.screen.inventory_no) {
this.$util.showToast({
title: "请输入盘点单号"
});
return false;
}
if (!this.screen.time) {
this.$util.showToast({
title: "请选择盘点时间"
});
return false;
}
if (!this.goodsIdArr.length) {
this.$util.showToast({
title: "请选择盘点数据"
});
return false;
}
if (this.globalStoreInfo.stock_config && this.globalStoreInfo.stock_config.is_audit == 1) {
this.$refs.tipsPop.open();
} else {
this.save();
}
},
save() {
// 检测库存是否填写,且提取数据
let isStock = false;
let saveData = [];
try {
this.goodsList.forEach((item, index) => {
if (this.goodsIdArr.includes(item.sku_id)) {
if (!parseFloat(item.goods_num || 0)) {
isStock = true;
let toast = "请输入" + item.sku_name + "的盘点数量";
this.$util.showToast({
title: toast
});
throw new Error('end');
}
var obj = {};
obj.goods_num = item.goods_num;
obj.goods_sku_id = item.sku_id;
saveData.push(obj);
}
})
} catch (e) {
if (e.message != "end") throw e;
}
if (isStock) return false;
if (this.isSubmit) return false;
this.isSubmit = true;
this.screen.stock_json = JSON.stringify(saveData)
let save = this.screen.inventory_id ? editInventory : addInventory
save(this.screen).then(res => {
this.isSubmit = false;
this.$util.showToast({
title: res.message
});
if (res.code >= 0) {
if (this.$refs.tipsPop) this.$refs.tipsPop.close();
setTimeout(() => {
this.backFn();
}, 500);
this.resetFn();
}
});
},
backFn() {
this.$util.redirectTo('/pages/stock/check');
},
calcTotalData() {//计算商品总数、盘盈、盘亏等
this.totalData.kindsNum = 0;
this.totalData.upNum = 0;
this.totalData.downNum = 0;
this.totalData.sameNum = 0;
this.goodsList.forEach((item, index) => {
if (this.goodsIdArr.includes(item.sku_id) && item.goods_num) {
if ((item.goods_num - item.stock) == 0) {
this.totalData.sameNum++;
} else if ((item.goods_num - item.stock) > 0) {
this.totalData.upNum++;
} else if ((item.goods_num - item.stock) < 0) {
this.totalData.downNum++;
}
}
})
this.totalData.kindsNum = this.goodsIdArr.length;
},
resetFn() {
this.goodsIdArr = [];
this.goodsShow = false;
this.totalData.kindsNum = 0;
this.totalData.countNum = 0;
this.totalData.price = 0;
},
changeTime(data) {
this.screen.time = data;
},
remarkConfirm() {
this.screen.remark = JSON.parse(JSON.stringify(this.remark))
this.$refs.remarkPopup.close()
}
}
};

View File

@@ -0,0 +1,224 @@
import {
getStorageDocumentNo,
getStorageDetailInEdit,
getSkuListForStock,
editStorage
} from '@/api/stock.js';
export default {
data() {
return {
params: {
search_text: '', //产品名称
},
goodsList: [], //已选择数据
goodsIdArr: [], //已选择数据id
goodsShow: false,
totalData: {
kindsNum: 0,
price: 0
},
screen: {
document_id: "",
document_no: "",
remark: "",
stock_json: "",
time: ""
},
remark: '',
isSubmit: false, //提交防抖
info: null, //详情原始数据
dialogVisible: false, //弹框
inputIndex: -1
};
},
onLoad(option) {
this.screen.document_id = option.document_id || '';
this.screen.time = this.$util.timeFormat(Date.parse(new Date()) / 1000);
if (this.screen.document_id) {
this.getEditData();
} else {
this.getDocumentNo()
}
},
watch: {
goodsIdArr(data) {
this.calcTotalData();
},
},
methods: {
getDocumentNo() {//获取单据号
getStorageDocumentNo().then(res => {
if (res.code >= 0) {
this.screen.document_no = res.data
} else {
this.$util.showToast({
title: res.message
});
}
});
},
getEditData() { //编辑时获取详情
getStorageDetailInEdit(this.screen.document_id).then(res => {
if (res.code >= 0 && res.data) {
this.info = res.data;
this.screen.document_no = this.info.document_no
this.screen.time = this.$util.timeFormat(this.info.time)
this.remark = JSON.parse(JSON.stringify(this.info.remark))
this.screen.remark = this.info.remark
for (let sku_id in this.info.goods_list) {
this.info.goods_list[sku_id].title = this.info.goods_list[sku_id].sku_name
this.goodsIdArr.push(parseInt(sku_id));
this.goodsList.push(this.info.goods_list[sku_id]);
}
}
});
},
getGoodsData({
detail
}, index) { //input回车处理
this.inputIndex = index
this.params.search_text = detail ? detail.value : ''
if (detail&&detail.value) {
getSkuListForStock({
search: detail ? detail.value : ''
}).then(res => {
if (res.code >= 0 && res.data.length == 1) {
this.selectGoods(res.data)
} else if (res.code >= 0) {
this.dialogVisible = true
} else {
this.$util.showToast({
title: res.message
});
}
});
} else {
this.dialogVisible = true
}
},
selectGoods(data) { //选择数据
data.forEach((el, index) => {
el.goods_num = 1;
el.goods_price = 0;
el.title = el.sku_name + ''
//点击或回车行为选择商品后当为第一行并且展示列表不存在选择的商品push到展示列表或者不为第一行并且展示列表中不存在时选择的商品除第一条全部push到展示列表
if (!this.goodsIdArr.includes(el.sku_id)) {
console.log(111);
this.goodsIdArr.push(el.sku_id);
this.goodsList.push(el);
} else {//只要展示列表存在直接累加
var elIndex = this.goodsIdArr.indexOf(el.sku_id)
if(this.params.search_text){
this.goodsList[elIndex].goods_num = parseFloat(this.goodsList[elIndex].goods_num) + 1
}
}
})
this.goodsShow = false;
this.params.search_text = '';
this.$forceUpdate();
},
delGoods(id) {//删除已选择的商品
this.goodsList.splice(this.goodsIdArr.indexOf(id), 1);
this.goodsIdArr.splice(this.goodsIdArr.indexOf(id), 1);
},
stockOutFn() {
if (!this.screen.document_no) {
this.$util.showToast({
title: "请输入入库单号"
});
return false;
}
if (!this.screen.time) {
this.$util.showToast({
title: "请选择入库时间"
});
return false;
}
if (!this.goodsIdArr.length) {
this.$util.showToast({
title: "请选择入库数据"
});
return false;
}
if (this.globalStoreInfo.stock_config && this.globalStoreInfo.stock_config.is_audit == 1) {
this.$refs.tipsPop.open();
} else {
this.save();
}
},
save() {
// 检测库存是否填写,且提取数据
let isStock = false;
let saveData = [];
try {
this.goodsList.forEach((item, index) => {
if (this.goodsIdArr.includes(item.sku_id)) {
if (!parseFloat(item.goods_num || 0)) {
isStock = true;
let toast = "请输入" + item.sku_name + "的入库数量";
this.$util.showToast({
title: toast
});
throw new Error('end');
}
var obj = {};
obj.goods_num = item.goods_num;
obj.goods_price = item.goods_price;
obj.goods_sku_id = item.sku_id;
saveData.push(obj);
}
})
} catch (e) {
if (e.message != "end") throw e;
}
if (isStock) return false;
if (this.isSubmit) return false;
this.isSubmit = true;
this.screen.stock_json = JSON.stringify(saveData)
editStorage(this.screen).then(res => {
this.isSubmit = false;
this.$util.showToast({
title: res.message
});
if (res.code >= 0) {
if (this.$refs.tipsPop) this.$refs.tipsPop.close();
setTimeout(() => {
this.backFn();
}, 500);
this.resetFn();
}
});
},
backFn() {
this.$util.redirectTo('/pages/stock/storage');
},
calcTotalData() {//计算商品种类、金额
this.totalData.price = 0;
this.totalData.kindsNum = 0;
this.goodsList.forEach((item, index) => {
if (this.goodsIdArr.includes(item.sku_id)) {
this.totalData.price += parseFloat(item.goods_price ?? 0) * parseFloat(item.goods_num ||
1);
}
})
this.totalData.kindsNum = this.goodsIdArr.length;
},
resetFn() {
this.goodsIdArr = [];
this.goodsShow = false;
this.totalData.kindsNum = 0;
this.totalData.price = 0;
},
changeTime(data) {//设置时间
this.screen.time = data;
},
remarkConfirm() {//设置备注
this.screen.remark = JSON.parse(JSON.stringify(this.remark))
this.$refs.remarkPopup.close()
}
}
};

View File

@@ -0,0 +1,217 @@
import {
getWastageDocumentNo,
getWastageDetailInEdit,
getSkuListForStock,
editWastage
} from '@/api/stock.js';
export default {
data() {
return {
params: {
search_text: '', //产品名称
},
goodsList: [], //已选择数据
goodsIdArr: [], //已选择数据id
goodsShow: false,
totalData: {
kindsNum: 0,
price: 0
},
screen: {
document_id: "",
document_no: "",
remark: "",
stock_json: "",
time: ""
},
remark: '',
isSubmit: false, //提交防抖
info: null, //详情原始数据
dialogVisible: false, //弹框
inputIndex: -1
};
},
onLoad(option) {
this.screen.document_id = option.document_id || 0;
this.screen.time = this.$util.timeFormat(Date.parse(new Date()) / 1000);
if (this.screen.document_id) {
this.getEditData();
} else {
this.getDocumentNo()
}
},
watch: {
goodsIdArr(data) {
this.calcTotalData();
},
},
methods: {
getDocumentNo() {//获取单据号
getWastageDocumentNo().then(res => {
if (res.code >= 0) {
this.screen.document_no = res.data
} else {
this.$util.showToast({
title: res.message
});
}
});
},
getEditData() {//编辑时获取详情
getWastageDetailInEdit(this.screen.document_id).then(res => {
if (res.code >= 0 && res.data) {
this.info = res.data;
this.screen.document_no = this.info.document_no
this.screen.time = this.$util.timeFormat(this.info.time)
this.remark = JSON.parse(JSON.stringify(this.info.remark))
this.screen.remark = this.info.remark
for (let sku_id in this.info.goods_list) {
this.info.goods_list[sku_id].title = this.info.goods_list[sku_id].sku_name
this.goodsIdArr.push(parseInt(sku_id));
this.goodsList.push(this.info.goods_list[sku_id]);
}
}
});
},
getGoodsData({
detail
}, index) { //input回车处理
this.inputIndex = index
if (detail && detail.value) {
getSkuListForStock({
search: detail ? detail.value : ''
}).then(res => {
if (res.code >= 0 && res.data.length == 1) {
this.selectGoods(res.data)
} else if (res.code >= 0) {
this.params.search_text = detail ? detail.value : ''
this.dialogVisible = true
} else {
this.$util.showToast({
title: res.message
});
}
});
} else {
this.params.search_text = detail ? detail.value : ''
this.dialogVisible = true
}
},
selectGoods(data) { //选择数据
data.forEach((el, index) => {
el.goods_num = 1;
el.goods_price = 0;
el.title = el.sku_name + ''
//点击或回车行为选择商品后当为第一行并且展示列表不存在选择的商品push到展示列表或者不为第一行并且展示列表中不存在时选择的商品除第一条全部push到展示列表
if (!this.goodsIdArr.includes(el.sku_id)) {
console.log(111);
this.goodsIdArr.push(el.sku_id);
this.goodsList.push(el);
} else {//只要展示列表存在直接累加
var elIndex = this.goodsIdArr.indexOf(el.sku_id)
if(this.params.search_text){
this.goodsList[elIndex].goods_num = parseFloat(this.goodsList[elIndex].goods_num) + 1
}
}
})
this.goodsShow = false;
this.params.search_text = '';
this.$forceUpdate();
},
delGoods(id) {//删除已选择的商品
this.goodsList.splice(this.goodsIdArr.indexOf(id), 1);
this.goodsIdArr.splice(this.goodsIdArr.indexOf(id), 1);
},
stockOutFn() {
if (!this.screen.document_no) {
this.$util.showToast({
title: "请输入出库单号"
});
return false;
}
if (!this.goodsIdArr.length) {
this.$util.showToast({
title: "请选择出库数据"
});
return false;
}
if (this.globalStoreInfo.stock_config && this.globalStoreInfo.stock_config.is_audit == 1) {
this.$refs.tipsPop.open();
} else {
this.save();
}
},
save() {
// 检测库存是否填写,且提取数据
let isStock = false;
let saveData = [];
try {
this.goodsList.forEach((item, index) => {
if (this.goodsIdArr.includes(item.sku_id)) {
if (!parseFloat(item.goods_num || 0)) {
isStock = true;
let toast = "请输入" + item.sku_name + "的出库数量";
this.$util.showToast({
title: toast
});
throw new Error('end');
}
var obj = {};
obj.goods_num = item.goods_num;
obj.goods_price = item.cost_price;
obj.goods_sku_id = item.sku_id;
saveData.push(obj);
}
})
} catch (e) {
if (e.message != "end") throw e;
}
if (isStock) return false;
if (this.isSubmit) return false;
this.isSubmit = true;
this.screen.stock_json = JSON.stringify(saveData)
editWastage(this.screen).then(res => {
this.isSubmit = false;
this.$util.showToast({
title: res.message
});
if (res.code >= 0) {
if (this.$refs.tipsPop) this.$refs.tipsPop.close();
setTimeout(() => {
this.backFn();
}, 500);
this.resetFn();
}
});
},
backFn() {
this.$util.redirectTo('/pages/stock/wastage');
},
calcTotalData() {//计算商品种类、金额
this.totalData.price = 0;
this.totalData.kindsNum = 0;
this.goodsList.forEach((item, index) => {
if (this.goodsIdArr.includes(item.sku_id)) {
this.totalData.price += parseFloat(item.cost_price ?? 0) * parseFloat(item.goods_num || 1);
}
})
this.totalData.kindsNum = this.goodsIdArr.length;
},
resetFn() {
this.goodsIdArr = [];
this.goodsShow = false;
this.totalData.kindsNum = 0;
this.totalData.price = 0;
},
changeTime(data) {
this.screen.time = data;
},
remarkConfirm() {
this.screen.remark = JSON.parse(JSON.stringify(this.remark))
this.$refs.remarkPopup.close()
}
}
}

View File

@@ -0,0 +1,222 @@
<template>
<base-page>
<view class="manage">
<view class="screen-warp common-form">
<view class="common-form-item">
<view class="form-inline">
<label class="form-label">业务类型</label>
<view class="form-input-inline">
<picker mode="selector" :range="classifyData.data" @change="pickerChange">
<view class="form-input">
{{ classifyData.currIndex === '' ? '请选择业务类型' : classifyData.data[classifyData.currIndex] }}
</view>
</picker>
</view>
</view>
</view>
<view class="common-form-item">
<view class="form-inline">
<label class="form-label">时间</label>
<view class="form-input-inline">
<picker mode="date" @change="startChange">
<view class="form-input">
{{ !searchData.start_time ? '请输入开始时间' : searchData.start_time }}
</view>
</picker>
</view>
<text class="form-mid">-</text>
<view class="form-input-inline">
<picker mode="date" @change="endChange">
<view class="form-input">{{ !searchData.end_time ? '请输入结束时间' : searchData.end_time }}</view>
</picker>
</view>
</view>
</view>
<view class="common-btn-wrap">
<button type="default" class="screen-btn" @click="searchFn()">筛选</button>
<button type="default" @click="resetFn()">重置</button>
</view>
</view>
<view class="manage-table">
<uni-table ref="table" :loading="table.loading" border stripe emptyText="暂无更多数据">
<uni-tr>
<uni-th width="100" align="left">时间</uni-th>
<uni-th width="100" align="center">商品信息</uni-th>
<uni-th width="100" align="center">操作人</uni-th>
<uni-th width="100" align="center">业务类型</uni-th>
<uni-th width="100" align="center">原库存</uni-th>
<uni-th width="100" align="center">库存变化</uni-th>
<uni-th width="100" align="center">现库存</uni-th>
<uni-th width="100" align="center">备注</uni-th>
<uni-th width="50" align="right">操作</uni-th>
</uni-tr>
<uni-tr v-for="(item, index) in table.data">
<uni-td align="left">{{ $util.timeFormat(item.create_time) }}</uni-td>
<uni-td align="center">{{ item.goods_sku_name }}</uni-td>
<uni-td align="center">{{ item.operater_name }}</uni-td>
<uni-td align="center">{{ item.name }}</uni-td>
<uni-td align="center">{{ item.before_store_stock }}</uni-td>
<uni-td align="center">{{ (item.type == 'input' ? '+' : '-') + item.goods_num }}</uni-td>
<uni-td align="center">{{ item.after_store_stock }}</uni-td>
<uni-td align="center">{{ item.remark }}</uni-td>
<uni-td align="right">
<view class="action-btn">
<text @click="toDetail(item)">查看</text>
</view>
</uni-td>
</uni-tr>
</uni-table>
<view class="paging-wrap">
<uni-pagination show-icon :page-size="paging.pageSize" :current="paging.pageCurrent" :total="paging.total" @change="paginChange" />
</view>
</view>
</view>
</base-page>
</template>
<script>
import {
getDocumentType,
getStockGoodsRecords
} from '@/api/stock.js';
export default {
data() {
return {
classifyData: {
data: [],
idArr: [],
currIndex: ''
},
table: {
loading: false, //表格加载动画
data: []
},
paging: {
pageSize: 9, // 每页数据量
pageCurrent: 1, // 当前页
total: 0 // 数据总量
},
searchData: {
type: '',
start_time: '',
end_time: ''
}
};
},
onLoad(option) {
this.DocumentType();
},
onShow() {
this.getTableData();
},
methods: {
searchFn() {
this.table.loading = true;
this.paging.pageCurrent = 1;
this.getTableData(this.searchData);
},
resetFn() {
this.table.loading = true;
this.paging.pageCurrent = 1;
this.classifyData.currIndex = '';
this.searchData.type = '';
this.searchData.start_time = '';
this.searchData.end_time = '';
this.getTableData(this.searchData);
},
getTableData(obj = {}) {
let data = {
page_size: this.paging.pageSize,
page: this.paging.pageCurrent
};
Object.assign(data, obj);
getStockGoodsRecords(data).then(res => {
this.table.loading = false;
if (res.code == 0) {
this.table.data = res.data.list;
this.$forceUpdate();
} else {
this.$util.showToast({
title: res.message
});
}
this.paging.total = res.data.count;
})
},
DocumentType() {
getDocumentType().then(res => {
let data = res.data;
if (res.code == 0 && data.length) {
data.forEach((item, index) => {
this.classifyData.data.push(item.name);
this.classifyData.idArr.push(item.key);
});
this.$forceUpdate();
}
})
},
pickerChange(e) {
let index = e.detail.value;
this.classifyData.currIndex = index;
this.searchData.type = this.classifyData.idArr[index];
},
// 切换分页
paginChange(e) {
this.table.loading = true;
this.paging.pageCurrent = e.current;
this.getTableData();
},
startChange(e) {
this.searchData.start_time = e.detail.value;
},
endChange(e) {
let start_time = this.$util.timeTurnTimeStamp(this.searchData.start_time),
end_time = this.$util.timeTurnTimeStamp(e.detail.value);
if (end_time <= start_time) {
this.$util.showToast({
title: '结束时间不能小于开始时间'
});
return false;
}
this.searchData.end_time = e.detail.value;
},
toDetail(data) {
let url = data.type == 'input' ? '/pages/stock/storage' : '/pages/stock/wastage';
this.$util.redirectTo(url, {
id: data.document_no
});
}
}
};
</script>
<style lang="scss" scoped>
.manage {
background-color: #fff;
padding: 0.15rem;
@extend %body-overhide;
}
// 筛选面板
.screen-warp {
padding: 0.15rem;
background-color: #f2f3f5;
margin-bottom: 0.15rem;
}
.paging-wrap {
margin-top: 0.1rem;
}
// 表格详情
.manage-table {
.action-btn {
text {
color: $primary-color;
}
}
}
</style>

View File

@@ -0,0 +1,133 @@
<template>
<base-page>
<view class="stock-body">
<view class="content-wrap" @click="goodsShow = false">
<view class="title">{{ screen.document_id ? '编辑入库单' : '添加入库单' }}</view>
<view class="screen-warp form-content">
<view class="form-item">
<label class="form-label">
<text class="required">*</text>
入库单号
</label>
<view class="form-inline input">
<input type="text" v-model="screen.document_no" :disabled="screen.document_id != ''" placeholder="请输入入库单号" />
</view>
</view>
<view class="form-item">
<label class="form-label">
<text class="required">*</text>
入库时间
</label>
<view class="form-inline">
<uni-datetime-picker v-model="screen.time" type="timestamp" :clearIcon="false" @change="changeTime" />
</view>
</view>
<view class="form-item store-info">
<view class="form-label">当前门店</view>
<view class="form-inline">{{ globalStoreInfo.store_name }}</view>
</view>
<view class="form-item store-info">
<view class="form-label">当前操作人</view>
<view class="form-inline">{{ userInfo ? userInfo.username : '' }}</view>
</view>
</view>
<view class="tips text-color" v-if="globalStoreInfo.stock_config && globalStoreInfo.stock_config.is_audit == 1">
说明待审核状态下只有经办人允许修改只有变为已审核状态后才会使库存发生变化已审核状态的单据不允许再修改</view>
<view class="table-wrap">
<view class="table-head">
<view class="table-tr">
<view class="table-th" style="flex: 3;">产品名称/规格/编码</view>
<view class="table-th" style="flex: 1;">当前库存</view>
<view class="table-th" style="flex: 1;">单位</view>
<view class="table-th" style="flex: 2;">成本价</view>
<view class="table-th" style="flex: 2;">数量</view>
<view class="table-th" style="flex: 1;">总金额</view>
<view class="table-th" style="flex: 1;">操作</view>
</view>
</view>
<view class="table-body">
<view class="table-tr">
<view class="table-td select-goods-input" style="flex: 3;" @click.stop="goodsShow = true">
<input type="text" @confirm="getGoodsData($event, -1)" placeholder="请输入产品名称/规格/编码" v-model="params.search_text" />
<text class="iconfont icontuodong" @click="getGoodsData({ detail: null }, -1)"></text>
</view>
<view class="table-td" style="flex: 1;"></view>
<view class="table-td" style="flex: 1;"></view>
<view class="table-td" style="flex: 2;"></view>
<view class="table-td" style="flex: 2;"></view>
<view class="table-td" style="flex: 1;"></view>
<view class="table-td" style="flex: 1;"></view>
</view>
<block v-for="(item, index) in goodsList" :key="index">
<view class="table-tr" v-if="goodsIdArr.includes(item.sku_id)">
<view class="table-td goods-name" style="flex: 3;">{{ item.title }}</view>
<view class="table-td" style="flex: 1;">{{ item.real_stock || 0 }}</view>
<view class="table-td" style="flex: 1;">{{ item.unit || '件' }}</view>
<view class="table-td" style="flex: 2;">
<input type="number" v-model="item.goods_price" placeholder="请输入成本价" @input="calcTotalData" />
</view>
<view class="table-td" style="flex: 2;">
<input type="number" v-model="item.goods_num" placeholder="请输入数量" @input="calcTotalData" />
</view>
<view class="table-td" style="flex: 1;">
{{ (item.goods_num * item.goods_price || 0).toFixed(2) }}
</view>
<view class="table-td" style="flex: 1;">
<button type="default" class="delete" @click="delGoods(item.sku_id)">删除</button>
</view>
</view>
</block>
<view class="table-tr table-empty" v-if="!goodsIdArr.length">暂无数据请选择商品数据</view>
</view>
</view>
</view>
<view class="action-wrap">
<view class="table-total">合计{{ totalData.kindsNum }} 种产品合计金额{{ totalData.price.toFixed(2) }}</view>
<view class="btn-wrap">
<button type="default" class="remark default" @click="$refs.remarkPopup.open()">备注</button>
<button type="default" class="stockout-btn" @click="stockOutFn" :loading="isSubmit">入库</button>
<button type="default" class="default" @click="backFn">返回</button>
</view>
</view>
</view>
<stock-goods-dialog v-model="dialogVisible" :params="params" @selectGoods="selectGoods" />
<uni-popup ref="tipsPop" type="center">
<view class="confirm-pop">
<view class="title">单据保存后将处于"待审核"状态只有经办人可以编辑或删除等操作是否确认保存</view>
<view class="btn">
<button type="primary" class="default-btn btn save" @click="$refs.tipsPop.close()">取消</button>
<button type="primary" class="primary-btn btn" @click="save">确定</button>
</view>
</view>
</uni-popup>
<uni-popup ref="remarkPopup" type="center">
<view class="remark-wrap">
<view class="header">
<text class="title">备注</text>
<text class="iconfont iconguanbi1" @click="$refs.remarkPopup.close()"></text>
</view>
<view class="body">
<textarea v-model="remark" placeholder="填写备注信息" placeholder-class="placeholder-class" />
</view>
<view class="footer">
<button type="default" class="primary-btn" @click="remarkConfirm">确认</button>
</view>
</view>
</uni-popup>
</base-page>
</template>
<script>
import stockin from "./public/js/stockin"
import stockGoodsDialog from '@/components/stock-goods-dialog/stock-goods-dialog.vue';
export default {
components: {
stockGoodsDialog
},
mixins: [stockin]
};
</script>
<style lang="scss" scoped>
@import './public/css/editStock.scss';
</style>

View File

@@ -0,0 +1,126 @@
<template>
<base-page>
<view class="stock-body">
<view class="content-wrap" @click="goodsShow = false">
<view class="title">{{ screen.document_id ? '编辑出库单' : '添加出库单' }}</view>
<view class="screen-warp form-content">
<view class="form-item">
<label class="form-label">
<text class="required">*</text>
出库单号
</label>
<view class="form-inline input">
<input type="text" v-model="screen.document_no" :disabled="screen.document_id != ''" placeholder="请输入出库单号" />
</view>
</view>
<view class="form-item">
<label class="form-label">
<text class="required">*</text>
出库时间
</label>
<view class="form-inline">
<uni-datetime-picker v-model="screen.time" type="timestamp" :clearIcon="false" @change="changeTime" />
</view>
</view>
<view class="form-item store-info">
<view class="form-label">当前门店</view>
<view class="form-inline">{{ globalStoreInfo.store_name }}</view>
</view>
<view class="form-item store-info">
<view class="form-label">当前操作人</view>
<view class="form-inline">{{ userInfo ? userInfo.username : '' }}</view>
</view>
</view>
<view class="tips text-color" v-if="globalStoreInfo.stock_config && globalStoreInfo.stock_config.is_audit == 1">说明待审核状态下只有经办人允许修改只有变为已审核状态后才会使库存发生变化已审核状态的单据不允许再修改</view>
<view class="table-wrap">
<view class="table-head">
<view class="table-tr">
<view class="table-th" style="flex: 3;">产品名称/规格/编码</view>
<view class="table-th" style="flex: 1;">当前库存</view>
<view class="table-th" style="flex: 1;">单位</view>
<view class="table-th" style="flex: 1;">成本</view>
<view class="table-th" style="flex: 2;">数量</view>
<view class="table-th" style="flex: 1;">操作</view>
</view>
</view>
<view class="table-body">
<view class="table-tr">
<view class="table-td select-goods-input" style="flex: 3;" @click.stop="goodsShow = true">
<input type="text" @confirm="getGoodsData($event, -1)" placeholder="请输入产品名称/规格/编码" v-model="params.search_text" />
<text class="iconfont icontuodong" @click="getGoodsData({ detail: null }, -1)"></text>
</view>
<view class="table-td" style="flex: 1;"></view>
<view class="table-td" style="flex: 1;"></view>
<view class="table-td" style="flex: 1;"></view>
<view class="table-td" style="flex: 2;"></view>
<view class="table-td" style="flex: 1;"></view>
</view>
<block v-for="(item, index) in goodsList" :key="index">
<view class="table-tr" v-if="goodsIdArr.includes(item.sku_id)">
<view class="table-td goods-name" style="flex: 3;">{{ item.title }}</view>
<view class="table-td" style="flex: 1;">{{ item.real_stock || 0 }}</view>
<view class="table-td" style="flex: 1;">{{ item.unit || '件' }}</view>
<view class="table-td" style="flex: 1;">{{ item.cost_price || '0.00' }}</view>
<view class="table-td" style="flex: 2;">
<input type="number" v-model="item.goods_num" placeholder="请输入数量" @input="calcTotalData" />
</view>
<view class="table-td" style="flex: 1;">
<button type="default" class="delete" @click="delGoods(item.sku_id)">删除</button>
</view>
</view>
</block>
<view class="table-tr table-empty" v-if="!goodsIdArr.length">暂无数据请选择商品数据</view>
</view>
</view>
</view>
<view class="action-wrap">
<view class="table-total">合计{{ totalData.kindsNum }}种产品合计金额{{ totalData.price.toFixed(2) }}</view>
<view class="btn-wrap">
<button type="default" class="remark default" @click="$refs.remarkPopup.open()">备注</button>
<button type="default" class="stockout-btn" @click="stockOutFn" :loading="isSubmit">出库</button>
<button type="default" class="default" @click="backFn">返回</button>
</view>
</view>
</view>
<stock-goods-dialog v-model="dialogVisible" :params="params" @selectGoods="selectGoods" />
<uni-popup ref="tipsPop" type="center">
<view class="confirm-pop">
<view class="title">单据保存后将处于"待审核"状态只有经办人可以编辑或删除等操作是否确认保存</view>
<view class="btn">
<button type="primary" class="default-btn btn save" @click="$refs.tipsPop.close()">取消</button>
<button type="primary" class="primary-btn btn" @click="save">确定</button>
</view>
</view>
</uni-popup>
<uni-popup ref="remarkPopup" type="center">
<view class="remark-wrap">
<view class="header">
<text class="title">备注</text>
<text class="iconfont iconguanbi1" @click="$refs.remarkPopup.close()"></text>
</view>
<view class="body">
<textarea v-model="remark" placeholder="填写备注信息" placeholder-class="placeholder-class" />
</view>
<view class="footer">
<button type="default" class="primary-btn" @click="remarkConfirm">确认</button>
</view>
</view>
</uni-popup>
</base-page>
</template>
<script>
import stockout from "./public/js/stockout";
import stockGoodsDialog from '@/components/stock-goods-dialog/stock-goods-dialog.vue';
export default {
components: {
stockGoodsDialog
},
mixins: [stockout]
}
</script>
<style lang="scss" scoped>
@import './public/css/editStock.scss';
</style>

View File

@@ -0,0 +1,354 @@
<template>
<base-page>
<view class="goodslist">
<view class="goodslist-box">
<view class="goodslist-left">
<view class="goods-title">
入库单查询
<text class="iconfont icongengduo1"></text>
</view>
<view class="goods-search">
<view class="search">
<text class="iconfont icon31sousuo"></text>
<input type="text" v-model="search_text" @input="search" placeholder="搜索入库单号" />
</view>
</view>
<scroll-view scroll-y="true" class="goods-list-scroll" :show-scrollbar="false" @scrolltolower="getListData">
<view class="item" @click="getDetailData(item.document_id, index)" v-for="(item, index) in list" :key="index" :class="{ itemhover: selectGoodsKeys == index }">
<view class="title">
<view>{{ item.document_no }}</view>
<view>{{ item.type_name }}</view>
</view>
<view class="other-info">
<view>{{ item.document_money }}</view>
<view>{{ item.operater_name }}</view>
<view>{{ item.status_name }}</view>
<view>{{ $util.timeFormat(item.create_time) }}</view>
</view>
</view>
<view class="notYet" v-if="!one_judge && !list.length">暂无数据</view>
</scroll-view>
<view class="add-wastage">
<button type="default" class="primary-btn" v-if="globalStoreInfo.stock_type == 'store'" @click="add()">添加入库单</button>
</view>
</view>
<view class="goodslist-right">
<view class="goods-title">入库单详情</view>
<view class="order-information" v-if="Object.keys(detail).length">
<view class="order-status">基本信息</view>
<view class="order-types">
<view class="type type1">
<view>入库单号</view>
<view>{{ detail.document_no }}</view>
</view>
<view class="type type1">
<view>制单人</view>
<view>{{ detail.operater_name || '--' }}</view>
</view>
<view class="type type1">
<view>制单时间</view>
<view class="message">{{ detail.create_time }}</view>
</view>
<view class="type type1">
<view>入库时间</view>
<view class="message">{{ detail.time }}</view>
</view>
<view class="type type1">
<view>单据类型</view>
<view class="message">{{ detail.type_name }}</view>
</view>
<view class="type type1">
<view>状态</view>
<view class="message">{{ detail.status_data.name }}</view>
</view>
<view class="type type1" v-if="detail.verifier_name">
<view>审核人</view>
<view class="message">{{ detail.verifier_name }}</view>
</view>
<view class="type type1" v-if="detail.audit_time">
<view>审核时间</view>
<view class="message">{{ detail.audit_time }}</view>
</view>
<view class="type type1" v-if="detail.status == -1">
<view>拒绝理由</view>
<view class="message">{{ detail.refuse_reason }}</view>
</view>
<view class="type type1">
<view>备注</view>
<view class="message">{{ detail.remark }}</view>
</view>
</view>
<view class="goods-info">
<view class="title">商品明细</view>
<view class="table">
<view class="table-th table-all">
<view class="table-td" style="width:45%;justify-content: flex-start;">商品名称/规格/条形码
</view>
<view class="table-td" style="width:15%">单位</view>
<view class="table-td" style="width:10%">数量</view>
<view class="table-td" style="width:15%">成本价()</view>
<view class="table-td" style="width:15%;justify-content: flex-end;">金额()</view>
</view>
<view class="table-tr table-all" v-for="(item, index) in detail.goods_sku_list_array" :key="index">
<view class="table-td table-goods-name" style="width:45%;justify-content: flex-start;">
<image :src="$util.img(item.goods_sku_img)" mode="aspectFill" />
<text class="multi-hidden">{{ item.goods_sku_name }}</text>
</view>
<view class="table-td" style="width:15%">{{ item.goods_unit || '件' }}</view>
<view class="table-td" style="width:10%">{{ item.goods_num }}</view>
<view class="table-td" style="width:15%">{{ item.goods_price }}</view>
<view class="table-td" style="width:15%;justify-content: flex-end;">{{ parseFloat(item.goods_sum).toFixed(2) }}</view>
</view>
</view>
<view class="total-money-num">
<view class="box">
<view>商品种类</view>
<view class="money">{{ detail.goods_count }}</view>
</view>
<view class="box">
<view>商品数量</view>
<view class="money">{{ detail.goods_price }}{{ detail.goods_unit }}</view>
</view>
<view class="box total">
<view>合计金额</view>
<view class="money">{{ parseFloat(detail.goods_total_price).toFixed(2) }}</view>
</view>
</view>
<view class="action-box">
<!-- 只有经办人才能操作入库单 -->
<template v-if="(detail.status == 1 || detail.status == -1) && detail.operater == detail.uid">
<button type="primary" class="default-btn" @click="open('deleteWastagePop')">删除</button>
<button type="primary" class="default-btn" @click="edit">编辑</button>
</template>
<!-- 只有管理员和拥有单据审核权限的才能审核 -->
<template v-if="detail.status == 1 && detail.is_audit == 0">
<button type="primary" class="default-btn" @click="open('refuseWastagePop')">审核拒绝</button>
<button type="primary" class="primary-btn" @click="open('agreeWastagePop')">审核通过</button>
</template>
</view>
</view>
</view>
<block v-else-if="!one_judge && !Object.keys(detail).length">
<image class="cart-empty" src="@/static/goods/goods_empty.png" mode="widthFix" />
</block>
</view>
</view>
</view>
<!-- 同意 -->
<unipopup ref="agreeWastagePop" type="center">
<view class="confirm-pop">
<view class="title">确定要通过该单据吗</view>
<view class="btn">
<button type="primary" class="default-btn btn save" @click="close('agreeWastagePop')">取消</button>
<button type="primary" class="primary-btn btn" @click="agree">确定</button>
</view>
</view>
</unipopup>
<!-- 拒绝 -->
<unipopup ref="refuseWastagePop" type="center">
<view class="confirm-pop message">
<view class="title">
拒绝理由
<text class="iconfont iconguanbi1" @click="close('refuseWastagePop')"></text>
</view>
<view class="textarea-box">
<textarea v-model="refuseReason" class="textarea" maxlength="200" placeholder="输入请不多于200字"></textarea>
</view>
<button @click="refuse" type="primary" class="primary-btn btn save">保存</button>
</view>
</unipopup>
<!-- 删除 -->
<unipopup ref="deleteWastagePop" type="center">
<view class="confirm-pop">
<view class="title">确定要删除该单据吗</view>
<view class="btn">
<button type="primary" class="default-btn btn save" @click="close('deleteWastagePop')">取消</button>
<button type="primary" class="primary-btn btn" @click="deleteDocument">确定</button>
</view>
</view>
</unipopup>
</base-page>
</template>
<script>
import {
getStorageLists,
getStorageDetail,
storageAgree,
storageRefuse,
storageDelete
} from '@/api/stock.js';
import unipopup from '@/components/uni-popup/uni-popup.vue';
export default {
components: {
unipopup
},
data() {
return {
selectGoodsKeys: 0,
//获取订单的页数
page: 1,
//每次获取订单的条数
page_size: 9,
// 订单搜索是用到的数据
search_text: '',
//初始时加载详情数据判断
one_judge: true,
// 订单列表数据
list: [],
//订单详情数据
detail: {},
repeatFlag: false,
refuseReason: ''
};
},
onLoad(option) {
if (option.id) {
this.search_text = option.id;
}
this.getListData();
},
methods: {
// 搜索
search() {
this.page = 1;
this.list = [];
this.one_judge = true;
this.getListData();
},
/**
* 获取订单列表
*/
getListData() {
getStorageLists({
page: this.page,
page_size: this.page_size,
search_text: this.search_text
}).then(res => {
if (res.data.list.length == 0 && this.one_judge) {
this.detail = {};
this.one_judge = false;
}
if (res.code >= 0 && res.data.list.length != 0) {
this.page += 1;
if (this.list.length == 0) {
this.list = res.data.list;
} else {
this.list = this.list.concat(res.data.list);
}
//初始时加载一遍详情数据
if (this.one_judge) {
this.getDetailData(this.list[0].document_id);
}
}
});
},
/**
* 获取订单详情数据
*/
getDetailData(document_id, keys = 0) {
this.selectGoodsKeys = keys;
this.type = 'detail';
getStorageDetail(document_id).then(res => {
if (res.code >= 0) {
this.detail = res.data;
this.$forceUpdate();
this.one_judge = false;
}
});
},
add() {
this.$util.redirectTo('/pages/stock/stockin');
},
edit() {
this.$util.redirectTo('/pages/stock/stockin', {
document_id: this.detail.document_id
});
},
open(action) {
this.$refs[action].open();
},
close(name) {
this.$refs[name].close();
},
agree() {
if (this.repeatFlag) return;
this.repeatFlag = true;
storageAgree(this.detail.document_id).then(res => {
this.$util.showToast({
title: res.message
});
if (res.code >= 0) {
this.search();
this.getDetailData(this.detail.document_id);
this.close('agreeWastagePop');
}
this.repeatFlag = false;
});
},
refuse() {
if (!this.refuseReason) {
this.$util.showToast({
title: '请输入拒绝理由'
});
return;
}
if (this.repeatFlag) return;
this.repeatFlag = true;
storageRefuse({
document_id: this.detail.document_id,
refuse_reason: this.refuseReason
}).then(res => {
this.$util.showToast({
title: res.message
});
if (res.code >= 0) {
this.search();
this.getDetailData(this.detail.document_id);
this.close('refuseWastagePop');
}
this.repeatFlag = false;
});
},
deleteDocument() {
if (this.repeatFlag) return;
this.repeatFlag = true;
storageDelete(this.detail.document_id).then(res => {
this.$util.showToast({
title: res.message
});
if (res.code >= 0) {
this.list.splice(this.selectGoodsKeys, 1);
if (this.selectGoodsKeys == 0) {
this.selectGoodsKeys = 0;
} else {
this.selectGoodsKeys -= 1;
}
this.getDetailData(this.list[this.selectGoodsKeys].document_id, this.selectGoodsKeys);
this.close('deleteWastagePop');
}
this.repeatFlag = false;
});
}
}
};
</script>
<style scoped lang="scss">
@import './public/css/orderlist.scss';
</style>

View File

@@ -0,0 +1,356 @@
<template>
<base-page>
<view class="goodslist">
<view class="goodslist-box">
<view class="goodslist-left">
<view class="goods-title">
出库单查询
<text class="iconfont icongengduo1"></text>
</view>
<view class="goods-search">
<view class="search">
<text class="iconfont icon31sousuo"></text>
<input type="text" v-model="search_text" @input="search" placeholder="搜索出库单号" />
</view>
</view>
<scroll-view scroll-y="true" class="goods-list-scroll" :show-scrollbar="false" @scrolltolower="getListData">
<view class="item" @click="getDetailData(item.document_id, index)" v-for="(item, index) in list" :key="index" :class="{ itemhover: selectGoodsKeys == index }">
<view class="title">
<view>{{ item.document_no }}</view>
<view>{{ item.type_name }}</view>
</view>
<view class="other-info">
<view>{{ item.document_money }}</view>
<view>{{ item.operater_name }}</view>
<view>{{ item.status_name }}</view>
<view>{{ $util.timeFormat(item.create_time) }}</view>
</view>
</view>
<view class="notYet" v-if="!one_judge && !list.length">暂无数据</view>
</scroll-view>
<view class="add-wastage">
<button type="default" class="primary-btn" v-if="globalStoreInfo.stock_type == 'store'" @click="add()">添加出库单</button>
</view>
</view>
<view class="goodslist-right">
<view class="goods-title">出库单详情</view>
<view class="order-information" v-if="Object.keys(detail).length">
<view class="order-status">基本信息</view>
<view class="order-types">
<view class="type type1">
<view>出库单号</view>
<view>{{ detail.document_no }}</view>
</view>
<view class="type type1">
<view>制单人</view>
<view>{{ detail.operater_name || '--' }}</view>
</view>
<view class="type type1">
<view>制单时间</view>
<view class="message">{{ detail.create_time }}</view>
</view>
<view class="type type1">
<view>出库时间</view>
<view class="message">{{ detail.time }}</view>
</view>
<view class="type type1">
<view>单据类型</view>
<view class="message">{{ detail.type_name }}</view>
</view>
<view class="type type1">
<view>状态</view>
<view class="message">{{ detail.status_data.name }}</view>
</view>
<view class="type type1" v-if="detail.verifier_name">
<view>审核人</view>
<view class="message">{{ detail.verifier_name }}</view>
</view>
<view class="type type1" v-if="detail.audit_time">
<view>审核时间</view>
<view class="message">{{ detail.audit_time }}</view>
</view>
<view class="type type1" v-if="detail.status == -1">
<view>拒绝理由</view>
<view class="message">{{ detail.refuse_reason }}</view>
</view>
<view class="type type1">
<view>备注</view>
<view class="message">{{ detail.remark }}</view>
</view>
</view>
<view class="goods-info">
<view class="title">商品明细</view>
<view class="table">
<view class="table-th table-all">
<view class="table-td" style="width:45%;justify-content: flex-start;">商品名称/规格/条形码</view>
<view class="table-td" style="width:15%">单位</view>
<view class="table-td" style="width:10%">数量</view>
<view class="table-td" style="width:15%">成本价()</view>
<view class="table-td" style="width:15%;justify-content: flex-end;">金额()</view>
</view>
<view class="table-tr table-all" v-for="(item, index) in detail.goods_sku_list_array" :key="index">
<view class="table-td table-goods-name" style="width:45%;justify-content: flex-start;">
<image :src="$util.img(item.goods_sku_img)" mode="aspectFill" />
<text class="multi-hidden">{{ item.goods_sku_name }}</text>
</view>
<view class="table-td" style="width:15%">{{ item.goods_unit || '件' }}</view>
<view class="table-td" style="width:10%">{{ item.goods_num }}</view>
<view class="table-td" style="width:15%">{{ item.goods_price }}</view>
<view class="table-td" style="width:15%;justify-content: flex-end;">
{{ parseFloat(item.goods_sum).toFixed(2) }}
</view>
</view>
</view>
<view class="total-money-num">
<view class="box">
<view>商品种类</view>
<view class="money">{{ detail.goods_count }}</view>
</view>
<view class="box">
<view>商品数量</view>
<view class="money">{{ detail.goods_price }}{{ detail.goods_unit }}</view>
</view>
<view class="box total">
<view>合计金额</view>
<view class="money">{{ parseFloat(detail.goods_total_price).toFixed(2) }}</view>
</view>
</view>
</view>
<view class="action-box">
<!-- 只有经办人才能操作入库单 -->
<template v-if="(detail.status == 1 || detail.status == -1) && detail.operater == detail.uid">
<button type="primary" class="default-btn" @click="open('deleteWastagePop')">删除</button>
<button type="primary" class="default-btn" @click="edit">编辑</button>
</template>
<!-- 只有管理员和拥有单据审核权限的才能审核 -->
<template v-if="detail.status == 1 && detail.is_audit == 0">
<button type="primary" class="default-btn" @click="open('refuseWastagePop')">审核拒绝</button>
<button type="primary" class="primary-btn" @click="open('agreeWastagePop')">审核通过</button>
</template>
</view>
</view>
<block v-else-if="!one_judge && !Object.keys(detail).length">
<image class="cart-empty" src="@/static/goods/goods_empty.png" mode="widthFix"/>
</block>
</view>
</view>
</view>
<!-- 同意 -->
<unipopup ref="agreeWastagePop" type="center">
<view class="confirm-pop">
<view class="title">确定要通过该单据吗</view>
<view class="btn">
<button type="primary" class="default-btn btn save" @click="close('agreeWastagePop')">取消</button>
<button type="primary" class="primary-btn btn" @click="agree">确定</button>
</view>
</view>
</unipopup>
<!-- 拒绝 -->
<unipopup ref="refuseWastagePop" type="center">
<view class="confirm-pop message">
<view class="title">
拒绝理由
<text class="iconfont iconguanbi1" @click="close('refuseWastagePop')"></text>
</view>
<view class="textarea-box">
<textarea v-model="refuseReason" class="textarea" maxlength="200" placeholder="输入请不多于200字"></textarea>
</view>
<button @click="refuse" type="primary" class="primary-btn btn save">保存</button>
</view>
</unipopup>
<!-- 删除 -->
<unipopup ref="deleteWastagePop" type="center">
<view class="confirm-pop">
<view class="title">确定要删除该单据吗</view>
<view class="btn">
<button type="primary" class="default-btn btn save" @click="close('deleteWastagePop')">取消</button>
<button type="primary" class="primary-btn btn" @click="deleteDocument">确定</button>
</view>
</view>
</unipopup>
</base-page>
</template>
<script>
import {
getWastageLists,
getWastageDetail,
storageAgree,
storageRefuse,
storageDelete
} from '@/api/stock.js';
import unipopup from '@/components/uni-popup/uni-popup.vue';
export default {
components: {
unipopup
},
data() {
return {
selectGoodsKeys: 0,
//获取订单的页数
page: 1,
//每次获取订单的条数
page_size: 9,
// 订单搜索是用到的数据
search_text: '',
//初始时加载详情数据判断
one_judge: true,
// 订单列表数据
list: [],
//订单详情数据
detail: {},
repeatFlag: false,
refuseReason: ''
};
},
onLoad(option) {
if (option.id) {
this.search_text = option.id;
}
this.getListData();
},
methods: {
// 搜索
search() {
this.page = 1;
this.list = [];
this.one_judge = true;
this.getListData();
},
/**
* 获取订单列表
*/
getListData() {
getWastageLists({
page: this.page,
page_size: this.page_size,
search_text: this.search_text
}).then(res => {
if (res.data.list.length == 0 && this.one_judge) {
this.detail = {};
this.one_judge = false;
}
if (res.code >= 0 && res.data.list.length != 0) {
this.page += 1;
if (this.list.length == 0) {
this.list = res.data.list;
} else {
this.list = this.list.concat(res.data.list);
}
//初始时加载一遍详情数据
if (this.one_judge) {
this.getDetailData(this.list[0].document_id);
}
}
});
},
/**
* 获取订单详情数据
*/
getDetailData(document_id, keys = 0) {
this.selectGoodsKeys = keys;
this.type = 'detail';
getWastageDetail(document_id).then(res => {
if (res.code >= 0) {
this.detail = res.data;
this.$forceUpdate();
this.one_judge = false;
}
});
},
add(data) {
this.$util.redirectTo('/pages/stock/stockout');
},
edit() {
this.$util.redirectTo('/pages/stock/stockout', {
document_id: this.detail.document_id
});
},
open(action) {
this.$refs[action].open();
},
close(name) {
this.$refs[name].close();
},
agree() {
if (this.repeatFlag) return;
this.repeatFlag = true;
storageAgree(this.detail.document_id).then(res => {
this.$util.showToast({
title: res.message
});
if (res.code >= 0) {
this.search();
this.getDetailData(this.detail.document_id);
this.close('agreeWastagePop');
}
this.repeatFlag = false;
});
},
refuse() {
if (!this.refuseReason) {
this.$util.showToast({
title: '请输入拒绝理由'
});
return;
}
if (this.repeatFlag) return;
this.repeatFlag = true;
storageRefuse({
document_id: this.detail.document_id,
refuse_reason: this.refuseReason
}).then(res => {
this.$util.showToast({
title: res.message
});
if (res.code >= 0) {
this.search();
this.getDetailData(this.detail.document_id);
this.close('refuseWastagePop');
}
this.repeatFlag = false;
});
},
deleteDocument() {
if (this.repeatFlag) return;
this.repeatFlag = true;
storageDelete(this.detail.document_id).then(res => {
this.$util.showToast({
title: res.message
});
if (res.code >= 0) {
this.list.splice(this.selectGoodsKeys, 1);
if (this.selectGoodsKeys == 0) {
this.selectGoodsKeys = 0;
} else {
this.selectGoodsKeys -= 1;
}
this.getDetailData(this.list[this.selectGoodsKeys].document_id, this
.selectGoodsKeys);
this.close('deleteWastagePop');
}
this.repeatFlag = false;
});
}
}
};
</script>
<style scoped lang="scss">
@import './public/css/orderlist.scss';
</style>

View File

@@ -0,0 +1,208 @@
<template>
<base-page>
<view class="manage">
<view class="title-back flex items-center cursor-pointer" @click="backFn">
<text class="iconfont iconqianhou1"></text>
<text class="left">返回</text>
<text class="content">|</text>
<text>账户记录</text>
</view>
<view class="screen-warp common-form">
<view class="common-form-item">
<view class="form-inline goods-category">
<label class="form-label">来源方式</label>
<view class="form-input-inline">
<select-lay :zindex="10" :value="screen.from_type" name="names" placeholder="请选择来源方式" :options="fromType" @selectitem="selectFromType"/>
</view>
</view>
<view class="form-inline">
<label class="form-label">发生时间</label>
<view class="form-input-inline">
<uni-datetime-picker v-model="screen.start_date" type="datetime" placeholder="请选择开始时间" :clearIcon="false" />
</view>
<view class="form-input-inline">
<uni-datetime-picker v-model="screen.end_date" type="datetime" placeholder="请选择结束时间" :clearIcon="false" />
</view>
</view>
<view class="form-inline">
<label class="form-label">备注</label>
<view class="form-input-inline">
<input type="text" v-model="screen.remark" placeholder="请输入备注" class="form-input" />
</view>
</view>
</view>
<view class="common-form-item">
<view class="form-inline common-btn-wrap">
<button type="default" class="screen-btn" @click="search()">筛选</button>
<button type="default" @click="reset()">重置</button>
<button type="default" class="screen-btn" @click="exportRecord()">导出</button>
</view>
</view>
</view>
<uni-data-table url="/store/storeapi/account/pages" :cols="cols" ref="table">
<template v-slot:action="data">
<view class="common-table-action" v-if="data.value.from_type == 'order' || data.value.from_type == 'refund'"><text @click="detail(data)">查看详情</text></view>
</template>
</uni-data-table>
</view>
</base-page>
</template>
<script>
import {
getAccountScreen,
accountExport,
} from '@/api/settlement.js';
export default {
data() {
return {
screen: {
page: 1,
start_date: '',
end_date: '',
from_type: '',
remark: '',
},
userList: [],
cols: [{
width: 12,
title: '来源方式',
field: 'type_name',
align: 'left'
}, {
width: 12,
title: '记录金额',
field: 'account_data',
align: 'right'
}, {
width: 18,
title: '发生时间',
align: 'center',
return: data => {
return data.create_time ? this.$util.timeFormat(data.create_time) : '';
}
}, {
width: 48,
title: '备注',
field: 'remark',
align: 'left'
},{
width: 10,
title: '操作',
action: true, // 表格操作列
align: 'right'
}],
fromType: [],
withdrawDetail: null
};
},
onLoad() {
this.getScreenContent();
},
methods: {
detail(data){
if(window.location.origin.indexOf('localhost') != -1){
window.open(window.location.origin+'/cashregister/pages/order/orderlist?order_no='+data.value.related_info.order_no+'&order_from='+data.value.related_info.order_from,'_blank');
}else{
window.open(this.$config.baseUrl+'/cashregister/pages/order/orderlist?order_no='+data.value.related_info.order_no+'&order_from='+data.value.related_info.order_from,'_blank');
}
},
switchStoreAfter() {
this.screen = {
page: 1,
start_date: '',
end_date: ''
};
this.$refs.table.load();
},
search() {
this.$refs.table.load(this.screen);
},
reset() {
this.screen = {
page: 1,
start_date: '',
end_date: '',
from_type: '',
remark: '',
};
},
getScreenContent() {
getAccountScreen().then(res => {
if (res.code == 0) {
this.fromType = Object.keys(res.data.from_type_list).map(index => {
return {
value: index,
label: res.data.from_type_list[index].type_name
};
});
}
});
},
selectFromType(index) {
this.screen.from_type = index == -1 ? '' : this.fromType[index].value;
this.$forceUpdate();
},
backFn() {
this.$util.redirectTo('/pages/store/settlement');
},
exportRecord() {
accountExport(this.screen).then(res => {
if (res.code == 0) {
window.open(this.$util.img(res.data.path));
}else{
this.$util.showToast({
title: res.message
});
}
});
},
}
};
</script>
<style lang="scss" scoped>
.manage {
position: relative;
background-color: #fff;
padding: 0.15rem;
height: 100vh;
box-sizing: border-box;
}
// 筛选面板
.screen-warp {
padding: 0.15rem;
background-color: #f2f3f5;
margin-bottom: 0.15rem;
display: flex;
justify-content: start;
flex-direction: column;
/deep/ .uni-date-x {
height: 0.35rem;
}
/deep/ .uni-select-lay {
background: #fff;
.uni-select-lay-select {
height: 0.37rem;
}
}
.primary-btn {
margin-left: 0;
}
&>* {
margin-right: 0.15rem;
}
.common-btn-wrap button{
margin-right: .1rem;
}
}
</style>

View File

@@ -0,0 +1,57 @@
<template>
<base-page>
<view class="empty-box">
<image src="@/static/cashier/store-close.png" mode="widthFix" />
<view>门店已停业</view>
<button class="btn" @click="$util.redirectTo('/pages/login/login')">返回</button>
</view>
</base-page>
</template>
<script>
export default {
data() {
return {};
},
onLoad() {},
onShow() {},
methods: {}
};
</script>
<style lang="scss" scoped>
.empty-box {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
height: 100%;
position: fixed;
left: 0;
top: 0;
background-color: #ffffff;
z-index: 10000;
image {
width: 3rem;
height: 3rem;
max-height: 3rem;
}
view {
text-align: center;
font-size: 0.16rem;
color: $primary-color;
margin: 0 0 0.3rem;
}
button {
background-color: #fff;
color: $primary-color;
border: 0.01rem solid $primary-color;
font-size: 0.165rem;
width: 1rem;
}
}
</style>

View File

@@ -0,0 +1,409 @@
<template>
<base-page>
<view class="store-config">
<view class="common-wrap common-form fixd common-scrollbar">
<view class="common-title">门店设置</view>
<view class="common-form-item">
<label class="form-label">门店名称</label>
<view class="form-input-inline">
<input type="text" v-model="storeData.store_name" class="form-input" />
</view>
<text class="form-word-aux-line">门店的名称招牌</text>
</view>
<view class="common-form-item store-img">
<label class="form-label">门店图片</label>
<view class="form-input-inline upload-box" @click="addImg">
<view class="upload" v-if="storeData.store_image">
<image :src="$util.img(storeData.store_image)" @error="$util.img(defaultImg.store)" mode="heightFix" />
</view>
<view class="upload" v-else>
<text class="iconfont iconyunshangchuan"></text>
<view>点击上传</view>
</view>
</view>
<text class="form-word-aux-line">门店图片在PC及移动端对应页面及列表作为门店标志出现建议图片尺寸100 * 100像素图片格式jpgpngjpeg</text>
</view>
<view class="common-form-item">
<label class="form-label">门店类型</label>
<view class="form-inline">
<radio-group @change="storeTypeChange" class="form-radio-group">
<label class="radio form-radio-item">
<radio value="directsale" :checked="storeData.store_type == 'directsale'" />
直营店
</label>
<label class="radio form-radio-item">
<radio value="franchise" :checked="storeData.store_type == 'franchise'" />
加盟店
</label>
</radio-group>
</view>
</view>
<view class="common-form-item" v-if="category.status">
<label class="form-label">门店分类</label>
<view class="form-input-inline">
<uni-data-select v-model="storeData.category_id" :localdata="category.list"></uni-data-select>
</view>
</view>
<view class="common-form-item" v-if="label.length">
<label class="form-label">门店标签</label>
<view class="form-block">
<checkbox-group class="form-checkbox-group" @change="labelChange">
<label class="form-checkbox-item" v-for="(item, index) in label">
<checkbox :value="item.label_id.toString()" :checked="labelChecked(item)" />
{{ item.label_name }}
</label>
</checkbox-group>
</view>
</view>
<view class="common-form-item">
<label class="form-label">门店电话</label>
<view class="form-input-inline">
<input type="number" v-model="storeData.telphone" class="form-input" />
</view>
</view>
<view class="common-form-item">
<label class="form-label">门店地址</label>
<view class="form-inline">
<pick-regions ref="selectArea" :default-regions="defaultRegions" @getRegions="handleGetRegions">
<view class="form-input-inline long">
<view class="form-input">{{ storeData.full_address }}</view>
</view>
</pick-regions>
</view>
</view>
<view class="common-form-item">
<label class="form-label"></label>
<view class="form-inline">
<view class="form-input-inline long">
<input type="text" v-model="storeData.address" class="form-input" />
</view>
<view class="form-input-inline short btn" @click="getLatLng()">查找</view>
</view>
</view>
<view class="common-form-item store-img">
<label class="form-label">地图定位</label>
<view class="form-inline">
<view class="map-box">
<image src="@/static/location.png" class="map-icon" />
<map style="width: 100%; height: 100%;" :latitude="storeData.latitude" :longitude="storeData.longitude" :markers="covers" @markertap="markertap" @regionchange="tap"></map>
</view>
</view>
</view>
<view class="common-btn-wrap">
<button type="default" class="screen-btn" @click="saveFn">保存</button>
<button type="default" @click="$util.redirectTo('/pages/store/index')">返回</button>
</view>
</view>
</view>
</base-page>
</template>
<script>
import {
editStore,
getAllStoreCategory,
getAllStoreLabel
} from '@/api/store.js'
import { getAddressByName, getTranAddressInfo } from '@/api/address.js'
export default {
data() {
return {
storeData: {},
covers: [{
latitude: 39.909,
longitude: 116.39742,
iconPath: '/static/location.png'
}],
defaultRegions: [],
category: {
status: 0,
list: []
},
label: [],
labelData: {}
};
},
onLoad() {
this.getLabel();
this.getCategory();
this.getData();
},
methods: {
getData() {
this.storeData = this.$util.deepClone(this.globalStoreInfo);
this.storeData.start_time = this.timeFormat(this.storeData.start_time);
this.storeData.end_time = this.timeFormat(this.storeData.end_time);
this.defaultRegions = [this.storeData.province_id, this.storeData.city_id, this.storeData.district_id];
this.$nextTick(() => {
this.$refs.selectArea.handleDefaultRegions();
});
},
getLabel() {
getAllStoreLabel().then(res => {
if (res.code == 0) {
this.label = res.data;
let labelData = {};
res.data.forEach(item => {
labelData[item.label_id] = item.label_name;
});
this.labelData = labelData;
}
});
},
getCategory() {
getAllStoreCategory().then(res => {
if (res.code == 0) {
this.category.status = res.data.status;
this.category.list = res.data.list.map(item => {
return {
value: item.category_id,
text: item.category_name
};
});
}
});
},
addImg() {
this.$util.upload(1, {
path: 'image'
}, res => {
if (res.length > 0) {
this.storeData.store_image = res[0];
this.$forceUpdate();
}
});
},
tap(e) {
if (e.detail && e.detail.centerLocation) {
this.storeData.latitude = e.detail.centerLocation.latitude;
this.storeData.longitude = e.detail.centerLocation.longitude;
this.covers = [{
latitude: this.storeData.latitude,
longitude: this.storeData.longitude,
iconPath: '/static/location.png'
}];
this.getAddress();
this.$forceUpdate();
}
},
handleGetRegions(regions) {
this.storeData.full_address = '';
this.storeData.full_address += regions[0] != undefined ? regions[0].label : '';
this.storeData.full_address += regions[1] != undefined ? '-' + regions[1].label : '';
this.storeData.full_address += regions[2] != undefined ? '-' + regions[2].label : '';
this.storeData.province_id = regions[0] != undefined ? regions[0].value : '';
this.storeData.city_id = regions[1] != undefined ? regions[1].value : '';
this.storeData.district_id = regions[2] != undefined ? regions[2].value : '';
this.defaultRegions = [this.storeData.province_id, this.storeData.city_id, this.storeData.district_id];
this.$forceUpdate();
this.getLatLng();
},
//获取详细地址
getAddress() {
let value = this.storeData.latitude + ',' + this.storeData.longitude;
getTranAddressInfo(value).then(res => {
if (res.code == 0) {
this.storeData.full_address = '';
this.storeData.full_address += res.data.province != undefined ? res.data.province : '';
this.storeData.full_address += res.data.city != undefined ? '-' + res.data.city : '';
this.storeData.full_address += res.data.district != undefined ? '-' + res.data.district : '';
this.storeData.address = res.data.address != undefined ? res.data.address : '';
this.storeData.province_id = res.data.province_id != undefined ? res.data.province_id : '';
this.storeData.city_id = res.data.city_id != undefined ? res.data.city_id : '';
this.storeData.district_id = res.data.district_id != undefined ? res.data.district_id : '';
this.defaultRegions = [this.storeData.province_id, this.storeData.city_id, this.storeData.district_id];
this.$forceUpdate();
}
});
},
//获取详细地址
getLatLng() {
let value = this.storeData.full_address + this.storeData.address;
getAddressByName(value).then(res => {
if (res.code == 0) {
this.storeData.latitude = res.data.latitude;
this.storeData.longitude = res.data.longitude;
}
});
},
storeTypeChange(e) {
this.storeData.store_type = e.detail.value;
},
getSaveData() {
let data = Object.assign({}, this.storeData);
data.start_time = this.timeTurnTimeStamp(data.start_time);
data.end_time = this.timeTurnTimeStamp(data.end_time);
data.time_week = this.storeData.time_week.toString();
return data;
},
checkData(data) {
if (data.store_name == '') {
this.$util.showToast({
title: '请输入门店名称'
});
return false;
}
if (!data.district_id || data.address == '') {
this.$util.showToast({
title: '请选择门店地址'
});
return false;
}
return true;
},
saveFn() {
let data = this.getSaveData();
if (this.checkData(data)) {
if (this.flag) return false;
this.flag = true;
editStore(data).then(res => {
this.flag = false;
this.$util.showToast({
title: res.message
});
if (res.code >= 0) {
this.$store.dispatch('app/getStoreInfoFn', {
callback: () => {
this.getData();
}
});
}
});
}
},
timeTurnTimeStamp(_time) {
let data = _time.split(':');
return data[0] * 3600 + data[1] * 60;
},
timeFormat(time) {
let h = time / 3600;
let i = (time % 3600) / 60;
h = h < 10 ? '0' + h : h;
i = i < 10 ? '0' + i : i;
return h + ':' + i;
},
labelChange(e) {
if (e.detail.value.length) {
this.storeData.label_id = ',' + e.detail.value.toString() + ',';
let labelName = [];
e.detail.value.forEach(item => {
labelName.push(this.labelData[item]);
});
this.storeData.label_name = ',' + labelName.toString() + ',';
} else {
this.storeData.label_id = '';
this.storeData.label_name = '';
}
},
labelChecked(item) {
let labelIdArr = [];
if (!this.storeData.label_id) return false;
if (typeof this.storeData.label_id == 'string') labelIdArr = this.storeData.label_id.split(',');
return labelIdArr.includes(item.label_id.toString());
}
}
};
</script>
<style lang="scss" scoped>
.store-config {
position: relative;
.common-wrap.fixd {
padding: 30rpx;
height: calc(100vh - 0.4rem);
overflow-y: auto;
// padding-bottom: 1rem !important;
box-sizing: border-box;
.form-label {
width: 1.5rem !important;
}
.form-input-inline /deep/ .uni-select {
border: none;
}
.common-btn-wrap {
position: absolute;
left: 0;
bottom: 0;
right: 0;
padding: 0.24rem 0.2rem;
}
.form-word-aux-line {
margin-left: 1.5rem !important;
}
}
.upload-box {
border: 0.01rem dashed #e6e6e6 !important;
width: 2.5rem !important;
height: 1.2rem !important;
display: flex;
align-items: center;
justify-content: center;
.upload {
text-align: center;
color: #5a5a5a;
.iconfont {
font-size: 0.3rem;
}
image {
max-width: 100%;
height: 1.2rem !important;
}
}
}
.store-img {
align-items: flex-start !important;
}
.map-box {
width: 6.5rem;
height: 5rem;
position: relative;
.map-icon {
position: absolute;
top: calc(50% - 0.36rem);
left: calc(50% - 0.18rem);
width: 0.36rem;
height: 0.36rem;
z-index: 100;
}
}
.form-input {
font-size: 0.16rem;
}
.form-input-inline.btn {
height: 0.37rem;
line-height: 0.35rem;
box-sizing: border-box;
border: 0.01rem solid #e6e6e6;
text-align: center;
cursor: pointer;
}
.common-title {
font-size: 0.18rem;
margin-bottom: 0.2rem;
}
}</style>

View File

@@ -0,0 +1,268 @@
<template>
<base-page>
<view class="deliverlist">
<view class="deliverlist-box">
<view class="deliverlist-left">
<view class="deliver-title">
配送员
<text class="iconfont icongengduo1"></text>
</view>
<view class="deliver-list-wrap">
<block v-if="list.length > 0">
<scroll-view scroll-y="true" class="deliver-list-scroll all-scroll" @scrolltolower="getDeliverList">
<view class="item" @click="deliverSelect(item, index)" v-for="(item, index) in list" :key="index" :class="index == selectDeliverKeys ? 'itemhover' : ''">
<view class="item-right">
<view class="deliver-name">{{ item.deliver_name }}</view>
<view class="deliver-money">{{ item.deliver_mobile }}</view>
</view>
</view>
</scroll-view>
</block>
<view class="notYet" v-else-if="!one_judge && list.length == 0">暂无配送员</view>
</view>
<view class="add-deliver">
<button type="default" class="primary-btn" @click="addDeliver">添加配送员</button>
</view>
</view>
<view class="deliverlist-right" v-show="!one_judge">
<view class="deliver-title">配送员详情</view>
<view class="deliver-information">
<block v-if="detail && Object.keys(detail).length">
<view class="title">基本信息</view>
<view class="information-box">
<view class="box-left">
<view class="information">
<view>姓名</view>
<view>{{ detail.deliver_name }}</view>
</view>
<view class="information">
<view>电话</view>
<view>{{ detail.deliver_mobile }}</view>
</view>
<view class="information">
<view>添加时间</view>
<view>{{ detail.create_time ? $util.timeFormat(detail.create_time) : '--' }}</view>
</view>
<view class="information">
<view>最后修改时间</view>
<view>{{ detail.modify_time ? $util.timeFormat(detail.modify_time) : '--' }}</view>
</view>
</view>
</view>
</block>
<block v-else>
<image class="cart-empty" src="@/static/goods/goods_empty.png" mode="widthFix" />
</block>
<view class="button-box" v-if="detail && Object.keys(detail).length">
<button class="default-btn" @click="$refs.deletePop.open()">删除</button>
<button class="default-btn" @click="openEditDeliverPop(detail.deliver_id)">修改</button>
</view>
</view>
</view>
<uni-popup ref="deliverpop" type="center">
<view class="common-wrap common-form">
<view class="common-title">{{ deliverData.deliver_id > 0 ? '修改' : '添加' }}配送员</view>
<view class="common-form-item">
<label class="form-label">
<text class="required">*</text>
姓名
</label>
<view class="form-input-inline">
<input type="text" v-model="deliverData.deliver_name" class="form-input" />
</view>
<text class="form-word-aux"></text>
</view>
<view class="common-form-item">
<label class="form-label">
<text class="required">*</text>
手机号
</label>
<view class="form-input-inline">
<input type="number" v-model="deliverData.deliver_mobile" class="form-input" />
</view>
<text class="form-word-aux"></text>
</view>
<view class="common-btn-wrap">
<button type="default" class="screen-btn" @click="addDeliverSave">{{ deliverData.deliver_id > 0 ? '修改' : '添加' }}</button>
<button type="primary" class="default-btn btn save" @click="addDeliverClose()">取消</button>
</view>
</view>
</uni-popup>
<!-- 删除 -->
<uni-popup ref="deletePop" type="center">
<view class="confirm-pop">
<view class="title">确定要删除吗</view>
<view class="btn">
<button type="primary" class="default-btn btn save" @click="$refs.deletePop.close()">取消</button>
<button type="primary" class="primary-btn btn" @click="deleteDeliverFn(detail.deliver_id)">确定</button>
</view>
</view>
</uni-popup>
<ns-loading :layer-background="{ background: 'rgba(255,255,255,.8)' }" ref="loading"></ns-loading>
</view>
</view>
</base-page>
</template>
<script>
import {
addDeliver,
deleteDeliver,
editDeliver,
getDeliverInfo,
getDeliverList
} from '@/api/deliver.js'
export default {
data() {
return {
search_text: '',
page: 1,
// 每次返回数据数
page_size: 8,
// 第一次请求列表做详情渲染判断
one_judge: true,
//详情数据
detail: {},
list: [],
selectDeliverKeys: 0,
flag: false,
deliverData: {
deliver_id: 0,
deliver_name: '',
deliver_mobile: ''
}
};
},
onLoad() {
this.getDeliverListFn();
},
methods: {
deliverSelect(item, keys) {
this.selectDeliverKeys = keys;
this.getDeliverDetail(item.deliver_id);
},
// 搜索员工
search() {
this.page = 1;
this.list = [];
this.one_judge = true;
this.getDeliverListFn();
},
addDeliver() {
this.$refs.deliverpop.open();
},
addDeliverClose() {
this.$refs.deliverpop.close();
},
addDeliverSave() {
if (this.deliverData.deliver_name == '') {
this.$util.showToast({
title: '请输入配送员名称'
});
return false;
}
if (this.deliverData.deliver_mobile == '') {
this.$util.showToast({
title: '请输入配送员电话'
});
return false;
}
if (this.flag) return false;
this.flag = true;
let action = '';
if (this.deliverData.deliver_id > 0) {
action = editDeliver(this.deliverData);
} else {
action = addDeliver(this.deliverData);
}
action.then(res => {
this.$util.showToast({
title: res.message
});
if (res.code == 0) {
this.page = 1;
this.list = [];
this.one_judge = true;
this.getDeliverListFn();
this.addDeliverClose();
this.deliverData = {
deliver_id: 0,
deliver_name: '',
deliver_mobile: ''
};
}
this.flag = false;
});
},
openEditDeliverPop(deliver_id) {
getDeliverInfo(deliver_id).then(res => {
if (res.code == 0) {
this.deliverData = res.data;
this.$refs.deliverpop.open();
}
});
},
/**
* 请求的列表数据
*/
getDeliverListFn() {
getDeliverList({
page: this.page,
page_size: this.page_size,
}).then(res => {
if (res.data.list.length == 0 && this.one_judge) {
this.detail = {};
this.one_judge = false;
}
this.$refs.loading.hide();
if (res.code >= 0 && res.data.list.length != 0) {
this.page += 1;
if (this.list.length == 0) {
this.list = res.data.list;
} else {
this.list = this.list.concat(res.data.list);
}
//初始时加载一遍详情数据
if (this.one_judge) {
this.getDeliverDetail(this.list[0].deliver_id);
}
}
});
},
getDeliverDetail(deliver_id) {
getDeliverInfo(deliver_id).then(res => {
if (res.code == 0) {
this.detail = res.data;
this.one_judge = false;
}
});
},
deleteDeliverFn(deliver_id) {
if (this.flag) return;
this.flag = true;
deleteDeliver(deliver_id).then(res => {
this.flag = false;
if (res.code >= 0) {
this.page = 1;
this.list = [];
this.one_judge = true;
this.$refs.deletePop.close()
this.getDeliverListFn();
} else {
this.$util.showToast({
title: res.message
});
}
});
}
}
};
</script>
<style scoped lang="scss">
@import './public/css/deliver.scss';
</style>

View File

@@ -0,0 +1,228 @@
<template>
<base-page>
<view class="">
<view class="store-information" v-if="addon.includes('store')">
<view class="store-status">门店信息</view>
<view class="store-types">
<view class="info-left">
<view class="type type1">
<view>门店名称</view>
<view>{{ storeData.store_name }}</view>
</view>
<view class="type type1">
<view>门店电话</view>
<view class="message">{{ storeData.telphone }}</view>
</view>
<view class="type type1">
<view>门店类型</view>
<view class="message">{{ storeData.store_type == 'directsale' ? '直营店' : '加盟店' }}</view>
</view>
<view class="type type1">
<view>门店地址</view>
<view class="message">{{ storeData.full_address }}{{ storeData.address }}</view>
</view>
</view>
<view class="info-img">
<image :src="$util.img(storeData.store_image)" @error="$util.img(defaultImg.store)" mode="aspectFit"/>
</view>
<view class="btn" @click="$util.redirectTo('/pages/store/config')">设置</view>
</view>
</view>
<view class="store-information">
<view class="store-status">运营信息</view>
<view class="store-types">
<view class="info-left">
<template v-if="addon.includes('store')">
<view class="type type1">
<view>营业状态</view>
<view class="message" v-if="storeData.is_frozen == 1">已停业</view>
<view class="message" v-else>{{ storeData.status == 1 ? '营业中' : '休息' }}</view>
</view>
<view class="type type1">
<view>营业时间</view>
<view class="message">{{ storeData.open_date }}</view>
</view>
<view class="type type1">
<view>物流配送</view>
<view class="message">{{ storeData.is_express ? '开启' : '关闭' }}</view>
</view>
<view class="type type1">
<view>同城配送</view>
<view>{{ storeData.is_o2o ? '开启' : '关闭' }}</view>
</view>
<view class="type type1">
<view>门店自提</view>
<view class="message">{{ storeData.is_pickup ? '开启' : '关闭' }}</view>
</view>
<view class="type type1">
<view>自提日期</view>
<view class="message" v-if="storeData.time_type == 1">
<text class="week" v-if="storeData.time_week.includes('1') || storeData.time_week.includes(1)">周一</text>
<text class="week" v-if="storeData.time_week.includes('2') || storeData.time_week.includes(2)">周二</text>
<text class="week" v-if="storeData.time_week.includes('3') || storeData.time_week.includes(3)">周三</text>
<text class="week" v-if="storeData.time_week.includes('4') || storeData.time_week.includes(4)">周四</text>
<text class="week" v-if="storeData.time_week.includes('5') || storeData.time_week.includes(5)">周五</text>
<text class="week" v-if="storeData.time_week.includes('6') || storeData.time_week.includes(6)">周六</text>
<text class="week" v-if="storeData.time_week.includes('0') || storeData.time_week.includes(0)">周日</text>
</view>
<view class="message" v-if="storeData.time_type == 0">每天</view>
</view>
<view class="type type1">
<view>自提时间</view>
<view class="message">{{ storeData.start_time }}-{{ storeData.end_time }}</view>
</view>
<view class="type type1">
<view>库存设置</view>
<view class="message">{{ storeData.stock_type == 'all' ? '总部统一库存' : '门店独立库存' }}</view>
</view>
</template>
<view class="type type1">
<view>会员搜索方式</view>
<view class="message">{{ memberSearchWayConfig.way == 'exact' ? '精确搜索' : '列表搜索' }}</view>
</view>
</view>
<view class="btn" @click="$util.redirectTo('/pages/store/operate')">设置</view>
</view>
</view>
</view>
</base-page>
</template>
<script>
import {mapGetters} from 'vuex';
export default {
data() {
return {
storeData: {
store_name: '',
store_image: '',
status: 0,
telphone: '',
open_date: '',
is_o2o: 0,
is_pickup: 0,
time_type: 0,
start_time: '00:00',
end_time: '23:59',
stock_type: 'all',
time_week: '',
latitude: 39.909,
longitude: 116.39742,
province_id: 110000,
city_id: 110100,
district_id: 110101,
address: '',
full_address: '',
store_type: 'directsale'
}
};
},
onLoad() {},
onShow() {
this.getData();
},
computed: {
...mapGetters(['memberSearchWayConfig'])
},
methods: {
getData() {
this.storeData = this.$util.deepClone(this.globalStoreInfo);
this.storeData.start_time = this.timeFormat(this.storeData.start_time);
this.storeData.end_time = this.timeFormat(this.storeData.end_time);
},
timeFormat(time) {
let h = parseInt(time / 3600);
let i = parseInt((time % 3600) / 60);
h = h < 10 ? '0' + h : h;
i = i < 10 ? '0' + i : i;
return h + ':' + i;
}
}
};
</script>
<style lang="scss" scoped>
.store-information {
width: 100%;
box-sizing: border-box;
padding-bottom: 0.1rem;
margin-bottom: 0.2rem;
.store-status {
font-size: 0.24rem;
font-weight: bold;
height: 0.6rem;
line-height: 0.6rem;
padding-left: 0.2rem;
}
.store-types {
width: 100%;
background: #ffffff;
padding: 0.2rem 0.3rem;
display: flex;
flex-direction: row;
justify-content: space-between;
margin-bottom: 0.2rem;
box-sizing: border-box;
position: relative;
.info-left {
display: flex;
flex-direction: column;
justify-content: space-between;
}
.btn {
position: absolute;
top: 0.2rem;
right: 0.2rem;
color: $primary-color;
cursor: pointer;
}
.info-img {
margin-top: 0.4rem;
image {
max-width: 1.5rem;
height: 1rem;
}
}
.type {
padding-left: 0.1rem;
view {
font-size: 0.14rem;
.look {
color: $primary-color;
margin-left: 0.24rem;
}
}
view:nth-child(1) {
width: 1rem;
text-align: right;
margin-right: 0.1rem;
}
}
.type1 {
display: flex;
align-items: center;
height: 0.34rem;
}
}
}
.week {
margin-right: 0.1rem;
}
</style>

View File

@@ -0,0 +1,569 @@
<template>
<base-page>
<view class="store-operate">
<view class="common-wrap common-form fixd common-scrollbar">
<view class="common-title">运营设置</view>
<template v-if="addon.includes('store')">
<view class="common-form-item">
<label class="form-label">门店名称</label>
<view class="form-input-inline">
<input type="text" v-model="storeData.store_name" disabled class="form-input" />
</view>
<text class="form-word-aux-line">门店的名称招牌</text>
</view>
<view class="common-form-item">
<label class="form-label">是否营业</label>
<view class="form-inline">
<radio-group @change="statusChange" class="form-radio-group">
<label class="radio form-radio-item">
<radio value="1" :checked="storeData.status == 1" />
</label>
<label class="radio form-radio-item">
<radio value="0" :checked="storeData.status == 0" />
</label>
</radio-group>
</view>
</view>
<view class="common-form-item">
<label class="form-label">营业时间</label>
<view class="form-inline">
<view class="form-input-inline long">
<input type="text" v-model="storeData.open_date" class="form-input" />
</view>
</view>
</view>
<view class="common-form-item">
<label class="form-label">物流配送</label>
<view class="form-inline">
<radio-group @change="expressChange" class="form-radio-group">
<label class="radio form-radio-item">
<radio value="1" :checked="storeData.is_express == 1" />
开启
</label>
<label class="radio form-radio-item">
<radio value="0" :checked="storeData.is_express == 0" />
关闭
</label>
</radio-group>
</view>
<text class="form-word-aux-line">物流配送只有在连锁门店模式有效在平台运营模式按照总店查询</text>
</view>
<view class="common-form-item">
<label class="form-label">同城配送</label>
<view class="form-inline">
<radio-group @change="o2oChange" class="form-radio-group">
<label class="radio form-radio-item">
<radio value="1" :checked="storeData.is_o2o == 1" />
开启
</label>
<label class="radio form-radio-item">
<radio value="0" :checked="storeData.is_o2o == 0" />
关闭
</label>
</radio-group>
</view>
<text class="form-word-aux-line">开启同城配送需要门店设置配送费用以及配送员</text>
</view>
<view class="common-form-item">
<label class="form-label">门店自提</label>
<view class="form-inline">
<radio-group @change="pickupChange" class="form-radio-group">
<label class="radio form-radio-item">
<radio value="1" :checked="storeData.is_pickup == 1" />
开启
</label>
<label class="radio form-radio-item">
<radio value="0" :checked="storeData.is_pickup == 0" />
关闭
</label>
</radio-group>
</view>
</view>
<block v-if="storeData.is_pickup == 1">
<view class="common-form-item">
<label class="form-label">自提日期</label>
<view class="form-inline">
<radio-group @change="timeTypeChange" class="form-radio-group">
<label class="radio form-radio-item">
<radio value="0" :checked="storeData.time_type == 0" />
每天
</label>
<label class="radio form-radio-item">
<radio value="1" :checked="storeData.time_type == 1" />
自定义
</label>
</radio-group>
</view>
</view>
<view class="common-form-item" v-if="storeData.time_type == 1">
<label class="form-label">自提时间</label>
<view class="form-block">
<checkbox-group class="form-checkbox-group" @change="checkboxChange">
<label class="form-checkbox-item">
<checkbox value="1" :checked="storeData.time_week.includes('1') || storeData.time_week.includes(1)" />
周一
</label>
<label class="form-checkbox-item">
<checkbox value="2" :checked="storeData.time_week.includes('2') || storeData.time_week.includes(2)" />
周二
</label>
<label class="form-checkbox-item">
<checkbox value="3" :checked="storeData.time_week.includes('3') || storeData.time_week.includes(3)" />
周三
</label>
<label class="form-checkbox-item">
<checkbox value="4" :checked="storeData.time_week.includes('4') || storeData.time_week.includes(4)" />
周四
</label>
<label class="form-checkbox-item">
<checkbox value="5" :checked="storeData.time_week.includes('5') || storeData.time_week.includes(5)" />
周五
</label>
<label class="form-checkbox-item">
<checkbox value="6" :checked="storeData.time_week.includes('6') || storeData.time_week.includes(6)" />
周六
</label>
<label class="form-checkbox-item">
<checkbox value="0" :checked="storeData.time_week.includes('0') || storeData.time_week.includes(0)" />
周日
</label>
</checkbox-group>
</view>
</view>
<view class="common-form-item" v-for="(item, index) in storeData.delivery_time" :key="index">
<label class="form-label">{{ index == 0 ? '时段设置' : '' }}</label>
<view class="form-inline">
<view class="form-input-inline">
<picker mode="time" class="form-input" :value="timeFormat(item.start_time)" @change="bindStartTimeChange($event, index)">
<view class="uni-input">{{ item.start_time ? timeFormat(item.start_time) : '00:00' }}</view>
</picker>
</view>
<text class="form-mid">-</text>
<view class="form-input-inline">
<picker mode="time" class="form-input" :value="timeFormat(item.end_time)" @change="bindEndTimeChange($event, index)">
<view class="uni-input">{{ item.end_time ? timeFormat(item.end_time) : '' }}</view>
</picker>
</view>
<view class="time-action" v-if="index == 0" @click="addDeliveryTime">添加</view>
<view class="time-action" v-else @click="deleteDeliveryTime(index)">删除</view>
</view>
</view>
<view class="common-form-item">
<label class="form-label">细分时段</label>
<view class="form-block">
<radio-group @change="timeIntervalChange" class="form-radio-group">
<label class="radio form-radio-item">
<radio value="30" :checked="storeData.time_interval == 30" />
30分钟
</label>
<label class="radio form-radio-item">
<radio value="60" :checked="storeData.time_interval == 60" />
一小时
</label>
<label class="radio form-radio-item">
<radio value="90" :checked="storeData.time_interval == 90" />
90分钟
</label>
<label class="radio form-radio-item">
<radio value="120" :checked="storeData.time_interval == 120" />
两小时
</label>
</radio-group>
</view>
</view>
<view class="common-form-item">
<label class="form-label">提现预约</label>
<view class="form-block">
<radio-group @change="advanceDayChange" class="form-radio-group">
<label class="radio form-radio-item">
<radio value="0" :checked="storeData.advance_day === 0" />
无需提前
</label>
<label class="radio form-radio-item">
<radio value="1" :checked="storeData.advance_day !== 0" />
需提前
<input type="number" v-model="storeData.advance_day" class="radio-input" :class="{ disabled: storeData.advance_day === 0 }" :disabled="storeData.advance_day === 0" />
</label>
</radio-group>
</view>
<text class="form-word-aux-line">预约提货是否需提前进行预约</text>
</view>
<view class="common-form-item">
<label class="form-label">最长预约</label>
<view class="form-block">
<radio-group @change="mostDayChange" class="form-radio-group">
<label class="radio form-radio-item">
<radio value="0" :checked="storeData.most_day === 0" />
无需提前
</label>
<label class="radio form-radio-item">
<radio value="1" :checked="storeData.most_day !== 0" />
可预约
<input type="number" v-model="storeData.most_day" class="radio-input" :class="{ disabled: storeData.most_day === 0 }" :disabled="storeData.most_day === 0" />
天内
</label>
</radio-group>
</view>
<text class="form-word-aux-line">预约提货最长可预约多少天内进行提货</text>
</view>
</block>
<view class="common-form-item">
<label class="form-label">库存设置</label>
<view class="form-inline">
<radio-group @change="stockTypeChange" class="form-radio-group">
<label class="radio form-radio-item">
<radio value="all" :disabled="Boolean(storeData.is_default)" :checked="storeData.stock_type == 'all'" />
总部统一库存
</label>
<label class="radio form-radio-item">
<radio value="store" :disabled="Boolean(storeData.is_default)" :checked="storeData.stock_type == 'store'" />
门店独立库存
</label>
</radio-group>
</view>
</view>
</template>
<view class="common-form-item">
<label class="form-label">会员搜索方式</label>
<view class="form-inline">
<radio-group @change="memberSearchWayChange" class="form-radio-group">
<label class="radio form-radio-item">
<radio value="exact" :checked="memberSearchWay == 'exact'" />
精确搜索
</label>
<label class="radio form-radio-item">
<radio value="list" :checked="memberSearchWay == 'list'" />
列表搜索
</label>
</radio-group>
</view>
</view>
<view class="common-btn-wrap">
<button type="default" class="screen-btn" @click="saveFn">保存</button>
<button type="default" @click="$util.redirectTo('/pages/store/index')">返回</button>
</view>
</view>
</view>
</base-page>
</template>
<script>
import {
editStore
} from '@/api/store.js'
import {setMemberSearchWayConfig} from '@/api/config.js'
import {mapGetters} from 'vuex';
export default {
data() {
return {
storeData: {},
covers: [{
latitude: 39.909,
longitude: 116.39742,
iconPath: '/static/location.png'
}],
defaultRegions: [],
memberSearchWay: 'exact'
};
},
onLoad() {},
onShow() {
this.getData();
},
computed: {
...mapGetters(['memberSearchWayConfig'])
},
watch: {
memberSearchWayConfig: {
immediate: true,
handler(newVal, oldVal) {
if(newVal) {
this.memberSearchWay = newVal.way;
}
}
}
},
methods: {
getData() {
this.storeData = this.$util.deepClone(this.globalStoreInfo);
this.storeData.start_time = this.timeFormat(this.storeData.start_time);
this.storeData.end_time = this.timeFormat(this.storeData.end_time);
if(this.memberSearchWayConfig) {
this.memberSearchWay = this.memberSearchWayConfig.way;
}
},
statusChange(e) {
this.storeData.status = e.detail.value;
},
o2oChange(e) {
this.storeData.is_o2o = e.detail.value;
},
expressChange(e) {
this.storeData.is_express = e.detail.value;
},
pickupChange(e) {
this.storeData.is_pickup = e.detail.value;
},
timeTypeChange(e) {
this.storeData.time_type = e.detail.value;
},
bindStartTimeChange(e, index) {
this.storeData.delivery_time[index].start_time = this.timeTurnTimeStamp(e.detail.value);
},
bindEndTimeChange(e, index) {
this.storeData.delivery_time[index].end_time = this.timeTurnTimeStamp(e.detail.value);
},
stockTypeChange(e) {
this.storeData.stock_type = e.detail.value;
},
memberSearchWayChange(e) {
this.memberSearchWay = e.detail.value;
},
timeIntervalChange(e) {
this.storeData.time_interval = e.detail.value;
},
checkboxChange(e) {
this.storeData.time_week = e.detail.value;
},
advanceDayChange(e) {
if (e.detail.value == 1) this.storeData.advance_day = '';
else this.storeData.advance_day = 0;
},
mostDayChange(e) {
if (e.detail.value == 1) this.storeData.most_day = '';
else this.storeData.most_day = 0;
},
getSaveData() {
let data = Object.assign({}, this.storeData);
data.start_time = this.timeTurnTimeStamp(data.start_time);
data.end_time = this.timeTurnTimeStamp(data.end_time);
data.time_week = this.storeData.time_week.toString();
data.advance_day = parseInt(this.storeData.advance_day);
data.most_day = parseInt(this.storeData.most_day);
data.delivery_time = JSON.stringify(this.storeData.delivery_time);
return data;
},
checkData(data) {
if (data.is_pickup) {
let deliveryTimeVerify = true;
for (let i = 0; i < this.storeData.delivery_time.length; i++) {
let time = this.storeData.delivery_time[i];
if (time.end_time == 0) {
this.$util.showToast({
title: '请选择时段结束时间'
});
deliveryTimeVerify = false;
break;
}
if (parseInt(time.start_time) > parseInt(time.end_time)) {
this.$util.showToast({
title: '时段结束时间不能小于开始时间'
});
deliveryTimeVerify = false;
break;
}
if ((parseInt(time.end_time) - parseInt(time.start_time)) / 60 < parseInt(data.time_interval)) {
this.$util.showToast({
title: '时段时间间隔不能小于' + data.time_interval + '分钟'
});
deliveryTimeVerify = false;
break;
}
}
if (!deliveryTimeVerify) return deliveryTimeVerify;
if (isNaN(data.advance_day)) {
this.$util.showToast({
title: '提前预约时间格式错误'
});
return false;
}
if (data.advance_day < 0) {
this.$util.showToast({
title: '提前预约时间不能为负数'
});
return false;
}
if (isNaN(data.most_day)) {
this.$util.showToast({
title: '最长可预约时间格式错误'
});
return false;
}
if (data.most_day < 0) {
this.$util.showToast({
title: '最长可预约时间不能为负数'
});
return false;
}
if (data.most_day > 15) {
this.$util.showToast({
title: '最长可预约时间不能超过15天'
});
return false;
}
}
return true;
},
saveFn() {
let data = this.getSaveData();
setMemberSearchWayConfig({
way : this.memberSearchWay
}).then((res)=>{
if(res.code >= 0){
this.$store.dispatch('app/getMemberSearchWayConfigFn');
if (!this.addon.includes('store')) {
this.$util.showToast({
title: res.message
});
}
}
})
if (this.addon.includes('store')) {
if (this.checkData(data)) {
if (this.flag) return false;
this.flag = true;
editStore(data).then(res => {
this.flag = false;
this.$util.showToast({
title: res.message
});
if (res.code >= 0) {
this.$store.dispatch('app/getStoreInfoFn', {
callback: () => {
this.getData();
}
});
}
});
}
}
},
timeTurnTimeStamp(_time) {
let data = _time.split(':');
return data[0] * 3600 + data[1] * 60;
},
timeFormat(time) {
let h = parseInt(time / 3600);
let i = parseInt((time % 3600) / 60);
h = h < 10 ? '0' + h : h;
i = i < 10 ? '0' + i : i;
return h + ':' + i;
},
addDeliveryTime() {
if (this.storeData.delivery_time.length >= 3) {
this.$util.showToast({
title: '最多添加三个时段'
});
return false;
}
this.storeData.delivery_time.push({
start_time: 0,
end_time: 0
});
},
deleteDeliveryTime(index) {
this.storeData.delivery_time.splice(index, 1);
}
}
};
</script>
<style lang="scss" scoped>
.store-operate {
position: relative;
.common-btn-wrap {
position: absolute;
left: 0;
bottom: 0;
right: 0;
padding: 0.24rem 0.2rem;
}
.common-wrap {
padding: 30rpx;
height: calc(100vh - 0.4rem);
overflow-y: auto;
// padding-bottom: 1rem !important;
box-sizing: border-box;
.form-label {
padding: .09rem .15rem;
text-align: right;
width: 1.2rem;
}
}
.store-img {
align-items: flex-start !important;
}
.map-box {
width: 6.5rem;
height: 5rem;
position: relative;
.map-icon {
position: absolute;
top: calc(50% - 0.36rem);
left: calc(50% - 0.18rem);
width: 0.36rem;
height: 0.36rem;
z-index: 100;
}
}
.form-input {
font-size: 0.16rem;
}
.form-input-inline.btn {
height: 0.37rem;
line-height: 0.35rem;
box-sizing: border-box;
border: 0.01rem solid #e6e6e6;
text-align: center;
cursor: pointer;
}
.common-title {
font-size: 0.18rem;
margin-bottom: 0.2rem;
}
.radio-input {
width: 0.6rem;
height: 0.35rem;
line-height: 0.35rem;
padding: 0 0.1rem;
margin: 0 0.1rem;
border: 0.01rem solid #eee;
&.disabled {
background: #f5f5f5;
}
}
.time-action {
color: $primary-color;
cursor: pointer;
}
}</style>

View File

@@ -0,0 +1,317 @@
.deliverlist {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: space-between;
box-sizing: border-box;
.deliverlist-box {
width: 100%;
height: 100%;
background: #ffffff;
display: flex;
.deliverlist-left {
width: 5rem;
height: 100%;
border-right: 0.01rem solid #e6e6e6;
box-sizing: border-box;
display: flex;
flex-direction: column;
.notYet {
color: #e6e6e6;
font-size: 0.4rem;
margin-top: 3rem;
text-align: center;
}
.add-deliver {
padding: 0.24rem 0.2rem;
background: #fff;
button {
height: .4rem;
line-height: .4rem;
}
}
.deliver-title {
text-align: center;
line-height: 0.6rem;
font-size: 0.18rem;
font-weight: 500;
height: 0.6rem;
border-bottom: 0.01rem solid #e6e6e6;
box-sizing: border-box;
position: relative;
.icongengduo1 {
position: absolute;
top: 50%;
right: 0.2rem;
transform: translateY(-50%);
font-size: 0.3rem;
color: $primary-color;
}
}
.deliver-list-wrap {
flex: 1;
height: 0;
}
.deliver-list-scroll {
width: 100%;
height: 100%;
.itemhover {
background: var(--primary-color-light-9);
}
.item {
width: 100%;
display: flex;
align-items: center;
padding: 0.2rem;
box-sizing: border-box;
border-bottom: 0.01rem solid #e6e6e6;
image {
width: 0.7rem;
height: 0.7rem;
margin-right: 0.1rem;
}
.item-right {
display: flex;
flex-direction: column;
justify-content: space-between;
height: 0.6rem;
.deliver-name {
font-size: 0.16rem;
}
.deliver-money {
font-size: 0.14rem;
}
}
}
}
}
.deliverlist-right {
width: 0;
flex: 1;
height: 100%;
box-sizing: border-box;
.deliver-title {
text-align: center;
line-height: 0.6rem;
font-size: 0.18rem;
font-weight: 500;
height: 0.6rem;
border-bottom: 0.01rem solid #e6e6e6;
box-sizing: border-box;
position: relative;
.icongengduo1, .iconguanbi1 {
position: absolute;
top: 50%;
right: 0.2rem;
transform: translateY(-50%);
font-size: 0.3rem;
color: $primary-color;
cursor: pointer;
}
}
.deliver-information {
width: 100%;
padding: 0.2rem 0.2rem 0.88rem 0.2rem;
box-sizing: border-box;
height: calc(100% - 0.6rem);
overflow: auto;
position: relative;
.title {
font-size: 0.18rem;
margin-bottom: 0.32rem;
}
.title2 {
margin-bottom: 0.35rem;
}
.information-box {
display: flex;
justify-content: space-between;
.box-left {
width: 5rem;
.information {
width: 100%;
padding-left: 0.1rem;
box-sizing: border-box;
display: flex;
align-items: center;
margin-bottom: 0.15rem;
view {
color: #303133;
font-size: 0.14rem;
}
view:nth-child(1) {
width: 1.3rem;
margin-right: 0.16rem;
text-align: right;
}
view:nth-child(2) {
width: 74%;
margin-right: 0.23rem;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
}
.information:last-child {
margin-bottom: 0.35rem;
}
}
.deliver-img {
width: 1.5rem;
height: 1.5rem;
}
}
.table {
width: 100%;
height: 2.6rem;
box-sizing: border-box;
.table-all {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 0.38rem;
box-sizing: border-box;
.table-td {
font-size: 0.14rem;
text-align: left;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
}
.table-th {
height: 0.56rem;
background: #f7f8fa;
}
.table-tb {
width: 100%;
height: calc(100% - 0.56rem);
.table-tr {
height: 0.7rem;
border-bottom: 0.01rem solid #e6e6e6;
box-sizing: border-box;
.table-td {
text-overflow: -o-ellipsis-lastline;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
line-clamp: 2;
-webkit-box-orient: vertical;
image {
width: 0.5rem;
height: 0.5rem;
}
}
}
}
}
}
}
}
}
view {
color: #303133;
}
/deep/ .uni-scroll-view::-webkit-scrollbar {
width: 0.05rem;
height: 0.3rem;
}
/deep/ .uni-scroll-view::-webkit-scrollbar-thumb {
border-radius: 0.1rem;
box-shadow: inset 0 0 0.05rem rgba(0, 0, 0, 0.2);
background: rgba(193, 193, 193, 1);
}
.deliver-information::-webkit-scrollbar {
width: 0.05rem;
height: 0.3rem;
}
.deliver-information::-webkit-scrollbar-thumb {
border-radius: 0.1rem;
box-shadow: inset 0 0 0.05rem rgba(0, 0, 0, 0.2);
background: rgba(193, 193, 193, 1);
}
.button-box {
position: absolute;
width: 100%;
right: 0;
bottom: 0;
background-color: #fff;
display: flex;
align-items: center;
justify-content: flex-end;
padding: 0.24rem 0.2rem;
box-sizing: border-box;
button {
min-width: 0.9rem;
height: 0.4rem;
line-height: 0.4rem;
margin: 0;
margin-left: 0.1rem;
}
}
.cart-empty {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 2.1rem;
}
.common-wrap {
padding: 30rpx;
margin: 30rpx;
background-color: #fff;
}
.common-title {
font-size: 0.18rem;
margin-bottom: 0.2rem;
}

View File

@@ -0,0 +1,543 @@
<template>
<base-page>
<view class="page-height uni-flex uni-column">
<view class="uni-flex uni-row">
<view class="account-wrap">
<view class="head-title">账户概览</view>
<view class="account-item">
<view @click="$util.redirectTo('/pages/store/acccount_record')">
<view class="account-title">待结算金额</view>
<view class="money">
{{ globalStoreInfo.account | moneyFormat }}
<text class="iconfont iconqianhou2"></text>
</view>
</view>
<view class="action">
<button type="default" class="primary-btn" v-if="
globalStoreInfo.is_settlement == 1 &&
withdrawConfig.is_settlement == 1 &&
withdrawConfig.period_type == 4 &&
globalStoreInfo.account > 0 &&
parseFloat(globalStoreInfo.account) >= parseFloat(withdrawConfig.withdraw_least)
" @click="applyWithdraw">
申请结算
</button>
</view>
</view>
<view class="uni-flex uni-row sub-bottom">
<view class="account-item" @click="$util.redirectTo('/pages/store/settlement_record')">
<view class="account-title">打款中金额(元)</view>
<view class="money">
{{ globalStoreInfo.account_apply | moneyFormat }}
<text class="iconfont iconqianhou2"></text>
</view>
</view>
<view class="account-item" @click="$util.redirectTo('/pages/store/settlement_record')">
<view class="account-title">已打款金额(元)</view>
<view class="money">
{{ globalStoreInfo.account_withdraw | moneyFormat }}
<text class="iconfont iconqianhou2"></text>
</view>
</view>
</view>
</view>
<view class="info-wrap">
<view class="head-title">结算账户</view>
<view class="info-content">
<block v-if="globalStoreInfo.is_settlement == 1 && withdrawConfig.is_settlement == 1">
<view class="info-text">
结算方式:
<text>总部收款,</text>
<text v-if="withdrawConfig.period_type == 1">每日自动结算</text>
<text v-if="withdrawConfig.period_type == 2">每周自动结算</text>
<text v-if="withdrawConfig.period_type == 3">每月自动结算</text>
<text v-if="withdrawConfig.period_type == 4">门店申请结算</text>
</view>
<view class="info-text">账户类型:{{ bankType[globalStoreInfo.bank_type] }}</view>
<block v-if="globalStoreInfo.bank_type == 1">
<view class="info-text">微信名:{{ globalStoreInfo.bank_user_name }}</view>
</block>
<block v-if="globalStoreInfo.bank_type == 2">
<view class="info-text">真实姓名:{{ globalStoreInfo.bank_user_name }}</view>
<view class="info-text">支付宝账号:{{ globalStoreInfo.bank_type_account }}</view>
</block>
<block v-if="globalStoreInfo.bank_type == 3">
<view class="info-text">开户行:{{ globalStoreInfo.bank_type_name }}</view>
<view class="info-text">户头:{{ globalStoreInfo.bank_user_name }}</view>
<view class="info-text">账户:{{ globalStoreInfo.bank_type_account }}</view>
</block>
</block>
<view class="empty" v-else>无需结算</view>
</view>
</view>
</view>
<view class="settlement-record uni-flex uni-column">
<view class="head-title">结算记录</view>
<view class="record-wrap common-scrollbar">
<uni-data-table url="/store/storeapi/withdraw/page" :cols="cols" ref="table" :pagesize="8">
<template v-slot:action="data">
<view class="common-table-action" v-if="data.value.transfer_type == 'wechatpay' && data.value.status == 1 && newWithdrawDetail && newWithdrawDetail.transfer_type" @click="showQRcode(data)"><text >收款</text></view>
<view class="common-table-action"><text @click="detail(data)">查看详情</text></view>
</template>
</uni-data-table>
</view>
</view>
</view>
<uni-popup ref="applyWithdraw" type="center">
<view class="apply-withdraw">
<view class="title">
本次可结算金额为
<text class="money" v-if="globalStoreInfo">{{ globalStoreInfo.account | moneyFormat }}</text>
元,是否申请结算?
</view>
<view class="btn">
<button type="primary" class="primary-btn btn" @click="apply">确定</button>
<button type="primary" class="default-btn btn save" @click="$refs.applyWithdraw.close()">取消</button>
</view>
</view>
</uni-popup>
<uni-popup ref="detailPopup">
<view class="pop-box">
<view class="pop-header">
<view class="">结算详情</view>
<view class="pop-header-close" @click="$refs.detailPopup.close()">
<text class="iconguanbi1 iconfont"></text>
</view>
</view>
<view class="pop-content common-scrollbar" v-if="withdrawDetail">
<view class="pop-content-item">
<view class="pop-content-text">结算信息</view>
<view class="pop-contents-text">结算编号:{{ withdrawDetail.withdraw_no }}</view>
<view class="pop-contents-text">结算状态:{{ withdrawDetail.status_name }}</view>
<view class="pop-contents-text" v-if="withdrawDetail.status == -1 || withdrawDetail.status == -2">拒绝理由:{{ withdrawDetail.refuse_reason }}</view>
<view class="pop-contents-text">结算金额:{{ withdrawDetail.money | moneyFormat }}</view>
<view class="pop-contents-text">结算方式:{{ withdrawDetail.transfer_type_name }}</view>
<view class="pop-contents-text">结算类型:{{ withdrawDetail.settlement_type_name }}</view>
<view class="pop-contents-text">结算申请时间:{{ withdrawDetail.apply_time | timeFormat }}</view>
<view class="pop-contents-text" v-if="withdrawDetail.transfer_type == 'bank'">银行名称:{{ withdrawDetail.bank_name }}</view>
<view class="pop-contents-text">结算收款账号:{{ withdrawDetail.account_number }}</view>
<view class="pop-contents-text">结算方式:{{ withdrawDetail.transfer_type_name }}</view>
<view class="pop-contents-text">真实姓名:{{ withdrawDetail.realname }}</view>
<view class="pop-contents-text flex" v-if="withdrawDetail.voucher_img">转账凭证:<image class="voucher-img" :src="$util.img(withdrawDetail.voucher_img)" /></view>
<view class="pop-contents-text" v-if="withdrawDetail.voucher_desc">凭证说明:{{ withdrawDetail.voucher_desc }}</view>
</view>
<view class="pop-content-item" v-if="withdrawDetail.settlement_type != 'apply'">
<view class="pop-content-text">周期结算</view>
<view class="pop-contents-text">周期结算编号:{{ withdrawDetail.settlement_info.settlement_no }}</view>
<view class="pop-contents-text">周期开始时间:{{ withdrawDetail.settlement_info.start_time }}</view>
<view class="pop-contents-text">周期结束时间:{{ withdrawDetail.settlement_info.end_time }}</view>
<view class="pop-contents-text">结算订单总额:{{ withdrawDetail.settlement_info.order_money }}</view>
<view class="pop-contents-text">结算总分销佣金:{{ withdrawDetail.settlement_info.commission }}</view>
</view>
</view>
</view>
</uni-popup>
<uni-popup ref="qrcodePopup">
<view class="pop-box qrcode">
<view class="pop-header">
<view class="">扫码收款</view>
<view class="pop-header-close" @click="closeQrcodePopup()">
<text class="iconguanbi1 iconfont"></text>
</view>
</view>
<view class="pop-content common-scrollbar qrcode-area" >
<image class="qr-img" :src="qrcode" mode="widthFix"></image>
</view>
</view>
</uni-popup>
</base-page>
</template>
<script>
import {
applyWithdraw,
getWithdrawConfig,
withdrawDetail,
withdrawConfig,
transferCode
} from '@/api/settlement.js'
export default {
data() {
return {
bankType: {
1: '微信',
2: '支付宝',
3: '银行卡'
},
withdrawConfig: {
is_settlement: 0
},
cols: [{
width: 12,
title: '结算方式',
field: 'transfer_type_name',
align: 'left'
}, {
width: 12,
title: '结算类型',
field: 'settlement_type_name',
align: 'left'
}, {
width: 12,
title: '结算金额',
align: 'left',
return: data => {
return this.$util.moneyFormat(data.money);
}
}, {
width: 12,
title: '结算状态',
field: 'status_name'
}, {
width: 15,
title: '申请时间',
align: 'center',
return: data => {
return data.apply_time ? this.$util.timeFormat(data.apply_time) : '';
}
}, {
width: 15,
title: '转账时间',
align: 'center',
return: data => {
return data.transfer_time ? this.$util.timeFormat(data.transfer_time) : '';
}
}, {
width: 20,
title: '操作',
action: true, // 表格操作列
align: 'right'
}],
isRepeat: false,
withdrawDetail: null,
newWithdrawDetail: null,
qrcode: '',
timer: null,
};
},
onLoad() {
},
onShow() {
this.getWithdrawConfigFn();
this.getNewWithdrawConfigFn();
this.$store.dispatch('app/getStoreInfoFn');
},
methods: {
closeQrcodePopup() {
this.$refs.qrcodePopup.close()
clearInterval(this.timer);
this.$refs.table.load();
},
checkWithdrawStatus(withdraw_id) {
this.timer = setInterval(() => {
withdrawDetail(withdraw_id).then(res => {
if (res.code == 0) {
if(res.data.status == 2){
clearInterval(this.timer);
this.$refs.qrcodePopup.close();
this.$refs.table.load();
}
}else{
clearInterval(this.timer);
}
});
}, 1000);
},
showQRcode(data) {
this.qrcode = '';
transferCode({
id: data.value.withdraw_id,
}).then(res => {
this.qrcode = res.data;
this.$refs.qrcodePopup.open();
this.checkWithdrawStatus(data.value.withdraw_id);
})
},
getNewWithdrawConfigFn() {
withdrawConfig().then(res => {
if (res.code == 0) {
this.newWithdrawDetail = res.data;
}
});
},
switchStoreAfter() {
this.$refs.table.load();
},
getWithdrawConfigFn() {
getWithdrawConfig().then(res => {
if (res.code == 0) {
this.withdrawConfig = res.data;
}
});
},
applyWithdraw() {
this.$refs.applyWithdraw.open();
},
apply() {
if (this.isRepeat) return;
this.isRepeat = true;
applyWithdraw(this.globalStoreInfo.account).then(res => {
if (res.code == 0) {
this.$store.dispatch('app/getStoreInfoFn');
this.$refs.applyWithdraw.close();
this.$refs.table.load();
setTimeout(() => {
this.isRepeat = false;
}, 500);
} else {
this.isRepeat = false;
this.$util.showToast({
title: res.message
});
}
});
},
detail(data) {
withdrawDetail(data.value.withdraw_id).then(res => {
if (res.code == 0) {
this.withdrawDetail = res.data;
this.$refs.detailPopup.open('center');
}
});
}
}
};
</script>
<style lang="scss" scoped>
.page-height {
height: 100%;
}
.account-wrap {
flex: 1;
width: 0;
padding: 0.15rem;
margin-right: 0.15rem;
background: #fff;
.head-title {
font-size: 0.16rem;
}
.account-item {
padding: 0.2rem 0;
cursor: pointer;
.account-title {
font-size: 0.14rem;
color: #aaa;
}
.money {
font-size: 0.2rem;
font-weight: bold;
margin-top: 0.15rem;
display: flex;
align-items: center;
.iconqianhou2 {
line-height: 1;
color: #bbb;
margin-left: 0.05rem;
}
}
.action {
margin-top: 0.3rem;
height: 0.4rem;
button {
display: inline-block;
margin-right: 0.1rem;
width: auto;
min-width: 0.8rem;
line-height: 0.4rem;
height: 0.4rem;
}
}
}
.sub-bottom {
border-top: 0.01rem solid #f5f5f5;
.account-item {
flex: 1;
}
}
}
.info-wrap {
width: 30vw;
padding: 0.15rem;
background: #fff;
.head-title {
font-size: 0.16rem;
}
.info-content {
margin-top: 0.2rem;
.info-text {
margin-bottom: 0.1rem;
}
}
.empty {
padding: 1rem;
text-align: center;
}
}
.settlement-record {
padding: 0.15rem;
flex: 1;
height: 0;
margin: 0.15rem 0;
background: #fff;
.head-title {
font-size: 0.16rem;
}
.record-wrap {
padding-top: 0.15rem;
flex: 1;
height: 0;
overflow-y: scroll;
}
}
.pop-box {
background: #ffffff;
width: 5rem;
height: 60vh;
display: flex;
flex-direction: column;
&.qrcode{
width: 2.8rem;
height: auto;
}
.pop-header {
width: 100%;
padding: 0 0.15rem 0 0.2rem;
height: 0.5rem;
// width: 3.5rem;
margin: 0 auto;
line-height: 0.5rem;
border-bottom: 0.01rem solid #f0f0f0;
font-size: 0.14rem;
color: #333;
overflow: hidden;
border-radius: 0.02rem 0.2rem 0 0;
box-sizing: border-box;
display: flex;
justify-content: space-between;
.pop-header-close {
cursor: pointer;
text {
font-size: 0.18rem;
}
}
}
.pop-content {
flex: 1;
height: 0;
padding: 0.1rem 0.2rem;
box-sizing: border-box;
font-weight: 900;
overflow-y: scroll;
}
.qrcode-area{
display: flex;
align-items: center;
justify-content: center;
padding: 0.2rem 0.2rem;
.qr-img{
width: 100%;
display: block;
}
}
.pop-contents {
margin-top: 0.3rem;
width: 3rem;
height: 0.8rem;
padding: 0.1rem 0.2rem;
box-sizing: border-box;
font-weight: 900;
display: flex;
flex-direction: column;
flex-wrap: wrap;
justify-content: space-between;
}
.pop-content-item {
margin-left: 0.3rem;
}
.pop-content-items {
margin-left: 0.3rem;
}
.pop-content-text {
padding: 0.1rem;
}
.pop-contents-text {
margin-left: 0.4rem;
font-weight: normal;
padding: 0.1rem;
}
}
.apply-withdraw {
width: 3.8rem;
border-radius: 0.06rem;
background: #ffffff;
padding: 0.6rem 0.15rem 0.2rem 0.15rem;
box-sizing: border-box;
.title {
font-size: 0.16rem;
text-align: center;
}
.money {
font-weight: bold;
font-size: 0.16rem;
}
.btn {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
margin-top: 0.3rem;
.btn {
width: auto;
padding: 0 0.3rem;
margin: 0;
height: 0.35rem;
}
.btn:last-child {
margin-left: 0.2rem;
}
}
}
.voucher-img {
width: 1.5rem;
}
</style>

View File

@@ -0,0 +1,349 @@
<template>
<base-page>
<view class="manage">
<view class="title-back flex items-center cursor-pointer" @click="backFn">
<text class="iconfont iconqianhou1"></text>
<text class="left">返回</text>
<text class="content">|</text>
<text>结算记录</text>
</view>
<view class="screen-warp common-form">
<view class="common-form-item">
<view class="form-inline goods-category">
<label class="form-label">结算方式</label>
<view class="form-input-inline">
<select-lay :zindex="10" :value="screen.transfer_type" name="names" placeholder="请选择结算方式" :options="transferType" @selectitem="selectTransferType"/>
</view>
</view>
<view class="form-inline goods-category">
<label class="form-label">结算类型</label>
<view class="form-input-inline">
<select-lay :zindex="9" :value="screen.settlement_type" name="names" placeholder="请选择结算类型" :options="settlementType" @selectitem="selectSettlementType"/>
</view>
</view>
</view>
<view class="common-form-item">
<view class="form-inline goods-category">
<label class="form-label">结算状态</label>
<view class="form-input-inline">
<select-lay :zindex="9" :value="screen.status" name="names" placeholder="请选择结算状态" :options="status" @selectitem="selectStatus"/>
</view>
</view>
<view class="form-inline">
<label class="form-label">申请时间</label>
<view class="form-input-inline">
<uni-datetime-picker v-model="screen.start_time" type="datetime" placeholder="请选择开始时间" :clearIcon="false" />
</view>
<view class="form-input-inline">
<uni-datetime-picker v-model="screen.end_time" type="datetime" placeholder="请选择结束时间" :clearIcon="false" />
</view>
</view>
</view>
<view class="common-form-item">
<view class="form-inline common-btn-wrap">
<button type="default" class="screen-btn" @click="search()">筛选</button>
<button type="default" @click="reset()">重置</button>
</view>
</view>
</view>
<uni-data-table url="/store/storeapi/withdraw/page" :cols="cols" ref="table">
<template v-slot:action="data">
<view class="common-table-action"><text @click="detail(data)">查看详情</text></view>
</template>
</uni-data-table>
<uni-popup ref="detailPopup">
<view class="pop-box">
<view class="pop-header">
<view class="pop-header-text">结算详情</view>
<view class="pop-header-close" @click="$refs.detailPopup.close()">
<text class="iconguanbi1 iconfont"></text>
</view>
</view>
<view class="pop-content common-scrollbar" v-if="withdrawDetail">
<view class="pop-content-item">
<view class="pop-content-text">结算信息</view>
<view class="pop-contents-text">结算编号{{ withdrawDetail.withdraw_no }}</view>
<view class="pop-contents-text">结算状态{{ withdrawDetail.status_name }}</view>
<view class="pop-contents-text">结算金额{{ withdrawDetail.money | moneyFormat }}</view>
<view class="pop-contents-text">结算方式{{ withdrawDetail.transfer_type_name }}</view>
<view class="pop-contents-text">结算类型{{ withdrawDetail.settlement_type_name }}</view>
<view class="pop-contents-text">结算申请时间{{ withdrawDetail.apply_time | timeFormat }}</view>
<view class="pop-contents-text" v-if="withdrawDetail.transfer_type == 'bank'">银行名称{{ withdrawDetail.bank_name }}</view>
<view class="pop-contents-text">结算收款账号{{ withdrawDetail.account_number }}</view>
<view class="pop-contents-text">结算方式{{ withdrawDetail.transfer_type_name }}</view>
<view class="pop-contents-text">真实姓名{{ withdrawDetail.realname }}</view>
</view>
<view class="pop-content-item" v-if="withdrawDetail.settlement_type != 'apply'">
<view class="pop-content-text">周期结算</view>
<view class="pop-contents-text">周期结算编号{{ withdrawDetail.settlement_info.settlement_no }}</view>
<view class="pop-contents-text">周期开始时间{{ withdrawDetail.settlement_info.start_time }}</view>
<view class="pop-contents-text">周期结束时间{{ withdrawDetail.settlement_info.end_time }}</view>
<view class="pop-contents-text">结算订单总额{{ withdrawDetail.settlement_info.order_money }}</view>
<view class="pop-contents-text">结算总分销佣金{{ withdrawDetail.settlement_info.commission }}</view>
</view>
</view>
</view>
</uni-popup>
</view>
</base-page>
</template>
<script>
import {
getWithdrawScreen,
withdrawDetail
} from '@/api/settlement.js';
export default {
data() {
return {
screen: {
page: 1,
start_time: '',
end_time: '',
withdraw_no: '',
transfer_type: '',
settlement_type: '',
status: 'all'
},
userList: [],
cols: [{
width: 12,
title: '结算方式',
field: 'transfer_type_name',
align: 'left'
}, {
width: 12,
title: '结算类型',
field: 'settlement_type_name',
align: 'left'
}, {
width: 12,
title: '结算金额',
align: 'left',
return: data => {
return this.$util.moneyFormat(data.money);
}
}, {
width: 12,
title: '结算状态',
field: 'status_name'
}, {
width: 15,
title: '申请时间',
align: 'center',
return: data => {
return data.apply_time ? this.$util.timeFormat(data.apply_time) : '';
}
}, {
width: 15,
title: '转账时间',
align: 'center',
return: data => {
return data.transfer_time ? this.$util.timeFormat(data.transfer_time) : '';
}
}, {
width: 20,
title: '操作',
action: true, // 表格操作列
align: 'right'
}],
status: [],
settlementType: [],
transferType: [],
withdrawDetail: null
};
},
onLoad() {
this.getScreenContent();
},
methods: {
switchStoreAfter() {
this.screen = {
page: 1,
start_time: '',
end_time: ''
};
this.$refs.table.load();
},
search() {
this.$refs.table.load(this.screen);
},
reset() {
this.screen = {
page: 1,
start_time: '',
end_time: '',
withdraw_no: '',
transfer_type: '',
settlement_type: '',
status: 'all'
};
},
getScreenContent() {
getWithdrawScreen().then(res => {
if (res.code == 0) {
this.status = Object.keys(res.data.status).map(index => {
return {
value: index,
label: res.data.status[index]
};
});
this.settlementType = Object.keys(res.data.settlement_type).map(index => {
return {
value: index,
label: res.data.settlement_type[index]
};
});
this.transferType = Object.keys(res.data.transfer_type_list).map(index => {
return {
value: index,
label: res.data.transfer_type_list[index]
};
});
}
});
},
selectTransferType(index) {
this.screen.transfer_type = index == -1 ? '' : this.transferType[index].value;
},
selectSettlementType(index) {
this.screen.settlement_type = index == -1 ? '' : this.settlementType[index].value;
},
selectStatus(index) {
this.screen.status = index == -1 ? 'all' : this.status[index].value;
},
detail(data) {
withdrawDetail(data.value.withdraw_id).then(res => {
if (res.code == 0) {
this.withdrawDetail = res.data;
this.$refs.detailPopup.open('center');
}
});
},
backFn() {
this.$util.redirectTo('/pages/store/settlement');
},
}
};
</script>
<style lang="scss" scoped>
.manage {
position: relative;
background-color: #fff;
padding: 0.15rem;
height: 100vh;
box-sizing: border-box;
}
// 筛选面板
.screen-warp {
padding: 0.15rem;
background-color: #f2f3f5;
margin-bottom: 0.15rem;
display: flex;
justify-content: start;
flex-direction: column;
/deep/ .uni-date-x {
height: 0.35rem;
}
/deep/ .uni-select-lay {
background: #fff;
.uni-select-lay-select {
height: 0.37rem;
}
}
.primary-btn {
margin-left: 0;
}
&>* {
margin-right: 0.15rem;
}
}
// pop弹框
.pop-box {
background: #ffffff;
width: 5rem;
height: 60vh;
display: flex;
flex-direction: column;
.pop-header {
width: 100%;
padding: 0 0.15rem 0 0.2rem;
height: 0.5rem;
// width: 3.5rem;
margin: 0 auto;
line-height: 0.5rem;
border-bottom: 0.01rem solid #f0f0f0;
font-size: 0.14rem;
color: #333;
overflow: hidden;
border-radius: 0.02rem 0.2rem 0 0;
box-sizing: border-box;
display: flex;
justify-content: space-between;
.pop-header-text {
font-weight: 900;
}
.pop-header-close {
cursor: pointer;
text {
font-size: 0.18rem;
}
}
}
.pop-content {
flex: 1;
height: 0;
padding: 0.1rem 0.2rem;
box-sizing: border-box;
font-weight: 900;
overflow-y: scroll;
}
.pop-contents {
margin-top: 0.3rem;
width: 3rem;
height: 0.8rem;
padding: 0.1rem 0.2rem;
box-sizing: border-box;
font-weight: 900;
display: flex;
flex-direction: column;
flex-wrap: wrap;
justify-content: space-between;
}
.pop-content-item {
margin-left: 0.3rem;
}
.pop-content-items {
margin-left: 0.3rem;
}
.pop-content-text {
padding: 0.1rem;
}
.pop-contents-text {
margin-left: 0.4rem;
font-weight: normal;
padding: 0.1rem;
}
}
</style>

View File

@@ -0,0 +1,430 @@
<template>
<base-page>
<view class="userlist">
<view class="userlist-box">
<view class="userlist-left">
<view class="user-title">
员工
<text class="iconfont icongengduo1"></text>
</view>
<view class="user-search">
<view class="search">
<text class="iconfont icon31sousuo"></text>
<input v-model="search_text" type="text" @input="search" placeholder="请输入员工名称/手机号" />
</view>
</view>
<view class="user-list-wrap">
<block v-if="list.length > 0">
<scroll-view :scroll-top="scrollTop" @scroll="scroll" scroll-y="true" class="user-list-scroll all-scroll" @scrolltolower="getUserListFn">
<view class="item" @click="userSelect(item, index)" v-for="(item, index) in list" :key="index" :class="index == selectUserKeys ? 'itemhover' : ''">
<image :src="$util.img(defaultImg.head)" mode="aspectFit"/>
<view class="item-right">
<view>
<view class="user-name">{{ item.username }}</view>
<view class="user-money">{{ item.group_name }}</view>
</view>
<view>
<view class="user-status">{{ item.status ? '正常' : '锁定' }}</view>
<view class="login-time">{{ item.login_time ? $util.timeFormat(item.login_time) : '--' }}</view>
</view>
</view>
</view>
</scroll-view>
</block>
<view class="notYet" v-else-if="!one_judge && list.length == 0">暂无员工</view>
</view>
<view class="add-user">
<button type="default" class="primary-btn" @click="addUser">添加员工</button>
</view>
</view>
<view class="userlist-right">
<view class="user-title">员工详情</view>
<view class="user-information">
<block v-if="JSON.stringify(detail) != '{}'">
<view class="title">基本信息</view>
<view class="information-box">
<view class="box-left">
<view class="information">
<view>员工名称</view>
<view>{{ detail.username }}</view>
</view>
<view class="information">
<view>员工角色</view>
<view>{{ detail.group_name }}</view>
</view>
<view class="information">
<view>员工状态</view>
<view>{{ detail.status ? '正常' : '锁定' }}</view>
</view>
<view class="information">
<view>最后登录IP</view>
<view>{{ detail.login_ip ? detail.login_ip : '--' }}</view>
</view>
<view class="information">
<view>最后登录时间</view>
<view>{{ detail.login_time ? $util.timeFormat(detail.login_time) : '--' }}</view>
</view>
</view>
<image class="user-img" :src="$util.img(defaultImg.head)" mode="widthFix"/>
</view>
<view class="title">操作日志</view>
<view>
<uni-table url="/cashier/storeapi/user/userlog" :cols="logCols" :option="{ uid: detail.uid }" :pagesize="7"></uni-table>
</view>
</block>
<block v-else>
<image class="cart-empty" src="@/static/cashier/cart_empty.png" mode="widthFix"/>
</block>
</view>
<view class="button-box flex justify-end" v-if="detail && (detail.is_admin == 0 || detail.is_system == 0)">
<button class="default-btn" @click="$refs.deletePop.open()">删除</button>
<button class="default-btn" @click="editUserAction(detail.uid)">修改</button>
</view>
</view>
<!-- 添加员工 -->
<uni-popup ref="addUserPop">
<view class="pop-box">
<view class="pop-header">
{{ parseInt(formData.uid) > 0 ? '修改' : '添加' }}员工
<view class="pop-header-close" @click="cancelAddUser()">
<text class="iconguanbi1 iconfont"></text>
</view>
</view>
<view class="common-scrollbar pop-content">
<view class="form-content">
<view class="form-item">
<view class="form-label">
<text class="required">*</text>
用户名
</view>
<view class="form-inline search-wrap">
<input type="text" :disabled="parseInt(formData.uid) > 0 ? true : false" class="form-input" v-model="formData.username" placeholder="请输入用户名" />
</view>
</view>
<view class="form-item" v-if="!parseInt(formData.uid)">
<view class="form-label">
<text class="required"></text>
密码
</view>
<view class="form-inline search-wrap">
<input type="text" class="form-input" v-model="formData.password" placeholder="请输入密码" />
</view>
</view>
<view class="form-item" v-else>
<view class="form-label">
<text class="required"></text>
状态
</view>
<view class="form-inline search-wrap">
<radio-group @change="statusChange" class="form-radio-group">
<label class="radio form-radio-item">
<radio value="1" :checked="formData.status == 1" />
正常
</label>
<label class="radio form-radio-item">
<radio value="0" :checked="formData.status == 0" />
锁定
</label>
</radio-group>
</view>
</view>
<view class="form-item">
<view class="form-label">
<text class="required"></text>
员工角色
</view>
<view class="form-inline">
<select-lay :zindex="10" :value="formData.group_id.toString()" name="names" placeholder="请选择员工角色" :options="userGroup" @selectitem="selectUserGroup"/>
</view>
</view>
</view>
</view>
<view class="pop-bottom">
<button type="primary" class="primary-btn" @click="save">{{ parseInt(formData.uid) > 0 ? '修改' : '添加' }}员工</button>
</view>
</view>
</uni-popup>
</view>
</view>
<!-- 删除 -->
<unipopup ref="deletePop" type="center">
<view class="confirm-pop">
<view class="title">确定要删除该员工数据吗</view>
<view class="btn">
<button type="primary" class="default-btn btn save" @click="$refs.deletePop.close()">取消</button>
<button type="primary" class="primary-btn btn" @click="deleteUserFn(detail.uid)">确定</button>
</view>
</view>
</unipopup>
</base-page>
</template>
<script>
import {
getUserList,
getUserDetail,
getAllGroups,
addUser,
editUser,
deleteUser
} from '@/api/user.js'
import unipopup from '@/components/uni-popup/uni-popup.vue';
export default {
components: {
unipopup
},
data() {
return {
//选中的员工下标
selectUserKeys: 0,
//搜索的数据
search_text: '',
// 初始是请求第几页
page: 1,
// 每次返回数据数
page_size: 8,
//员工列表数据
list: [],
// 第一次请求列表做详情渲染判断
one_judge: true,
//无限滚动请求锁
listLock: true,
scrollTop: 0,
//员工详情数据
detail: {},
logCols: [{
width: 60,
title: '操作记录',
align: 'left',
field: 'action_name'
}, {
width: 20,
title: '操作IP地址',
align: 'left',
field: 'ip'
}, {
width: 20,
title: '操作时间',
align: 'right',
templet: data => {
return this.$util.timeFormat(data.create_time);
}
}],
formData: {
username: '',
password: '',
group_id: ''
},
userGroup: [],
isRepeat: false
};
},
onLoad() {
// 初始化请求员工列表数据
this.getUserListFn();
this.getUserGroup();
},
methods: {
// 选中的员工数据
userSelect(item, keys) {
this.selectUserKeys = keys;
this.getUserDetailFn(item.uid);
this.one_judge = true;
this.isRepeat = false;
this.formData = {
username: '',
password: '',
group_id: ''
};
},
statusChange(e) {
this.formData.status = e.detail.value;
},
// 搜索员工
search() {
this.page = 1;
this.list = [];
this.one_judge = true;
this.listLock = true;
this.getUserListFn();
},
/**
* 请求的列表数据
*/
getUserListFn() {
if (!this.listLock) return false;
getUserList({
page: this.page,
page_size: this.page_size,
username: this.search_text
}).then(res => {
if (res.data.list.length == 0 && this.one_judge) {
this.detail = {};
this.one_judge = false;
}
if (res.code >= 0 && res.data.list.length != 0) {
if (this.list.length == 0) {
this.list = res.data.list;
} else {
this.list = this.list.concat(res.data.list);
}
//初始时加载一遍详情数据
if (this.one_judge) {
this.getUserDetailFn(this.list[0].uid);
}
}
if (this.page == 1) {
this.scrollTop = 0
}
if (res.data.list.length < this.page_size) {
this.listLock = false
} else {
this.page++
}
});
},
scroll(e) {
this.scrollTop = e.detail.scrollTop
},
getUserDetailFn(uid) {
getUserDetail(uid).then(res => {
if (res.code == 0) {
this.detail = res.data;
this.one_judge = false;
}
});
},
getUserGroup() {
getAllGroups().then(res => {
if (res.code == 0 && res.data) {
this.userGroup = res.data.map(item => {
return {
label: item.group_name,
value: item.group_id,
create_uid:item.create_uid,
store_id:item.store_id,
};
});
}
})
},
editUserAction(uid) {
getUserDetail(uid).then(res => {
if (res.code == 0) {
if(res.data.create_user_info){
this.formData = {
username: res.data.username,
group_id: res.data.group_id,
uid: res.data.uid,
status: res.data.status
};
this.$refs.addUserPop.open();
}
}
});
},
deleteUserFn(uid) {
if(this.isRepeat) return false;
this.isRepeat = true;
deleteUser(uid).then(res => {
if (res.code >= 0) {
this.page = 1;
this.list = [];
this.one_judge = true;
this.listLock = true;
this.getUserListFn();
this.$refs.deletePop.close()
} else {
this.$util.showToast({
title: res.message
});
}
this.isRepeat = false
});
},
addUser() {
this.$refs.addUserPop.open();
},
cancelAddUser() {
this.formData = {
username: '',
password: '',
group_id: ''
};
this.$refs.addUserPop.close();
},
selectUserGroup(index, item) {
if (index >= 0) {
this.formData.group_id = parseInt(item.value);
} else {
this.formData.group_id = 0;
}
},
save() {
if (!this.verify() || this.isRepeat) return;
this.isRepeat = true;
let action = '';
if (parseInt(this.formData.uid) > 0) {
action = editUser(this.formData);
} else {
action = addUser(this.formData);
}
action.then(res => {
if (res.code >= 0) {
this.$util.showToast({
title: '操作成功'
});
this.page = 1;
this.list = [];
this.one_judge = true;
this.listLock = true;
this.cancelAddUser();
this.getUserListFn();
this.isRepeat = false;
this.formData = {
username: '',
password: '',
group_id: ''
};
} else {
this.isRepeat = false;
this.$util.showToast({
title: res.message
});
}
});
},
verify() {
if (!this.formData.username) {
this.$util.showToast({
title: '请输入用户名'
});
return false;
}
if (parseInt(this.formData.uid) == 0 && !this.formData.password) {
this.$util.showToast({
title: '请输入密码'
});
return false;
}
if (!this.formData.group_id) {
this.$util.showToast({
title: '请选择员工角色'
});
return false;
}
return true;
}
}
};
</script>
<style scoped lang="scss">
@import './public/css/user.scss';
</style>

View File

@@ -0,0 +1,482 @@
.userlist {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: space-between;
box-sizing: border-box;
.userlist-box {
width: 100%;
height: 100%;
background: #ffffff;
display: flex;
.userlist-left {
width: 5rem;
height: 100%;
border-right: 0.01rem solid #e6e6e6;
box-sizing: border-box;
display: flex;
flex-direction: column;
.notYet {
color: #e6e6e6;
font-size: 0.4rem;
margin-top: 3rem;
text-align: center;
}
.add-user {
padding: 0.24rem 0.2rem;
background: #fff;
button {
height: .4rem;
line-height: .4rem;
}
}
.user-title {
text-align: center;
line-height: 0.6rem;
font-size: 0.18rem;
font-weight: 500;
height: 0.6rem;
border-bottom: 0.01rem solid #e6e6e6;
box-sizing: border-box;
position: relative;
.icongengduo1 {
position: absolute;
top: 50%;
right: 0.2rem;
transform: translateY(-50%);
font-size: 0.3rem;
color: $primary-color;
}
}
.user-search {
width: 100%;
height: 0.6rem;
border-bottom: 0.01rem solid #e6e6e6;
display: flex;
align-items: center;
justify-content: center;
padding: 0 0.2rem;
box-sizing: border-box;
.search {
width: 5.6rem;
height: 0.4rem;
border-radius: 0.04rem;
background: #f5f5f5;
display: flex;
align-items: center;
padding: 0 0.2rem;
box-sizing: border-box;
.iconfont {
font-size: 0.16rem;
color: #909399;
margin-right: 0.11rem;
}
input {
width: 80%;
height: 60%;
border: none;
font-size: 0.14rem;
}
}
}
.user-list-wrap {
flex: 1;
height: 0;
}
.user-list-scroll {
width: 100%;
height: 100%;
.itemhover {
background: var(--primary-color-light-9);
}
.item {
width: 100%;
display: flex;
align-items: center;
padding: 0.2rem;
box-sizing: border-box;
border-bottom: 0.01rem solid #e6e6e6;
image {
width: 0.7rem;
height: 0.7rem;
margin-right: 0.1rem;
}
.item-right {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
height: 0.6rem;
width: 100%;
.user-name {
font-size: 0.16rem;
}
.user-money {
font-size: 0.14rem;
margin-top: 0.1rem;
}
.login-time {
margin-top: 0.1rem;
}
.user-status {
text-align: right;
color: $primary-color;
font-size: 0.16rem;
}
}
}
}
}
.userlist-right {
width: 0;
flex: 1;
height: 100%;
border-right: 0.01rem solid #e6e6e6;
box-sizing: border-box;
position: relative;
.user-title {
text-align: center;
line-height: 0.6rem;
font-size: 0.18rem;
font-weight: 500;
height: 0.6rem;
border-bottom: 0.01rem solid #e6e6e6;
box-sizing: border-box;
position: relative;
.icongengduo1, .iconguanbi1 {
position: absolute;
top: 50%;
right: 0.2rem;
transform: translateY(-50%);
font-size: 0.3rem;
color: $primary-color;
cursor: pointer;
}
}
.user-information {
width: 100%;
padding: 0.2rem 0.2rem 0.2rem 0.2rem;
box-sizing: border-box;
height: calc(100% - 1.38rem);
overflow-y: auto;
position: relative;
.title {
font-size: 0.18rem;
margin-bottom: 0.32rem;
}
.title2 {
margin-bottom: 0.35rem;
}
.information-box {
display: flex;
justify-content: space-between;
.box-left {
width: 5rem;
.information {
width: 100%;
padding-left: 0.1rem;
box-sizing: border-box;
display: flex;
align-items: center;
margin-bottom: 0.15rem;
view {
color: #303133;
font-size: 0.14rem;
}
view:nth-child(1) {
width: 1.3rem;
margin-right: 0.16rem;
text-align: right;
}
view:nth-child(2) {
width: 74%;
margin-right: 0.23rem;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
}
.information:last-child {
margin-bottom: 0.35rem;
}
}
.user-img {
width: 1.5rem;
height: 1.5rem;
}
}
.table {
width: 100%;
height: 2.6rem;
box-sizing: border-box;
.table-all {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 0.38rem;
box-sizing: border-box;
.table-td {
font-size: 0.14rem;
text-align: left;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
}
.table-th {
height: 0.56rem;
background: #f7f8fa;
}
.table-tb {
width: 100%;
height: calc(100% - 0.56rem);
.table-tr {
height: 0.7rem;
border-bottom: 0.01rem solid #e6e6e6;
box-sizing: border-box;
.table-td {
image {
width: 0.5rem;
height: 0.5rem;
}
text-overflow: -o-ellipsis-lastline;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
line-clamp: 2;
-webkit-box-orient: vertical;
}
}
}
}
}
.button-box {
width: 100%;
position: absolute;
bottom: 0;
left: 0;
box-sizing: border-box;
padding: 0.24rem 0.2rem;
button {
width: 1rem;
height: 0.4rem;
line-height: 0.4rem;
margin-left: 0.1rem;
margin-right: 0;
}
}
}
}
}
view {
color: #303133;
}
/deep/ .uni-scroll-view::-webkit-scrollbar {
width: 0.05rem;
height: 0.3rem;
}
/deep/ .uni-scroll-view::-webkit-scrollbar-thumb {
border-radius: 0.1rem;
box-shadow: inset 0 0 0.05rem rgba(0, 0, 0, 0.2);
background: rgba(193, 193, 193, 1);
}
.user-information::-webkit-scrollbar {
width: 0.05rem;
height: 0.3rem;
}
.user-information::-webkit-scrollbar-thumb {
border-radius: 0.1rem;
box-shadow: inset 0 0 0.05rem rgba(0, 0, 0, 0.2);
background: rgba(193, 193, 193, 1);
}
.cart-empty {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 2.1rem;
}
.form-content {
margin-top: 0.2rem;
.form-item {
margin-bottom: 0.1rem;
display: flex;
.form-label {
width: 1.3rem;
text-align: right;
padding-right: 0.1rem;
box-sizing: border-box;
height: 0.32rem;
line-height: 0.32rem;
.required {
color: red;
margin-right: 0.03rem;
}
}
.form-inline {
width: 2.4rem;
line-height: 0.32rem;
margin-right: 0.1rem;
box-sizing: border-box;
.form-input {
border-width: 0.01rem;
border-style: solid;
background-color: #fff;
color: rgba(0, 0, 0, 0.85);
border-radius: 0.02rem;
padding-left: 0.1rem;
height: 0.32rem;
line-height: 0.32rem;
font-size: 0.14rem;
border-color: #e6e6e6;
}
button {
width: calc(50% - 0.05rem);
display: inline-block;
margin-right: 0.1rem;
&:nth-child(2) {
margin-right: 0;
}
}
}
.search-wrap {
position: relative;
}
}
}
.form-radio-group {
display: flex;
align-items: center;
}
.form-checkbox-item, .form-radio-item {
margin-right: 26rpx;
display: flex;
align-items: center;
}
/deep/ .uni-radio-input, .uni-checkbox-input {
width: .18rem;
height: .18rem;
}
// pop弹框
.pop-box {
background: #ffffff;
width: 4.2rem;
height: 3.38rem;
.pop-header {
padding: 0 0.15rem 0 0.2rem;
height: 0.5rem;
line-height: 0.5rem;
border-bottom: 0.01rem solid #f0f0f0;
font-size: 0.14rem;
color: #333;
overflow: hidden;
border-radius: 0.02rem 0.2rem 0 0;
box-sizing: border-box;
display: flex;
justify-content: space-between;
.pop-header-text {
}
.pop-header-close {
cursor: pointer;
text {
font-size: 0.18rem;
}
}
}
.pop-content {
height: calc(100% - 1.05rem);
padding: 0.2rem;
box-sizing: border-box;
}
.form-content {
margin-top: 0;
padding-top: 0.2rem;
display: flex;
flex-direction: column;
align-items: center;
.form-label {
width: .9rem;
}
}
.pop-bottom {
padding: 0.1rem;
border-top: 0.01rem solid #eee;
button {
width: 95%;
}
}
}

View File

@@ -0,0 +1,349 @@
<template>
<base-page>
<view class="uni-flex uni-row height-all">
<view class="container common-wrap" style="-webkit-flex: 1;flex: 1;" v-if="step == 'search'">
<view class="search-title">查询核销码核销</view>
<view class="search-wrap">
<view class="input-wrap">
<input type="text" value="" placeholder="请输入核销码或扫描核销码" placeholder-class="placeholder" v-model="code" @confirm="search" :focus="inputFocus" @focus="inputFocus = true" @blur="codeInputBlur" />
<!-- #ifdef APP-PLUS -->
<view class="iconfont iconsaoyisaosaoma" @click="scancode"></view>
<!-- #endif -->
</view>
<button type="default" class="primary-btn" @click="search">查询</button>
</view>
<view class="search-desc">使用扫码枪扫码时需注意光标需要停留在输入框中</view>
<view class="record" @click="$util.redirectTo('/pages/verify/list')"><text>核销记录</text></view>
</view>
<view class="content-box common-wrap" style="-webkit-flex: 1;flex: 1;" v-if="step == 'verify'">
<view class="input-wrap">
<input placeholder="请输入核销码" v-model="code" @confirm="search" />
<button type="default" class="primary-btn search" @click="search()">查询</button>
</view>
<view class="content-data">
<view class="content-top">
<view v-for="(item, index) in verifyInfo.data.item_array" :key="index" class="verify-item">
<view class="container-image">
<image :src="$util.img(item.img.split(',')[0], { size: 'small' })" mode="aspectFit" />
</view>
<view class="container-box">
<view class="content-name">{{ item.name }}</view>
<view class="content-name">x{{ item.num }}</view>
</view>
</view>
</view>
<view class="content-bottom">
<view class="bottom-item">
<view>核销状态{{ verifyInfo.is_verify == 0 ? '待核销' : '已核销' }}</view>
</view>
<view class="bottom-item">
<view>核销类型{{ verifyInfo.verify_type_name }}核销</view>
</view>
<view class="bottom-item">
<view>
总次数/已使用{{ verifyInfo.verify_total_count ? verifyInfo.verify_total_count : '不限' }}/{{ verifyInfo.verify_use_num }}
</view>
</view>
<view class="bottom-item">
<view>
有效期{{ verifyInfo.expire_time ? $util.timeFormat(verifyInfo.expire_time, 'Y-m-d H:i') : '永久' }}
</view>
</view>
</view>
<view class="verify-action">
<button type="primary" class="default-btn" @click="step = 'search'">取消</button>
<button type="default" class="primary-btn" @click="verify()" v-show="verifyInfo.is_verify == 0">立即核销</button>
</view>
</view>
</view>
</view>
</base-page>
</template>
<script>
import {
getVerifyInfo,
verifyCode
} from '@/api/verify.js';
export default {
data() {
return {
step: 'search',
code: '',
verifyInfo: null,
isRepeat: false,
inputFocus: false
};
},
onLoad() {
uni.hideTabBar();
this.$nextTick(()=>{
this.inputFocus = true;
})
},
methods: {
codeInputBlur() {
this.inputFocus = false;
if(!this.verifyInfo){
this.$nextTick(()=>{
this.inputFocus = true;
})
}
},
deleteCode() {
this.code = this.code.substr(0, this.code.length - 1);
},
search() {
if (!this.code) {
this.$util.showToast({
title: '请输入核销码'
});
return;
}
setTimeout(() => {
this.code = new URLSearchParams(this.code.split('?')[1]).get('code');
getVerifyInfo(this.code.trim()).then(res => {
this.code = '';
if (res.code >= 0) {
this.verifyInfo = res.data;
this.step = 'verify';
} else {
this.$util.showToast({
title: res.message
});
}
});
}, 200);
},
verify() {
if (!this.verifyInfo) {
this.$util.showToast({
title: '请先查询核销码信息'
});
return;
}
if (this.isRepeat) return;
this.isRepeat = true;
verifyCode(this.verifyInfo.verify_code).then(res => {
this.isRepeat = false;
if (res.code >= 0) {
this.step = 'search';
this.verifyInfo = null;
this.code = '';
}
this.$util.showToast({
title: res.message
});
});
},
scancode() {
uni.scanCode({
scanType: ['qrCode', 'barCode'],
success: res => {
this.code = res.result;
this.search();
},
fail: res => {
this.$util.showToast({
title: '扫码失败'
});
}
});
}
}
};
</script>
<style lang="scss" scoped>
.container {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
}
.search-title {
font-size: 0.18rem;
color: #303133;
}
.search-wrap {
display: flex;
margin-top: 0.3rem;
button {
width: 1rem;
text-align: center;
box-sizing: border-box;
line-height: 0.5rem;
}
}
.search-desc {
color: #909399;
font-size: 0.14rem;
margin-top: 0.3rem;
}
.input-wrap {
width: 4.5rem;
height: 0.5rem;
border: 0.01rem solid #cccccc;
display: flex;
border-radius: 0.02rem;
align-items: center;
input {
flex: 1;
padding: 0 0.15rem;
font-size: 0.16rem;
}
.placeholder {
flex: 1;
height: 0.58rem;
line-height: 0.58rem;
font-size: 0.16rem;
font-weight: 400;
color: #909399;
}
.iconfont {
font-size: 0.18rem;
padding: 0 0.15rem;
font-weight: bold;
}
}
.record {
text-align: center;
margin-top: 0.2rem;
text {
color: $primary-color;
font-size: 0.14rem;
cursor: pointer;
}
}
// 核销详情
.content-box {
padding: 0.15rem 0.15rem 0.15rem 0.15rem;
.input-wrap {
width: 6rem;
height: 0.4rem;
border: 0.01rem solid #cccccc;
display: flex;
border-radius: 0.02rem;
input {
flex: 1;
padding: 0 0.15rem;
height: 0.38rem;
line-height: 0.38rem;
font-size: 0.16rem;
font-weight: 400;
}
.placeholder {
font-weight: 400;
color: #909399;
font-size: 0.18rem;
}
.search {
border-radius: 0;
width: 1rem;
line-height: 0.38rem;
font-size: 0.16rem;
font-family: Source Han Sans CN;
&::after {
border: none;
}
}
}
.content-data {
border: 0.01rem solid #eee;
margin-top: 0.2rem;
padding: 0.15rem;
.verify-item {
display: flex;
padding: 0.15rem 0;
.container-image {
width: 1rem;
height: 1rem;
image {
width: 100%;
height: 100%;
}
}
.container-box {
display: flex;
flex-direction: column;
justify-content: space-between;
margin-left: 0.15rem;
width: 0;
flex: 1;
.content-name {
font-size: 0.15rem;
margin-top: 0.05rem;
}
.content-desc {
display: flex;
margin-top: 0.15rem;
color: #999;
font-size: 0.13rem;
.time {
margin-left: 0.5rem;
}
}
}
}
.verify-action {
display: flex;
justify-content: flex-end;
border-top: 0.01rem solid #eee;
padding-top: 0.15rem;
button {
width: 1rem;
height: 0.36rem;
margin: 0 0 0 0.15rem;
}
}
.content-bottom {
padding: 0.15rem 0;
border-top: 0.01rem solid #eee;
.bottom-item {
color: #999;
display: flex;
margin-top: 0.15rem;
width: 5rem;
justify-content: space-between;
view {
margin-right: 0.5rem;
}
}
}
}
}
</style>

View File

@@ -0,0 +1,353 @@
<template>
<base-page>
<view class="uni-flex uni-row check-wrap">
<view class="check-head">
<text>核销列表</text>
<text>核销详情</text>
</view>
<view class="check-content">
<view class="left-wrap-content">
<view class="wrap-search-box">
<view class="wrap-search">
<input placeholder="输入核销码" v-model="searchText" @input="search()" placeholder-style="font-size:0.14rem" />
<text class="iconfont icon31sousuo" @click="search()"></text>
</view>
</view>
<block v-if="list.length > 0">
<scroll-view scroll-y="true" class="check-list all-scroll" @scrolltolower="getRecordList">
<view class="item" v-for="(item, index) in list" :key="index" @click="tableDataFn(item)" :class="current_id == item.id ? 'item-hover' : ''">
<view class="item-box">
<view class="head">
<view class="nick-name">核销码{{ item.verify_code }}</view>
<view class="time">核销时间{{ $util.timeFormat(item.verify_time, 'Y-m-d H:i') }}</view>
</view>
<view class="body">
<text>{{ item.verifier_name }}</text>
</view>
</view>
</view>
</scroll-view>
</block>
<view class="not-record" v-else>暂无数据</view>
</view>
<view class="check-detail text">
<view class="form-content" v-if="detailInfo && Object.keys(detailInfo).length">
<view class="verify-item" v-for="(item, index) in detailInfo.verify_content_json.item_array" :key="index">
<view class="item-img">
<image :src="$util.img(item.img.split(',')[0], { size: 'small' })" mode="aspectFit"/>
</view>
<view class="item-info">
<view>{{ item.name }}</view>
</view>
</view>
<view class="form-item">
<view class="form-label">核销码</view>
<view class="form-inline">
<text>{{ detailInfo.verify_code }}</text>
</view>
</view>
<view class="form-item">
<view class="form-label">核销类型</view>
<view class="form-inline">{{ detailInfo.verify_type_name }}核销</view>
</view>
<view class="form-item">
<view class="form-label">核销员</view>
<view class="form-inline">{{ detailInfo.verifier_name }}</view>
</view>
<view class="form-item">
<view class="form-label">核销次数</view>
<view class="form-inline">{{ detailInfo.verify_num }}</view>
</view>
<view class="form-item">
<view class="form-label">核销时间</view>
<view class="form-inline">{{ $util.timeFormat(detailInfo.verify_time, 'Y-m-d H:i') }}</view>
</view>
<view class="form-item" v-if="detailInfo.member_id > 0">
<view class="form-label">所属会员</view>
<view class="form-inline">{{ detailInfo.nickname }}</view>
</view>
<view class="form-item" v-if="detailInfo.member_id > 0">
<view class="form-label">手机号</view>
<view class="form-inline">{{ detailInfo.mobile ? detailInfo.mobile : '--' }}</view>
</view>
</view>
<block v-else>
<image class="detail-empty" :src="$util.img('@/static/goods/goods_empty.png')" mode="widthFix"/>
</block>
</view>
</view>
</view>
</base-page>
</template>
<script>
import {
getVerifyRecordList,
getVerifyRecordDetail
} from '@/api/verify.js';
export default {
data() {
return {
detailInfo: null,
// 初始是请求第几页
page: 1,
// 每次返回数据数
page_size: 20,
list: [],
current_id: 0,
searchText: ''
};
},
onLoad() {
this.getRecordList();
},
methods: {
search() {
this.page = 1;
this.list = [];
this.getRecordList();
},
// 查询核销记录
getRecordList() {
getVerifyRecordList({
page: this.page,
page_size: this.page_size,
search_text: this.searchText
}).then(res => {
if (res.data.list.length == 0) {
this.detailInfo = {};
this.$forceUpdate();
}
if (res.code >= 0 && res.data.list.length != 0) {
this.page += 1;
this.list = this.list.concat(res.data.list);
}
if (this.list.length) {
this.tableDataFn(this.list[0]);
}
})
},
tableDataFn(e) {
this.current_id = e.id;
this.getInfo(e.id);
},
getInfo(id) {
getVerifyRecordDetail(id).then(res => {
if (res.code >= 0) {
this.detailInfo = null;
this.detailInfo = res.data;
} else {
this.$util.showToast({
title: res.message
});
}
});
}
}
};
</script>
<style lang="scss" scoped>
.check-wrap {
flex-direction: column;
background-color: #fff;
min-height: 100%;
.check-head {
display: flex;
justify-content: space-around;
line-height: 0.6rem;
font-weight: 500;
height: 0.6rem;
border-top: 0.01rem solid #e6e6e6;
border-bottom: 0.01rem solid #e6e6e6;
text {
width: 5rem;
text-align: center;
font-size: 0.18rem;
border-left: 0.01rem solid #e6e6e6;
box-sizing: border-box;
&:nth-child(2) {
flex: 1;
width: 0;
}
}
}
.check-content {
display: flex;
min-height: calc(100vh - 1rem);
>view {
padding: 0.2rem;
box-sizing: border-box;
}
.left-wrap-content {
display: flex;
flex-direction: column;
height: calc(100vh - 1rem);
padding: 0;
.wrap-search-box {
height: 0.35rem;
border-bottom: 0.01rem solid #e6e6e6;
padding: 0.1rem 0.15rem;
.wrap-search {
background: #f5f5f5;
display: flex;
position: relative;
padding: 0.05rem 0.15rem 0.05rem 0.4rem;
input {
width: 100%;
}
.iconfont {
position: absolute;
left: 0.15rem;
top: 0.08rem;
cursor: pointer;
}
}
}
}
.not-record {
color: #e6e6e6;
font-size: 0.4rem;
margin-top: 3rem;
text-align: center;
width: 5rem;
}
.check-list {
width: 5rem;
height: calc(100% - 0.5rem);
padding: 0;
.item-hover {
background: var(--primary-color-light-9);
}
.item {
position: relative;
padding: 0.2rem;
border-bottom: 0.01rem solid #e6e6e6;
cursor: pointer;
.name {
font-size: $uni-font-size-lg;
padding-bottom: 0.07rem;
}
.item-box {
.head {
display: flex;
justify-content: space-between;
}
.body {
margin-top: 0.15rem;
display: flex;
justify-content: space-between;
}
.time {
text-align: right;
}
}
.time,
.nick-name {
line-height: 1;
width: 50%;
font-size: $uni-font-size-lg;
}
.type {
position: absolute;
right: 0.25rem;
top: 50%;
transform: translateY(-50%);
}
}
}
.check-detail {
flex: 1;
width: 0;
border-left: 0.01rem solid #e6e6e6;
position: relative;
.detail-empty {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 2.1rem;
}
.form-content {
margin-top: 0.2rem;
.form-item {
margin-bottom: 0.1rem;
display: flex;
.form-label {
width: 1.6rem;
text-align: right;
padding-right: 0.1rem;
box-sizing: border-box;
height: 0.32rem;
line-height: 0.32rem;
}
.form-inline {
line-height: 0.32rem;
margin-right: 0.1rem;
box-sizing: border-box;
}
}
.verify-item {
display: flex;
padding: 0.15rem;
background: #f5f5f5;
margin-bottom: 0.1rem;
.item-img {
width: 0.8rem;
height: 0.8rem;
display: flex;
align-items: center;
justify-content: center;
image {
width: 100%;
}
}
.item-info {
flex: 1;
width: 0;
margin-left: 0.15rem;
}
}
}
}
}
}
</style>