Browse Source

Merge branch 'dev' of https://git.ouxuan.net/APP/ox_zhiNengZhuShou into pf_1807

tid1867
刘嘉炜 3 months ago
parent
commit
0b7334d855
  1. 138
      src/components/period_select.vue
  2. 66
      src/pages.json
  3. 2
      src/pages/index/index.vue
  4. 2
      src/pages/order_search/order_search.vue
  5. 175
      src/pages/write_off/douyin/poi_list.vue
  6. 237
      src/pages/write_off/mall/list/list.vue
  7. 131
      src/pages/write_off/menu/menu.vue
  8. 70
      src/pages/write_off/null/null.vue
  9. 496
      src/pages/write_off/number_of_people/number_of_people.vue
  10. 364
      src/pages/write_off/operate/operate.vue
  11. 339
      src/pages/write_off/search_result/search_result.vue
  12. BIN
      src/static/images/code_null.png
  13. BIN
      src/static/images/countdown_bg.png
  14. BIN
      src/static/images/order_null.png
  15. BIN
      src/static/images/scan_null.png
  16. BIN
      src/static/images/write_off/mall.png
  17. BIN
      src/static/images/write_off/order.png
  18. BIN
      src/static/images/write_off/people.png
  19. BIN
      src/static/images/write_off/site.png
  20. 4
      src/subpackage/blacklist/pages/abnormal_list/abnormal_list.vue
  21. 59
      src/subpackage/verification/components/head_bar.vue
  22. 78
      src/subpackage/verification/components/record/dy_item.vue
  23. 95
      src/subpackage/verification/components/record/mall_item.vue
  24. 87
      src/subpackage/verification/components/record/site_item.vue
  25. 15
      src/subpackage/verification/components/stadium_picker.vue
  26. 7
      src/subpackage/verification/js/api.js
  27. 282
      src/subpackage/verification/pages/index.vue
  28. 62
      src/subpackage/verification/pages/null.vue
  29. 394
      src/subpackage/verification/pages/record.vue
  30. 244
      src/subpackage/verification/pages/record_search.vue
  31. 5
      src/subpackage/verification/pages/site_people/index.vue
  32. 9
      src/subpackage/verification/pages/site_people/modules/not_leave_modal.vue
  33. 15
      src/subpackage/verification/pages/site_people/modules/stadium_select.vue
  34. BIN
      src/subpackage/verification/static/images/arrow_c9f.png
  35. BIN
      src/subpackage/verification/static/images/calendar.png
  36. BIN
      src/subpackage/verification/static/images/order/null_code.png
  37. BIN
      src/subpackage/verification/static/images/order/null_range.png
  38. BIN
      src/subpackage/verification/static/images/order/null_search.png
  39. BIN
      src/subpackage/verification/static/images/round_close.png
  40. BIN
      src/subpackage/verification/static/images/scan.png
  41. BIN
      src/subpackage/verification/static/images/search.png
  42. BIN
      src/subpackage/verification/static/images/tab0.png
  43. BIN
      src/subpackage/verification/static/images/tab1.png
  44. BIN
      src/subpackage/verification/static/images/tab2.png
  45. 3
      src/subpackage/wallet/js/api.js
  46. 15
      src/subpackage/wallet/pages/douyin_withdraw/index.vue
  47. 77
      src/subpackage/wallet/pages/index/index.vue
  48. 82
      src/subpackage/wallet/pages/index/modules/recharge_modal.vue
  49. 6
      src/subpackage/wallet/pages/index/modules/wallet_info.vue
  50. 137
      src/subpackage/wallet/pages/index/recharge_record.vue
  51. 6
      src/utils/util.js

138
src/components/period_select.vue

@ -0,0 +1,138 @@
<template>
<!-- 时间段选择 -->
<view class="period-select-mask" v-if="isShow" @click="isShow = false">
<view class="ol-period" @click.stop="()=>false">
<view class="op-tit">日期范围</view>
<picker mode="date" class="op-picker" @change="startTimeChange" :value="startTime">
<view class="op-time">
<text class="ot-tit">开始时间</text>
<view class="ot-right">
<input class="or-ipt" placeholder="选择时间" disabled :value="startTime"/>
<image class="or-icon" mode="aspectFit" src="/static/images/icon/arrow_b2.png"></image>
</view>
</view>
</picker>
<picker mode="date" class="op-picker" @change="endTimeChange" :value="endTime">
<view class="op-time">
<text class="ot-tit">截止时间</text>
<view class="ot-right">
<input class="or-ipt" placeholder="选择时间" disabled :value="endTime"/>
<image class="or-icon" mode="aspectFit" src="/static/images/icon/arrow_b2.png"></image>
</view>
</view>
</picker>
<view class="pl-btn active" @click="confirmBtn">确定</view>
</view>
</view>
</template>
<script>
import { showNone, showModal } from '@/utils/util';
export default {
props: {
value: {
type: String,
default: ''
}
},
watch: {
value: {
handler(val) {
let [start, end] = val.split('_');
this.startTime = start;
this.endTime = end;
},
immediate: true
}
},
data(){
return {
isShow: false,
startTime: '',
endTime: '',
}
},
methods: {
show(){
this.isShow = true
},
hide(){
this.isShow = false
},
startTimeChange(e){
this.startTime = e.detail.value;
},
endTimeChange(e){
this.endTime = e.detail.value;
},
confirmBtn(){
let { startTime, endTime } = this;
let _sTimestemp = new Date(startTime.replace(/\-/g,'/')).getTime();
let _eTimestemp = new Date(endTime.replace(/\-/g,'/')).getTime();
if(_sTimestemp > _eTimestemp)return showModal({ content: '开始时间不能大于结束时间' });
this.$emit('input', `${startTime}_${endTime}`);
this.hide();
}
}
}
</script>
<style lang="scss">
.period-select-mask{
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0,0,0,0.4);
z-index: 9999;
}
.ol-period{
position: absolute;
left: 0;
top: 0;
padding-left: 38upx;
padding-top: 66upx;
height: 472upx;
width: 100%;
background-color: #fff;
.op-tit{
@include flcw(24upx, 34upx, #9c9c9f);
}
.op-picker{
width: 100%;
}
.op-time{
padding-right: 40upx;
height: 124upx;
border-bottom: 2upx solid #D8D8D8;
@include ctf(space-between);
.ot-tit{
flex-shrink: 0;
@include flcw(32upx, 44upx, #1a1a1a);
}
.ot-right{
flex-grow: 1;
@include ctf(flex-end);
.or-ipt{
flex-grow: 1;
height: 100%;
text-align: right;
@include flcw(32upx, 44upx, #1a1a1a);
}
.or-icon{
flex-shrink: 0;
margin-left: 36upx;
width: 28upx;
height: 28upx;
}
}
}
.pl-btn{
min-height: 124upx;
text-align: center;
@include flcw(32upx, 124upx, $mColor, 500);
}
}
</style>

66
src/pages.json

@ -206,18 +206,6 @@
} }
}, },
{ {
"path": "pages/write_off/mall/list/list",
"style": {
"navigationBarTitleText": "商城订单核销"
}
},
{
"path": "pages/write_off/menu/menu",
"style": {
"navigationBarTitleText": "核销订单"
}
},
{
"path": "pages/write_off/ym_card_gated/ym_card_gated", "path": "pages/write_off/ym_card_gated/ym_card_gated",
"style": { "style": {
"navigationBarTitleText": "核销订单" "navigationBarTitleText": "核销订单"
@ -230,36 +218,12 @@
} }
}, },
{ {
"path": "pages/write_off/search_result/search_result",
"style": {
"navigationBarTitleText": "核销查询"
}
},
{
"path": "pages/write_off/operate/operate",
"style": {
"navigationBarTitleText": "核销订单"
}
},
{
"path": "pages/write_off/confirm_order/confirm_order", "path": "pages/write_off/confirm_order/confirm_order",
"style": { "style": {
"navigationBarTitleText": "核销订单" "navigationBarTitleText": "核销订单"
} }
}, },
{ {
"path": "pages/write_off/null/null",
"style": {
"navigationBarTitleText": "确认订单信息"
}
},
{
"path": "pages/write_off/douyin/poi_list",
"style": {
"navigationBarTitleText": "核销订单"
}
},
{
"path": "pages/employee/review_list/review_list", "path": "pages/employee/review_list/review_list",
"style": { "style": {
"navigationBarTitleText": "员工管理" "navigationBarTitleText": "员工管理"
@ -794,6 +758,12 @@
} }
}, },
{ {
"path": "pages/index/recharge_record",
"style" : {
"navigationBarTitleText": "充值记录"
}
},
{
"path": "pages/douyin_withdraw/index", "path": "pages/douyin_withdraw/index",
"style" : { "style" : {
"navigationBarTitleText": "平台提现" "navigationBarTitleText": "平台提现"
@ -930,10 +900,34 @@
"root": "subpackage/verification", "root": "subpackage/verification",
"pages": [ "pages": [
{ {
"path": "pages/null",
"style" : {
"navigationBarTitleText": "核销查询"
}
},
{
"path": "pages/record_search",
"style" : {
"navigationBarTitleText": "核销查询"
}
},
{
"path": "pages/index",
"style" : {
"navigationBarTitleText": "核销查询"
}
},
{
"path": "pages/site_people/index", "path": "pages/site_people/index",
"style" : { "style" : {
"navigationBarTitleText": "现场人数" "navigationBarTitleText": "现场人数"
} }
},
{
"path": "pages/record",
"style" : {
"navigationBarTitleText": "核销记录"
}
} }
] ]
}, },

2
src/pages/index/index.vue

@ -109,7 +109,7 @@
{ {
id: 4, id: 4,
name: '核销查询', name: '核销查询',
path: '/pages/write_off/menu/menu',
path: '/subpackage/verification/pages/index',
serverKey: 1008 // serverKey: 1008 //
}, },
{ {

2
src/pages/order_search/order_search.vue

@ -3,7 +3,7 @@
<view class="os-bar"> <view class="os-bar">
<view> <view>
<image mode="aspectFit" src="/static/images/icon/search.png"></image> <image mode="aspectFit" src="/static/images/icon/search.png"></image>
<input placeholder="输入订单号" v-model="searchTxt" confirm-type="search" @confirm="iptConfirm" />
<input placeholder="输入订单号" v-model="searchTxt" confirm-type="search" @confirm="iptConfirm" />
<image v-if="searchTxt!=''" mode="aspectFit" src="/static/images/icon/round_close.png" @click="clearSearch"></image> <image v-if="searchTxt!=''" mode="aspectFit" src="/static/images/icon/round_close.png" @click="clearSearch"></image>
</view> </view>
</view> </view>

175
src/pages/write_off/douyin/poi_list.vue

@ -1,175 +0,0 @@
<template>
<view class="dy-poi-ls">
<view class="dpl-header">
<stadium-picker
:stadium-list="stadiumList"
@change:stadium="stadiumChange"
></stadium-picker>
<!-- <period-picker></period-picker> -->
<view class="dh-number">核销数量{{ totalNum || 0 }}</view>
</view>
<view class="dpl-list">
<view class="dl-item" v-for="(e, i) in writeOffList" :key="i">
<list-item
:order-no="e.order_no"
:user-phone="e.user_phone"
:verify-code="e.verify_code"
:verify-method="e.verify_method"
:verify-time="e.verify_time"
></list-item>
</view>
</view>
<view class="r-bottom-btn"><view @click="toOperate">核销团购券</view></view>
</view>
</template>
<script>
import periodPicker from "../all_components/period_picker.vue";
import stadiumPicker from "../all_components/stadium_picker.vue";
import listItem from "../all_components/list_item.vue";
import { API } from '../../../js/api';
import { servers } from '../../../js/server';
import util from '../../../utils/util';
import { mapState } from 'vuex';
import { WRITE_OFF_STORE_NAME } from '../../../js/once_name';
export default {
computed: {
...mapState([ 'brandInfo' ]),
},
components: {
periodPicker,
stadiumPicker,
listItem
},
data() {
return {
totalNum: 0,
writeOffList: [],
stadiumList: [],
curStadium: {},
page: 1,
}
},
async onLoad() {
let _brand_id = this.brandInfo?.brand?.id || 63;
let _list = await this.getStoreList({ brand_id: _brand_id });
this.stadiumList = _list || [];
this.getList({ brand_id: _brand_id });
},
onReachBottom(){
let { page, curStadium } = this;
this.getList({
brand_id: curStadium?.brand_id,
stadium_id: curStadium?.id,
page: page + 1,
})
},
methods: {
toOperate(){
let { stadiumList, curStadium } = this;
util.$_emit(WRITE_OFF_STORE_NAME, {
stadiumList,
curStadium,
})
util.routeTo(`/pages/write_off/operate/operate?type=dypoi`, 'rT');
},
stadiumChange(stadium){
this.curStadium = stadium;
this.page = 1;
this.totalNum = 0;
this.writeOffList = [];
this.getList({
brand_id: stadium?.brand_id,
stadium_id: stadium?.id,
})
},
getList({ brand_id, stadium_id = '', date = '', page = 1, page_size = 20, order_status = 'used' }){
util.showLoad();
servers.get({
url: API.writeOff.dyPoiOrderList,
data: { brand_id, stadium_id, date, page, page_size, order_status },
failMsg: '加载失败!',
})
.then(res=>{
util.hideLoad();
this.totalNum = res.total || 0;
let _list = (res.list || []).map(e=>this.formating(e));
if(page == 1)return this.writeOffList = _list;
if(!_list.length)return util.showNone('没有更多!');
this.page = page;
this.writeOffList = [...this.writeOffList, ..._list];
})
},
formating(data){
let _code = data?.order_codes?.find(e=>e?.code_status == 'used');
return {
order_no: data?.order_no || '',
user_phone: data?.mobile || '',
verify_code: _code?.code || '',
verify_method: _code?.verification_method || '',
verify_time: _code?.verification_time || '',
}
},
getStoreList({
page=1,
page_size=9999,
brand_id='',
}){
return servers.get({
url: API.stadiumList,
data: {
page,
page_size,
brand_id,
},
failMsg: '获取列表失败!'
})
.then(res=>res.list || [])
},
}
}
</script>
<style lang="scss">
.dy-poi-ls{
@include isPd(150upx);
}
.dpl-header{
position: sticky;
padding-bottom: 24upx;
background: #fff;
.dh-number{
padding: 0 24upx;
text-align: right;
@include flcw(32upx, 44upx);
@include tHide;
}
}
.dpl-list{
padding: 24upx;
.dl-item+ .dl-item{
margin-top: 24upx;
}
}
.r-bottom-btn{
position: fixed;
left: 0;
bottom: 0;
width: 100%;
padding: 10upx 24upx;
padding-bottom: calc( 10upx + constant(safe-area-inset-bottom)); /* 兼容 iOS < 11.2 */
padding-bottom: calc( 10upx + env(safe-area-inset-bottom)); /* 兼容 iOS >= 11.2 */
background-color: #f2f2f7;
>view{
height: 112upx;
line-height: 112upx;
text-align: center;
font-size: 32upx;
border-radius: 10upx;
color: #fff;
background-color: $mColor;
}
}
</style>

237
src/pages/write_off/mall/list/list.vue

@ -1,237 +0,0 @@
<template>
<view class="mall-order-ls">
<view class="mol-date">
<view class="md-txt">核销日期</view>
<view class="md-picker">
<picker mode="date" @change="stChange">
<view>
<input :value="startTime" disabled placeholder="请选择时间" />
<image mode="aspectFit" src="/static/images/icon/arrow_c33.png"></image>
</view>
</picker>
</view>
<view class="md-txt"></view>
<view class="md-picker">
<picker mode="date" @change="edChange">
<view>
<input :value="endTime" disabled placeholder="请选择时间" />
<image mode="aspectFit" src="/static/images/icon/arrow_c33.png"></image>
</view>
</picker>
</view>
</view>
<view class="mol-list">
<view class="ml-item" v-for="(e, i) in writeOffList" :key="i">
<view class="mi-order-no">
<view class="mon-num">订单编号{{ e.product_order_no || '-' }}</view>
<view class="mon-btn" @click="copyBtn(e.product_order_no || '-')">复制</view>
</view>
<view class="mi-info">
<view class="mi-line">取货码{{ e.product_order_no || '-' }}</view>
<view class="mi-line">取货人{{ e.product_order_self_pickup_info.name || '-' }} {{ e.product_order_self_pickup_info.phone || '-' }}</view>
<view class="mi-line">商品{{ e.product_order_goods.join(';') }}</view>
<view class="mi-line">核验人{{ e.optuname }}</view>
<view class="mi-line">取货时间{{ e.created_at || '-' }}</view>
</view>
</view>
</view>
<view class="mol-fixed">
<view @click="toOperate">核销订单</view>
</view>
</view>
</template>
<script>
import { API } from '../../../../js/api';
import { servers } from '../../../../js/server';
import util from '../../../../utils/util';
import { mapState } from 'vuex';
import { WRITE_OFF_STORE_NAME } from '../../../../js/once_name';
export default {
computed: {
...mapState([ 'brandInfo' ]),
},
data(){
return {
writeOffList: [],
page: 1,
startTime: '',
endTime: '',
}
},
onReachBottom(){
let { brandInfo, startTime, endTime, page } = this;
this.getList({
brand_id: brandInfo.brand.id,
stime: startTime || '',
etime: endTime || '',
page: ++page
})
},
onLoad(){
// 1
let _startDate = util.formatDate({
date: new Date().getTime() - 30*24*60*60*1000
}).substr(0, 10);
let _endDate = util.formatDate({ }).substr(0, 10);
this.startTime = _startDate;
this.endTime = _endDate;
// 1
this.$nextTick(_=> this.refreshPage());
},
methods: {
refreshPage(){
let { brandInfo, startTime, endTime } = this;
this.page = 1;
this.writeOffList = [];
this.$nextTick(_=>{
this.getList({
brand_id: brandInfo.brand.id,
stime: startTime || '',
etime: endTime || '',
})
})
},
copyBtn(data){
uni.setClipboardData({ data })
},
stChange(e){
console.warn(e)
this.startTime = e.detail.value;
this.$nextTick(_=>this.refreshPage());
},
edChange(e){
this.endTime = e.detail.value;
this.$nextTick(_=>this.refreshPage());
},
toOperate(){
util.$_emit(WRITE_OFF_STORE_NAME, null);
util.routeTo(`/pages/write_off/operate/operate?type=mall`, 'nT');
},
getList({ brand_id, page = 1, page_size = 15, stime = '', etime = '' }){
util.showLoad();
servers.get({
url: API.writeOff.shop2WriteoffList,
data: { brand_id, page, page_size, stime, etime },
failMsg: '加载失败!',
})
.then(res=>{
util.hideLoad();
this.totalNum = res.total || 0;
let _list = res.list || [];
if(page == 1)return this.writeOffList = _list;
if(!_list.length)return util.showNone('没有更多!');
this.page = page;
this.writeOffList = [...this.writeOffList, ..._list];
})
},
}
}
</script>
<style lang="scss">
@import '~style/public.scss';
.mall-order-ls{
padding-bottom: 122upx;
padding-bottom: calc( 122upx + constant(safe-area-inset-bottom)); /* 兼容 iOS < 11.2 */
padding-bottom: calc( 122upx + env(safe-area-inset-bottom)); /* 兼容 iOS >= 11.2 */
}
.mol-date{
padding: 0 28upx;
height: 148upx;
background-color: #fff;
@include centerFlex(flex-start);
.md-txt{
font-size: 32upx;
line-height: 44upx;
color: #1a1a1a;
}
.md-picker{
margin: 0 20upx;
width: 226upx;
border: 2upx solid #D8D8D8;
border-radius: 10upx;
overflow: hidden;
view{
padding: 0 10upx;
height: 88upx;
background-color: #f2f2f7;
@include centerFlex(space-between);
>input{
flex-grow: 1;
height: 100%;
font-size: 28upx;
color: #1a1a1a;
}
>image{
margin-left: 10upx;
flex-shrink: 0;
width: 22upx;
height: 22upx;
}
}
}
}
.mol-list{
padding: 24upx;
.ml-item{
margin-bottom: 24upx;
padding: 0 24upx;
background-color: #fff;
.mi-order-no{
padding: 30upx 4upx;
border-bottom: 2upx solid #f2f2f7;
@include centerFlex(space-between);
.mon-num{
font-size: 28upx;
font-weight: 500;
line-height: 40upx;
color: #1a1a1a;
}
.mon-btn{
flex-shrink: 0;
margin-left: 20upx;
font-size: 28upx;
line-height: 40upx;
color: $themeColor;
}
}
.mi-info{
padding: 30upx 4upx;
.mi-line{
font-size: 28upx;
line-height: 52upx;
color: #9C9C9F;
@include textHide(1);
}
}
}
}
.mol-fixed{
position: fixed;
left: 0;
bottom: 0;
width: 100%;
background-color: #fff;
padding: 10upx 40upx;
padding-bottom: calc( 10upx + constant(safe-area-inset-bottom)); /* 兼容 iOS < 11.2 */
padding-bottom: calc( 10upx + env(safe-area-inset-bottom)); /* 兼容 iOS >= 11.2 */
>view{
height: 112upx;
line-height: 112upx;
text-align: center;
font-size: 32upx;
color: #fff;
background-color: $themeColor;
border-radius: 10upx;
}
}
</style>

131
src/pages/write_off/menu/menu.vue

@ -1,131 +0,0 @@
<template>
<view class="write-off-menu">
<view class="wom-section">
<view class="ws-tit">场地订单核销</view>
<view class="ws-ls">
<view class="wl-item" @click="toOperate('site')">
<image mode="aspectFit" src="/static/images/write_off/site.png"></image>
<view>场地订单核销</view>
</view>
<view class="wl-item" @click="toSiteList">
<image mode="aspectFit" src="/static/images/write_off/order.png"></image>
<view>场地订单核销记录</view>
</view>
</view>
</view>
<view class="wom-section">
<view class="ws-tit">商城订单核销</view>
<view class="ws-ls">
<view class="wl-item" @click="toOperate('mall')">
<image mode="aspectFit" src="/static/images/write_off/mall.png"></image>
<view>商城订单核销</view>
</view>
<view class="wl-item" @click="toMallLs">
<image mode="aspectFit" src="/static/images/write_off/order.png"></image>
<view>商城订单核销记录</view>
</view>
</view>
</view>
<view class="wom-section">
<view class="ws-tit">抖音团购核销</view>
<view class="ws-ls">
<view class="wl-item" @click="toOperate('dypoi')">
<image mode="aspectFit" src="/static/images/write_off/site.png"></image>
<view>抖音团购核销</view>
</view>
<view class="wl-item" @click="toDypoiOrderLs">
<image mode="aspectFit" src="/static/images/write_off/order.png"></image>
<view>抖音团购核销记录</view>
</view>
</view>
</view>
<view class="wom-section">
<view class="ws-tit">现场散客人数</view>
<view class="ws-ls">
<view class="wl-item" @click="toPeopleNum">
<image mode="aspectFit" src="/static/images/write_off/people.png"></image>
<view>现场散客人数查询</view>
</view>
</view>
</view>
</view>
</template>
<script>
import util from '../../../utils/util';
import { WRITE_OFF_STORE_NAME } from '../../../js/once_name';
export default {
data(){
return {
brand_id: ''
}
},
onLoad(options){
this.brand_id = options?.brand_id || ''
},
methods: {
toPeopleNum(){
let _qryStr = `brand_id=${this.brand_id}`
util.routeTo(`/subpackage/verification/pages/site_people/index?${_qryStr}`, 'nT');
},
toOperate(type){
util.$_emit(WRITE_OFF_STORE_NAME, null);
util.routeTo(`/pages/write_off/operate/operate?type=${type}`, 'nT');
},
toSiteList(){
util.routeTo(`/pages/write_off/search_result/search_result`, 'nT');
},
toMallLs(){
util.routeTo(`/pages/write_off/mall/list/list`, 'nT');
},
toDypoiOrderLs(){
util.routeTo(`/pages/write_off/douyin/poi_list`, 'nT');
}
}
}
</script>
<style lang="scss">
@import '~style/public.scss';
.write-off-menu{
padding: 60upx 68upx 0upx;
.wom-section{
margin-bottom: 30upx;
.ws-tit{
margin-bottom: 20upx;
font-size: 32upx;
font-weight: 500;
line-height: 44upx;
color: #1a1a1a;
}
.ws-ls{
@include centerFlex(space-between);
flex-wrap: wrap;
.wl-item{
padding-top: 58upx;
margin-bottom: 32upx;
width: 288upx;
height: 220upx;
border-radius: 10upx;
background-color: #fff;
>image{
margin: 0 auto 22upx;
display: block;
width: 60upx;
height: 60upx;
}
>view{
text-align: center;
line-height: 40upx;
font-size: 28upx;
color: #9c9c9f;
@include textHide(1);
}
}
}
}
}
</style>

70
src/pages/write_off/null/null.vue

@ -1,70 +0,0 @@
<template>
<view class="null-container">
<image mode="aspectFit" :src="imgPath"></image>
<view class="c-tip" v-if="operateType == 'decrypt_text'">很抱歉获取不到二维码订单信息</view>
<view class="c-tip" v-if="operateType == 'verify_code'">很抱歉获取不到验证码订单信息</view>
<view class="c-btn" @click="toBlack">返回</view>
</view>
</template>
<script>
import util from '../../../utils/util';
export default {
computed: {
imgPath(){
let { operateType } = this;
if(operateType == 'verify_code')return '/static/images/code_null.png';
if(operateType == 'decrypt_text')return '/static/images/scan_null.png';
}
},
onLoad(options){
let { type } = options;
this.operateType = options.type
},
data(){
return {
isScan: false,
operateType: '', // verify_code()/decrypt_text()
}
},
methods: {
toBlack(){
util.routeTo();
}
}
}
</script>
<style lang="scss">
@import "~style/public.scss";
page{
background-color: #fff;
}
.null-container{
padding-top: 90upx;
>image{
display: block;
margin: 0 auto 86upx;
width: 420upx;
height: 420upx;
}
.c-tip{
margin-bottom: 260upx;
line-height: 40upx;
text-align: center;
font-size: 28upx;
color: #9c9c9f;
}
.c-btn{
margin: 0 auto;
width: 280upx;
text-align: center;
height: 92upx;
line-height: 88upx;
font-size: 32upx;
border: 2upx solid $themeColor;
color: $themeColor;
border-radius: 46upx;
}
}
</style>

496
src/pages/write_off/number_of_people/number_of_people.vue

@ -1,496 +0,0 @@
<template>
<view class="number-of-people">
<view class="nop-store-name">
<picker :range="stadiumList" range-key="name" @change="stadiumChange">
<view class="nsn-frame">
<input placeholder="请选择店铺" :value="curStadium.name" disabled />
<image mode="aspectFit" src="/static/images/icon/arrow_c33.png"></image>
</view>
</picker>
</view>
<view class="nop-main">
<view class="nm-date">日期{{ dateStr || '-' }}</view>
<view class="nm-tit">现场散客人数</view>
<view class="nm-num">
<image mode="aspectFit" src="/static/images/countdown_bg.png"></image>
<view class="nn-txt-num">{{peopleInfo.present_person_number || 0}}</view>
</view>
<view class="nm-txt" @click="checkNotLeave">查看未离场订单</view>
<view class="nm-btn" @click="isChangeNum = true">修改人数</view>
<view class="nm-line">
<view class="nl-txt">凌晨自动清零</view>
<view class="nl-switch" @click="switchChange">
<switch color="#009777" disabled style="transform:scale(0.8)" :checked="peopleInfo. present_person_number_clear"></switch>
</view>
</view>
<view class="nm-tip">
<text>* 不开启凌晨自动清零则现场灯光按现场散客人数去判断是否开启或关闭修改人数会直接影响现场灯光开关\n\r* 开启凌晨自动清零则现场灯光按散客订单未离场数量去判断是否开启或关闭修改人数不会影响现场灯光开关但如有散客订单一直未扫码离场可能会无法关灯需要将未离场的散客订单设置为已离场后才可关闭灯光</text>
</view>
</view>
<view class="ox-dark-mask" v-if="isChangeNum">
<view class="nop-modifies-modal">
<image class="nmm-close" @click="isChangeNum = false" src="/static/images/icon/x_close.png"></image>
<view class="nmm-tit">修改现场散客人数</view>
<view class="nmm-info">
<view class="ni-num">当前现场散客人数为{{peopleInfo.present_person_number || 0}}</view>
<view class="ni-ipt">
<input placeholder="请输入散客人数" v-model="changeNum" type="number" />
</view>
<view class="ni-tip">修改现场人数可能会影响现场灯光开关请谨慎操作</view>
</view>
<view class="nmm-btns">
<view @click="isChangeNum = false">取消</view>
<view @click="confirmChange">确认</view>
</view>
</view>
</view>
<view class="ox-dark-mask" v-if="isNotLeave">
<view class="nop-modifies-modal">
<image class="nmm-close" @click="isNotLeave = false" src="/static/images/icon/x_close.png"></image>
<view class="nmm-tit nmm-btm">未离场订单</view>
<view class="nmm-line" v-if="orderNum.person_number>0">
<view>次卡未离场{{orderNum.person_number || 0}}</view>
<view @click="checkBtn(0)">查看</view>
</view>
<view class="nmm-line" v-if="orderNum.person_timing>0">
<view>计时未离场{{orderNum.person_timing || 0}}</view>
<view @click="checkBtn(1)">查看</view>
</view>
<view class="nmm-line">
<view>年月卡未离场{{orderNum.monthly_card||0}}</view>
<view @click="checkBtn(0)">查看</view>
</view>
</view>
</view>
</view>
</template>
<script>
import { API } from '../../../js/api'
import { servers } from '../../../js/server'
import { mapState } from 'vuex';
import util from '../../../utils/util';
let timer = null;
export default {
computed: {
...mapState([ 'brandInfo' ]),
},
data(){
return {
isChangeNum: false,
stadiumList: [],
curStadium: {
name: ''
},
peopleInfo: {},
dateStr: '-',
changeNum: '',
isNotLeave: false,
orderNum: {}, //
}
},
onLoad(options){
this.initStore();
this.dateStr = util.formatDate({ partition: 'zh' }) || '-';
},
onUnload(){
this.clearTime();
},
methods: {
confirmChange: util.debounce(function(){
let { changeNum } = this;
if(isNaN(changeNum))return util.showNone('请输入正确人数!');
this.isChangeNum = false;
this.setStadiumPresentNumber(changeNum);
}, 200, true),
setStadiumPresentNumber(num){
let { curStadium } = this;
util.showLoad();
servers.get({
url: API.writeOff.setStadiumPresentNumber,
data: {
brand_id: curStadium.brand_id,
stadium_id: curStadium.id,
number: +num,
},
isDefaultGet: false,
})
.then(res=>{
util.hideLoad();
if(res.data.code == 0){
util.showNone(res.data.message || '操作成功!');
setTimeout(_=>{
this.getUserNum({
stadium_id: curStadium.id,
brand_id: curStadium.brand_id
})
this.initInertval();
}, 1200)
}else{
util.showNone(res.data.message || '操作失败!');
}
})
.catch(util.hideLoad)
},
initInertval(){
this.clearTime();
let { curStadium } = this;
if(!curStadium.id || !curStadium.brand_id)return;
timer = setInterval(_=>{
if(!curStadium.id || !curStadium.brand_id)return this.clearTime();
this.getUserNum({
stadium_id: curStadium.id,
brand_id: curStadium.brand_id
})
}, 3000);
},
clearTime(){
clearInterval(timer);
timer = null;
},
stadiumChange(e){
let { stadiumList } = this;
let _curStadium = stadiumList[e.detail.value] || {};
if(!_curStadium.id || !_curStadium.brand_id)return;
this.curStadium = _curStadium;
this.getUserNum({
stadium_id: _curStadium.id,
brand_id: _curStadium.brand_id
})
this.initInertval();
},
async initStore(){
let { brandInfo } = this;
try{
util.showLoad();
let _storeList = await this.getStoreList({ brand_id: brandInfo.brand.id || '' });
if(!_storeList || !_storeList.length)return util.showNone('没有店铺信息');
this.stadiumList = _storeList || [];
let _curStadium = _storeList[0] || {};
this.curStadium = _curStadium;
this.initInertval();
this.getUserNum({
stadium_id: _curStadium.id,
brand_id: _curStadium.brand_id
})
util.hideLoad();
}catch(err){
util.hideLoad();
util.showNone('初始化店铺数据失败!');
console.warn('加载数据失败!', err);
}
},
//
getStoreList({
page=1,
page_size=9999,
brand_id='',
}){
return servers.get({
url: API.stadiumList,
data: {
page,
page_size,
brand_id,
},
failMsg: '获取列表失败!'
})
.then(res=>{
let _list = res.list || [];
return _list
})
},
getUserNum({
stadium_id,
brand_id,
}){
servers.get({
url: API.writeOff.timingNumber,
data: { stadium_id, brand_id },
failMsg: '加载现场人数失败!'
})
.then(res=>{
this.peopleInfo = res
})
},
// -
checkNotLeave(){
let { curStadium } = this;
util.showLoad();
servers.get({
url: API.writeOff.notLeavingNums,
data: {
brand_id: curStadium.brand_id,
stadium_id: curStadium.id,
},
// isDefaultGet: false,
failMsg: '请求失败!'
})
.then(res=>{
util.hideLoad();
this.orderNum = res
this.$nextTick(_=>{
this.isNotLeave = true
})
})
},
checkBtn(type){
if(type == 0)return util.routeTo(`/pages/write_off/search_result/search_result`, 'nT');
if(type == 1)return util.routeTo(`/pages/order_list/order_list?order_type=1`, 'nT');
},
switchChange(){
let { peopleInfo, curStadium } = this
this.$nextTick(_=>{
util.showModal({
title: '提示',
content: peopleInfo.present_person_number_clear==false?'是否确认开启凌晨自动清零?':peopleInfo.present_person_number_clear==true?'是否确认关闭凌晨自动清零?':'',
showCancel: true,
success: modalRes=>{
if(modalRes.confirm){
util.showLoad();
servers.get({
url: API.writeOff.timingOpen, ///
data: {
brand_id: curStadium.brand_id,
stadium_id: curStadium.id,
status: peopleInfo.present_person_number_clear==false?1:peopleInfo.present_person_number_clear==true?0:'',
},
failMsg: '请求失败!'
})
.then(res=>{
util.hideLoad();
util.showNone('操作成功!');
})
}
}
})
})
},
}
}
</script>
<style lang="scss">
@import '~style/public.scss';
page{
background-color: #fff;
}
.number-of-people{
.nop-store-name{
height: 144upx;
@include centerFlex(center);
.nsn-frame{
padding: 0 20upx;
width: 702upx;
height: 92upx;
border-radius: 10upx;
background-color: #F2F2F7;
@include centerFlex(space-between);
>input{
flex-grow: 1;
line-height: 40upx;
font-size: 28upx;
color: #1A1A1A;
}
>image{
flex-shrink: 0;
margin-left: 20upx;
width: 28upx;
height: 28upx;
}
}
}
.nop-main{
padding: 8upx 0upx 0;
.nm-date{
margin: 0 24rpx 86rpx;
line-height: 44upx;
font-size: 32upx;
color: #1a1a1a;
}
.nm-tit{
margin: 0 30rpx 16rpx;
text-align: center;
font-size: 32upx;
font-weight: 500;
}
.nm-num{
position: relative;
margin: 0 auto;
display: block;
width: 400upx;
height: 400upx;
.nn-txt-num{
line-height: 400upx;
text-align: center;
font-size: 96upx;
font-weight: 500;
color: $themeColor;
}
>image {
position: absolute;
left: 50%;
top: 50%;
z-index: -1;
margin-left: -250upx;
margin-top: -250upx;
display: block;
width: 500upx;
height: 500upx;
animation: Rotate 6s linear infinite
}
@keyframes Rotate{
0% {transform: rotate(360deg);}
50% {transform: rotate(180deg);}
100% {transform: rotate(0deg);}
}
}
.nm-txt{
margin: 10rpx auto 42rpx;
color: #9C9C9F;
font-size: 28rpx;
text-align: center;
line-height: 40rpx;
text-decoration: underline;
}
.nm-btn{
margin: 0 auto;
width: 618upx;
line-height: 112upx;
height: 112upx;
text-align: center;
border-radius: 10upx;
font-size: 38upx;
color: #fff;
background-color: $themeColor;
}
.nm-line{
margin: 46rpx 0 0;
padding: 34rpx 28rpx 20rpx 34rpx;
border-top: 2rpx solid #F2F2F7;
@include centerFlex(space-between);
.nl-txt{
color: #1A1A1A;
font-size: 32rpx;
line-height: 44rpx;
}
.nl-switch{
flex-shrink: 0;
flex-grow: 0;
}
}
.nm-tip{
margin: 0 32rpx 30rpx 34rpx;
font-size: 28upx;
line-height: 52upx;
color: #9C9C9F;
}
}
.nop-modifies-modal{
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
padding-top: 78upx;
width: 620upx;
height: 706upx;
background-color: #fff;
border-radius: 10upx;
.nmm-close{
position: absolute;
right: 30upx;
top: 30upx;
width: 34upx;
height: 34upx;
}
.nmm-tit{
line-height: 44upx;
text-align: center;
font-weight: 500;
font-size: 32upx;
color: #1A1A1A;
}
.nmm-info{
padding: 54upx 80upx 80upx;
.ni-num{
margin-bottom: 30upx;
font-size: 28upx;
line-height: 48upx;
color: #1A1A1A;
@include textHide(1);
}
.ni-ipt{
margin-bottom: 26upx;
padding: 0 20upx;
height: 88upx;
border-radius: 10upx;
border: 2upx solid #D8D8D8;
>input{
flex-grow: 1;
height: 100%;
font-size: 28upx;
color: #1A1A1A;
}
}
.ni-tip{
font-size: 24upx;
line-height: 34upx;
color: #EA5061;
}
}
.nmm-btns{
@include centerFlex(center);
>view{
margin: 0 10upx;
width: 240upx;
height: 88upx;
line-height: 84upx;
text-align: center;
font-size: 32upx;
border-radius: 10upx;
border: 2upx solid $themeColor;
color: $themeColor;
&+view{
color: #fff;
background-color: $themeColor;
}
}
}
.nmm-btm{
margin-bottom: 8rpx;
}
.nmm-line{
margin: 78rpx 70rpx 0 74rpx;
@include centerFlex(space-between);
>view{
&:first-child{
color: #1A1A1A;
font-size: 28rpx;
line-height: 48rpx;
}
&:nth-child(2){
width: 156rpx;
height: 68rpx;
border: 2rpx solid #009874;
border-radius: 10rpx;
color: #009874;
font-size: 32rpx;
line-height: 64rpx;
text-align: center;
}
}
}
}
}
</style>

364
src/pages/write_off/operate/operate.vue

@ -1,364 +0,0 @@
<template>
<view class="operate-container">
<view class="store-bar">
<text>当前门店</text>
<picker mode="selector" :range="stadiumList" range-key="name" @change="stadiumChange">
<view>
<input disabled v-model="curStadium.name" />
<image mode="aspectFit" src="/static/images/icon/arrow_c33.png"></image>
</view>
</picker>
</view>
<view class="c-scan-btn" @click="scanCodeBtn">
<image mode="aspectFit" src="/static/images/icon/scan_code_btn.png"></image>
</view>
<view class="c-verification-code">
<view><input placeholder="输入订单验证码" v-model="iptCode" /></view>
<view @click="confirmBtn">确认核销</view>
</view>
</view>
</template>
<script>
import util from '../../../utils/util';
import { API } from '../../../js/api';
import { servers } from '../../../js/server';
import { WRITE_OFF_STORE_NAME, WRITE_OFF_ORDER_INFO, WRITE_OFF_MALL_ORDER_INFO } from '../../../js/once_name';
import { mapState } from 'vuex';
export default {
data(){
return {
iptCode: '',
stadiumList: [],
curStadium: {},
writeOffType: '', // site()/ mall()/ dypoi()
}
},
computed: {
...mapState([ 'brandInfo' ]),
},
onLoad(options){
this.writeOffType = options.type || '';
util.$_once(WRITE_OFF_STORE_NAME, data => { //
if(!data)return this.initStore();
this.curStadium = data.curStadium;
this.stadiumList = data.stadiumList;
})
},
methods: {
async initStore(){
let { brandInfo } = this;
try{
util.showLoad();
let _storeList = await this.getStoreList({ brand_id: brandInfo.brand.id || '' });
if(!_storeList || !_storeList.length)return util.showNone('没有店铺信息');
this.stadiumList = _storeList || [];
if(_storeList.length) this.curStadium = _storeList[0];
util.hideLoad();
}catch(err){
util.hideLoad();
util.showNone('初始化店铺数据失败!');
}
},
//
getStoreList({
page=1,
page_size=99999,
brand_id='',
}){
return servers.get({
url: API.stadiumList,
data: {
page,
page_size,
brand_id,
},
failMsg: '获取列表失败!'
})
.then(res=>{
let _list = res.list || [];
return _list
})
},
scanCodeBtn: util.debounce(function(){
uni.scanCode({
onlyFromCamera: true,
scanType: 'qrCode',
success: res=> {
if(util.changeLowerCase(res.scanType) !== 'qr_code')return util.showNone('不支持此类型!');
this.analysisOrder({ decrypt_text: res.result });
},
fail: function(err) {
util.showNone('扫码失败!');
console.warn('扫码失败--->', err);
}
})
}, 300, true),
stadiumChange(e){
let { stadiumList } = this;
this.curStadium = stadiumList[e.detail.value];
},
confirmBtn: util.debounce(function(){
let { iptCode } = this;
if(!iptCode)return util.showNone('请输入核销码!');
this.analysisOrder({ verify_code: this.iptCode });
}, 300, true),
//
analysisOrder({ verify_code = '', decrypt_text = '' }){
let { curStadium, writeOffType } = this;
if(!verify_code&&!decrypt_text)return;
let _query = {
brand_id: curStadium.brand_id,
stadium_id: curStadium.id,
}
let _vType = '';
if(!!verify_code){
_vType = 'verify_code';
writeOffType == 'site'&&(_query['verify_code'] = verify_code);
writeOffType == 'mall'&&(_query['vcode'] = verify_code);
}
if(!!decrypt_text){
_vType = 'decrypt_text';
writeOffType == 'site'&&(_query['decrypt_text'] = decrypt_text);
writeOffType == 'mall'&&(_query['vcode'] = decrypt_text);
}
if(writeOffType == 'site')return this.siteGet({ query: _query, vType: _vType, });
if(writeOffType == 'mall')return this.mallGet({ query: _query, vType: _vType, });
if(writeOffType == 'dypoi'){
let _code = verify_code;
if(decrypt_text){
try{
_code = JSON.parse(decrypt_text)?.code;
}catch(err){console.warn(err)}
}
return this.dypoiGet({
..._query,
code: _code,
});
}
},
//
dypoiGet(query){
util.showLoad();
servers.get({
url: API.writeOff.dyPoiEnterVerifyOrder,
data: query,
isDefaultGet: false
})
.then(res=>{
util.hideLoad();
let { code, data, message } = res?.data || {};
if(code!==0)return util.showModal({
title: '提示',
content: message || '查询失败!',
confirmText: '好的'
})
if(data?.order?.order_no)return util.showModal({
title: data?.order?.product_cache?.name || '提示',
content: '核销数量:1',
showCancel: true,
confirmText: '确认核销',
cancelText: '取消',
success: res=>{
if(res.confirm){
this.dypoiConfirm({ ...query });
}
}
})
console.log('订单查询---->', res);
})
.catch(util.hideLoad)
},
dypoiConfirm({
stadium_id = '',
brand_id = '',
code = '',
}){
util.showLoad();
servers.post({
url: API.writeOff.dyPoiAssistantVerify,
data: {
stadium_id,
brand_id,
code,
},
isDefaultGet: false
})
.then(res=>{
util.hideLoad();
let { code, data, message } = res?.data || {};
if(code!==0)return util.showModal({
title: '提示',
content: message || '核销失败!',
confirmText: '好的'
})
util.showModal({
title: '提示',
content: message || '核销成功!',
confirmText: '关闭'
})
})
.catch(util.hideLoad)
},
//
mallGet({ query = {}, vType = '', }){
util.showLoad();
servers.get({
url: API.writeOff.shop2WriteoffGet,
data: query,
isDefaultGet: false
})
.then(res=>{
util.hideLoad();
if(res.data.code == 0){
let _data = res.data.data || {};
if(_data.has_order){
util.$_emit(WRITE_OFF_MALL_ORDER_INFO, {..._data.order || {}});
util.routeTo(`/pages/write_off/mall/confirm/confirm?type=${vType}`, 'nT');
}else{
util.routeTo(`/pages/write_off/null/null?type=${vType}`, 'nT');
}
}else{
util.showNone(res.data.message || '操作失败!')
// util.routeTo(`/pages/write_off/null/null?type=${vType}`, 'nT');
}
})
.catch(util.hideLoad)
},
// / /
// @vType verify_code()/ decrypt_text()
siteGet({ query = {}, vType = '', }){
util.showLoad();
servers.get({
url: API.writeOff.enterVerifyOrder,
data: query,
isDefaultGet: false
})
.then(res=>{
util.hideLoad();
if(res.data.code == 0){
let _data = res.data.data || {}
//
if(_data.extension&&_data.extension.verify_order_type === 'monthly_card'){
util.$_emit(WRITE_OFF_ORDER_INFO, { data: _data, query });
util.routeTo(`/pages/write_off/ym_confirm/ym_confirm?type=${vType}`, 'nT');
return
}
//
if(_data.extension&&_data.extension.verify_order_type === 'match_order'){
util.$_emit(WRITE_OFF_ORDER_INFO, {..._data});
util.routeTo(`/pages/write_off/events_order/events_order?type=${vType}`, 'nT');
return
}
util.$_emit(WRITE_OFF_ORDER_INFO, {..._data});
util.routeTo(`/pages/write_off/confirm_order/confirm_order?type=${vType}`, 'nT');
}else{
util.routeTo(`/pages/write_off/null/null?type=${vType}`, 'nT');
}
console.log('订单查询---->', res);
})
.catch(util.hideLoad)
}
}
}
</script>
<style lang="scss">
@import '~style/public.scss';
page{
background-color: #f2f2f7;
}
.operate-container{
.store-bar{
margin-bottom: 24upx;
padding: 0 24upx;
height: 144upx;
background-color: #fff;
@include centerFlex(space-between);
>text{
margin-right: 20upx;
flex-shrink: 0;
font-size: 28upx;
color: #9C9C9F;
}
>picker{
flex-grow: 1;
}
view{
padding: 0 20upx;
height: 92upx;
border-radius: 10upx;
background: #f2f2f2;
@include centerFlex(space-between);
>input{
flex-grow: 1;
height: 100%;
font-size: 28upx;
color: #1A1A1A;
}
>image{
flex-shrink: 0;
flex-grow: 0;
width: 28upx;
height: 28upx;
}
}
}
.c-scan-btn{
margin: 0 auto 24upx;
width: 702upx;
height: 360upx;
border-radius: 10upx;
background-color: #fff;
@include centerFlex(center);
>image{
width: 172upx;
height: 172upx;
}
}
.c-verification-code{
padding: 40upx;
border-radius: 10upx;
background-color: #fff;
>view{
&:first-child{
margin-bottom: 30upx;
padding: 0 20upx;
height: 112upx;
border-radius: 10upx;
background-color: #f2f2f7;
>input{
height: 100%;
width: 100%;
font-size: 32upx;
color: #1a1a1a;
}
}
&+view{
height: 112upx;
text-align: center;
line-height: 112upx;
border-radius: 10upx;
font-size: 32upx;
color: #fff;
background-color: $themeColor;
}
}
}
}
</style>

339
src/pages/write_off/search_result/search_result.vue

@ -1,339 +0,0 @@
<template>
<view class="search-result">
<view class="store-bar">
<text>当前门店</text>
<picker mode="selector" :range="stadiumList" range-key="name" @change="stadiumChange">
<view>
<input disabled v-model="curStadium.name" />
<image mode="aspectFit" src="/static/images/icon/arrow_c33.png"></image>
</view>
</picker>
</view>
<view class="r-timer-select">
<picker mode="date" @change="dateChange">
<view>
<text>核销日期{{curDate || '-'}}</text>
<image mode="aspectFit" src="/static/images/icon/arrow_c33.png"></image>
</view>
</picker>
<view>核销数量{{writeOffList.length || 0}}</view>
</view>
<view class="r-order-list">
<view class="l-item" v-for="(e, i) in writeOffList" :key="i">
<view class="i-name">{{ e.extension.stadium_name || '-' }}</view>
<view class="i-lines">
<view>
<view>订单编号{{ e.order_no || '-' }}</view>
<view>{{ e.type || '-' }}</view>
</view>
<view>
<view>用户信息{{ e.extension.user_phone || '-' }}{{ e.extension.nickname || '-' }}</view>
</view>
<view>
<view>核销码&#12288;{{e.verify_code || '-' }}</view>
</view>
<view>
<view>验证方式{{ e.desc || '-' }}</view>
</view>
<view>
<view>核销时间{{ e.verify_time || '-'}}</view>
</view>
<view>
<view>离场时间{{ e.verify_leave_time || ''}}</view>
</view>
</view>
<view class="i-btn" v-if="e.verify_leave_time==''" @click="leaveBtn(e)">手动离场</view>
</view>
</view>
<view class="r-bottom-btn"><view @click="toOperate">核销订单</view></view>
</view>
</template>
<script>
import util from '../../../utils/util';
import { API } from '../../../js/api';
import { servers } from '../../../js/server';
import { mapState } from 'vuex';
import { WRITE_OFF_STORE_NAME } from '../../../js/once_name';
export default {
computed: {
...mapState([ 'brandInfo' ]),
},
data(){
return {
stadiumList: [], //
curStadium: {}, //
writeOffList: [], // ,
curDate: util.formatDate({}),
page: 1,
totalNum: 0,
}
},
// 20210716
// onReachBottom(){
// let { page, curDate, curStadium } = this;
// this.getList({
// brand_id: curStadium.brand_id || '',
// stadium_id: curStadium.id || '',
// date: curDate || '',
// page: ++page,
// });
// },
onLoad(){
this.initPage();
},
onShow(){
let { curStadium } = this;
if(curStadium&&curStadium.id)this.refreshList();
},
methods: {
refreshList(){
let { curDate, curStadium } = this;
this.page = 1;
this.writeOffList = [];
this.getList({
brand_id: curStadium.brand_id || '',
stadium_id: curStadium.id || '',
date: curDate || '',
});
},
dateChange(e){
this.curDate = e.detail.value;
this.$nextTick(this.refreshList);
},
stadiumChange(e){
let { stadiumList } = this;
this.curStadium = stadiumList[e.detail.value];
this.$nextTick(this.refreshList);
},
async initPage(){
let { brandInfo } = this;
try{
let _storeList = await this.getStoreList({ brand_id: brandInfo.brand.id || '' });
this.stadiumList = _storeList || [];
if(_storeList.length) this.curStadium = _storeList[0];
this.$nextTick(this.refreshList);
}catch(err){
console.warn('加载数据失败!', err);
}
},
toOperate(){
let { stadiumList, curStadium } = this;
util.$_emit(WRITE_OFF_STORE_NAME, {
stadiumList,
curStadium,
})
util.routeTo(`/pages/write_off/operate/operate?type=site`, 'nT');
},
getList({ brand_id, stadium_id = '', date = '', page = 1, page_size = '' }){
util.showLoad();
servers.get({
url: API.writeOff.listVerifyRecord,
data: { brand_id, stadium_id, date, page, page_size },
failMsg: '加载失败!',
})
.then(res=>{
util.hideLoad();
this.totalNum = res.total || 0;
let _list = res.list || [];
if(page == 1)return this.writeOffList = _list;
if(!_list.length)return util.showNone('没有更多!');
this.page = page;
this.writeOffList = [...this.writeOffList, ..._list];
})
},
getStoreList({
page=1,
page_size=9999,
brand_id='',
}){
return servers.get({
url: API.stadiumList,
data: {
page,
page_size,
brand_id,
},
failMsg: '获取列表失败!'
})
.then(res=>{
let _list = res.list || [];
return _list
})
},
leaveBtn(item){
let { curStadium } = this;
util.showModal({
title: '提示',
content: '是否确认手动离场?',
showCancel: true,
success: modalRes=>{
if(modalRes.confirm){
util.showLoad();
servers.get({
url: API.writeOff.leaveVerifyOrder,
data: {
brand_id: curStadium.brand_id,
id: item.id,
},
failMsg: '请求失败!'
})
.then(res=>{
util.hideLoad();
util.showNone('操作成功!');
this.refreshList()
})
}
}
})
},
}
}
</script>
<style lang="scss">
@import "~style/public.scss";
page{
background-color: #f2f2f7;
}
.search-result{
padding-bottom: 132upx;
padding-bottom: calc( 132upx + constant(safe-area-inset-bottom)); /* 兼容 iOS < 11.2 */
padding-bottom: calc( 132upx + env(safe-area-inset-bottom)); /* 兼容 iOS >= 11.2 */
.store-bar{
padding: 0 24upx;
height: 144upx;
background-color: #fff;
@include centerFlex(space-between);
>text{
margin-right: 20upx;
flex-shrink: 0;
font-size: 28upx;
color: #9C9C9F;
}
>picker{
flex-grow: 1;
}
view{
padding: 0 20upx;
height: 92upx;
border-radius: 10upx;
background: #f2f2f2;
@include centerFlex(space-between);
>input{
flex-grow: 1;
height: 100%;
font-size: 28upx;
color: #1A1A1A;
}
>image{
flex-shrink: 0;
flex-grow: 0;
width: 28upx;
height: 28upx;
}
}
}
.r-timer-select{
padding: 0 24upx;
margin-bottom: 10upx;
@include centerFlex(space-between);
picker{
flex-shrink: 0;
view{
padding: 24upx 0;
>text{
font-weight: 500;
font-size: 32upx;
}
>image{
margin-left: 16upx;
vertical-align: middle;
width: 22upx;
height: 22upx;
}
}
}
>view{
max-width: 40%;
text-align: right;
font-weight: 500;
font-size: 32upx;
@include textHide(1);
}
}
.r-order-list{
padding: 0 24upx;
.l-item{
position: relative;
margin-bottom: 24upx;
padding: 0 20upx;
border-radius: 10upx;
background-color: #fff;
.i-name{
height: 100upx;
line-height: 98upx;
border-bottom: 2upx solid #D8D8D8;
font-weight: 500;
font-size: 28upx;
color: #1a1a1a;
}
.i-lines{
padding-top: 8upx;
padding-bottom: 32upx;
>view{
display: flex;
>view{
min-width: 0;
line-height: 52upx;
font-size: 28upx;
color: #9c9c9f;
@include textHide(1);
&+view{
flex-shrink: 0;
color: $themeColor;
}
}
}
}
.i-btn{
position: absolute;
right: 20rpx;
bottom: 32rpx;
background-color: #009874;
border-radius: 10rpx;
width: 156rpx;
height: 68rpx;
color: #FFFFFF;
font-size: 28rpx;
text-align: center;
line-height: 68rpx;
}
}
}
.r-bottom-btn{
position: fixed;
left: 0;
bottom: 0;
width: 100%;
padding: 10upx 24upx;
padding-bottom: calc( 10upx + constant(safe-area-inset-bottom)); /* 兼容 iOS < 11.2 */
padding-bottom: calc( 10upx + env(safe-area-inset-bottom)); /* 兼容 iOS >= 11.2 */
background-color: #f2f2f7;
>view{
height: 112upx;
line-height: 112upx;
text-align: center;
font-size: 32upx;
border-radius: 10upx;
color: #fff;
background-color: $themeColor;
}
}
}
</style>

BIN
src/static/images/code_null.png

Before

Width: 380  |  Height: 380  |  Size: 7.4 KiB

BIN
src/static/images/countdown_bg.png

Before

Width: 700  |  Height: 700  |  Size: 33 KiB

BIN
src/static/images/order_null.png

Before

Width: 380  |  Height: 380  |  Size: 8.5 KiB

BIN
src/static/images/scan_null.png

Before

Width: 420  |  Height: 420  |  Size: 11 KiB

BIN
src/static/images/write_off/mall.png

Before

Width: 128  |  Height: 128  |  Size: 1.4 KiB

BIN
src/static/images/write_off/order.png

Before

Width: 128  |  Height: 128  |  Size: 1.0 KiB

BIN
src/static/images/write_off/people.png

Before

Width: 128  |  Height: 128  |  Size: 1.8 KiB

BIN
src/static/images/write_off/site.png

Before

Width: 120  |  Height: 120  |  Size: 1.4 KiB

4
src/subpackage/blacklist/pages/abnormal_list/abnormal_list.vue

@ -102,10 +102,10 @@ export default {
async onLoad(options){ async onLoad(options){
try{ try{
let _date = this.curDate = util.formatDate({}); let _date = this.curDate = util.formatDate({});
let _stadiumLs = await this.getStoreList({});
let _stadiumLs = await this.getStoreList({ brand_id: options?.brand_id ?? '' });
let { curTimeTab } = this; let { curTimeTab } = this;
this.getRecords({ this.getRecords({
brand_id: options.brand_id,
brand_id: options?.brand_id ?? '',
[ curTimeTab?.label || '-' ]: _date [ curTimeTab?.label || '-' ]: _date
}); });
}catch(err){ }catch(err){

59
src/subpackage/verification/components/head_bar.vue

@ -0,0 +1,59 @@
<template>
<view class="head-bar">
<picker class="hb-picker" :range="range" :range-key="rangeKey" @change="$emit('change', $event)">
<view class="hp-frame">
<input class="hf-ipt" type="text" disabled :value="value" :placeholder="placeholder">
<image class="hf-icon" mode="aspectFit" src="/subpackage/verification/static/images/arrow_c9f.png"></image>
</view>
</picker>
<image v-if="search" class="hb-icon" mode="aspectFit" src="/subpackage/verification/static/images/search.png" @click="$emit('click:search')"></image>
</view>
</template>
<script>
export default {
props: {
value: { type: String, default: '' },
placeholder: { type: String, default: '' },
range: { type: Array, default: [] },
rangeKey: { type: String, default: '' },
search: { type: Boolean, default: false }
}
}
</script>
<style lang="scss">
.head-bar{
padding-left: 24upx;
padding-right: 24upx;
height: 144upx;
background: #fff;
@include ctf(space-between);
.hb-picker{
flex-grow: 1;
.hp-frame{
padding: 0 24upx;
height: 92upx;
background: #f2f2f7;
@include ctf(space-between);
.hf-ipt{
flex-grow: 1;
height: 100%;
@include flcw(28upx, 40upx, #333);
}
.hf-icon{
flex-shrink: 0;
width: 28upx;
height: 28upx;
}
}
}
.hb-icon{
flex-shrink: 0;
margin-right: 16upx;
margin-left: 26upx;
width: 40upx;
height: 40upx;
}
}
</style>

78
src/subpackage/verification/components/record/dy_item.vue

@ -0,0 +1,78 @@
<template>
<view class="site-item">
<!-- <view class="si-stadium">{{ stadiumName || '-' }}</view> -->
<view class="si-lines">
<view class="sl-item">
<view class="sl-left">订单编号{{ orderNum || '-' }}</view>
</view>
<view class="sl-item">
<view class="sl-left">用户信息{{ userPhone || '-' }}</view>
</view>
<view class="sl-item">
<view class="sl-left">券码 {{ verifyCode || '-' }}</view>
</view>
<view class="sl-item">
<view class="sl-left">验证方式{{ verifyMethod || '-' }}</view>
</view>
<view class="sl-item">
<view class="sl-left">核销时间{{ verifyTime || '-' }}</view>
</view>
</view>
</view>
</template>
<script>
export default {
props: [
// 'stadiumName',
'orderNum',
'userPhone',
'verifyCode',
'verifyMethod',
'verifyTime',
]
}
</script>
<style lang="scss">
.site-item{
position: relative;
padding: 0 20upx;
border-radius: 10upx;
background: #fff;
.si-stadium{
min-height: 100upx;
border-bottom: 2upx solid #D8D8D8;
@include flcw(28upx, 98upx, #1A1A1A, 500);
@include tHide;
}
.si-lines{
padding-top: 8upx;
padding-bottom: 32upx;
.sl-item{
display: flex;
.sl-left{
@include flcw(28upx, 52upx, #9c9c9f);
@include tHide;
}
.sl-right{
max-width: 200upx;
flex-shrink: 0;
margin-left: 10upx;
@include flcw(28upx, 52upx, $mColor);
@include tHide;
}
}
}
.si-btn{
position: absolute;
right: 20upx;
bottom: 32upx;
width: 192upx;
text-align: center;
background-color: $mColor;
border-radius: 10upx;
@include flcw(32upx, 80upx, #fff, 500);
}
}
</style>

95
src/subpackage/verification/components/record/mall_item.vue

@ -0,0 +1,95 @@
<template>
<view class="site-item">
<view class="si-order-num">
<view class="son-txt">订单编号{{ orderNum || '-' }}</view>
<view class="son-copy" @click="copyBtn">复制</view>
</view>
<view class="si-lines">
<view class="sl-item">
<view class="sl-left">取货码{{ orderCode || '-' }}</view>
</view>
<view class="sl-item">
<view class="sl-left">取货人{{ userName || '-' }} {{ userPhone || '-' }}</view>
</view>
<view class="sl-item">
<view class="sl-left">商品{{ goodsStr || '-' }}</view>
</view>
<view class="sl-item">
<view class="sl-left">核验人{{ optUser || '-' }}</view>
</view>
<view class="sl-item">
<view class="sl-left">取货时间{{ createdAt || '-' }}</view>
</view>
</view>
</view>
</template>
<script>
export default {
props: [
'orderNum',
'orderCode',
'userPhone',
'userName',
'goodsStr',
'optUser',
'createdAt',
],
methods: {
copyBtn(){
uni.setClipboardData({ data: this.orderNum });
}
}
}
</script>
<style lang="scss">
.site-item{
position: relative;
padding: 0 20upx;
border-radius: 10upx;
background: #fff;
.si-order-num{
min-height: 100upx;
border-bottom: 2upx solid #D8D8D8;
@include ctf;
.son-txt{
flex-grow: 1;
@include flcw(28upx, 98upx, #1A1A1A, 500);
@include tHide;
}
.son-copy{
padding-right: 20upx;
margin-left: 20upx;
flex-shrink: 0;
@include flcw(28upx, 98upx, $mColor, 500);
}
}
.si-lines{
padding-top: 8upx;
padding-bottom: 32upx;
.sl-item{
display: flex;
.sl-left{
@include flcw(28upx, 52upx, #9c9c9f);
@include tHide;
}
.sl-right{
max-width: 200upx;
flex-shrink: 0;
margin-left: 10upx;
@include flcw(28upx, 52upx, $mColor);
@include tHide;
}
}
}
.si-btn{
position: absolute;
right: 20upx;
bottom: 32upx;
width: 192upx;
text-align: center;
background-color: $mColor;
border-radius: 10upx;
@include flcw(32upx, 80upx, #fff, 500);
}
}
</style>

87
src/subpackage/verification/components/record/site_item.vue

@ -0,0 +1,87 @@
<template>
<view class="site-item">
<view class="si-stadium">{{ stadiumName || '-' }}</view>
<view class="si-lines">
<view class="sl-item">
<view class="sl-left">订单编号{{ orderNum || '-' }}</view>
<view class="sl-right">{{ orderType || '-' }}</view>
</view>
<view class="sl-item">
<view class="sl-left">用户信息{{ userPhone || '-' }}({{ userNickname || '-' }})</view>
</view>
<view class="sl-item">
<view class="sl-left">核销码 {{ verifyCode || '-' }}</view>
</view>
<view class="sl-item">
<view class="sl-left">验证方式{{ verifyMethod || '-' }}</view>
</view>
<view class="sl-item">
<view class="sl-left">核销时间{{ verifyTime || '-' }}</view>
</view>
<view class="sl-item">
<view class="sl-left">离场时间{{ verifyLeaveTime || '-' }}</view>
</view>
</view>
<view class="si-btn" v-if="verifyLeaveTime === ''" @click="$emit('click:leave')">手动离场</view>
</view>
</template>
<script>
export default {
props: [
'stadiumName',
'orderNum',
'orderType',
'userPhone',
'userNickname',
'verifyCode',
'verifyMethod',
'verifyTime',
'verifyLeaveTime',
]
}
</script>
<style lang="scss">
.site-item{
position: relative;
padding: 0 20upx;
border-radius: 10upx;
background: #fff;
.si-stadium{
min-height: 100upx;
border-bottom: 2upx solid #D8D8D8;
@include flcw(28upx, 98upx, #1A1A1A, 500);
@include tHide;
}
.si-lines{
padding-top: 8upx;
padding-bottom: 32upx;
.sl-item{
display: flex;
.sl-left{
@include flcw(28upx, 52upx, #9c9c9f);
@include tHide;
}
.sl-right{
max-width: 200upx;
flex-shrink: 0;
margin-left: 10upx;
@include flcw(28upx, 52upx, $mColor);
@include tHide;
}
}
}
.si-btn{
position: absolute;
right: 20upx;
bottom: 32upx;
width: 192upx;
text-align: center;
background-color: $mColor;
border-radius: 10upx;
@include flcw(32upx, 80upx, #fff, 500);
}
}
</style>

15
src/subpackage/verification/components/stadium_picker.vue

@ -0,0 +1,15 @@
<template>
<view class="stadium-picker">
</view>
</template>
<script>
export default {
}
</script>
<style lang="scss">
</style>

7
src/subpackage/verification/js/api.js

@ -6,6 +6,13 @@ export const SUB_API = {
skNotLeavingNums: `${ORIGIN}/stadium/sk/notLeavingNums`, // 【1001536】散客人数 - 未离场订单数量 skNotLeavingNums: `${ORIGIN}/stadium/sk/notLeavingNums`, // 【1001536】散客人数 - 未离场订单数量
setStadiumPresentNumber: `${ORIGIN}/admin/stadium/setStadiumPresentNumber`, // 商家助手散客人数校正 setStadiumPresentNumber: `${ORIGIN}/admin/stadium/setStadiumPresentNumber`, // 商家助手散客人数校正
timingOpen: `${ORIGIN}/stadium/person/timing/open`, // 【20220208】凌晨自动清零【开/关】 timingOpen: `${ORIGIN}/stadium/person/timing/open`, // 【20220208】凌晨自动清零【开/关】
// tid1803
enterVerifyOrder: `${ORIGIN}/admin/stadium/order/enterVerifyOrder`, // 商家助手-核销查询-输入验证码
listVerifyRecord: `${ORIGIN}/admin/stadium/order/listVerifyRecord`, // 商家助手-核销查询列表
leaveVerifyOrder:`${ORIGIN}/admin/stadium/order/leaveVerifyOrder`, // 【20220208】核销记录列表 - 手动离场
dyPoiOrderList: `${ORIGIN}/admin/douyinPlatformProductOrder/list`, // 商家助手-dypoi订单
shop2WriteoffList: `${ORIGIN}/admin/assistant/shop2/writeoffList`, // 商城订单核销 - 列表
} }

282
src/subpackage/verification/pages/index.vue

@ -0,0 +1,282 @@
<template>
<view class="write-off-index">
<head-bar
:range="stadiumList" range-key="name" @change="stadiumChange"
placeholder="请选择场馆" :value="curStadium.name"
></head-bar>
<view class="woi-section">
<view class="ws-ipt-box">
<input class="wib-ipt" type="text" placeholder="请输入券码" v-model="iptCode" />
<image @click="scanCode" class="wib-img" mode="aspectFit" src="/subpackage/verification/static/images/scan.png"></image>
</view>
<view class="ws-txt">可输入订场次卡年月卡赛事商城到店领取商品的验证码/券码进行核销或点扫码图标进入扫描界面扫码核销</view>
<view class="ws-btn" @click="confirmBtn">确认</view>
</view>
<view class="woi-btns">
<view class="wb-items" @click="toAbnormal">
<image class="wi-icon" mode="aspectFit" src="/subpackage/verification/static/images/tab0.png"></image>
<view class="wi-txt">进场人数异常</view>
</view>
<view class="wb-items" @click="toSitePeople">
<image class="wi-icon" mode="aspectFit" src="/subpackage/verification/static/images/tab1.png"></image>
<view class="wi-txt">现场人数</view>
</view>
<view class="wb-items" @click="toRecord">
<image class="wi-icon" mode="aspectFit" src="/subpackage/verification/static/images/tab2.png"></image>
<view class="wi-txt">核销记录</view>
</view>
</view>
</view>
</template>
<script>
import API from "../js/api.js";
import server from "../js/server.js";
import { showLoad, hideLoad, showModal, showNone, debounce, changeLowerCase, $_emit, routeTo, jsonStr } from "@/utils/util.js";
import { WRITE_OFF_ORDER_INFO } from '@/js/once_name';
import headBar from "../components/head_bar.vue";
export default {
components: { headBar },
data(){
return{
brand_id: '',
stadiumList: [],
curStadium: {},
iptCode: '',
}
},
/**
* @param {String} options.brand_id 品牌id
* @param {String} options.stadium_id 场馆id
*/
async onLoad(options){
let _brand_id = options?.brand_id || '';
this.brand_id = _brand_id;
let _stadiumLs = await this.getStadiumLs({ brand_id: _brand_id });
if(options?.stadium_id&&_stadiumLs?.length){
//
let _selected = _stadiumLs.find(ele => +ele.id === +(options?.stadium_id ?? ''));
if(_selected?.id)this.curStadium = _selected;
}
},
methods: {
//
toSitePeople(){
let { brand_id, curStadium } = this;
let _qryStr = `brand_id=${brand_id}`
if(curStadium?.id) _qryStr += `&stadium_id=${curStadium.id}`;
routeTo(`/subpackage/verification/pages/site_people/index?${_qryStr}`, 'nT');
},
//
toAbnormal(){
let { brand_id, curStadium } = this;
let _qryStr = `brand_id=${brand_id}`
if(curStadium?.id) _qryStr += `&stadium_id=${curStadium.id}`;
routeTo(`/subpackage/blacklist/pages/abnormal_list/abnormal_list?${_qryStr}`, 'nT');
},
toRecord(){
let { brand_id, curStadium } = this;
let _qryStr = `brand_id=${brand_id}`
if(curStadium?.id) _qryStr += `&stadium_id=${curStadium.id}`;
routeTo(`/subpackage/verification/pages/record?${_qryStr}`, 'nT');
},
confirmBtn: debounce(function(){
let { iptCode } = this;
let { curStadium } = this;
if(!curStadium?.id)return showModal({ content: '请选择场馆!' });
this.verifyOrder({
brand_id: curStadium?.brand_id ?? '',
stadium_id: curStadium?.id ?? '',
verify_code: iptCode ?? '',
})
}, 300, true),
scanCode: debounce(function(){
let { curStadium } = this;
if(!curStadium?.id)return showModal({ content: '请选择场馆!' });
uni.scanCode({
onlyFromCamera: true,
scanType: 'qrCode',
success: res=> {
if(changeLowerCase(res.scanType) !== 'qr_code')return showNone('不支持此类型!');
let { curStadium } = this;
this.verifyOrder({
brand_id: curStadium?.brand_id ?? '',
stadium_id: curStadium?.id ?? '',
decrypt_text: res?.result ?? '',
})
},
fail: function(err) {
showNone('扫码失败!');
console.warn('扫码失败--->', err);
}
})
}, 300, true),
stadiumChange(e){
let { stadiumList } = this;
this.curStadium = stadiumList[e.detail.value];
},
//
getStadiumLs({ brand_id }){
showLoad();
return server.post({
url: API.stadiumList,
data: { page_size: 9999, page: 1, brand_id },
isDefaultGet: false,
})
.then(res => {
hideLoad();
let _data = res?.data || {};
if(_data.code === 0){
let _ls = _data?.data?.list || [];
return this.stadiumList = _ls;
}else{
return Promise.reject(_data);
}
})
.catch(err => {
hideLoad();
showModal({
title: '提示',
content: err.message || '加载店铺失败!'
})
console.warn('verification index getStadiumLs err --->', err);
// return Promise.reject(err);
})
},
/**
* 订单预检验
* @param {String} brand_id
* @param {String} stadium_id
* @param {String} verify_code 订单验证码
* @param {String} decrypt_text 二维码数据
* */
verifyOrder({ brand_id, stadium_id, verify_code = '', decrypt_text = '' }){
let _vType = verify_code ? 'verify_code' : decrypt_text ? 'decrypt_text' : '';
showLoad();
return server.post({
url: API.enterVerifyOrder,
data: { brand_id, stadium_id, verify_code, decrypt_text },
isDefaultGet: false,
})
.then(res => {
hideLoad();
let _data = res?.data || {};
if(_data.code === 0){
let _orderData = _data?.data || {};
//
if(_orderData?.extension?.verify_order_type === 'product_order'){
$_emit(WRITE_OFF_MALL_ORDER_INFO, { data: _orderData });
routeTo(`/pages/write_off/mall/confirm/confirm?type=${_vType}`, 'nT');
return
}
//
if(_orderData?.extension?.verify_order_type === 'monthly_card'){
$_emit(WRITE_OFF_ORDER_INFO, { data: _orderData, query: { brand_id, stadium_id, verify_code, decrypt_text } });
routeTo(`/pages/write_off/ym_confirm/ym_confirm?type=${_vType}`, 'nT');
return
}
//
if(_orderData?.extension?.verify_order_type === 'match_order'){
$_emit(WRITE_OFF_ORDER_INFO, {..._orderData});
routeTo(`/pages/write_off/events_order/events_order?type=${_vType}`, 'nT');
return
}
//
if(['person_number', 'venue_number'].includes(_orderData?.extension?.verify_order_type)){
$_emit(WRITE_OFF_ORDER_INFO, { ..._orderData });
routeTo(`/pages/write_off/confirm_order/confirm_order?type=${_vType}`, 'nT');
return
}
showModal({ content: '暂不支持该类型核销!' })
}else if(_data.code === 805){
routeTo(`/subpackage/verification/pages/null?tip=${jsonStr(_data?.message ?? '')}`, 'nT');
}else{
return Promise.reject(_data);
}
})
.catch(err => {
hideLoad();
showModal({
title: '提示',
content: err.message || '核销查询失败!'
})
console.warn('verification index verifyOrder err --->', err);
// return Promise.reject(err);
})
},
}
}
</script>
<style lang="scss">
.write-off-index{
.woi-section{
margin-top: 24upx;
padding-top: 26upx;
padding-bottom: 80upx;
background: #fff;
.ws-ipt-box{
margin: 0 auto;
padding: 0 20upx;
width: 702upx;
height: 92upx;
background: #F2F2F7;
border-radius: 10upx;
@include ctf;
.wib-ipt{
flex-grow: 1;
height: 100%;
@include flcw(28upx, 40upx, #333);
}
.wib-img{
flex-shrink: 0;
margin-left: 20upx;
width: 60upx;
height: 60upx;
}
}
.ws-txt{
margin-top: 24upx;
padding: 0 32upx;
@include flcw(28upx, 52upx, #333);
}
.ws-btn{
margin: 22upx auto 0;
text-align: center;
width: 240upx;
border-radius: 10upx;
background: $mColor;
@include flcw(32upx, 88upx, #fff);
}
}
.woi-btns{
margin-top: 24upx;
padding: 38upx 24upx;
background: #fff;
@include ctf(space-between);
.wb-items{
padding: 18upx 0;
flex-grow: 0;
flex-shrink: 0;
width: 226upx;
.wi-icon{
display: block;
margin: 0 auto;
width: 64upx;
height: 64upx;
}
.wi-txt{
margin-top: 24upx;
text-align: center;
@include flcw(28upx, 40upx, #333);
@include tHide;
}
}
}
}
</style>

62
src/subpackage/verification/pages/null.vue

@ -0,0 +1,62 @@
<template>
<view class="null-container">
<image v-if="tipHas('二维码')" class="nc-pic" mode="aspectFit" src="/subpackage/verification/static/images/order/null_code.png"></image>
<image v-else-if="tipHas('范围')" class="nc-pic" mode="aspectFit" src="/subpackage/verification/static/images/order/null_range.png"></image>
<image v-else class="nc-pic" mode="aspectFit" src="/subpackage/verification/static/images/order/null_search.png"></image>
<view class="nc-txt">{{ tip || '很抱歉!获取找不到订单信息' }}</view>
<view class="nc-btn" @click="routeTo">返回</view>
</view>
</template>
<script>
import { jsonPar, routeTo } from '@/utils/util';
export default {
data(){
return {
tip: '',
}
},
onLoad(options){
let _tip = options?.tip ?? '';
this.tip = jsonPar(_tip);
},
methods: {
tipHas(txt){
let { tip } = this;
return tip.indexOf(txt) > -1;
},
routeTo,
}
}
</script>
<style lang="scss">
page{
background: #fff;
}
.null-container{
padding-top: 220upx;
.nc-pic{
display: block;
width: 400upx;
height: 400upx;
margin: 0 auto;
}
.nc-txt{
padding: 0 30upx;
margin-top: 80upx;
text-align: center;
@include flcw(28upx, 40upx, #9C9C9F);
}
.nc-btn{
margin: 260upx auto 0;
width: 280upx;
text-align: center;
height: 92upx;
border-radius: 10upx;
border: 2upx solid $mColor;
@include flcw(32upx, 88upx, $mColor);
}
}
</style>

394
src/subpackage/verification/pages/record.vue

@ -0,0 +1,394 @@
<template>
<view class="verification-record">
<view class="vr-header">
<head-bar
:range="stadiumList" range-key="name" @change="stadiumChange"
placeholder="请选择场馆" :value="curStadium.name"
search
@click:search="toSearch"
></head-bar>
<view class="vh-tabs">
<view v-for="(e,i) in tabs" :key="i" :class="{ 'vt-item': true, active: curTab === i }" @click="curTab = i">{{ e }}</view>
</view>
</view>
<view class="vr-time-board">
<view class="vtb-time" @click="showPeriodModal">
<view class="vt-txt">{{ showPeriodStr }}</view>
<image class="vt-icon" mode="aspectFit" src="/subpackage/verification/static/images/calendar.png"></image>
</view>
<view class="vtb-num">核销数量{{ recordLs.length || 0 }}</view>
</view>
<view class="vr-list">
<block v-for="(e, i) in recordLs" :key="i">
<site-item
v-if="curTab === 0"
:stadium-name="e.extension&&e.extension.stadium_name"
:order-num="e.order_no"
:order-type="e.type"
:user-phone="e.extension&&e.extension.user_phone"
:user-nickname="e.extension&&e.extension.nickname"
:verify-code="e.verify_code"
:verify-method="e.desc"
:verify-time="e.verify_time"
:verify-leave-time="e.verify_leave_time"
@click:leave="siteLeaveBtn(e, i)"
></site-item>
<dy-item
v-if="curTab === 1"
:order-num="e.order_no"
:user-phone="e.user_phone"
:verify-code="e.verify_code"
:verify-method="e.verify_method"
:verify-time="e.verify_time"
></dy-item>
<mall-item
v-if="curTab === 2"
:order-num="e.product_order_no"
:order-code="e.product_order_self_pickup_info.gcode"
:user-phone="e.product_order_self_pickup_info.phone"
:user-name="e.product_order_self_pickup_info.name"
:goods-str="e.product_order_goods.join(';')"
:opt-user="e.optuname"
:created-at="e.created_at"
></mall-item>
<view class="vl-space" style="height: 24rpx;"></view>
</block>
</view>
<period-select ref="periodSelect" v-model="periodStr" ></period-select>
</view>
</template>
<script>
import headBar from "../components/head_bar.vue";
import siteItem from "../components/record/site_item.vue";
import dyItem from "../components/record/dy_item.vue";
import mallItem from "../components/record/mall_item.vue";
import periodSelect from "@/components/period_select.vue";
import { formatDate, showLoad, hideLoad, showModal, showNone, debounce, formatTime, routeTo } from "@/utils/util";
import API from "../js/api.js";
import server from "../js/server.js";
export default {
components: { headBar, siteItem, dyItem, mallItem, periodSelect },
computed: {
//
showPeriodStr(){
let { periodStr } = this;
return periodStr ? periodStr.replace(/\_/, ' 至 ').replace(/\-/g, '.') : ''
},
//
periodObj(){
let { periodStr } = this;
if(!periodStr)return {};
let [start, end] = periodStr.split('_');
if(start)start += ' 00:00:00';
if(end)end += ' 23:59:59';
return {
start: start ?? '',
end: end ?? '',
}
},
},
watch: {
periodStr(nVal, oVal){
if(oVal&&nVal&&nVal !== oVal)this.refreshRecordLs();
},
curTab(nVal, oVal){
if(nVal !== oVal)this.reloadRecordLs();
}
},
data(){
return {
brand_id: '',
tabs: [ '场地核销记录', '抖音核销记录', '商城核销记录' ],
curTab: 0,
periodStr: '',/** ex: 2025-01-01_2025-01-02 */
stadiumList: [],
curStadium: {},
recordLs: [],
page: 1,
}
},
/**
* @param {Object} options
* @param {String} options.brand_id // id
* @param {String} options.stadium_id // id
*/
async onLoad(options){
this.brand_id = options?.brand_id ?? '';
let _stadiumLs = await this.getStadiumLs({ brand_id: options?.brand_id ?? '' });
if(options?.stadium_id&&_stadiumLs?.length){
//
let _selected = _stadiumLs.find(ele => +ele.id === +(options?.stadium_id ?? ''));
if(_selected?.id)this.curStadium = _selected;
}
this.reloadRecordLs();
},
onReachBottom(){
let { curStadium, periodObj, page, brand_id } = this;
this.getRecordLs({
brand_id: brand_id ?? '',
stadium_id: curStadium?.id ?? '',
start_time: periodObj?.start ?? '',
end_time: periodObj?.end ?? '',
page: page + 1,
});
},
methods: {
//
toSearch(){
let { brand_id, curTab } = this;
routeTo(`/subpackage/verification/pages/record_search?brand_id=${brand_id}&type=${curTab}`, 'nT');
},
//
siteLeaveBtn: debounce(function(e, idx){
console.log(e, idx);
showModal({
content: '是否确认手动离场?',
showCancel: true,
success: async mRes=>{
if(mRes.confirm){
let _status = await this.leaveVerifyOrder({ brand_id: e?.brand_id ?? '', id: e?.id ?? '' });
if(_status)this.recordLs[idx].verify_leave_time = formatTime(new Date());
this.$forceUpdate();
}
}
})
}, 300, true),
//
initPeriodStr(){
let _today = new Date();
let _todayTimestamp = _today.getTime();
let _eStr = formatDate({ date: _today });
let _first30DaysTimestamp = _todayTimestamp - 30 * 24 * 60 * 60 * 1000;
let _sStr = formatDate({ date: new Date(_first30DaysTimestamp) });
return this.periodStr = `${_sStr}_${_eStr}`;
},
showPeriodModal(){
this.$refs?.periodSelect?.show?.();
},
//
stadiumChange(e){
let { stadiumList } = this;
let _curStadium = stadiumList?.[e?.detail?.value ?? 0] ?? {};
this.curStadium = _curStadium;
this.refreshRecordLs();
},
// /
reloadRecordLs(){
let { brand_id } = this;
this.page = 1;
this.recordLs = [];
this.initPeriodStr();
let { periodObj, curStadium } = this;
this.getRecordLs({
brand_id: brand_id ?? '' ,
stadium_id: curStadium.id ?? '',
start_time: periodObj.start,
end_time: periodObj.end,
});
},
// /
refreshRecordLs(){
let { curStadium, periodObj, brand_id } = this;
this.page = 1;
this.recordLs = [];
this.getRecordLs({
brand_id: brand_id ?? '',
stadium_id: curStadium?.id ?? '',
start_time: periodObj?.start ?? '',
end_time: periodObj?.end ?? '',
});
},
//
getStadiumLs({ brand_id }){
showLoad();
return server.post({
url: API.stadiumList,
data: { page_size: 9999, page: 1, brand_id },
isDefaultGet: false,
})
.then(res => {
hideLoad();
let _data = res?.data || {};
if(_data.code === 0){
let _ls = _data?.data?.list || [];
return this.stadiumList = _ls;
}else{
return Promise.reject(_data);
}
})
.catch(err => {
hideLoad();
showModal({
title: '提示',
content: err.message || '加载门店失败!'
})
console.warn('verification record getStadiumLs err --->', err);
// return Promise.reject(err);
})
},
// -
getRecordLs({ brand_id, stadium_id = '', start_time = '', end_time = '', page = 1, page_size = 20 }){
showLoad();
return server.post({
url: this.getRecordLsAPI(),
data: this.formatQuery({ brand_id, stadium_id, start_time, end_time, page, page_size }),
isDefaultGet: false,
})
.then(res => {
hideLoad();
let _data = res?.data || {};
if(_data.code === 0){
let _ls = this.formatRecordLs(_data?.data?.list || []);
if(page === 1)return this.recordLs = _ls;
if(!_ls.length)return showNone('没有更多!');
this.page = page;
this.recordLs = [ ...this.recordLs, ..._ls ];
return _ls;
}else{
return Promise.reject(_data);
}
})
.catch(err => {
hideLoad();
showModal({
title: '提示',
content: err.message || '加载数据失败!'
})
console.warn('verification record getRecordLs err --->', err);
// return Promise.reject(err);
})
},
// API
getRecordLsAPI(){
let { curTab } = this;
if(curTab === 0)return API.listVerifyRecord
if(curTab === 1)return API.dyPoiOrderList
if(curTab === 2)return API.shop2WriteoffList
},
//
formatQuery(query){
let { curTab } = this;
if(curTab === 1)query['order_status'] = 'used';
if(curTab === 2){
query['stime'] = query?.start_time ?? '';
query['etime'] = query?.end_time ?? '';
delete query.start_time
delete query.end_time
}
return query;
},
//
formatRecordLs(ls){
let { curTab } = this;
//
if(curTab === 1){
return ls.map(item=>{
let _code = item?.order_codes?.find(e=>e?.code_status == 'used');
console.log('_code',item);
return {
order_no: item?.order_no ?? '',
user_phone: item?.mobile ?? '',
verify_code: _code?.code ?? '',
verify_method: _code?.verification_method ?? '',
verify_time: _code?.verification_time ?? '',
};
})
}
return ls;
},
// -
leaveVerifyOrder({ brand_id, id }){
showLoad();
return server.post({
url: API.leaveVerifyOrder,
data: { brand_id, id },
isDefaultGet: false,
})
.then(res => {
hideLoad();
let _data = res?.data || {};
if(_data.code === 0){
showNone(_data?.message || '操作成功!')
return true;
}else{
return Promise.reject(_data);
}
})
.catch(err => {
hideLoad();
showModal({
title: '提示',
content: err.message || '操作失败!'
})
console.warn('verification record leaveVerifyOrder err --->', err);
// return Promise.reject(err);
return false;
})
},
}
}
</script>
<style lang="scss">
.verification-record{
@include isPd(20upx);
}
.vr-header{
background: #fff;
.vh-tabs{
@include ctf(space-around);
.vt-item{
position: relative;
@include flcw(28upx, 88upx, #2D2D2D);
&.active{
color: $mColor;
&::after{
content: '';
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 100%;
height: 4upx;
background: $mColor;
}
}
}
}
}
.vr-time-board{
padding: 24upx;
@include ctf(space-between);
.vtb-time{
flex-shrink: 0;
padding: 0 14upx;
height: 62upx;
background: #fff;
@include ctf;
.vt-txt{
max-width: 400upx;
@include flcw(24upx, 34upx, #1A1A1A, 500);
@include tHide;
}
.vt-icon{
flex-shrink: 0;
margin-left: 30upx;
width: 32upx;
height: 32upx;
}
}
.vtb-num{
margin-left: 20upx;
@include flcw(32upx, 44upx, #1A1A1A, 500);
@include tHide;
}
}
.vr-list{
padding: 0 24upx;
}
</style>

244
src/subpackage/verification/pages/record_search.vue

@ -0,0 +1,244 @@
<template>
<view class="record-search">
<view class="os-bar">
<view>
<image mode="aspectFit" src="/subpackage/verification/static/images/search.png"></image>
<input placeholder="请输入手机号/核销码" v-model="searchTxt" confirm-type="search" @confirm="iptConfirm" />
<image v-if="searchTxt!==''" mode="aspectFit" src="/subpackage/verification/static/images/round_close.png" @click="clearSearch"></image>
</view>
</view>
<view class="rs-ls">
<block v-for="(e, i) in searchLs" :key="i">
<site-item
v-if="orderType === 0"
:stadium-name="e.extension&&e.extension.stadium_name"
:order-num="e.order_no"
:order-type="e.type"
:user-phone="e.extension&&e.extension.user_phone"
:user-nickname="e.extension&&e.extension.nickname"
:verify-code="e.verify_code"
:verify-method="e.desc"
:verify-time="e.verify_time"
:verify-leave-time="e.verify_leave_time"
@click:leave="siteLeaveBtn(e, i)"
></site-item>
<dy-item
v-if="orderType === 1"
:order-num="e.order_no"
:user-phone="e.user_phone"
:verify-code="e.verify_code"
:verify-method="e.verify_method"
:verify-time="e.verify_time"
></dy-item>
<mall-item
v-if="orderType === 2"
:order-num="e.product_order_no"
:order-code="e.product_order_self_pickup_info.gcode"
:user-phone="e.product_order_self_pickup_info.phone"
:user-name="e.product_order_self_pickup_info.name"
:goods-str="e.product_order_goods.join(';')"
:opt-user="e.optuname"
:created-at="e.created_at"
></mall-item>
<view class="vl-space" style="height: 24rpx;"></view>
</block>
</view>
</view>
</template>
<script>
import { formatDate, showLoad, hideLoad, showModal, showNone, debounce, formatTime, routeTo } from "@/utils/util";
import API from "../js/api.js";
import server from "../js/server.js";
import siteItem from "../components/record/site_item.vue";
import dyItem from "../components/record/dy_item.vue";
import mallItem from "../components/record/mall_item.vue";
export default {
components: { siteItem, dyItem, mallItem },
data(){
return {
brand_id: '',
orderType: '',
searchTxt: '',
page: 1,
searchLs: [],
}
},
onLoad(options){
this.brand_id = options?.brand_id ?? '';
this.orderType = +(options?.type ?? '');
},
onReachBottom(){
let { searchTxt, page } = this;
this.getRecordLs({
keyword: searchTxt,
page: ++page
})
},
methods: {
clearSearch(){
this.searchTxt = '';
},
iptConfirm(e){
let { brand_id } = this;
console.log(e);
this.page = 1;
this.searchLs = [];
this.getRecordLs({
brand_id,
keyword: e?.detail?.value || ''
})
},
//
siteLeaveBtn: debounce(function(e, idx){
showModal({
content: '是否确认手动离场?',
showCancel: true,
success: async mRes=>{
if(mRes.confirm){
let _status = await this.leaveVerifyOrder({ brand_id: e?.brand_id ?? '', id: e?.id ?? '' });
if(_status)this.searchLs[idx].verify_leave_time = formatTime(new Date());
this.$forceUpdate();
}
}
})
}, 300, true),
// -
leaveVerifyOrder({ brand_id, id }){
showLoad();
return server.post({
url: API.leaveVerifyOrder,
data: { brand_id, id },
isDefaultGet: false,
})
.then(res => {
hideLoad();
let _data = res?.data || {};
if(_data.code === 0){
showNone(_data?.message || '操作成功!')
return true;
}else{
return Promise.reject(_data);
}
})
.catch(err => {
hideLoad();
showModal({
title: '提示',
content: err.message || '操作失败!'
})
console.warn('verification record_search leaveVerifyOrder err --->', err);
// return Promise.reject(err);
return false;
})
},
// -
getRecordLs({ brand_id, stadium_id = '', start_time = '', end_time = '', page = 1, page_size = 20, keyword = '' }){
showLoad();
return server.post({
url: this.getRecordLsAPI(),
data: this.formatQuery({ brand_id, stadium_id, start_time, end_time, page, page_size, keyword }),
isDefaultGet: false,
})
.then(res => {
hideLoad();
let _data = res?.data || {};
if(_data.code === 0){
let _ls = this.formatRecordLs(_data?.data?.list || []);
if(page === 1)return this.searchLs = _ls;
if(!_ls.length)return showNone('没有更多!');
this.page = page;
this.searchLs = [ ...this.searchLs, ..._ls ];
return _ls;
}else{
return Promise.reject(_data);
}
})
.catch(err => {
hideLoad();
showModal({
title: '提示',
content: err.message || '加载数据失败!'
})
console.warn('verification record_search getRecordLs err --->', err);
// return Promise.reject(err);
})
},
getRecordLsAPI(){
let { orderType } = this;
if(orderType === 0)return API.listVerifyRecord
if(orderType === 1)return API.dyPoiOrderList
if(orderType === 2)return API.shop2WriteoffList
},
formatQuery(query){
let { orderType } = this;
if(orderType === 1)query['order_status'] = 'used';
if(orderType === 2){
query['stime'] = query?.start_time ?? '';
query['etime'] = query?.end_time ?? '';
delete query.start_time
delete query.end_time
}
return query;
},
formatRecordLs(ls){
let { orderType } = this;
//
if(orderType === 1){
return ls.map(item=>{
let _code = item?.order_codes?.find(e=>e?.code_status == 'used');
return {
order_no: item?.order_no ?? '',
user_phone: item?.mobile ?? '',
verify_code: _code?.code ?? '',
verify_method: _code?.verification_method ?? '',
verify_time: _code?.verification_time ?? '',
};
})
}
return ls;
},
}
}
</script>
<style lang="scss">
.record-search{
@include isPd(20upx);
}
.os-bar{
margin-bottom: 24upx;
height: 144upx;
background-color: #fff;
@include ctf(center);
>view{
padding: 0 20upx;
height: 92upx;
width: 702upx;
border-radius: 10upx;
background-color: #f2f2f7;
@include ctf(center);
>image{
margin-right: 20upx;
flex-shrink: 0;
width: 40upx;
height: 40upx;
}
>input{
height: 100%;
flex-grow: 1;
@include flcw(32upx, 44upx, #1a1a1a);
&+image{
flex-shrink: 0;
margin-right: 0;
margin-left: 20upx;
width: 32upx;
height: 32upx;
}
}
}
}
.rs-ls{
padding: 0 24upx;
}
</style>

5
src/subpackage/verification/pages/site_people/index.vue

@ -77,7 +77,10 @@ export default {
} }
}, },
async onLoad(options){ async onLoad(options){
this.$refs.stadiumSelect.initStadium(options?.brand_id || '')
this.$refs.stadiumSelect.initStadium({
brand_id: options?.brand_id ?? '',
stadium_id: options?.stadium_id ?? '',
})
.then(stadiumInfo=>{ .then(stadiumInfo=>{
if(!stadiumInfo?.id) return; if(!stadiumInfo?.id) return;
this.stadiumInfo = stadiumInfo; this.stadiumInfo = stadiumInfo;

9
src/subpackage/verification/pages/site_people/modules/not_leave_modal.vue

@ -27,7 +27,9 @@ export default {
data(){ data(){
return { return {
visible: false, visible: false,
notLeaveInfo: {}
notLeaveInfo: {},
brand_id: '',
stadium_id: '',
} }
}, },
methods: { methods: {
@ -39,6 +41,8 @@ export default {
}, },
initData(e){ initData(e){
let { igsType, key, stadium_id, brand_id } = e; let { igsType, key, stadium_id, brand_id } = e;
this.brand_id = brand_id ?? '';
this.stadium_id = stadium_id ?? '';
this.show(); this.show();
let _keyName = igsType === 1 ? 'gate_id' : igsType === 2 ? 'venue_type_key' : ''; let _keyName = igsType === 1 ? 'gate_id' : igsType === 2 ? 'venue_type_key' : '';
let _query = { brand_id, stadium_id }; let _query = { brand_id, stadium_id };
@ -69,7 +73,8 @@ export default {
}) })
}, },
checkBtn(type){ checkBtn(type){
if(type == 0)return routeTo(`/pages/write_off/search_result/search_result`, 'nT');
let { brand_id, stadium_id } = this;
if(type == 0)return routeTo(`/subpackage/verification/pages/record?brand_id=${brand_id?? ''}&stadium_id=${stadium_id??''}`, 'nT');
if(type == 1)return routeTo(`/pages/order_list/order_list?order_type=1`, 'nT'); if(type == 1)return routeTo(`/pages/order_list/order_list?order_type=1`, 'nT');
}, },
} }

15
src/subpackage/verification/pages/site_people/modules/stadium_select.vue

@ -27,7 +27,7 @@ export default {
this.curStadium = stadiumLs?.[value] || {}; this.curStadium = stadiumLs?.[value] || {};
this.$emit('change:stadium', this.curStadium); this.$emit('change:stadium', this.curStadium);
}, },
async initStadium(brand_id){
async initStadium({ brand_id, stadium_id }){
try{ try{
showLoad(); showLoad();
let _ls = await this.getStadiumLs({ brand_id }); let _ls = await this.getStadiumLs({ brand_id });
@ -36,10 +36,19 @@ export default {
// }) // })
this.stadiumLs = _ls || []; this.stadiumLs = _ls || [];
hideLoad(); hideLoad();
if(_ls.length){
if(stadium_id&&_ls?.length){
let _cur = _ls.find(e=>Number(e.id) === Number(stadium_id));
if(_cur){
this.curStadium = _cur;
return _cur;
} else {
this.curStadium = _ls[0];
return _ls[0];
}
} else if (_ls.length){
this.curStadium = _ls[0]; this.curStadium = _ls[0];
return _ls[0]; return _ls[0];
}else{
} else {
showNone('暂无店铺信息!'); showNone('暂无店铺信息!');
} }
}catch(err){ }catch(err){

BIN
src/subpackage/verification/static/images/arrow_c9f.png

After

Width: 28  |  Height: 28  |  Size: 271 B

BIN
src/subpackage/verification/static/images/calendar.png

After

Width: 16  |  Height: 16  |  Size: 369 B

BIN
src/subpackage/verification/static/images/order/null_code.png

After

Width: 200  |  Height: 148  |  Size: 7.6 KiB

BIN
src/subpackage/verification/static/images/order/null_range.png

After

Width: 185  |  Height: 185  |  Size: 3.6 KiB

BIN
src/subpackage/verification/static/images/order/null_search.png

After

Width: 185  |  Height: 185  |  Size: 4.4 KiB

BIN
src/subpackage/verification/static/images/round_close.png

After

Width: 32  |  Height: 32  |  Size: 369 B

BIN
src/subpackage/verification/static/images/scan.png

After

Width: 60  |  Height: 60  |  Size: 429 B

BIN
src/subpackage/verification/static/images/search.png

After

Width: 20  |  Height: 20  |  Size: 245 B

BIN
src/subpackage/verification/static/images/tab0.png

After

Width: 64  |  Height: 64  |  Size: 1001 B

BIN
src/subpackage/verification/static/images/tab1.png

After

Width: 64  |  Height: 64  |  Size: 940 B

BIN
src/subpackage/verification/static/images/tab2.png

After

Width: 64  |  Height: 64  |  Size: 519 B

3
src/subpackage/wallet/js/api.js

@ -8,6 +8,9 @@ export const WALLET_API = {
// 宝付 // 宝付
getPayAssureConfigs:`${ORIGIN}/admin/pay/assure/getPayAssureConfigs`, // 查看可选择的支付账户列表 getPayAssureConfigs:`${ORIGIN}/admin/pay/assure/getPayAssureConfigs`, // 查看可选择的支付账户列表
baofuV2Gateway:`${ORIGIN}/admin/pay/assure/baofuV2/gateway`, // 宝付v2获取金额信息 baofuV2Gateway:`${ORIGIN}/admin/pay/assure/baofuV2/gateway`, // 宝付v2获取金额信息
// tid1819
wxpayinfo:`${ORIGIN}/admin/assistant/merchantwallet/wxpayinfo`, // 这个是充值
rechargeList:`${ORIGIN}/admin/merchantwallet/recharge/list`, // 这是充值记录
} }
export default WALLET_API; export default WALLET_API;

15
src/subpackage/wallet/pages/douyin_withdraw/index.vue

@ -26,7 +26,7 @@
<script> <script>
import { WALLET_API } from '../../js/api'; import { WALLET_API } from '../../js/api';
import servers from '../../js/server'; import servers from '../../js/server';
import { routeTo, showLoad, hideLoad } from '@/utils/util';
import { routeTo, showLoad, hideLoad, showModal } from '@/utils/util';
import platformItem from "./modules/platform_item.vue"; import platformItem from "./modules/platform_item.vue";
export default { export default {
@ -35,6 +35,7 @@ export default {
}, },
data(){ data(){
return { return {
balance: '',
brand_id: '', brand_id: '',
balanceInfo: { balanceInfo: {
/** /**
@ -46,7 +47,9 @@ export default {
} }
}, },
onLoad(options){ onLoad(options){
this.brand_id = options.brand_id || '';
this.brand_id = options?.brand_id || '';
this.balance = options?.balance ?? '';
}, },
onShow(){ onShow(){
this.getDouyinWalletBalance(this.brand_id); this.getDouyinWalletBalance(this.brand_id);
@ -59,6 +62,14 @@ export default {
// //
// md241024 241113 01 // md241024 241113 01
applyBtn(source){ applyBtn(source){
let { balance } = this;
if(!isNaN(balance) && Number(balance) < 0)return showModal({
content: '系统检测到您在欧轩有未支付的账单,请先完成支付后再提现。',
confirmText: '前往',
success: res=>{
if(res.confirm)routeTo();
}
})
routeTo(`/subpackage/wallet/pages/douyin_withdraw/apply?brand_id=${this.brand_id}&source=${source}`, 'nT'); routeTo(`/subpackage/wallet/pages/douyin_withdraw/apply?brand_id=${this.brand_id}&source=${source}`, 'nT');
}, },
/** /**

77
src/subpackage/wallet/pages/index/index.vue

@ -5,6 +5,8 @@
@click:douyin="dyBtnClick" @click:douyin="dyBtnClick"
@click:baofu="bfBtnClick" @click:baofu="bfBtnClick"
@click:admin="toWebView" @click:admin="toWebView"
@click:recharge="rechargeBtn"
@click:record="toRechargeRecord"
></wallet-info> ></wallet-info>
<view class="wi-tips"> <view class="wi-tips">
<view class="wt-tit">温馨提示</view> <view class="wt-tit">温馨提示</view>
@ -17,20 +19,27 @@
</text> </text>
</view> </view>
</view> </view>
<wallet-modal v-if="false"></wallet-modal>
<wallet-modal-success ref="walletModalSuccess" :title="'充值成功'" @click:button="toRechargeRecord">
<template v-slot:tip>充值成功</template>
<template v-slot:btn>充值记录</template>
</wallet-modal-success>
<recharge-modal :balance="balance" ref="rechargeModal"></recharge-modal>
</view> </view>
</template> </template>
<script> <script>
import walletInfo from './modules/wallet_info.vue' import walletInfo from './modules/wallet_info.vue'
import walletModalSuccess from '../../components/wallet_modal_success.vue'
import walletModalSuccess from '../../components/wallet_modal_success.vue';
import rechargeModal from "./modules/recharge_modal.vue";
import { WALLET_API } from '../../js/api'; import { WALLET_API } from '../../js/api';
import servers from '../../js/server'; import servers from '../../js/server';
import { routeTo, showLoad, hideLoad } from '@/utils/util';
import { routeTo, showLoad, hideLoad, debounce, showModal } from '@/utils/util';
export default { export default {
components: { components: {
'wallet-info': walletInfo, 'wallet-info': walletInfo,
'wallet-modal': walletModalSuccess,
walletModalSuccess,
rechargeModal
}, },
data(){ data(){
return { return {
@ -44,7 +53,32 @@ export default {
this.getWalletBalance(options.brand_id); this.getWalletBalance(options.brand_id);
console.log(uni.getAccountInfoSync().miniProgram) console.log(uni.getAccountInfoSync().miniProgram)
}, },
onReady(){
// this.$refs?.walletModalSuccess?.alert();
},
methods: { methods: {
toRechargeRecord(){
let { brand_id } = this;
routeTo(`/subpackage/wallet/pages/index/recharge_record?brand_id=${brand_id ?? ''}`, 'nT');
},
rechargeBtn: debounce(function(){
let { brand_id } = this;
this.$refs?.rechargeModal?.show?.({
success: async num =>{
let { wxpay_info } = await this.getPayInfo({ brand_id, pay_amount: num });
uni.requestPayment({
...wxpay_info,
success: res => {
this.$refs?.walletModalSuccess?.alert?.();
},
fail: err => {
console.log('wallet index rechargeBtn fail --->', err);
if(err?.errMsg?.indexOf?.('cancel') === -1)showModal({ content: err?.errMsg ?? '支付失败!' })
}
})
}
})
}, 300, true),
toWebView(){ toWebView(){
routeTo(`/pages/web_view/web_view?src=${encodeURIComponent(this.getAdminAddress())}`,'nT'); routeTo(`/pages/web_view/web_view?src=${encodeURIComponent(this.getAdminAddress())}`,'nT');
}, },
@ -77,12 +111,41 @@ export default {
}) })
}, },
dyBtnClick(){ dyBtnClick(){
routeTo(`/subpackage/wallet/pages/douyin_withdraw/index?brand_id=${this.brand_id ?? ''}`, 'nT');
let { brand_id, balance } = this;
let _qryStr = `brand_id=${brand_id ?? ''}&balance=${balance ?? 0}`;
routeTo(`/subpackage/wallet/pages/douyin_withdraw/index?${_qryStr}`, 'nT');
}, },
bfBtnClick(){ bfBtnClick(){
routeTo(`/subpackage/wallet/pages/baofu_withdraw/index?brand_id=${this.brand_id ?? ''}`, 'nT'); routeTo(`/subpackage/wallet/pages/baofu_withdraw/index?brand_id=${this.brand_id ?? ''}`, 'nT');
}
},
//
getPayInfo({ brand_id, pay_amount }){
showLoad();
return servers.post({
url: WALLET_API.wxpayinfo,
data: { brand_id, pay_amount },
isDefaultGet: false,
})
.then(res => {
hideLoad();
let _data = res?.data || {};
if(_data.code === 0){
return _data?.data ?? {};
}else{
return Promise.reject(_data);
}
})
.catch(err => {
hideLoad();
showModal({
title: '提示',
content: err.message || '加载支付信息失败!'
})
console.warn('wallet index getPayInfo err --->', err);
// return Promise.reject(err);
})
},
} }
} }
</script> </script>

82
src/subpackage/wallet/pages/index/modules/recharge_modal.vue

@ -0,0 +1,82 @@
<template>
<wallet-modal title="充值" :show="isShow" @click:close="hide">
<view class="recharge-container">
<view class="rc-balance">
<text class="rb-txt">钱包余额</text>
{{ balance || 0 }}
</view>
<input type="digit" class="rc-ipt" v-model="iptNum" placeholder="请输入金额">
<view class="rc-btns">
<wm-button @click="hide">取消</wm-button>
<wm-button green @click="confirmBtn">确认</wm-button>
</view>
</view>
</wallet-modal>
</template>
<script>
import walletModal from '../../../components/wallet_modal.vue';
import wmButton from '../../../components/wm_button.vue';
import { showNone } from '@/utils/util';
export default {
props: {
balance: {
type: Number,
default: 0
}
},
components: {
walletModal,
wmButton,
},
data() {
return {
isShow: false,
iptNum: '',
initData: {},
}
},
methods: {
show(data){
this.isShow = true;
this.initData = data ?? {};
},
hide(){
this.isShow = false;
},
confirmBtn(){
let { initData, iptNum, hide } = this;
if(!iptNum || isNaN(iptNum) || Number(iptNum) <= 0)return showNone('请输入正确金额!');
initData?.success?.(iptNum);
hide();
}
}
}
</script>
<style lang="scss">
.recharge-container{
padding: 0 50upx;
.rc-balance{
margin-top: 60upx;
@include flcw(28upx, 40upx, $mColor);
@include tHide;
.rb-txt{
color: #1A1A1A;
}
}
.rc-ipt{
margin-top: 20upx;
padding: 0 20upx;
display: block;
height: 108upx;
border-radius: 10upx;
background: #F2F2F7;
@include flcw(32upx, 44upx, #1A1A1A);
}
.rc-btns{
margin-top: 80upx;
@include ctf(space-between);
}
}
</style>

6
src/subpackage/wallet/pages/index/modules/wallet_info.vue

@ -7,10 +7,10 @@
<view class="wi-account"> <view class="wi-account">
<veiw class="wa-top"> <veiw class="wa-top">
<view class="wt-name">欧轩内部钱包账户余额</view> <view class="wt-name">欧轩内部钱包账户余额</view>
<!-- <view class="wt-record">
<view class="wt-record" @click="$emit('click:record')">
<text>充值记录</text> <text>充值记录</text>
<image class="wr-icon" mode="aspect" src="/subpackage/wallet/static/images/arrow_b2.png"></image> <image class="wr-icon" mode="aspect" src="/subpackage/wallet/static/images/arrow_b2.png"></image>
</view> -->
</view>
</veiw> </veiw>
<view class="wa-tip">(用于购买服务使用)</view> <view class="wa-tip">(用于购买服务使用)</view>
<view class="wa-balance"> <view class="wa-balance">
@ -18,7 +18,7 @@
<text class="wm-unit">¥</text> <text class="wm-unit">¥</text>
{{ balance }} {{ balance }}
</view> </view>
<!-- <view class="wb-btn">充值</view> -->
<view class="wb-btn" @click="$emit('click:recharge')">充值</view>
</view> </view>
</view> </view>
<view class="wi-btns"> <view class="wi-btns">

137
src/subpackage/wallet/pages/index/recharge_record.vue

@ -0,0 +1,137 @@
<template>
<view class="recharge-record">
<filtrate-bar
:filter-list="['全部', '已完成', '已退款']"
ref="filtrateBar"
@change:times="timesChange"
@change:filter="filterBtn"
></filtrate-bar>
<view class="rr-ls">
<view class="rl-item" v-for="(e, i) in rechargeList" :key="i">
<record-line name="充值金额" :tag="getTagTxt(e.pay_status)" >{{ e.amount || 0 }}</record-line>
<record-line name="充值单号">{{ e.order_no || '-' }}</record-line>
<record-line name="充值时间">{{ e.pay_time || '-' }}</record-line>
<record-line name="支付方式">{{ e.pay_type || '-' }}</record-line>
<record-line name="交易流水号">{{ e.trans_no || '-' }}</record-line>
<record-line name="充值途径">
{{ e.optsourse || '-' }} <block v-if="e.optname"> {{ e.optname }} </block>
</record-line>
</view>
</view>
</view>
</template>
<script>
import filtrateBar from '../../components/filtrate_bar.vue';
import recordLine from '../../components/record_line.vue';
import { WALLET_API } from '../../js/api';
import servers from '../../js/server';
import { routeTo, showLoad, hideLoad, debounce, showModal, showNone } from '@/utils/util';
export default {
components: {
filtrateBar,
recordLine,
},
data(){
return {
rechargeList: [],
page: 1,
brand_id: '',
stime: '',
etime: '',
status: '' // 0:, 1:, 2:退
}
},
onLoad(opts){
let _bid = opts?.brand_id ?? '';
this.brand_id = _bid;
let { startDate, endDate } = this.$refs.filtrateBar.getTimes();
this.stime = startDate;
this.etime = endDate;
this.getRechargeList({ brand_id: _bid, stime: startDate, etime: endDate });
},
onReachBottom(){
let { brand_id, page, stime, etime } = this;
this.getRechargeList({ brand_id, page: ++page, stime, etime });
},
methods: {
getTagTxt(status = ''){
return status === 0 ? '未支付' :
status === 1 ? '已完成' :
status === 2 ? '已退款' : '';
},
timesChange(e){
let { startDate, endDate } = e;
this.stime = startDate ?? '';
this.etime = endDate ?? '';
this.refreshLs();
},
filterBtn(idx) {
let _status = idx === 0 ? '' : idx;
this.status = _status;
this.refreshLs();
},
refreshLs(){
let { brand_id, stime, etime, status } = this;
this.page = 1;
this.rechargeList = [];
this.getRechargeList({
brand_id: brand_id,
pay_status: status,
stime,
etime,
});
},
//
getRechargeList({ brand_id, pay_status = '', stime = '', etime = '', page_size = 20, page = 1 }){
showLoad();
return servers.post({
url: WALLET_API.rechargeList,
data: { brand_id, pay_status, stime, etime, page_size, page },
isDefaultGet: false,
})
.then(res => {
hideLoad();
let _data = res?.data || {};
if(_data.code === 0){
let _ls = _data?.data?.list || [];
if(page === 1)return this.rechargeList = _ls;
if(_ls?.length <= 0)return showNone('没有更多!');
this.rechargeList = [ ...this.rechargeList, ..._ls ];
this.page = page;
}else{
return Promise.reject(_data);
}
})
.catch(err => {
hideLoad();
showModal({
title: '提示',
content: err.message || '加载失败!'
})
console.warn('wallet index getPayInfo err --->', err);
// return Promise.reject(err);
})
},
}
}
</script>
<style lang="scss">
.recharge-record{
}
.rr-ls{
padding: 24upx;
.rl-item{
padding: 26upx 20upx;
border-radius: 10upx;
background: #fff;
&+ .rl-item{
margin-top: 24upx;
}
}
}
</style>

6
src/utils/util.js

@ -366,7 +366,7 @@ function isProfile(){
return !!uni.getUserProfile return !!uni.getUserProfile
} }
function changeLowerCase(str){
export function changeLowerCase(str){
return str.toString().toLocaleLowerCase(); return str.toString().toLocaleLowerCase();
} }
@ -375,7 +375,7 @@ function changeLowerCase(str){
// 大数据量跨页/跨组件传参------$_once && $_emit // 大数据量跨页/跨组件传参------$_once && $_emit
// 单次监听器 // 单次监听器
// 到文件src\js\once_name.js,进行命名,防止命名冲突导致错误监听 // 到文件src\js\once_name.js,进行命名,防止命名冲突导致错误监听
function $_once(name, cb){
export function $_once(name, cb){
uni.$once(name + '',function(data){ uni.$once(name + '',function(data){
cb&&cb(data); cb&&cb(data);
}) })
@ -384,7 +384,7 @@ function $_once(name, cb){
}, 50) }, 50)
} }
// 促发单次监听 // 促发单次监听
function $_emit(name, data){
export function $_emit(name, data){
uni.$once((name + '')+'1',function(){ uni.$once((name + '')+'1',function(){
uni.$emit(name + '', data); uni.$emit(name + '', data);
}) })

Loading…
Cancel
Save