first commit

This commit is contained in:
wtq
2025-11-13 10:16:36 +08:00
commit cbdb6758a0
394 changed files with 57767 additions and 0 deletions

23
.gitignore vendored Normal file
View File

@@ -0,0 +1,23 @@
.DS_Store
node_modules/
unpackage/
dist/
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Editor directories and files
.project
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw*

28
.hbuilderx/launch.json Normal file
View File

@@ -0,0 +1,28 @@
{
// launch.json 配置了启动调试时相关设置configurations下节点名称可为 app-plus/h5/mp-weixin/mp-baidu/mp-alipay/mp-qq/mp-toutiao/mp-360/
// launchtype项可配置值为local或remote, local代表前端连本地云函数remote代表前端连云端云函数
"version" : "0.0",
"configurations" : [
{
"app-plus" : {
"launchtype" : "local"
},
"default" : {
"launchtype" : "local"
},
"mp-weixin" : {
"launchtype" : "local"
},
"type" : "uniCloud"
},
{
"customPlaygroundType" : "local",
"playground" : "custom",
"type" : "uni-app:app-android"
},
{
"playground" : "custom",
"type" : "uni-app:app-ios"
}
]
}

3
.stignore Normal file
View File

@@ -0,0 +1,3 @@
node_modules/
dist/
.git/

359
README.md Normal file
View File

@@ -0,0 +1,359 @@
# 京西菜市门店管理
- 开发:
张树伟
- 日期:
2022年12月05日
- 项目说明:
京西菜市门店管理版本兼容《微信小程序》《Android》《Ios》
- 技术栈Vue3/VueX/Ts/Vite/UniApp
- 【注意】请勿使用pinia
- node版本16.18.0
## 项目仓库名字
- jx-Applets-Android-Ios
## 微信小程序
- 分支名字:微信小程序
- https://e.coding.net/rosydev/jx-Applets-Android-Ios/zsw-jx-store.git
## 苹果安卓App
- 分支名字:苹果和微信
- https://e.coding.net/rosydev/jx-Applets-Android-Ios/zsw-jx-store.git
## 主分支master
- 微信小程序和苹果安卓App都是从主分支分出来的主分支受到保护不允许修改分支不允许合并
# 目录解构
- 【注意】由于是小程序与App公用这个书名文件可能有些文件没有
```
├── dist # 编译后的文件
├── nativeplugins # 原生插件
├── node_modules # 依赖文件
├── src # 项目文件
│ │
│ ├── api # api接口管理
│ │ │
│ │ ├── https # 分模块接口管理
│ │ │ ├── login.ts # 登录类接口
│ │ │ ├── merchant.ts # 商家管理类接口
│ │ │ ├── order.ts # 订单管理类接口
│ │ │ └── shopping.ts # 商品管理类接口
│ │ │
│ │ ├── config.ts # 环境配置文件
│ │ ├── index.ts # 接汇总导出文件
│ │ └── request.ts # 接口请求文件
│ │
│ ├── components # 组件
│ │ │
│ │ ├── dialog # 兼容安卓自定义弹窗
│ │ ├── globalAlert # 兼容安卓与IOS全局弹窗
│ │ ├── jx-empty # 空状态占位组件
│ │ ├── jx-icon # icon图标组件
│ │ ├── jx-input # 三段式input输入组件
│ │ ├── jx-ios-android # 安卓与ios渲染判断组件
│ │ ├── jx-loading # 数据加载loading组件
│ │ ├── jx-load-more # 上拉加载更多展示组件
│ │ ├── jx-login-empty # 未登录展示组件
│ │ ├── jx-popup # 兼容ios popup组件
│ │ ├── jx-price # 自动格式化价格组件
│ │ ├── jx-real-income # 京西菜市订单单价组件
│ │ ├── jx-real-income-jxgy # 京西果园订单单价组件
│ │ ├── jx-update # 软件更新组件
│ │ └── jx-upload-img # 七牛云图片上传组件
│ │
│ ├── composables # 公共hooks
│ │ │
│ │ ├── useGlobalFunc.ts # 全局公用 hooks
│ │ └── useOrderInfo.ts # 订单专用 hooks
│ │
│ ├── pages # tabbar页面
│ │ │
│ │ ├── goods-manager # 商品管理页面
│ │ ├── merchant # 商家中心页面
│ │ ├── message # 消息
│ │ └── order-manager # 订单管理页面
│ │
│ ├── static # 静态文件
│ │ │
│ │ ├── agreement # 静态版权文件
│ │ ├── audio # 项目音频文件
│ │ ├── font # 项目图标文件
│ │ ├── image # 项目图片文件
│ │ ├── merchant-icon # 商家中心图标文件
│ │ └── style # 公共样式文件
│ │
│ ├── store # vuex状态管理
│ │ │
│ │ ├── useServeInfoStore # 项目服务类vuex模块
│ │ ├── useStoreInfoStore # 项目门店类vuex模块
│ │ └── index.ts # vuex 入口文件
│ │
│ ├── subPages # 分包页面
│ │ │
│ │ ├── agreement # 静态版权文件
│ │ ├── login # 登录相关类页面
│ │ ├── merchantChild # 商家中心类子页面
│ │ │ │
│ │ │ ├── activity # 活动信息页面
│ │ │ ├── backstageApp # 后台运行能力页面
│ │ │ ├── bill # 我的账单页面
│ │ │ ├── billDetaile # 账单详情页面
│ │ │ ├── businessLicense # 营业资质页面
│ │ │ ├── enterGroupChat # 进入群聊页面
│ │ │ ├── evaluateM # 评价管理页面
│ │ │ ├── helpCenter # 帮助中心页面
│ │ │ ├── message # 消息列表页面
│ │ │ ├── messageDetail # 消息详情页面
│ │ │ ├── modifyPrice # 调价包页面
│ │ │ ├── orderRealTime # 京西菜市营业数据页面
│ │ │ ├── orderRealTimeJxgy # 京西果园营业数据页面
│ │ │ ├── platformM # 已开通店铺店铺页面
│ │ │ ├── printerSetUp # 蓝牙打印机设置页面
│ │ │ ├── setUp # 设置页面
│ │ │ ├── storeScore # 门店评分页面
│ │ │ ├── storeScoreDetaile # 评分详情页面
│ │ │ ├── useInfo # 个人信息页面
│ │ │ ├── waitGoods # 待配商品页面
│ │ │ ├── accountBalance # 配送余额
│ │ │ └── waitGoodsDetaile # 商品详情页面
│ │ │
│ │ ├── messageChild # 消息子页面
│ │ │ │
│ │ │ └── msgChat # 聊天界面
│ │ │
│ │ ├── orderChild # 订单类子页面
│ │ │ │
│ │ │ ├── afterSalesOrderDetail # 售后订单页面
│ │ │ ├── createAfterSales # 异常订单页面
│ │ │ ├── deliverManager # 配送管理页面
│ │ │ ├── getPhone # 联系平台页面
│ │ │ └── orderDetail # 订单详情页面
│ │ │
│ │ ├── shoppingChild # 商品管理类子页面
│ │ │ │
│ │ │ └── createGoods # 创建商品
│ │ │
│ │ └── switchStore # 切换门店
│ │
│ ├── utils # 工具
│ │ │
│ │ ├── bluetoothPrinter # 蓝牙打印机类工具
│ │ ├── android_ios.ts # 安卓插件类工具
│ │ ├── configCms.ts # 项目系统配置文件
│ │ ├── location.ts # 本地存储工具
│ │ ├── toast.ts # 公共请提示工具
│ │ └── tools.ts # 混合类处理工具
│ │
│ ├── androidPrivacy.json # 安卓打包文件
│ ├── App.ts # 根组件逻辑
│ ├── App.vue # 根组件页面
│ ├── apple-app-site-association # ios 关联域
│ ├── env.d.ts # type 授权文件
│ ├── main.ts # 入口文件
│ ├── manifest.json # 打包配置文件
│ ├── pages.json # 页面路径配置
│ └── uni.scss # 公共样式
├── package-lock.json # ***
├── package.json # 包管理文件
├── README.md # README
├── tsconfig.node.json # ts配置文件
└── vite.config.ts # vite 配置
```
# 路径管理
## 验证登录
路径:
/subPages/login/index
### 选择门店
路径:
/subPages/switchStore/switchStore
#### 商家中心
##### 帮助中心
路径:
/subPages/merchantChild/helpCenter/helpCenter
##### 营业数据
###### 京西菜市
路径:
/subPages/merchantChild/orderRealTime/orderRealTime
###### 京西果园
路径:
/subPages/merchantChild/orderRealTimeJxgy/orderRealTimeJxgy
##### 已开通店铺
路径:
/subPages/merchantChild/platformM/platformM
##### 调价包
路径:
/subPages/merchantChild/modifyPrice/modifyPrice
##### 我的账单
路径:
/subPages/merchantChild/bill/bill
##### 账单详情
路径:
/subPages/merchantChild/billDetaile/billDetaile
##### 评价管理
路径:
/subPages/merchantChild/evaluateM/evaluateM
##### 门店评分
路径:
/subPages/merchantChild/storeScore/storeScore
##### 评分详情
路径:
/subPages/merchantChild/storeScoreDetaile/storeScoreDetaile
##### 待配商品
路径:
/subPages/merchantChild/waitGoods/waitGoods
##### 商品详情
路径:
/subPages/merchantChild/waitGoodsDetaile/waitGoodsDetaile
##### 进入群聊
路径:
/subPages/merchantChild/enterGroupChat/enterGroupChat
##### 消息列表
路径:
/subPages/merchantChild/message/message
##### 最新消息
路径:
/subPages/merchantChild/messageDetail/messageDetail
##### 活动信息
路径:
/subPages/merchantChild/activity/activity
##### 设置
路径:
/subPages/merchantChild/setUp/setUp
##### 蓝牙打印机设置
路径:
/subPages/merchantChild/printerSetUp/printerSetUp
##### 营业资质
路径:
/subPages/merchantChild/businessLicense/businessLicense
##### 后台运行优化
路径:
/subPages/merchantChild/backstageApp/backstageApp
##### 个人信息
路径:
/subPages/merchantChild/useInfo/useInfo
##### 配送余额
路径:
/subPages/merchantChild/accountBalance/accountBalance
#### 消息
#### 商品管理
##### 创建商品
路径:
/subPages/shoppingChild/createGoods/createGoods
#### 订单管理
##### 联系平台
路劲:
/subPages/orderChild/getPhone/getPhone
##### 订单详情
路劲:
/subPages/orderChild/orderDetail/orderDetail
##### 配送管理
路劲:
/subPages/orderChild/deliverManager/deliverManager
##### 售后详情
路劲:
/subPages/orderChild/afterSalesOrderDetail/afterSalesOrderDetail
##### 创建售后订单
路劲:
/subPages/orderChild/createAfterSales/createAfterSales

64
dfslkf Normal file
View File

@@ -0,0 +1,64 @@
commit 7901bd96fe23f9d130bbedfe0bc441fab52fc59e (HEAD -> master, origin/master, origin/HEAD)
Author: ZSW <2966211270@qq.com>
Date: Wed Jan 4 18:39:57 2023 +0800
2023-01-04提交
commit f6d6996ffbad8d07f1b129f3f1304c819c53e561
Author: ZSW <2966211270@qq.com>
Date: Tue Jan 3 18:43:00 2023 +0800
!
commit 9b41c0ff3a3c875ef455e2d5e8958568f21face2
Author: ZSW <2966211270@qq.com>
Date: Fri Dec 30 18:32:55 2022 +0800
开发新商家版,手写虚拟列表
commit 9658b3d85f6f872d7b72102a3448b52c29bd456d
Author: ZSW <2966211270@qq.com>
Date: Wed Dec 28 18:34:01 2022 +0800
!
commit 79b2c5bdb5137a457f5f9f690f7ac6b4ac020ca7
Author: ZSW <2966211270@qq.com>
Date: Tue Dec 27 18:34:44 2022 +0800
重写京西菜市商家版
commit 1b8cf88cc744e9f0726645082a26124f6567baa6
Author: ZSW <2966211270@qq.com>
Date: Mon Dec 26 18:38:37 2022 +0800
新京西菜市商家版开发中
commit 7270386733f06f60a35ebd538b49b5dc6a9af967
Author: ZSW <2966211270@qq.com>
Date: Thu Dec 15 11:53:30 2022 +0800
!
commit dd19476dcecbe77d51d14bd4b25254b1f737b535
Author: ZSW <2966211270@qq.com>
Date: Mon Dec 12 18:29:15 2022 +0800
登录界面向店铺切换兼容已经处理
commit 38c0633c4276496845d87e8193fc5f9c121ac051
Author: ZSW <2966211270@qq.com>
Date: Fri Dec 9 18:53:54 2022 +0800
创建新编京西菜市商家版兼容微信小程序安卓Appiso
commit 6095cb13ce5472a9ea46781bf0be4c4c8b107117
Author: 张树伟 <2966211270@qq.com>
Date: Fri Dec 9 18:50:54 2022 +0800
Initial Commit

25
index.html Normal file
View File

@@ -0,0 +1,25 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<script>
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||
CSS.supports('top: constant(a)'))
document.write(
'<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
(coverSupport ? ', viewport-fit=cover' : '') + '" />')
</script>
<title></title>
<!--preload-links-->
<!--app-context-->
</head>
<body>
<div id="app">
<!--app-html-->
</div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,46 @@
{
"name": "DCloud-PushSound",
"id": "DCloud-PushSound",
"version": "1.0.2",
"description": "自定义推送铃声",
"_dp_type": "nativeplugin",
"_dp_nativeplugin": {
"ios": {
"plugins": [
{
"type": "module",
"name": "DCloud-PushSound",
"class": "DCPushSound"
}
],
"deploymentTarget": "9.0",
"integrateType": "library",
"resources": [
"afsOrder.caf",
"cancelOrder.caf",
"newOrder.caf",
"newMsg.caf"
],
"privacies": [
"NSLocationAlwaysUsageDescription",
"NSLocationAlwaysAndWhenInUseUsageDescription",
"NSLocationWhenInUseUsageDescription"
]
},
"android": {
"plugins": [
{
"type": "module",
"name": "DCloud-PushSound",
"class": "io.dcloud.uniplugin.custom_push_channel.CustomNotificationChannel"
}
],
"integrateType": "aar",
"compileOptions": {
"sourceCompatibility": "1.8",
"targetCompatibility": "1.8"
},
"minSdkVersion": "19"
}
}
}

6693
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

71
package.json Normal file
View File

@@ -0,0 +1,71 @@
{
"name": "uni-preset-vue",
"version": "0.0.0",
"scripts": {
"dev:app": "uni -p app",
"dev:app-android": "uni -p app-android",
"dev:app-ios": "uni -p app-ios",
"dev:custom": "uni -p",
"dev:h5": "uni",
"dev:h5:ssr": "uni --ssr",
"dev:mp-alipay": "uni -p mp-alipay",
"dev:mp-baidu": "uni -p mp-baidu",
"dev:mp-kuaishou": "uni -p mp-kuaishou",
"dev:mp-lark": "uni -p mp-lark",
"dev:mp-qq": "uni -p mp-qq",
"dev:mp-toutiao": "uni -p mp-toutiao",
"dev:mp-weixin": "uni -p mp-weixin",
"dev:quickapp-webview": "uni -p quickapp-webview",
"dev:quickapp-webview-huawei": "uni -p quickapp-webview-huawei",
"dev:quickapp-webview-union": "uni -p quickapp-webview-union",
"build:app": "uni build -p app",
"build:app-android": "uni build -p app-android",
"build:app-ios": "uni build -p app-ios",
"build:custom": "uni build -p",
"build:h5": "uni build",
"build:h5:ssr": "uni build --ssr",
"build:mp-alipay": "uni build -p mp-alipay",
"build:mp-baidu": "uni build -p mp-baidu",
"build:mp-kuaishou": "uni build -p mp-kuaishou",
"build:mp-lark": "uni build -p mp-lark",
"build:mp-qq": "uni build -p mp-qq",
"build:mp-toutiao": "uni build -p mp-toutiao",
"build:mp-weixin": "uni build -p mp-weixin",
"build:quickapp-webview": "uni build -p quickapp-webview",
"build:quickapp-webview-huawei": "uni build -p quickapp-webview-huawei",
"build:quickapp-webview-union": "uni build -p quickapp-webview-union"
},
"dependencies": {
"@dcloudio/uni-app": "3.0.0-3061820230117001",
"@dcloudio/uni-app-plus": "3.0.0-3061820230117001",
"@dcloudio/uni-components": "3.0.0-3061820230117001",
"@dcloudio/uni-h5": "3.0.0-3061820230117001",
"@dcloudio/uni-mp-alipay": "3.0.0-3061820230117001",
"@dcloudio/uni-mp-baidu": "3.0.0-3061820230117001",
"@dcloudio/uni-mp-kuaishou": "3.0.0-3061820230117001",
"@dcloudio/uni-mp-lark": "3.0.0-3061820230117001",
"@dcloudio/uni-mp-qq": "3.0.0-3061820230117001",
"@dcloudio/uni-mp-toutiao": "3.0.0-3061820230117001",
"@dcloudio/uni-mp-weixin": "3.0.0-3061820230117001",
"@dcloudio/uni-quickapp-webview": "3.0.0-3061820230117001",
"@dcloudio/uni-ui": "^1.4.23",
"add": "^2.0.6",
"js-md5": "^0.7.3",
"md5": "^2.3.0",
"vue": "3.2.45",
"vuex": "^4.0.2"
},
"devDependencies": {
"@dcloudio/types": "3.2.11",
"@dcloudio/uni-automator": "3.0.0-3061820230117001",
"@dcloudio/uni-cli-shared": "3.0.0-3061820230117001",
"@dcloudio/uni-stacktracey": "3.0.0-3061820230117001",
"@dcloudio/vite-plugin-uni": "3.0.0-3061820230117001",
"@types/js-md5": "^0.4.3",
"@types/node": "^18.11.11",
"crypto-js": "^4.1.1",
"sass": "^1.56.1",
"typescript": "^4.8.4",
"vite": "3.2.4"
}
}

313
src/App.ts Normal file
View File

@@ -0,0 +1,313 @@
/**
* 全局文件配置
*/
import { store } from '@/store'
import { setStorage, getStorage } from "@/utils/storage";
import Bluetooth from '@/utils/bluetoothPrinter/bluetooth'
import useGlobalFunc from './composables/useGlobalFunc';
import { onShow } from '@dcloudio/uni-app';
import useOrderInfo from './composables/useOrderInfo';
import util from '@/utils/bluetoothPrinter/util'
function App() {
const bluetooth = new Bluetooth()
const { setPrinterStatus } = useGlobalFunc()
const { bluetoothPrinter,orderDetail } = useOrderInfo()
/*************************************************
* 页面出现
*/
let reconnectTime1: any = null
onShow(async () => {
if (getStorage('deviceName')) {
reconnectTime1 = setTimeout(async () => {
await bluetooth.reconnect()
clearTimeout(reconnectTime1)
}, 1000)
}
})
/**
* 获取设备信息
*/
async function SystemInfo() {
uni.getSystemInfo({
success(res) {
setStorage('brand', res.brand || 'pc')
// 保存本机系统信息
// 详细字段信息参考 https://uniapp.dcloud.net.cn/api/system/info.html#%E7%B3%BB%E7%BB%9F%E4%BF%A1%E6%81%AF%E7%9A%84%E6%A6%82%E5%BF%B5
store.commit('serveInfo/setSystemInfo', JSON.stringify(res))
},
})
}
/*************************************************
* 监听网络类型
*/
function onNetWorkStatusChange() {
uni.onNetworkStatusChange((res) => {
if (res.isConnected == false) {
uni.createPushMessage({
title: '网络提示',
content: '网络被断开,请检查网络设置'
})
} else {
plus.push.clear()
}
store.commit('serveInfo/setIsNetWorkS', res.isConnected)
})
}
/*************************************************
* 应用保活常驻通知栏
*/
function appKeepAlive() {
let port = uni.getSystemInfoSync()
switch (port.platform) {
case 'android':
const JModule = uni.requireNativePlugin('J-FrontService')
JModule.startFrontService({
title: '京西菜市',
content: '京西菜市正在运行',
})
// 设置oppo通道
if (port.brand == 'oppo' || port.brand == 'oneplus' || port.brand == 'pacm00') {
const plugin = uni.requireNativePlugin("DCloud-PushSound")
plugin.setCustomPushChannel({
soundName: "neworder",
channelId: "10110",
channelDesc: "订单类通知提醒",
enableLights: true,
enableVibration: true,
importance: 4,
lockscreenVisibility: 1
});
plugin.setCustomPushChannel({
soundName: "msg",
channelId: "10111",
channelDesc: "顾客IM信息提示",
enableLights: true,
enableVibration: true,
importance: 4,
lockscreenVisibility: 1
});
}
case 'ios':
console.log('iOS不支持此功能')
break
}
}
/*************************************************
* 监听穿透消息
*/
// const playVoid = uni.createInnerAudioContext()
function vendorName(text:string) {
switch (text) {
case '京东到家':
return 0
case '美团外卖':
return 1
case '饿了么':
return 2
case '饿百新零售':
return 3
case '京东商城':
return 5
case '京西菜市':
return 9
case '微盟':
return 11
case '抖音小时购':
return 14
case '淘鲜达':
return 16
default:
return -1
}
}
let orderList:Array<AnyObject> = [] // 20s之内没有新订单置空
function listenMsg() {
// 获取cid
plus.push.getClientInfoAsync((info) => {
let cid = info["clientid"]
setStorage('cid', cid)
}, () => { })
uni.onPushMessage((res) => {
// 监听通知信息/
// console.log('监听通知信息,门店信息是否一致9999999999',getStorage("storeName"))
if (res.type == 'receive') {
let newData: any = res.data.payload
// console.log(newData.store_title,'监听通知信息,门店信息是否一致',getStorage("storeName"))
// newData = modifyOrderMsg()
// newData.notyTime = 0 // 通知时间
// orderList.push(newData)
if (newData.store_title == getStorage("storeName")) orderList.push(newData)
// console.log(newData.msg_type,'有新的订单 /// 消息 ,,newData,,新消息',newData)
// newData
if (newData.msg_type == 'newOrder') {
// let content = JSON.parse(res.data.content)
// content.business_type = 2 // 模拟预订单
// if(content.business_type && content.business_type === 2 && newData.store_title == getStorage("storeName")){
// let advanceArderList = JSON.parse(getStorage('advanceArder')) || []
// let findIndex = advanceArderList.findIndex((item:string) => item === newData.vendor_order_id)
// if(findIndex === -1){
// advanceArderList.unshift(newData.vendor_order_id)
// if(advanceArderList.length > 10) advanceArderList = advanceArderList.slice(0, 10)
// setStorage('advanceArder', JSON.stringify(advanceArderList))
// }else return // 预订单存在,不执行通知操作
// }
let data: any = getStorage('commitBTDevCharact')
util.notifyBLEState(data.deviceId, data.serviceId, data.uuid).then((res: any) => {
if (res == 12) {
if (newData.store_title != getStorage("storeName")) return
bluetoothPrinter(newData.vendor_order_id)
}
})
}
// 创建通知
if (newData.store_title != getStorage("storeName")) return
if (newData.msg_type == 'newImMsg') {
store.commit('storeInfo/setImMessage', newData.context)
uni.createPushMessage({
title: newData.store_title,
content: '有新的顾客信息,请及时查看',
icon:'./static/image/global/message.png',
payload:{
page: '/pages/message/index', // 目标页面路径
storeID:newData.store_id,
storeName:newData.store_title,
type:'message'
}
})
uni.showTabBarRedDot({index:2})
} else {
store.commit('serveInfo/setUpdateOrder', Date.now())
uni.createPushMessage({
title: newData.store_title,
content: `${newData.context}${newData.vendor_name}#${newData.order_sqs}号订单)`,
icon:'./static/image/global/newOrder.png',
payload:{
page: '/subPages/orderChild/orderDetail/orderDetail', // 目标页面路径
vendorOrderID: '' + newData.vendor_order_id, // 订单id
vendorID:vendorName(newData.vendor_name),
type:'order'
}
})
}
// console.log('当前订单属于哪个门店',newData.store_title)
// console.log('门店信息',getStorage('storeName'))
if(+getStorage('defaultOrderReminder') === 1 || getStorage('defaultOrderReminder') === '' ){
let src = `/static/audio/${newData.msg_type}.mp3`
// playVoid.src = `/static/audio/${newData.msg_type}.mp3`
// playVoid.stop()
// playVoid.play()
// console.log('通知消息,,,',newData)
watchAudio(src) // findIndex
}
}
// 监听通知栏点击
if (res.type == 'click') {
let currentOrder:any = res.data.payload
if(currentOrder.type === 'order') orderDetail(currentOrder.vendorOrderID, currentOrder.vendorID)
else if(currentOrder.storeID) {
setStorage("storeID", currentOrder.storeID)
setStorage('storeName', currentOrder.storeName)
setStorage('storeMessge', 'message')
uni.switchTab({ url: currentOrder.page })
}
}
})
}
/**
* 模拟订单通知消息
*/
// const modifyOrderMsg = () => {
// let arr = ['newOrder','newImMsg','newCancelOrder','newAfsOrder']
// let index = Math.floor(Math.random() * arr.length)
// let obj = {
// "business_type": 1,
// "context": "老板,你有新的订单了!",
// "msg_type": arr[index],
// "order_sqs": "34",
// "store_id": 100296,
// "store_title": "谢卫路店",
// "vendor_name": "美团外卖",
// "vendor_order_id": "3301829894026603225",
// 'notyTime':0
// }
// return obj
// }
/**
* 监听音频播放事件 音频播放结束事件,通知完毕,清除 orderList中的数据 findIndex:number
*/
let isWait = false
const watchAudio = (newData:string) => {
console.log(isWait,'isWait',newData)
if(isWait) return // 阻止多个音频同时播放
if(newData){
const playVoid = uni.createInnerAudioContext()
playVoid.src = newData
playVoid.volume = 1
isWait = true
playVoid.play()
playVoid.onEnded(() => {
isWait = false
orderList.shift() // 头部删除
// console.log('音频播放结束事件,依次播放,判断是否还有订单',orderList)
// `/static/audio/${newData.msg_type}.mp3`
// if(orderList.length>0) watchAudio(orderList[0].msg_type)
if(orderList.length>0) watchAudio(`/static/audio/${orderList[0].msg_type}.mp3`)
})
}
// 20s之后
}
/*************************************************
* 打印机检测
*/
let reconnectTime: any = null
async function onPrinterChange() {
if (getStorage('deviceName')) {
setPrinterStatus()
reconnectTime = setTimeout(async () => {
await bluetooth.reconnect()
clearTimeout(reconnectTime)
}, 1000)
}
}
return {
SystemInfo, // 获取本机系统信息
onNetWorkStatusChange, // 监听网络状态
appKeepAlive, // 安卓应用保活
listenMsg, // 监听消息
onPrinterChange, // 监听打印机状态
}
}
export default App

61
src/App.vue Normal file
View File

@@ -0,0 +1,61 @@
<script setup lang="ts">
import jxMOdal from '@/components/dialog/dialogUtil'
import { onLaunch, onShow } from '@dcloudio/uni-app'
import App from './App'
import globalAlert from '@/components/globalAlert/globalAlert'
import useGlobalFunc from './composables/useGlobalFunc'
// import { isOpenNotice } from './utils/android_ios'
import { getStorage, setStorage } from './utils/storage'
import { store } from "@/store";
const {
appKeepAlive, // 应用保活
listenMsg, // 监听消息
} = App()
const { watchVersion } = useGlobalFunc() // 监听版本
// 三端通用
const {
SystemInfo, //获取本机设备信息
onNetWorkStatusChange, // 监听网络状态
onPrinterChange, // 监听打印机状态
} = App()
// 进入应用
onLaunch(() => {
SystemInfo() // 获取本机设备信息
uni['jxAlert'] = jxMOdal.alert // 全局挂载 jxMOdal
uni['jxConfirm'] = jxMOdal.confirm // 全局挂载 jxMOdal
onNetWorkStatusChange() // 监听网络状态
onPrinterChange() // 监听打印机状态
appKeepAlive() // 应用保活
listenMsg() // 监听消息穿透
uni['globalAlert'] = globalAlert // 挂载全局可覆盖tabar弹窗
plus.device.setWakelock(true) //打开程序后一直保持唤醒状态(常亮)
watchVersion((isUpdate: boolean) => {
// 检查是否更新版本
if (isUpdate) {
uni.globalAlert({
data: {
type: 3,
},
})
}
})
// 初始化平台
if (!getStorage('terrace')) setStorage('terrace', 'jxcs')
store.dispatch('serveInfo/get_services')
})
// 应用进入前台
onShow(() => {
// 清除角标
plus.runtime.setBadgeNumber(0)
})
</script>
<style>
@import './static/font/iconfont.css';
page {
background-color: #efefef;
}
</style>

14
src/androidPrivacy.json Normal file
View File

@@ -0,0 +1,14 @@
{
"version" : "2",
"prompt" : "template",
"title" : "服务协议和隐私政策",
"message" : "  请您务必审慎阅读、充分理解“服务协议”和“隐私政策”各条款,包括但不限于:为了更好的向您提供服务,我们需要收集您的设备标识、操作日志等信息用于分析、优化应用性能。<br/>  您可阅读<a href=\"https://www.jxc4.com/managerApp/service.html\">《服务协议》</a>和<a href=\"https://www.jxc4.com/managerApp/privacy.html\">《隐私政策》</a>了解详细信息。如果您同意,请点击下面按钮开始接受我们的服务。",
"buttonAccept" : "同意并接受",
"buttonRefuse" : "暂不同意",
"second" : {
"title" : "确认提示",
"message" : "  进入应用前,您需先同意<a href=\"https://www.jxc4.com/managerApp/service.html\">《用户协议》</a>和<a href=\"https://www.jxc4.com/managerApp/privacy.html\">《隐私政策》</a>,否则将退出应用。",
"buttonAccept" : "同意并继续",
"buttonRefuse" : "退出应用"
}
}

26
src/api/config.ts Normal file
View File

@@ -0,0 +1,26 @@
import { getStorage } from "@/utils/storage"
/**
* model: 配置文件
* 作者zhang-shu-wei
* 日期2022年8月10日
* 邮箱2966211270@qq.com
*/
let url_config = '' // 用户登录
if (process.env.NODE_ENV === 'development') {
// 开发环境 配置域名
console.log('~开发环境~')
getStorage('brand') == 'pc'
? url_config = '/jx'
: url_config = 'https://wx.jxc4.com'
} else {
// 生产环境
console.log('~生产环境~')
url_config = "https://wx.jxc4.com"
}
export default url_config

114
src/api/https/login.ts Normal file
View File

@@ -0,0 +1,114 @@
/*************************************************
*@description: 登录模块
*@return {*}
*@param {}-
*/
import request from '../request'
import { getStorage } from "@/utils/storage";
import { setLoading } from '@/utils/tools';
const login = {
/*************************************************
* 获取微信登录code
*/
get_jx_code: (): Promise<AnyObject> => new Promise((resolve, reject) => {
setLoading('登录中...')
uni.login({
provider: 'weixin',
success: (res) => {
resolve(res)
},
fail: (error) => {
reject(error)
}
})
}),
/*************************************************
* 获取用户信息
*/
applets_login: async (params: AnyObject): Promise<AnyObject> => {
setLoading('登录中...')
params.cId = getStorage('cid')
return await request.api('/v2/auth2/Login', 'POST', params)
},
/*************************************************
* 用户绑定手机号
*/
add_auth_bind: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/auth2/AddAuthBindWithMobile', 'POST', params)
},
/*************************************************
* 获取用户手机号
*/
getUser_by_mini_info: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/auth2/GetUserByMiniInfo', 'POST', params)
},
/*************************************************
* 刷新token
*/
get_token_info: async (params?: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/auth2/GetTokenInfo', 'GET', params)
},
/*************************************************
* 获取手机登录验证码
*/
send_verify_code: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/auth2/SendVerifyCode', 'POST', params)
},
/*************************************************
* 注册用户
*/
register_user: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/user2/RegisterUser', 'POST', params)
},
/*************************************************
* 选择门店
*/
get_my_store_list: async (params?: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/user2/GetMyStoreList', 'GET', params)
},
/*************************************************
* 获取系统数据
*/
get_service_info: async (params?: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/cms/GetServiceInfo', 'GET', params)
},
/*************************************************
* 查询用户其他信息,比如角色等
*/
get_self_info: async (params?: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/user2/GetSelfInfo', 'GET', params)
},
/*************************************************
* 修改密码
*/
change_password: async (params?: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/auth2/ChangePassword', 'PUT', params)
}
}
export default login

266
src/api/https/merchant.ts Normal file
View File

@@ -0,0 +1,266 @@
/**
* @description: 商家中心
* @return {*}
* @param {}-
*/
import request from "../request";
const merchant = {
/**
* 获取门店营业状态
*/
get_stores: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/store/GetStores', 'GET', params)
},
/**
* @desc 多用型接口
* 设置门店营业 休息
* 切换未拣货提醒方式
* 修改印业资质
*/
update_store: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/store/UpdateStore', 'PUT', params)
},
/**
* 修改线上淘鲜达时间
*/
update_txd_store: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/store/UpdateTxdStore', 'POST', params)
},
/**
* 更新平台营业状态 线上
*/
update_vendors_store_states: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/store/UpdateVendorStoreBussinessStatus', 'POST', params)
},
/**
* @desc 修改门店映射信息
* @param {object} params 请求参数 storeID int 门店ID vendorID int 厂商ID
*/
update_store_vendor_map: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('v2/store/UpdateStoreVendorMap','PUT',params)
},
/**
* 查询是否有新账单
*/
get_store_bills: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/financial/GetStoreBills', 'GET', params)
},
/**
* 获取门店今日完成实时数据
*/
get_store_order_sale_info: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/order/GetStoresOrderSaleInfo', 'GET', params, 30000)
},
/**
* 获取用户注册时间
*/
get_self_info: async (params?: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/user2/GetSelfInfo', 'GET', params)
},
/**
* 获取调价包
*/
query_configs: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/cms/QueryConfigs', "GET", params)
},
/**
* 修改调价包
*/
update_store_price_pack: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/store/UpdateStorePricePack', "PUT", params)
},
/**
* 获取差评数量
*/
tmp_get_jx_bad_comments_no: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/store/TmpGetJxBadCommentsNo', 'GET', params)
},
/**
* 获取评论
*/
Tmp_get_jx_bad_comments_by_storeId: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/store/TmpGetJxBadCommentsByStoreId', 'GET', params)
},
/**
* 获取店铺评分
*/
get_weekly_store_score: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/store/GetWeeklyStoreScore', 'GET', params)
},
/**
* 获取待配商品
*/
get_order_ders_accept: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/order/GetOrdersAccept', 'GET', params)
},
/**
* 通过skuID skuName 获取商品
*/
get_stores_skus: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/store/sku/GetStoresSkus', "GET", params)
},
/**
* 获取信息通知
*/
Get_store_message_statuses: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/msg/GetStoreMessageStatuses', 'GET', params)
},
/**
* 获取信息详情
*/
get_store_messages: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/msg/GetStoreMessages', 'GET', params)
},
/**
* 修改信息为已读
*/
read_store_message: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/msg/ReadStoreMessage', 'PUT', params)
},
/**
* 获取门店活动信息
*/
query_acts: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/act/QueryActs', 'GET', params)
},
/**
* 获取打印机能识别的数据
*/
get_order_sku_info: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/order/GetOrderSkuInfo', 'GET', params)
},
/**
* 判断蓝牙打印机是否需要打印标题
*/
get_brands: async (prams: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/store/GetBrands', 'GET', prams)
},
/**
* 修改打印状态为 true
*/
set_order_print_status: async (prams: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/order/SetOrderPrintStatus', 'PUT', prams)
},
/**
* 清空打印队列
*/
delete_printer_seq: async (params: AnyObject): Promise<AnyObject> => {
return request.api('/v2/store/DeletePrinterSeq', 'POST', params)
},
/**
* 扫码绑定易联云
*/
bind_net_printer: async (params: AnyObject): Promise<AnyObject> => {
return request.api('/v2/store/BindPrinter', 'POST', params)
},
/**
* 获取七牛云TOKEN
*/
get_qiniu_upload_token: async (params: AnyObject): Promise<AnyObject> => {
return request.api('/v2/cms/GetQiniuUploadToken', 'GET', params)
},
/**
* 扫码进店,获取当前门店的二维码
*/
get_weixin_unlimited: async (params: AnyObject): Promise<AnyObject> => {
return request.api('/v2/event/GetWeixinUnlimited', 'POST', params)
},
/**
* 获取app版本号
*/
get_app_varsion: async (params: AnyObject): Promise<AnyObject> => {
return request.api('/v2/version/GetVersionController', 'GET', params)
},
/**
* 获取门店信息
*/
get_store_vendor_maps: async (params: AnyObject): Promise<AnyObject> => {
return request.api('/v2/store/GetStoreVendorMaps', 'GET', params)
},
/**
* 查询美团门店IM单聊开关状态
* @return {string} appPoiCode:美团门店id
*/
get_mt_store_im_status: async (params: AnyObject): Promise<AnyObject> => {
return request.api('/v2/im/GetPoiIMStatus', 'GET', params)
},
/**
* 设置美团门店IM线上状态
* @param {object} params 请求参数
* @return {object} appPoiCode:美团门店id imStatus:状态 0-关闭 1-开启
*/
set_mt_store_im_status: async (params: AnyObject): Promise<AnyObject> => {
return request.api('/v2/im/SetPoiIMStatus', 'POST', params)
},
/**
* 查询远端门店的营业状态
* @param {object} params 请求参数
*/
get_vendor_store:async(params:AnyObject): Promise<AnyObject> =>{
return request.api('/v2/store/GetVendorStore', 'GET', params)
}
}
export default merchant

48
src/api/https/message.ts Normal file
View File

@@ -0,0 +1,48 @@
/**
* @description: IM消息管理
* @return {*}
* @param {}-
*/
import request from "../request";
const message = {
/*************************************************
* 获取消息用户列表
*/
get_IM_user_list: async (params: AnyObject): Promise<AnyObject> => {
return request.api('/v2/im/GetIMUserList', 'GET', params)
},
/*************************************************
* 解析饿了么消息中的mediaID
*/
get_url_by_mediaID: async (params: AnyObject): Promise<AnyObject> => {
return request.api('/v2/im/GetElmMedia', 'GET', params)
},
/*************************************************
* 获取聊天详情
*/
get_IM_chat_detail: async (params: AnyObject): Promise<AnyObject> => {
return request.api('/v2/im/GetImChatDetail', 'GET', params)
},
/*************************************************
* 设置消息为已读
*/
set_IM_msg_read: async (params: AnyObject): Promise<AnyObject> => {
return request.api('/v2/im/SetImMsgRead', 'POST', params)
},
/*************************************************
* 发送消息接口
*/
send_to_vendor: async (params: AnyObject): Promise<AnyObject> => {
return request.api('/v2/im/SendToVendorV2', 'POST', params)
},
}
export default message

517
src/api/https/order.ts Normal file
View File

@@ -0,0 +1,517 @@
import request from '../request'
/**
* 订单类接口
* @param *
* @return *
*/
const order = {
/***********************************************************
* 获取商户订单数量(统计)
* @param {object} params 请求参数
* @return {object} code状态 data数据 desc错误信息
*/
Get_store_rder_count_info: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/order/GetStoreOrderCountInfo', 'GET', params)
},
/***********************************************************
* 获取售后单(统计)
* @param {object} params 请求参数
* @return {object} code状态 data数据 desc错误信息
*/
Get_store_afs_order_countinfo: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/order/GetStoreAfsOrderCountInfo', 'GET', params)
},
/***********************************************************
* 获取对应状态的订单数据
* @param {object} params 请求参数
* @return {object} code状态 data{totalCount总条数data分页数据} desc错误信息
*/
get_orders: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/order/GetOrders', 'GET', params)
},
/*************************************************************
* 确认接单
* @param {object} params 请求参数
* @return {object} code状态 data数据desc错误信息
*/
accept_or_refuse_order: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/order/AcceptOrRefuseOrder', 'POST', params)
},
/*************************************************************
* 获取打印机状态
* @param {object} params 请求参数
* @return {object} code状态 data数据 desc错误信息
*/
get_printer_status: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/order/GetPrinterStatus', 'GET', params)
},
/*************************************************************
* 网络打印机打印订单
* @param {object} params 请求参数
* @return {object} code状态 data数据 desc错误信息
*/
print_order: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/order/PrintOrder', 'PUT', params)
},
/*************************************************************
* 拣货完成
* @param {object} params 请求参数
* @return {object} code状态 data数据 desc错误信息
*/
finished_pickup: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/order/FinishedPickup', 'POST', params)
},
/*************************************************************
* 自提订单 京西订单不用自提 id
* @param {object} params 请求参数
* @return {object} code状态 data数据 desc错误信息
*/
confirm_self_take: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/order/ConfirmSelfTake', 'POST', params)
},
/*************************************************************
* 确认送送达
* @param {object} params 请求参数
* @return {object} code状态 data数据 desc错误信息
*/
self_delivered: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/order/SelfDelivered', 'POST', params)
},
/*************************************************************
* 获取售后订单
* @param {object} params 请求参数
* @return {object} code状态 data数据 desc错误信息
*/
get_afs_orders: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/order/GetAfsOrders', 'GET', params)
},
/*************************************************************
* 非饿百订单 退货退款
* @param {object} params 请求参数
* @return {object} code状态 data数据 desc错误信息
*/
agree_orRefuse_refund: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/order/AgreeOrRefuseRefund', 'PUT', params)
},
/*************************************************************
* @description 扫码枪 到店扫码支付订单退款 收获退款 post jxorder/RefundOnlineOrder
* @Param token header string true "认证token"
* @Param vendorOrderID formData string true "订单ID"
* @Param skuIds formData string true "[key:value]退款商品 skuId:count,int" Map类型
* @Param Reason formData string true "退单原因"
*/
refund_online_order: async(params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/jxorder/RefundOnlineOrder','POST', params)
},
/*************************************************************
* 饿佰取消订单 京东的异常单售后
* @param {object} params 请求参数
* @return {object} code状态 data数据 desc错误信息
*/
agree_or_refuse_cancel: async (params: AnyObject): Promise<AnyObject> => {
// 原来饿百订单退款或者驳回的接口有问题,更换成原来的退款
return await request.api('/v2/order/AgreeOrRefuseCancel', 'PUT', params)
},
/*************************************************************
* 退货待确认
* @param {object} params 请求参数
* @return {object} code状态 data数据 desc错误信息
*/
confirm_received_return_goods: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/order/ConfirmReceivedReturnGoods', 'PUT', params)
},
/*************************************************************
* 退货待确认
* @param {object} params 请求参数
* @return {object} code状态 data数据 desc错误信息
*/
get_order_info: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/order/GetOrderInfo', 'GET', params)
},
/*************************************************************
* 查询取消订单
* @param {object} params 请求参数
* @return {object} code状态 data数据 desc错误信息
*/
getafs_orders: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/order/getafsOrders', 'POST', params)
},
/*************************************************************
* 取消订单
* @param {object} params 请求参数
* @return {object} code状态 data数据 desc错误信息
*/
cancel_order: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/order/CancelOrder', 'PUT', params)
},
/*************************************************************
* 获取条形码
* @param {object} params 请求参数
* @return {object} code状态 data数据 desc错误信息
*/
create_qrOr_bar_code: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/cms/CreateQrOrBarCode', 'POST', params)
},
/*************************************************************
* 查询是否是京西新用户
* @param {object} params 请求参数
* @return {object} code状态 data数据 desc错误信息
*/
get_order_user_buy_first: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/order/GetOrderUserBuyFirst', 'GET', params)
},
/*************************************************************
* 获取运单状态
* @param {object} params 请求参数
* @return {object} code状态 data数据 desc错误信息
*/
get_order_status_list: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/order/GetOrderStatusList', 'GET', params)
},
/*************************************************************
* 获取商品列表
* @param {object} params 请求参数
* @return {object} code状态 data数据 desc错误信息
*/
get_order_sku_info: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/order/GetOrderSkuInfo', 'GET', params)
},
/*************************************************************
* 获取订单差评骑手列表
* @param {object} params 请求参数
* @return {object} code状态 data数据 desc错误信息
*/
complaint_rider_list: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/order/ComplaintRiderList', 'GET', params)
},
/*************************************************************
* 差评骑手
* @param {object} params 请求参数
* @return {object} code状态 data数据 desc错误信息
*/
complaint_rider: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/order/ComplaintRider', 'POST', params)
},
/*************************************************************
* 商品部分退款
* @param {object} params 请求参数
* @return {object} code状态 data数据 desc错误信息
*/
part_refund_order: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/order/PartRefundOrder', 'PUT', params)
},
/*************************************************************
* 商品全额退款并创建售后单
* @param {object} params 请求参数
* @return {object} code状态 data数据 desc错误信息
*/
refund_order: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/order/RefundOrder', 'PUT', params)
},
/*************************************************************
* 直接部分退款
* @param {object} params 请求参数
* @return {object} code状态 data数据 desc错误信息
*/
adjust_order: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/order/AdjustOrder', 'PUT', params)
},
/*************************************************************
* 售后商品
* @param {object} params 请求参数
* @return {object} code状态 data数据 desc错误信息
*/
get_afs_order_sku_info: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/order/GetAfsOrderSkuInfo', 'GET', params)
},
/*************************************************************
* 获取运单费用
* @param {object} params 请求参数
* @return {object} code状态 data数据 desc错误信息
*/
query_order_waybill_fee_info: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/order/QueryOrderWaybillFeeInfo', 'GET', params)
},
/*************************************************************
* 获取品牌余额
* @param {object} params 请求参数
* @return {object} code状态 data数据 desc错误信息
*/
get_brands: async (params?: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/store/GetBrands', 'GET', params)
},
/*************************************************************
* 获取门店账号余额
* @param {object} params 请求参数
* @return {object} code状态 data数据 desc错误信息
*/
get_store_acct_balance: async (params?: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/store/GetStoreAcctBalance', 'GET', params)
},
/*************************************************************
* 创建订单
* @param {object} params 请求参数
* @return {object} code状态 data数据 desc错误信息
*/
create_store_acct_order: async (params?: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/jxorder/CreateStoreAcctOrder', 'POST', params)
},
/*************************************************************
* 支付订单
* @param {object} params 请求参数
* @return {object} code状态 data数据 desc错误信息
*/
pay4_user: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/jxorder/Pay4User', 'POST', params)
},
/*************************************************************
* 非抖音订单转自送
* @param {object} params 请求参数
* @return {object} code状态 data数据 desc错误信息
*/
self_delivering: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/order/SelfDelivering', 'POST', params)
},
/*************************************************************
* 添加小费
* @param {object} params 请求参数
* @return {object} code状态 data数据 desc错误信息
*/
update_order_waybill_tip: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/order/UpdateOrderWaybillTip', 'POST', params)
},
/*************************************************************
* 切换发单方式
* @param {object} params 请求参数
* @return {object} code状态 data数据 desc错误信息
*/
update_store_courier_map: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/store/UpdateStoreCourierMap', 'PUT', params)
},
/*************************************************************
* 创建三方配送
* @param {object} params 请求参数
* @return {object} code状态 data数据 desc错误信息
*/
create_waybill_on_providers: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/order/CreateWaybillOnProviders', 'POST', params)
},
/*************************************************************
* 取消订单
* @param {object} params 请求参数
* @return {object} code状态 data数据 desc错误信息
*/
cancel_waybill: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/order/CancelWaybill', 'POST', params)
},
/*************************************************************
* 骑手
* @param {object} params 请求参数
* @return {object} code状态 data数据 desc错误信息
*/
accept_or_refuse_failed_get_order: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/order/AcceptOrRefuseFailedGetOrder', 'PUT', params)
},
/*************************************************************
* 重新召唤骑手
* @param {object} params 请求参数
* @return {object} code状态 data数据 desc错误信息
*/
callP_m_courier: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/order/CallPMCourier', 'PUT', params)
},
/*************************************************************
* 退回货物
* @param {object} params 请求参数
* @return {object} code状态 data数据 desc错误信息
*/
confirm_receive_goods: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/order/ConfirmReceiveGoods', 'PUT', params)
},
/*************************************************************
* 查看客户距离
* @param {object} params 请求参数
* @return {object} code状态 data数据 desc错误信息
*/
get_ST_o_U_riding_distance: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/cms/GetSToURidingDistance', 'GET', params)
},
/*************************************************************
* 获取骑手位置
* @param {object} params 请求参数
* @return {object} code状态 data数据 desc错误信息
*/
get_rider_lng: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/order/GetRiderLng', 'POST', params)
},
/*************************************************************
* 获取骑手位置(实时)
* @param {object} params 请求参数
* @return {object} code状态 data数据 desc错误信息
*/
get_store_to_riding_distance: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/cms/GetSToURidingDistance2', 'GET', params)
},
/*************************************************************
* 取消所有三方运单(取消所有配送)
* @param {object} params 请求参数
* @return {object} code状态 data数据 desc错误信息
*/
cancel_all_3rd_waybills: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/order/CancelAll3rdWaybills', 'POST', params)
},
/**
* 测试推送消息(订单)
* @param vendorOrderID 订单id
*/
test_uni_app_push: async (params?: string): Promise<AnyObject> => {
return await request.api(`/v2/event/TestUniAppPush?vendorOrderID=${params}`, 'GET', params)
},
/***************************************************************
* 查询发票信息,美团
* @Param storeId formData int false "门店id"
* @Param startTime formData string true "开始时间"
* @Param endTime formData string true "结束时间"
* @Param status formData string false "发票回复状态[1未回复/2回复]"
* @Param offset query int false "结果起始序号以0开始缺省为0"
* @Param pageSize query int false "结果页大小缺省为50-1表示全部"
*/
query_mt_invoice: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/order/GetInvoiceRecord', 'POST', params)
},
/**
* 上传发票图片
* @Param token header string true "认证token"
* @Param orderId formData string true "订单ID"
* @Param invoiceUrl formData string true "发票地址[10M内pdf/png/jpeg/jpg]"
* @Param invoiceId formData string true "发票号码"
*/
upload_invoice_img: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/order/UploadOrderInvoice', 'POST', params)
},
/**
* 发票设置 饿百
* @Title 批量更新门店发票设置
* @Description 批量更新门店发票设置
* @Param token header string true "认证token"
* @Param vendorId formData string true "平台ID"
* @Param vendorStoreID formData string true "平台门店ID"
* @Param payload formData string true "json数据,格式为 ebaiapi.StoreInvoiceSetting"见JXC4-BACKSTAGE
*/
bath_update_invoice_setting: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/order/BathUpdateInvoiceSetting', 'POST', params)
},
/**
* 查询饿百门店发票设置
*/
query_invoice_setting: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/order/QueryInvoiceSetting', 'GET', params)
},
/**
* 获取发票申请列表 饿百
*/
get_invoice_info: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/order/QueryUnansweredInvoice', 'GET', params)
},
}
export default order

98
src/api/https/shopping.ts Normal file
View File

@@ -0,0 +1,98 @@
/**
* @description: 商品管理
* @return {*}
* @param {}-
*/
import request from "../request";
const shopping = {
/*************************************************
* 修改商品价格
*/
update_stores_skus: async (params: AnyObject): Promise<AnyObject> => {
return request.api('/v2/store/sku/UpdateStoresSkus', 'PUT', params)
},
/*************************************************
* 修改商品为临时不可售
*/
update_stores_skus_sale: async (params: AnyObject): Promise<AnyObject> => {
return request.api('/v2/store/sku/UpdateStoresSkusSale', 'PUT', params)
},
/*************************************************
* 获取商品分类
*/
getStore_category_map: async (params: AnyObject): Promise<AnyObject> => {
return request.api('/v2/store/GetStoreCategoryMap', 'GET', params)
},
/*************************************************
* 备用获取分类列表
*/
get_categories: async (params?: AnyObject): Promise<AnyObject> => {
return request.api('/v2/sku/GetCategories', 'GET', params)
},
/*************************************************
* 获取商品
*/
get_stores_skus_for_store: async (params?: AnyObject): Promise<AnyObject> => {
return request.api('/v2/store/sku/GetStoresSkusForStore', 'GET', params)
},
/*************************************************
* 获取商品
*/
get_top_skus_by_city_code: async (params?: AnyObject): Promise<AnyObject> => {
return request.api('/v2/store/sku/GetTopSkusByCityCode', 'GET', params)
},
/*************************************************
* 获取待审核列表
*/
get_store_sku_audit: async (params?: AnyObject): Promise<AnyObject> => {
return request.api('/v2/store/sku/GetStoreSkuAudit', 'GET', params)
},
/*************************************************
* 获取待审核列表
*/
get_sku_names_new: async (params?: AnyObject): Promise<AnyObject> => {
return request.api('/v2/sku/GetSkuNamesNew', 'GET', params)
},
/*************************************************
* 审核商品
*/
store_sku_price_audit: async (params: AnyObject): Promise<AnyObject> => {
return request.api('/v2/store/sku/StoreSkuPriceAudit', 'POST', params)
},
/*************************************************
* 请求京东商品库
*/
get_jd_upc_code_by_name: async (params: AnyObject): Promise<AnyObject> => {
return request.api('/v2/sku/GetJdUpcCodeByName', 'GET', params)
},
/*************************************************
* 微信扫码创建商品
*/
create_skus_and_focus_from_wx: async (params: AnyObject): Promise<AnyObject> => {
return request.api('/v2/store/sku/CreateSkusAndFocusFromWx', 'POST', params)
},
}
export default shopping

146
src/api/mockData/index.ts Normal file
View File

@@ -0,0 +1,146 @@
/**
* 模拟后端返回的数据
*/
// 聊天消息
export const msgInfo = {
// 用户列表
userList: {
code: '0',
data: {
'5873:18003191:1': ['{"vendorID":1,"userID":"11555094096","orderID":"","NewMessageNum":0,"latestMsg":"eAcvT+OGsaVYx/Avh6VagA==","latestTime":1695691485}'],
// '34665:1157916361:3': ['{\"vendorID\":3,\"userID\":\"11555094096\",\"orderID\":\"\",\"NewMessageNum\":0,\"latestMsg\":\"{\\\"extensions\\\":{\\\"appName\\\":\\\"ELEME\\\",\\\"industryType\\\":\\\"NEW_RETAIL\\\",\\\"current_msg_source\\\":\\\"ELEME\\\",\\\"imsdk_role_name\\\":\\\"顾客\\\",\\\"imsdk_self_show_name\\\":\\\"45d46975e\\\",\\\"imsdk_other_show_name\\\":\\\"45d46975e\\\"},\\\"text\\\":\\\"[微笑]\\\"}\", "latestTime": 1695691485}'],
'34665:1157916361:3': [
JSON.stringify({
vendorID: 3,
userID: "$2$13205337818$PNM",
orderID: "",
NewMessageNum: 1,
latestMsg: JSON.stringify({
extensions: {
appName: "ELEME",
industryType: "NEW_RETAIL",
current_msg_source: "ELEME",
imsdk_role_name: "顾客",
imsdk_self_show_name: "45d46975e",
imsdk_other_show_name: "45d46975e"
},
text: "[微笑]",
}),
latestTime: 1698303946914
})
]
},
desc: ''
// code: "0",
// data: {
// '34665:1157916361:3': ['{"vendorID":3,"userID":"$2$13205337818$PNM","orderID":"","NewMessageNum":1,"latestMsg":"{"extensions":{"appName":"ELEME","industryType":"NEW_RETAIL","current_msg_source":"ELEME","imsdk_role_name":"顾客","imsdk_self_show_name":"45d46975e","imsdk_other_show_name":"45d46975e"},"text":"[微笑]"}","latestTime":1698303946914}'],
// '5873:18003191:1': ['{"vendorID":1,"userID":"9533643193","orderID":"","NewMessageNum":0,"latestMsg":"dTZiwxiOJI5b5zwb1/uCwcCxh3F9MrZtyR+ojZoql4wtzgMh/gzuGRffhgWQd4Sz","latestTime":1698295674}", "{"vendorID":1,"userID":"12169240445","orderID":"1100782041270894459","NewMessageNum":0,"latestMsg":"ZiiFa7hQp0BV60OuBKPExiN6IN7fRkjzmcVpaA+kQoQ=","latestTime":1698295257}', '{"vendorID":1,"userID":"10892282642","orderID":"1100782384203287879","NewMessageNum":0,"latestMsg":"K/qIurzlbi2B7zv65/mCQg==","latestTime":1698295422}', '{"vendorID":1,"userID":"11009807262","orderID":"","NewMessageNum":0,"latestMsg":"+tFz6s6u+O8Ndpc2dwP4HA==","latestTime":1698297046}', '{"vendorID":1,"userID":"11436731575","orderID":"","NewMessageNum":0,"latestMsg":"iMqYgHLYMjKY3JoSMG9YLQ==","latestTime":1698295279}', '{"vendorID":1,"userID":"9167982931","orderID":"","NewMessageNum":0,"latestMsg":"R4cR7u9LPax/LDKqVHWVLw==","latestTime":1698300481}', '{"vendorID":1,"userID":"11432640354","orderID":"","NewMessageNum":0,"latestMsg":"QY5plA6VHEKS7GqXV4jJElsh0x90ftjPFGGoZjX4M/84LQn7ucu0ZeruelSd/VmmZ0OD966b6g5+0ZrgsLBIZiDo2sEOk8a02UUwNt60FPKZEhaCURWvYjCBqDJA8laH","latestTime":1698304171}', '{"vendorID":1,"userID":"10946780381","orderID":"1100782881905266609","NewMessageNum":1,"latestMsg":"dtj7qIlXCPm1ZWUjwfEPc65cnsG57UYatDG6g/kYjYU+CSzeFNPE1THgv2cHUB0QhpNo6jEnCDc0Vte2V5h14J7NJ5Zbaprfysx+gLRua68o2Pp4pF0LDSMLQ+7pGh/GRDjdfYYS4qFqU17eBbT82x1LjsuY1HWe8Z2znWyo43nEcLbtPFU09HwXFgxOQLBhF4As08Inc7bvN6BPR8F46QtQR52+PvxiWdsDRV54/F2CqxuoFR3up6wKmxvyzDWyEAgFI8Ym7zqItVBfG8HtEXTezY3gCjtpK0qRoYJqJ+dIuQewnDXbbxyqu/JvXSdiLYVRdrZgY9UI1hBDQU4zN6XI2u/w8tzk3a6mSrTCfUyaB0xr5/bwLYfgwV4WDw0EaLQEr2R0OmMerlRMheR3A+GMYVxl+BcYx0fUrKuH7Fs1TNSRCS4ug4iMr/GoTv76J8jl1b2ihrFDPiVQRxPdSw==","latestTime":1698308642}']
// },
// desc: ""
},
// 聊天详情
chatDetail: {
// code: '0',
// data: {
// '5873:18003191:1:11555094096': [
// // '{"sendType":"mt","msgContent":{"app_id":5873,"app_poi_code":"18003191","msg_id":1400636412362739712,"msg_content":"eAcvT+OGsaVYx/Avh6VagA==","msg_source":2,"msg_type":1,"cts":1695691485,"open_user_id":11555094096,"order_id":1100738343654371431,"group_id":0,"app_spu_codes":""}}'
// '{"sendType":"mt","msgContent":{"app_id":5873,"app_poi_code":"18003191","msg_id":1400636412362739712,"msg_content":"kJhw2zGHISMeeNatcB62eoctFxbqneVDKiP75531PhYMisp7wJN44Yk/JpwHwbcg","msg_source":2,"msg_type":1,"cts":1695691485,"open_user_id":11555094096,"order_id":1100738343654371431,"group_id":0,"app_spu_codes":""}}'
// ]
// },
// desc: ''
code: "0",
// data: {
// "34665:1157916361:3": [
// "{\"vendorID\":3,\"userID\":\"$2$13205337818$PNM\",\"orderID\":\"\",\"NewMessageNum\":1,\"latestMsg\":\"{\\\"extensions\\\":{\\\"appName\\\":\\\"ELEME\\\",\\\"industryType\\\":\\\"NEW_RETAIL\\\",\\\"current_msg_source\\\":\\\"ELEME\\\",\\\"imsdk_role_name\\\":\\\"顾客\\\",\\\"imsdk_self_show_name\\\":\\\"45d46975e\\\",\\\"imsdk_other_show_name\\\":\\\"45d46975e\\\"},\\\"text\\\":\\\"[微笑]\\\"}\",\"latestTime\":1698303946914}"], "5873:18003191:1": ["{\"vendorID\":1,\"userID\":\"9533643193\",\"orderID\":\"\",\"NewMessageNum\":0,\"latestMsg\":\"dTZiwxiOJI5b5zwb1/uCwcCxh3F9MrZtyR+ojZoql4wtzgMh/gzuGRffhgWQd4Sz\",\"latestTime\":1698295674}", "{\"vendorID\":1,\"userID\":\"12169240445\",\"orderID\":\"1100782041270894459\",\"NewMessageNum\":0,\"latestMsg\":\"ZiiFa7hQp0BV60OuBKPExiN6IN7fRkjzmcVpaA+kQoQ=\",\"latestTime\":1698295257}", "{\"vendorID\":1,\"userID\":\"10892282642\",\"orderID\":\"1100782384203287879\",\"NewMessageNum\":0,\"latestMsg\":\"K/qIurzlbi2B7zv65/mCQg==\",\"latestTime\":1698295422}", "{\"vendorID\":1,\"userID\":\"11009807262\",\"orderID\":\"\",\"NewMessageNum\":0,\"latestMsg\":\"+tFz6s6u+O8Ndpc2dwP4HA==\",\"latestTime\":1698297046}", "{\"vendorID\":1,\"userID\":\"11436731575\",\"orderID\":\"\",\"NewMessageNum\":0,\"latestMsg\":\"iMqYgHLYMjKY3JoSMG9YLQ==\",\"latestTime\":1698295279}", "{\"vendorID\":1,\"userID\":\"9167982931\",\"orderID\":\"\",\"NewMessageNum\":0,\"latestMsg\":\"R4cR7u9LPax/LDKqVHWVLw==\",\"latestTime\":1698300481}", "{\"vendorID\":1,\"userID\":\"11432640354\",\"orderID\":\"\",\"NewMessageNum\":0,\"latestMsg\":\"QY5plA6VHEKS7GqXV4jJElsh0x90ftjPFGGoZjX4M/84LQn7ucu0ZeruelSd/VmmZ0OD966b6g5+0ZrgsLBIZiDo2sEOk8a02UUwNt60FPKZEhaCURWvYjCBqDJA8laH\",\"latestTime\":1698304171}", "{\"vendorID\":1,\"userID\":\"10946780381\",\"orderID\":\"1100782881905266609\",\"NewMessageNum\":1,\"latestMsg\":\"dtj7qIlXCPm1ZWUjwfEPc65cnsG57UYatDG6g/kYjYU+CSzeFNPE1THgv2cHUB0QhpNo6jEnCDc0Vte2V5h14J7NJ5Zbaprfysx+gLRua68o2Pp4pF0LDSMLQ+7pGh/GRDjdfYYS4qFqU17eBbT82x1LjsuY1HWe8Z2znWyo43nEcLbtPFU09HwXFgxOQLBhF4As08Inc7bvN6BPR8F46QtQR52+PvxiWdsDRV54/F2CqxuoFR3up6wKmxvyzDWyEAgFI8Ym7zqItVBfG8HtEXTezY3gCjtpK0qRoYJqJ+dIuQewnDXbbxyqu/JvXSdiLYVRdrZgY9UI1hBDQU4zN6XI2u/w8tzk3a6mSrTCfUyaB0xr5/bwLYfgwV4WDw0EaLQEr2R0OmMerlRMheR3A+GMYVxl+BcYx0fUrKuH7Fs1TNSRCS4ug4iMr/GoTv76J8jl1b2ihrFDPiVQRxPdSw==\",\"latestTime\":1698308642}"]
// },
data: {
"34665:1157916361:3:$2$13205337818$PNM": [
"{\"sendType\":\"elm\",\"msgContent\":{\"subBizType\":\"SEND_MESSAGE\",\"bizType\":\"IM\",\"payLoad\":{\"senderId\":\"10154538612\",\"receiverIds\":[\"301157916361\",\"10154538612\",\"321921188187760\"],\"createTime\":1698303833173,\"groupId\":\"$2$13205337818$PNM\",\"msgId\":\"1997094742949.PNM\",\"contentType\":2,\"content\":\"{\\\"elements\\\":[{\\\"elementContent\\\":\\\"{\\\\\\\"atAll\\\\\\\":false,\\\\\\\"defaultNick\\\\\\\":\\\\\\\"商家\\\\\\\",\\\\\\\"uid\\\\\\\":{\\\\\\\"appUid\\\\\\\":\\\\\\\"301157916361\\\\\\\",\\\\\\\"domain\\\\\\\":\\\\\\\"eleme\\\\\\\"}}\\\",\\\"elementType\\\":3},{\\\"elementContent\\\":\\\"{\\\\\\\"extensions\\\\\\\":{\\\\\\\"imsdk_self_show_name\\\\\\\":\\\\\\\"45d46975e\\\\\\\",\\\\\\\"appName\\\\\\\":\\\\\\\"ELEME\\\\\\\",\\\\\\\"imsdk_role_name\\\\\\\":\\\\\\\"顾客\\\\\\\",\\\\\\\"imsdk_other_show_name\\\\\\\":\\\\\\\"45d46975e\\\\\\\",\\\\\\\"industryType\\\\\\\":\\\\\\\"NEW_RETAIL\\\\\\\",\\\\\\\"current_msg_source\\\\\\\":\\\\\\\"ELEME\\\\\\\"},\\\\\\\"text\\\\\\\":\\\\\\\"您好,请问我的订单还要多久送达?\\\\\\\"}\\\",\\\"elementType\\\":1}]}\"},\"platformShopId\":\"1157916361\"}}", "{\"sendType\":\"elm\",\"msgContent\":{\"subBizType\":\"SEND_MESSAGE\",\"bizType\":\"IM\",\"payLoad\":{\"senderId\":\"10154538612\",\"receiverIds\":[\"301157916361\",\"10154538612\",\"321921188187760\"],\"createTime\":1698303918483,\"groupId\":\"$2$13205337818$PNM\",\"msgId\":\"1996910978679.PNM\",\"contentType\":1,\"content\":\"{\\\"extensions\\\":{\\\"industryType\\\":\\\"NEW_RETAIL\\\",\\\"imsdk_other_show_name\\\":\\\"45d46975e\\\",\\\"imsdk_role_name\\\":\\\"顾客\\\",\\\"imsdk_self_show_name\\\":\\\"45d46975e\\\",\\\"appName\\\":\\\"ELEME\\\",\\\"current_msg_source\\\":\\\"ELEME\\\"},\\\"text\\\":\\\"您好\\\"}\"},\"platformShopId\":\"1157916361\"}}", "{\"sendType\":\"elm\",\"msgContent\":{\"subBizType\":\"SEND_MESSAGE\",\"bizType\":\"IM\",\"payLoad\":{\"senderId\":\"10154538612\",\"receiverIds\":[\"301157916361\",\"10154538612\",\"321921188187760\"],\"createTime\":1698303946914,\"groupId\":\"$2$13205337818$PNM\",\"msgId\":\"1991934371357.PNM\",\"contentType\":1,\"content\":\"{\\\"extensions\\\":{\\\"appName\\\":\\\"ELEME\\\",\\\"industryType\\\":\\\"NEW_RETAIL\\\",\\\"current_msg_source\\\":\\\"ELEME\\\",\\\"imsdk_role_name\\\":\\\"顾客\\\",\\\"imsdk_self_show_name\\\":\\\"45d46975e\\\",\\\"imsdk_other_show_name\\\":\\\"45d46975e\\\"},\\\"text\\\":\\\"[微笑]\\\"}\"},\"platformShopId\":\"1157916361\"}}"
]
},
desc: ""
}
// // 美团音频数据
// code: "0"
// data: "{"5873:18003191:1:11555094096":["{\"sendType\":\"mt\",\"msgContent\":{\"app_id\":5873,\"app_poi_code\":\"18003191\",\"msg_id\":1411251415327150080,\"msg_content\":\"QYYLNKWSeCO+c2Sw/K73hBtYPD54B+AT5Vndt26ynS0VQW/QJ87hZGwwBVBaM8GB3edmiLPqLzAwR4tzvZjGBO2VmlOjNb6+vYiAWjGY1ACbPdlAq3bLvwlyCe/Kx68Sf2kKF+jWTWFF/bON2VQI/O8C6xBTh2GY4B5jpfEKWllJvqwQXqWc5ietgLEWmuTP7/NcCFZGt8JJfdA7yFQqqb/AS130qAv0/JIvgv9c+ZgAuJmmInjxnEyij7vKntDF5/fDozT+H7zApPunkK+QrE+ewCmErQkk2oWK8m+I1gqLWdYr31sBN72Og81l3u4W8E/hV+sO50U7sQbuHWEASQ==\",\"msg_source\":2,\"msg_type\":3,\"cts\":1698222298,\"open_user_id\":11555094096,\"order_id\":0,\"group_id\":0,\"app_spu_codes\":\"\"}}"]}"
// desc: ""
// 美团音频数据
// QYYLNKWSeCO+c2Sw/K73hBtYPD54B+AT5Vndt26ynS0VQW/QJ87hZGwwBVBaM8GB3edmiLPqLzAwR4tzvZjGBO2VmlOjNb6+vYiAWjGY1ACbPdlAq3bLvwlyCe/Kx68Sf2kKF+jWTWFF/bON2VQI/O8C6xBTh2GY4B5jpfEKWllJvqwQXqWc5ietgLEWmuTP7/NcCFZGt8JJfdA7yFQqqb/AS130qAv0/JIvgv9c+ZgAuJmmInjxnEyij7vKntDF5/fDozT+H7zApPunkK+QrE+ewCmErQkk2oWK8m+I1gqLWdYr31sBN72Og81l3u4W8E/hV+sO50U7sQbuHWEASQ==
// https://file.neixin.cn/proxy/0/s3/afc/698bce4c-ddc6-4b10-a24b-3790120a0fa6_1698222298877?AWSAccessKeyId=115479efca564d62820d47f9153702f9&Expires=1698308699&Signature=dOhRnfq0udZFrVPz5sK8j4tj9uo%3D&gtm=1698222299573&filename=2023-10-25+16%3A24%3A58+907.amr
// 用户列表
// code: "0"
// data: "{"5873:18003191:1":["{\"vendorID\":1,\"userID\":\"9099662511\",\"orderID\":\"1100756014203287879\",\"NewMessageNum\":0,\"latestMsg\":\"sgfc6Fw3EEC+N4h7mR8iLTTIuu6o2eMXVL6JqmAx9LHWroiRUNZXQNLzwrd9bG6I\",\"latestTime\":1696737412}","{\"vendorID\":1,\"userID\":\"11161356777\",\"orderID\":\"\",\"NewMessageNum\":0,\"latestMsg\":\"ML73Il8Yl/02TZ7hYx39/Q==\",\"latestTime\":1696748470}","{\"vendorID\":1,\"userID\":\"10492988799\",\"orderID\":\"1100756704146983163\",\"NewMessageNum\":0,\"latestMsg\":\"HFi0BcKs2zyQwwgwk6kUDQ==\",\"latestTime\":1696743753}","{\"vendorID\":1,\"userID\":\"11555094096\",\"orderID\":\"\",\"NewMessageNum\":0,\"latestMsg\":\"FskpgyfRcmbvR3Ut0sPVgvRKwIrjZ+uXRjW1HK9k7mQ=\",\"latestTime\":1696752752}","{\"vendorID\":1,\"userID\":\"11121583583\",\"orderID\":\"1100756913067981796\",\"NewMessageNum\":0,\"latestMsg\":\"wXP3NiYAF1hhFM+CD/P3HOzbADez/9KCNvD6L+R0uD0=\",\"latestTime\":1696752253}"]}"
// desc: ""
// 聊天详情
// code: "0"
// data: "{"5873:18003191:1:11161356777":["{\"sendType\":\"mt\",\"msgContent\":{\"app_id\":5873,\"app_poi_code\":\"18003191\",\"msg_id\":1405065885751885824,\"msg_content\":\"dtj7qIlXCPm1ZWUjwfEPc65cnsG57UYatDG6g/kYjYU+CSzeFNPE1THgv2cHUB0QhpNo6jEnCDc0Vte2V5h14J7NJ5Zbaprfysx+gLRua68o2Pp4pF0LDSMLQ+7pGh/GRDjdfYYS4qFqU17eBbT82x1LjsuY1HWe8Z2znWyo43lQ6CpTqmwcGYGriWDe92cWJ9eptuKRkZFmirAkYmuHKyKi3ce9lJ9MH3JogKczw+tmb4ooRd8z9ZiFIMTQ9pG11peV45qLmcZXgMo9Q7t3cZEgX4fU2RGdT2gpGXOTl48599Y79ic49DQU9szebnLslUwZekawLCwt99laGfhPfSZhR5CmeuzfYe/VFlTbQG++BxrK2ZSPrJtqStLVN7gGfnR/cHwmIfSDL3JZwymQ1cA641E8P3BmTQPzboOMNqrbWXYMdiiCbpLfEmYz7i+KoT4CsrBZEmPFuK3C8RynGBUDz9ZTGq+tB1sWC6kFDFN+BbeZz6gzrPFw6ydCHIDh\",\"msg_source\":2,\"msg_type\":5,\"cts\":1696747553,\"open_user_id\":11161356777,\"order_id\":1100756844146983163,\"group_id\":0,\"app_spu_codes\":\"\"}}","{\"sendType\":\"mt\",\"msgContent\":{\"app_id\":5873,\"app_poi_code\":\"18003191\",\"msg_id\":1405065906828263424,\"msg_content\":\"cCwNlL9ukNzOfS/A76CWnA==\",\"msg_source\":2,\"msg_type\":1,\"cts\":1696747558,\"open_user_id\":11161356777,\"order_id\":1100756844146983163,\"group_id\":0,\"app_spu_codes\":\"\"}}","{\"sendType\":\"mt\",\"msgContent\":{\"app_id\":5873,\"app_poi_code\":\"18003191\",\"msg_id\":1405065937144692736,\"msg_content\":\"Cx7e5k07X34v9MXn/dPKX3t9cKUo2RTKFegWCoFIg7s=\",\"msg_source\":2,\"msg_type\":1,\"cts\":1696747565,\"open_user_id\":11161356777,\"order_id\":1100756844146983163,\"group_id\":0,\"app_spu_codes\":\"\"}}","{\"sendType\":\"mt\",\"msgContent\":{\"app_id\":5873,\"app_poi_code\":\"18003191\",\"msg_id\":1405066156422905856,\"msg_content\":\"51kZuOfsFBtHME6GxxkY9SzIP7XDBD1QVKPY/G+RVucUSI32PuK3+5yRI2j2UboLPh8dXFsrLKzbXxwV9P8B6QGlHyiE8V19v4cwFo6hxt0=\",\"msg_source\":2,\"msg_type\":1,\"cts\":1696747618,\"open_user_id\":11161356777,\"order_id\":1100756844146983163,\"group_id\":0,\"app_spu_codes\":\"\"}}","{\"sendType\":\"mt\",\"msgContent\":{\"app_id\":5873,\"app_poi_code\":\"18003191\",\"msg_id\":1405066372173709312,\"msg_content\":\"TsXJ4usAgosTFgs1ar9DcusMZ5cK5ZfLxBuIjtu3d7k=\",\"msg_source\":2,\"msg_type\":1,\"cts\":1696747669,\"open_user_id\":11161356777,\"order_id\":1100756844146983163,\"group_id\":0,\"app_spu_codes\":\"\"}}","{\"sendType\":\"mt\",\"msgContent\":{\"app_id\":5873,\"app_poi_code\":\"18003191\",\"msg_id\":1405069732759126016,\"msg_content\":\"ML73Il8Yl/02TZ7hYx39/Q==\",\"msg_source\":2,\"msg_type\":1,\"cts\":1696748470,\"open_user_id\":11161356777,\"order_id\":0,\"group_id\":0,\"app_spu_codes\":\"\"}}"]}"
// desc: ""
// 加密内容
// "kJhw2zGHISMeeNatcB62eoctFxbqneVDKiP75531PhYMisp7wJN44Yk/JpwHwbcg"
// 译文:啦啦啦[大哭][睡]忆往昔[嘘]哈哈
// 表情
// code: "0"
// data: "{"5873:18003191:1:11555094096":["{\"sendType\":\"mt\",\"msgContent\":{\"app_id\":5873,\"app_poi_code\":\"18003191\",\"msg_id\":1401396902286315520,\"msg_content\":\"rq+Y2WYA/UjW7inVLzG3IQ==\",\"msg_source\":2,\"msg_type\":1,\"cts\":1695872799,\"open_user_id\":11555094096,\"order_id\":0,\"group_id\":0,\"app_spu_codes\":\"\"}}"]}"
// desc: ""
// rq+Y2WYA/UjW7inVLzG3IQ==\
// M/whRohCtpsVTviiMAK8hQ==
}
// 饿百用户列表
// code: "0"
// data: "{"34665:1157916361:3":["{\"vendorID\":3,\"userID\":\"$2$13205337818$PNM\",\"orderID\":\"\",\"NewMessageNum\":1,\"latestMsg\":\"{\\\"extensions\\\":{\\\"appName\\\":\\\"ELEME\\\",\\\"industryType\\\":\\\"NEW_RETAIL\\\",\\\"current_msg_source\\\":\\\"ELEME\\\",\\\"imsdk_role_name\\\":\\\"顾客\\\",\\\"imsdk_self_show_name\\\":\\\"45d46975e\\\",\\\"imsdk_other_show_name\\\":\\\"45d46975e\\\"},\\\"text\\\":\\\"[微笑]\\\"}\",\"latestTime\":1698303946914}"],"5873:18003191:1":["{\"vendorID\":1,\"userID\":\"9533643193\",\"orderID\":\"\",\"NewMessageNum\":0,\"latestMsg\":\"dTZiwxiOJI5b5zwb1/uCwcCxh3F9MrZtyR+ojZoql4wtzgMh/gzuGRffhgWQd4Sz\",\"latestTime\":1698295674}","{\"vendorID\":1,\"userID\":\"12169240445\",\"orderID\":\"1100782041270894459\",\"NewMessageNum\":0,\"latestMsg\":\"ZiiFa7hQp0BV60OuBKPExiN6IN7fRkjzmcVpaA+kQoQ=\",\"latestTime\":1698295257}","{\"vendorID\":1,\"userID\":\"10892282642\",\"orderID\":\"1100782384203287879\",\"NewMessageNum\":0,\"latestMsg\":\"K/qIurzlbi2B7zv65/mCQg==\",\"latestTime\":1698295422}","{\"vendorID\":1,\"userID\":\"11009807262\",\"orderID\":\"\",\"NewMessageNum\":0,\"latestMsg\":\"+tFz6s6u+O8Ndpc2dwP4HA==\",\"latestTime\":1698297046}","{\"vendorID\":1,\"userID\":\"11436731575\",\"orderID\":\"\",\"NewMessageNum\":0,\"latestMsg\":\"iMqYgHLYMjKY3JoSMG9YLQ==\",\"latestTime\":1698295279}","{\"vendorID\":1,\"userID\":\"9167982931\",\"orderID\":\"\",\"NewMessageNum\":0,\"latestMsg\":\"R4cR7u9LPax/LDKqVHWVLw==\",\"latestTime\":1698300481}","{\"vendorID\":1,\"userID\":\"11432640354\",\"orderID\":\"\",\"NewMessageNum\":0,\"latestMsg\":\"QY5plA6VHEKS7GqXV4jJElsh0x90ftjPFGGoZjX4M/84LQn7ucu0ZeruelSd/VmmZ0OD966b6g5+0ZrgsLBIZiDo2sEOk8a02UUwNt60FPKZEhaCURWvYjCBqDJA8laH\",\"latestTime\":1698304171}","{\"vendorID\":1,\"userID\":\"10946780381\",\"orderID\":\"1100782881905266609\",\"NewMessageNum\":1,\"latestMsg\":\"dtj7qIlXCPm1ZWUjwfEPc65cnsG57UYatDG6g/kYjYU+CSzeFNPE1THgv2cHUB0QhpNo6jEnCDc0Vte2V5h14J7NJ5Zbaprfysx+gLRua68o2Pp4pF0LDSMLQ+7pGh/GRDjdfYYS4qFqU17eBbT82x1LjsuY1HWe8Z2znWyo43nEcLbtPFU09HwXFgxOQLBhF4As08Inc7bvN6BPR8F46QtQR52+PvxiWdsDRV54/F2CqxuoFR3up6wKmxvyzDWyEAgFI8Ym7zqItVBfG8HtEXTezY3gCjtpK0qRoYJqJ+dIuQewnDXbbxyqu/JvXSdiLYVRdrZgY9UI1hBDQU4zN6XI2u/w8tzk3a6mSrTCfUyaB0xr5/bwLYfgwV4WDw0EaLQEr2R0OmMerlRMheR3A+GMYVxl+BcYx0fUrKuH7Fs1TNSRCS4ug4iMr/GoTv76J8jl1b2ihrFDPiVQRxPdSw==\",\"latestTime\":1698308642}"]}"
// desc: ""
// $2$13205337818$PNM
// 饿百聊天详情
// code: "0"
// data: "{"34665:1157916361:3:$2$13205337818$PNM":["{\"sendType\":\"elm\",\"msgContent\":{\"subBizType\":\"SEND_MESSAGE\",\"bizType\":\"IM\",\"payLoad\":{\"senderId\":\"10154538612\",\"receiverIds\":[\"301157916361\",\"10154538612\",\"321921188187760\"],\"createTime\":1698303833173,\"groupId\":\"$2$13205337818$PNM\",\"msgId\":\"1997094742949.PNM\",\"contentType\":8,\"content\":\"{\\\"elements\\\":[{\\\"elementContent\\\":\\\"{\\\\\\\"atAll\\\\\\\":false,\\\\\\\"defaultNick\\\\\\\":\\\\\\\"商家\\\\\\\",\\\\\\\"uid\\\\\\\":{\\\\\\\"appUid\\\\\\\":\\\\\\\"301157916361\\\\\\\",\\\\\\\"domain\\\\\\\":\\\\\\\"eleme\\\\\\\"}}\\\",\\\"elementType\\\":3},{\\\"elementContent\\\":\\\"{\\\\\\\"extensions\\\\\\\":{\\\\\\\"imsdk_self_show_name\\\\\\\":\\\\\\\"45d46975e\\\\\\\",\\\\\\\"appName\\\\\\\":\\\\\\\"ELEME\\\\\\\",\\\\\\\"imsdk_role_name\\\\\\\":\\\\\\\"顾客\\\\\\\",\\\\\\\"imsdk_other_show_name\\\\\\\":\\\\\\\"45d46975e\\\\\\\",\\\\\\\"industryType\\\\\\\":\\\\\\\"NEW_RETAIL\\\\\\\",\\\\\\\"current_msg_source\\\\\\\":\\\\\\\"ELEME\\\\\\\"},\\\\\\\"text\\\\\\\":\\\\\\\"您好,请问我的订单还要多久送达?\\\\\\\"}\\\",\\\"elementType\\\":1}]}\"},\"platformShopId\":\"1157916361\"}}","{\"sendType\":\"elm\",\"msgContent\":{\"subBizType\":\"SEND_MESSAGE\",\"bizType\":\"IM\",\"payLoad\":{\"senderId\":\"10154538612\",\"receiverIds\":[\"301157916361\",\"10154538612\",\"321921188187760\"],\"createTime\":1698303918483,\"groupId\":\"$2$13205337818$PNM\",\"msgId\":\"1996910978679.PNM\",\"contentType\":1,\"content\":\"{\\\"extensions\\\":{\\\"industryType\\\":\\\"NEW_RETAIL\\\",\\\"imsdk_other_show_name\\\":\\\"45d46975e\\\",\\\"imsdk_role_name\\\":\\\"顾客\\\",\\\"imsdk_self_show_name\\\":\\\"45d46975e\\\",\\\"appName\\\":\\\"ELEME\\\",\\\"current_msg_source\\\":\\\"ELEME\\\"},\\\"text\\\":\\\"您好\\\"}\"},\"platformShopId\":\"1157916361\"}}","{\"sendType\":\"elm\",\"msgContent\":{\"subBizType\":\"SEND_MESSAGE\",\"bizType\":\"IM\",\"payLoad\":{\"senderId\":\"10154538612\",\"receiverIds\":[\"301157916361\",\"10154538612\",\"321921188187760\"],\"createTime\":1698303946914,\"groupId\":\"$2$13205337818$PNM\",\"msgId\":\"1991934371357.PNM\",\"contentType\":1,\"content\":\"{\\\"extensions\\\":{\\\"appName\\\":\\\"ELEME\\\",\\\"industryType\\\":\\\"NEW_RETAIL\\\",\\\"current_msg_source\\\":\\\"ELEME\\\",\\\"imsdk_role_name\\\":\\\"顾客\\\",\\\"imsdk_self_show_name\\\":\\\"45d46975e\\\",\\\"imsdk_other_show_name\\\":\\\"45d46975e\\\"},\\\"text\\\":\\\"[微笑]\\\"}\"},\"platformShopId\":\"1157916361\"}}"]}"
// desc: ""
// 饿百用户发送消息时
// 模拟客户发消息
// let msg1 = JSON.stringify({
// sendType: 'elm',
// msgContent: {
// subBizType: 'SEND_MESSAGE',
// bizType: 'IM',
// payLoad: {
// senderId: "10154538612",
// receiverIds: ["301157916361", "10154538612", "321921188187760"],
// createTime: 1698303946914,
// groupId: "$2$13205337818$PNM",
// msgId: new Date().getTime() + '',
// contentType: 1,
// content: JSON.stringify({
// extensions: {
// appName: "ELEME",
// industryType: "NEW_RETAIL",
// current_msg_source: "ELEME",
// imsdk_role_name: "顾客",
// imsdk_self_show_name: "45d46975e",
// imsdk_other_show_name: "45d46975e"
// },
// text: "11问问"
// })
// }
// }
// })
// 饿百,待解密结构体
// "34665:1157916361:3:$2$13315405121$PNM":[
// "{\"sendType\":\"elm\",\"msgContent\":{\"subBizType\":\"SEND_MESSAGE\",\"bizType\":\"IM\",\"payLoad\":{\"senderId\":\"101000124198002\",\"receiverIds\":[\"321921188187760\",\"101000124198002\",\"301157916361\"],\"createTime\":1699000572978,\"groupId\":\"$2$13315405121$PNM\",\"msgId\":\"2011596619981.PNM\",\"contentType\":\"2\",\"content\":\"{\\\"fileType\\\":3,\\\"mediaId\\\":\\\"$igHNA-kCpGpwZWcDAQTNAc4FzQPoBtoAI4QBpCFQvEYCqrkXr-dN527mZcwDzwAAAYuUU1obBM4Al-xzB88AAFvb7IZscggACgQLzgAB9EQ\\\",\\\"orientation\\\":0,\\\"size\\\":128068}\"},\"platformShopId\":\"1157916361\"}}",
// "{\"sendType\":\"elm\",\"msgContent\":{\"subBizType\":\"SEND_MESSAGE\",\"bizType\":\"IM\",\"payLoad\":{\"senderId\":\"101000124198002\",\"receiverIds\":[\"321921188187760\",\"101000124198002\",\"301157916361\"],\"createTime\":1699000587153,\"groupId\":\"$2$13315405121$PNM\",\"msgId\":\"2019467437200.PNM\",\"contentType\":\"1\",\"content\":\"{\\\"extensions\\\":{},\\\"text\\\":\\\"是现杀的新鲜鸡\\\"}\"},\"platformShopId\":\"1157916361\"}}",
// "{\"sendType\":\"elm\",\"msgContent\":{\"subBizType\":\"SEND_MESSAGE\",\"bizType\":\"IM\",\"payLoad\":{\"senderId\":\"101000124198002\",\"receiverIds\":[\"321921188187760\",\"101000124198002\",\"301157916361\"],\"createTime\":1699000598697,\"groupId\":\"$2$13315405121$PNM\",\"msgId\":\"2019605209369.PNM\",\"contentType\":\"8\",\"content\":\"{\\\"elements\\\":[{\\\"elementContent\\\":\\\"{\\\\\\\"atAll\\\\\\\":false,\\\\\\\"defaultNick\\\\\\\":\\\\\\\"\\\\\\\",\\\\\\\"uid\\\\\\\":{\\\\\\\"appUid\\\\\\\":\\\\\\\"301157916361\\\\\\\",\\\\\\\"domain\\\\\\\":\\\\\\\"eleme\\\\\\\"}}\\\",\\\"elementType\\\":3},{\\\"elementContent\\\":\\\"{\\\\\\\"extensions\\\\\\\":{},\\\\\\\"text\\\\\\\":\\\\\\\"还是冻的?@商家 \\\\\\\"}\\\",\\\"elementType\\\":1}]}\"},\"platformShopId\":\"1157916361\"}}"
// ]
// }

191
src/api/request.ts Normal file
View File

@@ -0,0 +1,191 @@
/**
*@description: 请求接口配置文件
*@return {*}
*@param
*/
import urlConfig from "./config";
import toast from "@/utils/toast";
import { getStorage } from "@/utils/storage";
import { store } from "@/store";
import { addTask, jx_trembling } from "@/utils/tools";
import configCms from "@/utils/configCms";
import useGlobalFunc from "@/composables/useGlobalFunc";
// 定义请求类型
type methodsType = "GET" | "OPTIONS" | "HEAD" | "POST" | "PUT" | "DELETE" | "TRACE" | "CONNECT" | undefined
// 定义方法中的类型
type FnApiType = {
(url: string, methods: methodsType, data?: AnyObject | string, timeout?: number, baseURL?: string, contentType?: string): Promise<AnyObject>
}
// 定义方法类型
interface Api {
api: FnApiType
}
// 请求类型请求头
let cType = 'application/x-www-form-urlencoded'
// 最大超时时间默认15秒
let timeouts: any = 0
// 清空定时器在800毫秒内数据请求回来了就清空定时器
let timer: any
// 最大请求加载图层时间
let timer1: any
// 保存请求中断
let requestTask: any = null
/*************************************************
* 封装请求方法
* @param {string} [url] 请求地址
* @param {methodsType} [method] 请求方法默认GET
* @param {object} [data] 请求参数默认""
* @param {number} [timeout] 请求超时时间
* @param {string} [baseURL] 请求根路径默认https://wx.jxc4.com
* @param {string} [contentType] 请求头类型默认'application/x-www-form-urlencoded'
* @return {promist} [resolve, reject] promist成功与失败
*/
const request: Api = {
api: (url, method = 'GET', data = "", timeout = 1000 * 20, baseURL = urlConfig, contentType = cType) => {
if (requestGuard(url)) {
return new Promise((resolve, reject) => { })
}
let newUrl = url
if(getStorage('terrace') !== 'jxcs') newUrl = `/${getStorage('terrace')}` + url
if(getStorage('terrace') == 'jxgy' && url == '/v2/version/GetVersionController') newUrl = url
timeouts = timeout
store.commit('storeInfo/jxLoadingFn', false) // 关闭自定义加载图vuex)
clearTimeout(timer)
timer = setTimeout(() => {
// 显示自定义加载图(vuex)
store.commit('storeInfo/jxLoadingFn', true)
// 最大时间加载图
tremblingJxLoadingFn()
}, 500)
return new Promise((resolve, reject) => {
requestTask = uni.request({
url: baseURL + newUrl,
method: method,
data: data,
timeout: timeout,
header: {
'content-type': contentType,
'token': getStorage('token') ? getStorage('token') : 'jxcs'
},
success: (res) => {
store.commit('storeInfo/jxLoadingFn', false) // 关闭自定义加载图vuex)
if (res.statusCode >= 200 && res.statusCode < 300) {
// 通过token 验证 通过store 验证
if ((res.data as AnyObject).code == '-2') {
uni.jxAlert({
title: '提示',
content: '登录信息已过期',
confirmText: '重新登录',
success: () => {
const { logOutFn } = useGlobalFunc()
logOutFn()
uni.reLaunch({ url: '/subPages/login/wxLogin/wxLogin' })
}
})
return false
} else {
// 验证通过
try {
const jsonData = JSON.parse((res.data as AnyObject).data)
resolve({
code: (res.data as AnyObject).code,
data: jsonData,
desc: (res.data as AnyObject).desc
})
} catch (error) {
resolve(res.data as AnyObject)
}
}
} else if (res.statusCode >= 400 && res.statusCode < 500) {
toast('客户端出错', 2)
reject('客户端出错')
} else if (res.statusCode >= 500) {
toast('服务端出错', 2)
reject('服务端出错')
} else {
toast('网络请求出错', 2)
}
},
fail: (error) => {
if (error.errMsg == 'request:fail abort') {
// 中断请求
return false
}
toast('网络请求超时', 2)
console.log('ZSW-网络请求超时', error);
reject(`网络请求超时 -- request.ts, ${error}`)
},
complete: () => {
uni.stopPullDownRefresh()
store.commit('storeInfo/jxLoadingFn', false) // 关闭自定义加载图vuex)
uni.hideLoading()
clearTimeout(timer) // 清空定时器
}
})
// 添加请求记录到缓存
if (url == '/v2/cms/GetNewOrderMsg') return
addTask(requestTask)
})
}
}
/*************************************************
* 防抖超时加载图层
*/
const tremblingJxLoadingFn = jx_trembling(() => {
clearTimeout(timer1)
timer1 = setTimeout(() => {
store.commit('storeInfo/jxLoadingFn', false) // 关闭自定义加载图vuex)
console.log('ZSW-超时关闭加载图层');
clearTimeout(timer1)
}, timeouts)
}, 500)
/*************************************************
* 登录守卫
*/
function requestGuard(url: string) {
// 获取网络状态
uni.getNetworkType({
success: (res) => {
if (res.networkType == 'none') {
store.commit('serveInfo/setIsNetWorkS', false)
} else {
store.commit('serveInfo/setIsNetWorkS', true)
}
}
})
// 验证token
if (!getStorage('token') && !configCms.whiteListUrl.includes(url)) {
store.commit('serveInfo/setIsFirestLogin', true)
return true
}
// 验证storeID
if (!getStorage('storeID') && !configCms.whiteListUrl.includes(url)) {
rulerStoreID()
return true
}
// 验证网络状态
if (!store.state.serveInfo.isNetWork) {
return true
}
store.commit('serveInfo/setIsFirestLogin', false)
return false
}
// 门店防抖节流
const rulerStoreID = jx_trembling(() => {
uni.navigateTo({ url: "/subPages/switchStore/switchStore" })
}, 1000)
export default request

View File

@@ -0,0 +1,13 @@
{
"applinks": {
"apps": [],
"details": [
{
"appID": "FWL4T58A47.com.jxc4.www",
"paths": [
"*"
]
}
]
}
}

View File

@@ -0,0 +1,55 @@
export default {
// 链接处理
getLink(params: AnyObject) {
let url = "/components/dialog/dialogCom";
if (params) {
let paramStr = "";
for (let name in params) {
paramStr += `&${name}=${params[name]}`
}
if (paramStr) {
url += `?${paramStr.substr(1)}`
}
}
return url;
},
// 全局弹窗
dialog(params = {}, callback: Function) {
uni.navigateTo({
url: this.getLink(params),
success(e) {
uni.$off("jx_dialog");
uni.$on("jx_dialog", (type) => {
callback && callback(type)
})
}
})
},
// 弹出提示弹窗
alert(data = {}, callback: Function, close?: Function) {
let obj1 = { type: "alert", isCloseBtn: '0', isMaskClose: '0' };
let params = Object.assign(obj1, data)
this.dialog(params, (type: string) => {
if ("confirm" == type) {
callback && callback()
} else {
close && close()
}
})
},
// 确认提示框弹窗
confirm(data = {}, confirm: Function, cancel: Function) {
let obj1 = { type: "confirm", isCloseBtn: '0', isMaskClose: '0' };
let params = Object.assign(obj1, data)
this.dialog(params, (type: string) => {
if ("confirm" == type) {
confirm && confirm()
} else if ("cancel" == type) {
cancel && cancel()
}
})
}
}

View File

@@ -0,0 +1,206 @@
<template>
<view @tap="itemClick('mask')" class="mask-content">
<view class="dialog-content" @tap.stop="">
<view
class="head-content"
v-if="info.title"
:style="info.content ? '' : 'min-height:90rpx;padding: 30rpx'"
>
<text>{{ info.title }}</text>
</view>
<scroll-view class="main-content" scroll-y v-if="info.content">
<view class="info-content">
<text>{{ info.content }}</text>
</view>
</scroll-view>
<view class="foot-content alert" v-if="'alert' == info.type">
<view
class="btn active"
hover-class="active1"
hover-start-time="0"
hover-stay-time="0"
@tap.stop="itemClick('confirm')"
>
{{ info.confirmText }}
</view>
</view>
<view class="foot-content confirm" v-if="'confirm' == info.type">
<view
class="btn cancel"
hover-class="active1"
hover-start-time="0"
hover-stay-time="0"
@tap="itemClick('cancel')"
>
{{ info.cancelText }}
</view>
<view
class="btn active"
hover-class="active1"
hover-start-time="0"
hover-stay-time="0"
@tap.stop="itemClick('confirm')"
>
{{ info.confirmText }}
</view>
</view>
</view>
</view>
</template>
<script lang="ts" setup>
import { onBackPress, onLoad } from '@dcloudio/uni-app'
import { ref } from 'vue'
interface InfoType {
type: string
title: string
content: string
cancelText: string
confirmText: string
isMaskClose: string
}
const info = ref<InfoType>({
type: 'alert', //alert:单按钮,confirm:双按钮
title: '', //
content: '',
cancelText: '取消',
confirmText: '确定',
isMaskClose: '1', //1点击遮罩层关闭弹窗
})
let isReturn = false
onBackPress((options: any) => {
options.isReturn = isReturn
if (options.from == 'backbutton' && options.isReturn == 0) {
return true
} else if (options.from == 'navigateBack' && options.isReturn == 1) {
return false
}
})
onLoad((options) => {
isReturn = options!.isReturn
info.value.type = options!.type
info.value.title = options!.title
info.value.content = options!.content
info.value.cancelText = options!.cancelText
info.value.confirmText = options!.confirmText
info.value.isMaskClose = options!.isMaskClose
})
function itemClick(type: string) {
if (type == 'mask' && info.value.isMaskClose != '1') {
return
}
uni.navigateBack()
uni.$emit('jx_dialog', type)
}
</script>
<style lang="scss">
$btncolor: #0b7ffe;
page {
background: transparent;
}
.mask-content {
position: fixed;
left: 0;
top: 0;
right: 0;
bottom: 0;
display: flex;
justify-content: center;
align-items: center;
background-color: rgba(0, 0, 0, 0.3);
.dialog-content {
background-color: rgba(255, 255, 255, 0.82);
backdrop-filter: blur(30px);
border-radius: 25px;
width: 560rpx;
border-radius: 22rpx;
animation: centerScale 0.15s;
@keyframes centerScale {
0% {
transform: scale(1.3);
}
100% {
transform: scale(1);
}
}
.head-content {
display: flex;
align-items: center;
justify-content: center;
color: #000000;
font-weight: bold;
font-size: 32rpx;
padding: 10rpx 30rpx;
padding-top: 25rpx;
}
.main-content {
max-height: 350rpx;
.info-content {
min-height: 80rpx;
padding: 10rpx 30rpx 20rpx 30rpx;
font-size: 30rpx;
color: #000000;
display: flex;
justify-content: center;
text {
text-align: center;
}
}
}
.foot-content {
border-top: 1rpx solid #e4e4e4;
display: flex;
justify-content: center;
align-items: center;
.btn {
font-weight: bold;
height: 80rpx;
display: flex;
justify-content: center;
align-items: center;
}
&.alert {
.btn {
border-top: 1rpx solid #e4e4e4;
display: flex;
justify-content: center;
align-items: center;
width: 100%;
color: $btncolor;
height: 80rpx;
padding: 10rpx 0;
font-weight: bold;
}
}
&.confirm {
display: flex;
justify-content: space-between;
.btn {
width: 100%;
height: 100rpx;
&.active {
border-left: 1rpx solid #e4e4e4;
color: $btncolor;
font-weight: bold;
}
&.cancel {
border-right: 1rpx solid #e4e4e4;
color: $btncolor;
font-weight: bold;
}
}
}
}
}
.active1 {
background-color: #dddddd;
}
}
</style>

View File

@@ -0,0 +1,64 @@
import dialog from "./dialog"
const jxMOdal = {
/**
* 弹出提示
*/
alert(options: any) {
let platform = uni.getSystemInfoSync().platform
if (platform == 'android') {
dialog.alert({
content: options.content,
title: options.title,
confirmText: options.confirmText || '确定',
isReturn: options.isReturn || 0
}, options.success)
} else {
uni.showModal({
title: options.title,
content: options.content,
confirmText: options.confirmText || '确定',
showCancel: false,
confirmColor: "#51b535",
success: options.success
})
}
},
/**
* 确认提示框
*/
confirm(options: any) {
let platform = uni.getSystemInfoSync().platform
if (platform == 'android') {
dialog.confirm({
content: options.content,
title: options.title,
confirmText: options.confirmText || '确定',
cancelText: options.cancelText || '取消',
isReturn: options.isReturn || 0,
}, options.success, options.fail)
} else {
uni.showModal({
content: options.content,
title: options.title,
confirmText: options.confirmText || '确定',
cancelText: options.cancelText || '取消',
confirmColor: "#51b535",
success: (e) => {
if (e.confirm) {
options.success && options.success()
} else if (e.cancel) {
options.fail && options.fail()
}
},
fail: (e) => {
console.log(e, '自定义弹窗发生错误')
}
})
}
}
}
export default jxMOdal

View File

@@ -0,0 +1,20 @@
/*************************************************
* 覆盖 tabbat的公共弹窗
*@author zhang-shu-wei <2966211270@qq.com>
*@date 2023-02-09 11:16:58
*@param {object} [data] 传递参数
*@param {Function} [fn] 回调函数
*/
function globalAlert(options: any): void {
uni.navigateTo({
url: `/components/globalAlert/globalAlert?data=${JSON.stringify(options.data)}`,
success(e) {
uni.$off("jx_dialog");
uni.$on("jx_dialog", () => {
options.fn && options.fn(options.data)
})
}
})
}
export default globalAlert

View File

@@ -0,0 +1,89 @@
<template>
<!-- 版本更新 -->
<template v-if="globalData.type == 3">
<version-update :id="appId" @close="close" @check="check" />
</template>
<template v-else>
<view class="returnClass-root">
<image src="https://image.jxc4.com/image/70143fcf48aefe74537533f35a0a8153.jpg" mode="scaleToFill" />
<view @tap="closeReturn" class="returnClass">返回</view>
</view>
</template>
</template>
<script lang="ts" setup>
import { onBackPress, onLoad } from '@dcloudio/uni-app'
import versionUpdate from '@/components/jx-update/update-cel/version-update/varsion-update.nvue'
import configCms from '@/utils/configCms'
import { ref } from 'vue'
/*************************************************
* 禁止返回
*/
onBackPress((options) => {
if (options.from == 'backbutton') {
return true
} else if (options.from == 'navigateBack') {
return false
}
})
/*************************************************
* 接收数据
*/
const globalData = ref<AnyObject>({
type: 0,
})
onLoad((options) => {
globalData.value = JSON.parse(options!.data) || globalData.value.type == 0
})
function close() {
uni.navigateBack()
}
function check(res: AnyObject) {
if (res.isTest == true) {
globalData.value.type = 0
}
if (res.needUpdate == false) {
globalData.value.type = 0
}
}
function closeReturn() {
uni.navigateBack()
}
const appId = ref<string>(configCms.appId)
</script>
<style>
page {
background: transparent;
}
</style>
<style lang="scss" scoped>
.returnClass-root {
position: fixed;
flex-direction: column;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
background-color: rgba($color: #000000, $alpha: 0.8);
.returnClass {
width: 500rpx;
background-color: $jx-primary;
padding: 30rpx 0;
border-radius: 50rpx;
text-align: center;
color: #fff;
}
image {
width: 200rpx;
height: 200rpx;
border-radius: 15rpx;
margin-bottom: 50rpx;
}
}
</style>

View File

@@ -0,0 +1,60 @@
<template>
<view class="copyright" @tap="jump" v-if="copyrightText.length>0">
备案号:{{copyrightText}}
</view>
</template>
<script lang="ts" setup>
import { onLoad } from '@dcloudio/uni-app'
import { ref } from 'vue'
import { getStorage } from '@/utils/storage'
import toast from '@/utils/toast'
interface Copyright {
}
let copyrightText = ref('蜀ICP备18030159号')
withDefaults(defineProps<Copyright>(), {
})
// 获取机型
onLoad(() => {
let brand = getStorage('brand')
// console.log('获取手机品牌信息',brand)
// copyrightText.value = copyrightText.value + '-4A' // 京西菜市门店管理
if(brand === 'xiaomi') copyrightText.value = copyrightText.value + '4A' // 京西菜市门店管理
else copyrightText.value = ''
})
function jump() {
if(copyrightText.value.length === 0) return
uni.setClipboardData({
data: copyrightText.value,
success() {
toast('复制备案号成功', 1)
},
})
const timer = setTimeout(() => {
plus.runtime.openURL('http://beian.miit.gov.cn/')
clearTimeout(timer)
},500)
}
</script>
<style lang="scss" scoped>
.copyright{
display: flex;
justify-content: flex-end;
font-size: 12px;
position: fixed;
left: -5px;
bottom: 10px;
color:#9b9b9b;
width: 750rpx;
box-sizing: border-box;
text-align: center;
}
</style>

View File

@@ -0,0 +1,57 @@
<template>
<view class="empty-root">
<image
class="img"
:src="src"
mode="scaleToFill"
/>
<text class="text">{{ title }}</text>
<slot></slot>
</view>
</template>
<script lang="ts" setup>
interface EmptyType {
icon?: string
size?: number
title?: string
color?: string
src?: string
}
withDefaults(defineProps<EmptyType>(), {
icon: 'kongzhuangtai',
size: 150,
title: '暂无数据...',
color: '#7fc86c',
// src: 'empty.png',
src: '/static/image/global/empty.png',
// src: 'https://image.jxc4.com/image/d0adecd3671e8a1c2294783b22a46426.png',
})
</script>
<style lang="scss" scoped>
.empty-root {
position: absolute;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
z-index: 99;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
.img {
width: 400rpx;
height: 400rpx;
}
.text {
color: v-bind(color);
text-decoration: none;
margin-top: -70rpx;
text-align: center;
}
}
</style>

View File

@@ -0,0 +1,29 @@
<template>
<text
class="iconfont"
:class="'icon-' + icon"
:style="{ 'font-size': size + 'rpx', color: color }"
></text>
</template>
<script lang="ts" setup>
/**
* @icon: iconfonti 图标
* @size: 图标大小
* @color图标颜色
*/
interface IconType {
icon: string;
size?: number;
color?: string;
}
withDefaults(defineProps<IconType>(), {
size: 32,
color: "#000",
});
</script>
<style lang="scss" scoped>
</style>

View File

@@ -0,0 +1,27 @@
<template>
<view class="jx-input">
<view class="left">
<slot name="left"></slot>
</view>
<slot name="middle"></slot>
<view class="left">
<slot name="right"></slot>
</view>
</view>
</template>
<script lang="ts" setup>
</script>
<style lang="scss" scoped>
.jx-input {
display: flex;
align-items: center;
width: 100%;
.left,
.right {
padding: 10rpx 20rpx 10rpx 20rpx;
}
}
</style>

View File

@@ -0,0 +1,20 @@
<template>
<view v-if="system == isShow">
<slot></slot>
</view>
</template>
<script lang="ts" setup >
import { computed } from 'vue'
interface propsType {
isShow: string
}
defineProps<propsType>()
const system = computed(() => {
return uni.getSystemInfoSync().platform
})
</script>
<style lang="scss" scoped>
</style>

View File

@@ -0,0 +1,72 @@
<template>
<view class="jx-load-more">
<view v-show="isLoad" class="isLoad">
<text class="load-icon"></text>
<text class="load-text">{{ loadText }}</text>
</view>
<text v-show="!isLoad">
<text class="text"></text>
&nbsp;{{ tip }}&nbsp;
<text class="text"></text>
</text>
</view>
</template>
<script lang="ts" setup >
interface jxLoadMoreType {
color?: string
loadText?: string
tip?: string
size?: string
isLoad: boolean
marginTop?: string
}
withDefaults(defineProps<jxLoadMoreType>(), {
color: '#aaa',
loadText: '正在加载中...',
tip: '没有更多了',
size: '22rpx',
marginTop: '0rpx',
})
</script>
<style lang="scss" scoped>
.jx-load-more {
display: flex;
justify-content: center;
align-items: center;
color: v-bind(color);
font-size: v-bind(size);
padding-bottom: 20rpx;
margin-top: v-bind(marginTop);
.load-icon {
display: inline-block;
width: 30rpx;
height: 30rpx;
border-width: 4rpx;
border-style: solid;
border-radius: 50%;
margin-right: 10rpx;
border-right-color: rgba($color: $jx-primary, $alpha: 0.2);
border-top-color: rgba($color: $jx-primary, $alpha: 0.2);
border-bottom-color: rgba($color: $jx-primary, $alpha: 0.2);
border-left-color: $jx-primary;
border-radius: 50%;
animation: identifier 0.7s linear infinite;
}
@keyframes identifier {
0% {
transform: rotate(0);
}
100% {
transform: rotate(360deg);
}
}
.text {
color: rgb(220, 220, 220);
}
}
</style>

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

View File

@@ -0,0 +1,114 @@
<template>
<view class="login-empty" v-if="!store.state.serveInfo.isNetWork">
<jx-empty :title="notWifi" src="https://image.jxc4.com/image/85a01a6ee723403fae65cfa55441aaa9.png" color="#9b9b9b">
<view
class="first-login"
hover-class="hoverLogin"
hover-start-time="0"
hover-stay-time="100"
@tap="retry"
>在试一次</view
>
</jx-empty>
<jx-copyright></jx-copyright>
</view>
<view class="login-empty" v-else-if="store.state.serveInfo.isFirstLogin">
<jx-empty :title="title" color="#9b9b9b">
<view
class="first-login"
hover-class="hoverLogin"
hover-start-time="0"
hover-stay-time="1200"
@tap="firstLogin"
>立即登录</view
>
</jx-empty>
<jx-copyright></jx-copyright>
</view>
</template>
<script lang="ts" setup >
import { store } from '@/store'
import toast from '@/utils/toast'
import { onBeforeUnmount, ref } from 'vue'
function firstLogin() {
uni.reLaunch({
url: '/subPages/login/wxLogin/wxLogin',
})
}
interface propsType {
title?: string
}
defineProps<propsType>()
// 无无网络
const notWifi = ref<string>(`
没有检测到网络
请检查手机是否连上网络
`)
// 再试一次
let timer: any = null
function retry() {
uni.showLoading({ title: '请稍后' })
uni.getNetworkType({
success: (res) => {
if (res.networkType == 'none') {
timer = setTimeout(() => {
toast('未连接网络', 2)
store.commit('serveInfo/setIsNetWorkS', false)
clearTimeout(timer)
}, 1200)
} else {
timer = setTimeout(() => {
store.commit('serveInfo/setIsNetWorkS', true)
clearTimeout(timer)
}, 1200)
}
},
complete: () => {
timer = setTimeout(() => {
uni.hideLoading()
clearTimeout(timer)
}, 1100)
},
})
}
onBeforeUnmount(() => {
clearTimeout(timer)
})
</script>
<style lang="scss" scoped>
.login-empty {
position: fixed;
z-index: 99999999999;
top: 0;
left: 0;
height: 100vh;
width: 100vw;
background-color: #fff;
}
.first-login {
margin-top: 30rpx;
background-color: $jx-primary;
color: #fff;
font-weight: bold;
font-size: 35rpx;
border: 2rpx solid #fff;
padding: 15rpx 100rpx;
border-radius: 100rpx;
}
.hoverLogin {
background-color: #fff;
border: 2rpx solid $jx-primary;
color: $jx-primary;
}
</style>

View File

@@ -0,0 +1,233 @@
<template>
<view
class="jx-popup"
v-show="hideen"
:class="{ popupAnimation: isPopup }"
@tap="maskClice"
@touchmove.prevent
>
<!-- jx-popup 内容 -->
<view class="popup-center" :class="[type, popupActive]" @tap.stop>
<slot></slot>
</view>
</view>
</template>
<script lang="ts" setup>
/**
* jx-popup 组件
* @param (open) 打开popup
* @param (close) 关闭popup
* @emit (mask) mask 触发事件
* @param (isMask) 是否允许点击 mask 关闭
* @param (type) popup 打开方式
*/
import { ref, computed } from 'vue'
/**
* props
*/
interface PropType {
isMask?: boolean
time?: number
type: string
}
const props = withDefaults(defineProps<PropType>(), {
isMask: false,
time: 300,
})
/**
* emit
*/
const emit = defineEmits<{
(e: 'mask'): void
}>()
/**
* 打开popup
*/
// mask 动画
const isPopup = ref<boolean>(false)
// 动画 class
const popupActive = ref<string>('')
// 使用 v-show 避免重新渲染组件
const hideen = ref<boolean>(false)
let openTimer: any = null
function open() {
let ruler = ['top', 'right', 'bottom', 'left', 'center']
if (!ruler.includes(props.type)) {
return console.error(
'this is param need is top or right or bottom or left or center'
)
}
// 先显示了在执行动画
hideen.value = true
// 执行动画
clearTimeout(openTimer)
openTimer = setTimeout(() => {
isPopup.value = true
switch (props.type) {
case 'top':
popupActive.value = 'topAnimation'
break
case 'right':
popupActive.value = 'rightAnimation'
break
case 'bottom':
popupActive.value = 'bottomAnimation'
break
case 'left':
popupActive.value = 'leftAnimation'
break
case 'center':
popupActive.value = 'centerAnimation'
break
}
// 20 兼容 app 渲染过快
}, 20)
}
/**
* 关闭popup
*/
let closeTimer: any = null
function close(fun?: Function) {
isPopup.value = false
popupActive.value = ''
clearTimeout(closeTimer)
closeTimer = setTimeout(() => {
hideen.value = false
fun && fun()
}, props.time)
}
/**
* 点击 mask 是否允许关闭
*/
let maskTimer: any = null
function maskClice() {
if (props.isMask) return
// 遮罩层事件
emit('mask')
isPopup.value = false
popupActive.value = ''
// 动画执行完了在隐藏
clearTimeout(maskTimer)
maskTimer = setTimeout(() => {
hideen.value = false
}, props.time)
}
/**
* 暴露方法提供父组件调用
*/
defineExpose({
open, // 打开 popup
close, // 关闭 popup
})
const transitionTImer = computed(() => {
return `${props.time / 1000}s`
})
</script>
<style lang="scss" scoped>
.jx-popup {
position: fixed;
top: 0;
left: 0;
height: 100%;
width: 100%;
background-color: rgba(0, 0, 0, 0.4);
opacity: 0;
transition: all v-bind(transitionTImer);
.popup-center {
transition: all v-bind(transitionTImer);
}
.top {
position: absolute;
top: 0;
width: 100%;
transform: translateY(-100%);
}
.right {
position: absolute;
right: 0;
height: 100%;
overflow: auto;
transform: translateX(100%);
}
.bottom {
position: absolute;
bottom: 0;
width: 100%;
transform: translateY(100%);
}
.left {
position: absolute;
left: 0;
height: 100%;
overflow: auto;
transform: translateX(-100%);
}
.center {
position: absolute;
width: auto;
height: auto;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) scale(0);
animation: centerScale v-bind(transitionTImer);
}
}
// mask 遮罩层
.popupAnimation {
z-index: 999999999999;
opacity: 1;
}
// top 顶部弹出
.topAnimation {
transform: translateY(0%) !important;
}
// right 右侧弹出
.rightAnimation {
transform: translateX(0%) !important;
}
// bottom 底部弹出
.bottomAnimation {
transform: translateY(0%) !important;
}
// left 左侧弹出
.leftAnimation {
transform: translateX(0%) !important;
}
// 居中弹出
.centerAnimation {
transform: translate(-50%, -50%) scale(1) !important;
}
@keyframes centerScale {
0% {
transform: translate(-50%, -50%) scale(0);
}
85% {
transform: translate(-50%, -50%) scale(1.02);
}
100% {
transform: translate(-50%, -50%) scale(1);
}
}
</style>

View File

@@ -0,0 +1,64 @@
<template>
<view class="price-root">
<text v-if="isSymbol" class="money">{{ symbol }}</text>
<text class="number">{{ money }}</text>
</view>
</template>
<script lang="ts" setup>
/**
* jx-price 组件
* @param (symbol) ¥ 占位符
* @param (isSymbol) 是否显示 ¥ 符号 默认显示
* @emit (isMoney) 是否格式化
* @param (price) 金钱
* @param (color) 颜色
* @param (size) 大小
*/
import { computed } from 'vue'
interface priceType {
symbol?: string
isSymbol?: boolean
isMoney?: boolean
price?: number | string
color?: string
size?: string
sizeM?: string
sizeN?: string
}
const props = withDefaults(defineProps<priceType>(), {
symbol: '¥',
isSymbol: true,
price: '0',
isMoney: true,
color: '#969696',
size: '32rpx',
sizeM: '32rpx',
sizeN: '32rpx',
})
const money = computed(() => {
if (props.isMoney) {
return (+props.price / 100).toFixed(2)
} else {
return props.price
}
})
</script>
<style lang="scss" scoped>
.price-root {
display: inline-block;
color: v-bind(color);
font-size: v-bind(size);
}
.money {
font-size: v-bind(sizeM);
}
.number {
font-size: v-bind(sizeN);
}
</style>

View File

@@ -0,0 +1,89 @@
<template>
<text>¥{{ earning }}</text>
<image
class="not-rot"
v-if="earning >= 100 && isTip"
src="https://image.jxc4.com/image/55bf8b7218f23db8cf3b39531dccf738.png"
mode="scaleToFill"
/>
</template>
<script lang="ts" setup>
import { store } from '@/store'
import { computed } from 'vue'
interface PropsType {
order: AnyObject
color?: string
isTip?: boolean
}
const props = withDefaults(defineProps<PropsType>(), {
color: '#000',
isTip: true,
})
const isPointStore = computed(() => {
return store.getters['storeInfo/isPointStore']
})
const earning = computed(() => {
const order = props.order
if (Object.keys(order).length) {
if (isPointStore.value) {
return order.newEarningPrice
? (order.newEarningPrice / 100).toFixed(2)
: '0.00'
} else {
return order.earningPrice ? (order.earningPrice / 100).toFixed(2) : '0.00'
}
} else {
return 0.0
}
})
</script>
<style lang="scss" scoped>
text {
color: v-bind(color);
}
// 商品数量
.order-totalCount {
display: flex;
align-items: center;
padding: 15rpx;
border-bottom: 2rpx dashed #e7e7e7;
color: #585858;
.play-money {
margin-left: 30rpx;
}
.totalCount {
margin-right: 25rpx;
}
}
.not-rot {
position: absolute;
bottom: 125rpx;
right: 20rpx;
width: 150rpx;
height: 150rpx;
text-align: center;
animation: enlarge 1s linear infinite;
}
@keyframes enlarge {
0% {
transform: scale(0.95);
}
50% {
transform: scale(1.05);
}
100% {
transform: scale(0.95);
}
}
</style>

View File

@@ -0,0 +1,107 @@
<template>
<text>¥{{ earning }}</text>
<image
class="not-rot"
v-if="earning >= 100 && isTip"
src="https://image.jxc4.com/image/55bf8b7218f23db8cf3b39531dccf738.png"
mode="scaleToFill"
/>
</template>
<script lang="ts" setup >
import { store } from '@/store'
import { computed } from 'vue'
interface propsType {
orderData: AnyObject
color?: string
isTip?: boolean
size?: string
}
const props = withDefaults(defineProps<propsType>(), {
color: '#000',
isTip: true,
size: '32rpx',
})
const isPointStore = computed(() => {
return store.getters['storeInfo/isPointStore']
})
const earning: any = computed(() => {
const order = props.orderData
if (Object.keys(order).length) {
if (new Date(order.orderCreatedAt) < new Date('2020-06-07 18:00:00')) {
if (!(order.oldPayPercentage >= 50 && order.oldPayPercentage <= 100)) {
// 小于50
return (
((order.totalShopMoney - order.desiredFee) *
(100 - order.oldPayPercentage / 2)) /
100 /
100
).toFixed(2)
} else {
// 大于等于50
return (order.earningPrice / 100).toFixed(2)
}
} else {
let calcData = {
vendorPayPercentage: order.vendorPayPercentage,
actualPayPrice: order.actualPayPrice,
shopPrice: order.shopPrice,
isPointStore: isPointStore.value,
payPercentage: order.payPercentage,
earningPrice: order.earningPrice,
}
return singleCalcPrice(calcData)
}
} else {
return 0.0
}
})
function singleCalcPrice(calcData: any) {
if (calcData.vendorPayPercentage != 0) {
if (calcData.vendorPayPercentage < 50) {
return (calcData.actualPayPrice / 100).toFixed(2)
} else {
return (calcData.earningPrice / 100).toFixed(2)
}
} else {
if (calcData.isPointStore) {
return (calcData.actualPayPrice / 100).toFixed(2)
} else {
return (calcData.earningPrice / 100).toFixed(2)
}
}
}
</script>
<style lang="scss" scoped>
text {
color: v-bind(color);
font-size: v-bind(size);
font-weight: bold;
}
.not-rot {
position: absolute;
bottom: 125rpx;
right: 20rpx;
width: 150rpx;
height: 150rpx;
text-align: center;
animation: enlarge 1s linear infinite;
}
@keyframes enlarge {
0% {
transform: scale(0.95);
}
50% {
transform: scale(1.05);
}
100% {
transform: scale(0.95);
}
}
</style>

View File

@@ -0,0 +1,45 @@
/* common */
.view {
/* #ifndef APP-NVUE */
position: relative;
display: flex;
flex-direction: column;
/* #endif */
}
.flex-row {
flex-direction: row !important;
/* #ifndef APP-NVUE */
position: relative;
display: flex;
flex-direction: column;
/* #endif */
}
.items-center {
align-items: center !important;
/* #ifndef APP-NVUE */
position: relative;
display: flex;
flex-direction: column;
/* #endif */
}
.justify-center {
justify-content: center !important;
/* #ifndef APP-NVUE */
position: relative;
display: flex;
flex-direction: column;
/* #endif */
}
.absolute {
position: absolute;
}
//仅编译到vue页面
/* #ifndef APP-NVUE */
.show-scrollbar ::-webkit-scrollbar {width: 0;height: 0;background-color: transparent;}
.z-index{z-index: 999;}
/* #endif */

View File

@@ -0,0 +1,131 @@
export function getVersion() {
uni.hideLoading();
return new Promise((RES, REJ) => {
// 如果是app才检测
plus.runtime.getProperty(plus.runtime.appid, (inf) => {
RES(inf.version);
})
console.log('非app环境,不进行版本检测')
})
}
export function checkUpdate(version, sysInfo, config) {
return new Promise((RES, REJ) => {
let flag = true
let loading = false;
setTimeout(() => {
if (flag && config.loading) {
loading = true;
uni.showLoading({
title: config.loadingText,
mask: config.loadingMask
})
}
}, config.loadingDelay)
uni.request({
url: config.apiUrl,
method: 'GET',
sslVerify: false,
data: {
appId: config.id
},
success: (res) => {
flag = false
if (loading) {
uni.hideLoading();
}
if (res.statusCode === 200) {
if (res.data.code == 0) {
let newVarsion = JSON.parse(JSON.parse(res.data.data)[0].value).update
RES(newVarsion);
} else {
REJ('更新版本失败');
}
} else {
REJ('未知错误')
}
},
fail: (err) => {
flag = false
if (loading) {
uni.hideLoading();
}
uni.getNetworkType({
complete: res => {
let networkType = res.networkType || 'none';
if (networkType === 'none') {
REJ('当前无网络,请检查您的网络连接')
} else if (err.errMsg !== 'request:fail') {
console.error('err:', err)
REJ('未知错误')
}
}
});
}
})
})
}
export function restart() {
if (plus.os.name.toLowerCase() === 'android') {
plus.runtime.quit();
} else {
const threadClass = plus.ios.importClass("NSThread");
const mainThread = plus.ios.invoke(threadClass, "mainThread");
plus.ios.invoke(mainThread, "exit");
}
}
//style转化为通用
export function styleInto(str) {
let styleObject = '';
for (let i in str) {
styleObject += i.replace(/([A-Z])/g, "-$1").toLowerCase() + ':' + str[i] + ';'
}
return styleObject;
}
let tempFilePath
export function downloadFile({
url,
success,
fail,
progress
}) {
if (tempFilePath) {
progress(100)
success(tempFilePath)
} else {
let percent = 0
uni.downloadFile({
url: url,
success: (res) => {
if (res.statusCode === 200) {
progress(100)
tempFilePath = res.tempFilePath
success(res.tempFilePath)
} else {
fail()
uni.showToast({
title: '下载失败,请重试',
duration: 2000,
icon: 'none'
})
}
},
fail: () => {
fail()
uni.showToast({
title: '下载失败,请重试',
duration: 2000,
icon: 'none'
})
}
}).onProgressUpdate((res) => {
if (percent !== res.progress) {
percent = res.progress
progress(res.progress)
}
});
}
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,57 @@
<template>
<view
:style="buttonStyle"
class="flex-row justify-center items-center new-update"
>
<text>{{ text }}</text>
</view>
</template>
<script lang="ts" setup >
import { computed, ref } from 'vue'
import { styleInto } from '../../js/api'
interface propsType {
text?: string
size?: string | number
color?: string
width?: number
height?: number
background?: string
disabledBackground?: string
radius?: number
disabled?: boolean
isIcon?: boolean
}
const props = withDefaults(defineProps<propsType>(), {
text: 'DNVUE',
size: 30,
color: 'white',
width: 520,
height: 80,
background: '#04c260',
disabledBackground: '#d9d9d9',
radius: 8,
disabled: false,
isIcon: false,
})
const status = ref<boolean>(false)
const buttonStyle = computed(() => {
let style: any = {
width: `${props.width}rpx`,
height: `${props.height}rpx`,
borderRadius: `${props.radius}rpx`,
opacity: status.value ? 0.8 : 1,
color: props.color,
}
return style
})
</script>
<style lang="scss" scoped>
@import '../../css/index.scss';
.new-update {
background-image: linear-gradient(125deg, #84e366, #04c260);
}
</style>

View File

@@ -0,0 +1,158 @@
<template>
<view class="z-index view">
<varsion-transition
@click="onMask"
:mode-class="['fade']"
:style-custom="maskClass"
:show="isShow"
>
</varsion-transition>
<varsion-transition
@change="onChange"
:mode-class="popupData[direction].modeClass"
:style-custom="popupData[direction].popupClass"
:show="isShow"
>
<slot></slot>
</varsion-transition>
</view>
</template>
<script lang="ts" setup>
/**
* popup 弹出层
* @description 弹出层组件
* @tutorial https://dnvue.dengqichang.cn/component/feedback_component/n-popup.html
* @property {Boolean} show 控制显示或者隐藏
* @property {String} direction 弹出层方向
* @value top 顶部弹出
* @value bottom 底部弹出
* @value left 左侧弹出
* @value right 右侧弹出
* @value center 中间弹出
* @property {Boolean} mask-close 点击遮罩层是否可关闭
* @event {Function()} change 当打开或者关闭时返回弹出层状态
*/
import { ref, watch } from 'vue'
import varsionTransition from './varsion-transition.nvue'
interface propsType {
show?: boolean
direction?: string
maskClose?: boolean
}
const props = withDefaults(defineProps<propsType>(), {
show: false,
direction: 'bottom',
maskClose: true,
})
const isShow = ref<boolean>(false)
// 遮罩层
const maskClass = ref<AnyObject>({
position: 'fixed',
bottom: 0,
top: 0,
left: 0,
right: 0,
backgroundColor: 'rgba(0, 0, 0, 0.4)',
})
const popupData = ref<AnyObject>({
top: {
modeClass: ['slide-top', 'fade'],
popupClass: {
position: 'fixed',
left: 0,
right: 0,
top: 0,
backgroundColor: '#FFFFFF',
},
},
bottom: {
modeClass: ['slide-bottom', 'fade'],
popupClass: {
position: 'fixed',
left: 0,
right: 0,
bottom: 0,
backgroundColor: '#FFFFFF',
},
},
left: {
modeClass: ['slide-left', 'fade'],
popupClass: {
position: 'fixed',
bottom: 0,
top: 0,
left: 0,
backgroundColor: '#FFFFFF',
},
},
right: {
modeClass: ['slide-right', 'fade'],
popupClass: {
position: 'fixed',
bottom: 0,
top: 0,
right: 0,
backgroundColor: '#FFFFFF',
},
},
center: {
modeClass: ['fade', 'zoom-in'],
popupClass: {
position: 'fixed',
bottom: 0,
left: 0,
right: 0,
top: 0,
justifyContent: 'center',
alignItems: 'center',
},
},
})
// 监听是否有新版本
watch(
() => props.show,
(newVal: boolean) => {
if (newVal) {
open()
} else {
close()
}
}
)
//打开弹出层
function open() {
isShow.value = true
}
//关闭弹出层
function close(e?: AnyObject) {
if (isShow.value) {
isShow.value = false
}
}
//点击关闭弹出层
function onMask(e: AnyObject) {
if (props.maskClose) {
isShow.value = false
}
}
const emit = defineEmits<{
(e: 'change', data: any): void
}>()
//当打开或者关闭返回信息
function onChange(e: AnyObject) {
emit('change', {
detail: e.detail,
})
}
</script>
<style lang="scss" scoped>
@import '../../css/index.scss';
</style>

View File

@@ -0,0 +1,281 @@
<template>
<view
style="display: flex; flex-direction: column"
v-if="isShow"
ref="anis"
class="view wrap-transition"
:class="[ani.in]"
:style="'transform:' + transform + ';' + stylesObject"
@click.stop="change"
@click.stop.prevent
@touchmove.stop.prevent
>
<slot></slot>
</view>
</template>
<script lang="ts" setup>
import { computed, nextTick, ref, watch } from 'vue'
/**
* Transition 过渡动画
* @description 简单过渡动画组件
* @tutorial
* @property {Boolean} show = [false|true] 控制组件显示或隐藏
* @property {Array} modeClass = [fade|slide-top|slide-right|slide-bottom|slide-left|zoom-in|zoom-out] 过渡动画类型
* @value fade 渐隐渐出过渡
* @value slide-top 由上至下过渡
* @value slide-right 由右至左过渡
* @value slide-bottom 由下至上过渡
* @value slide-left 由左至右过渡
* @value zoom-in 由小到大过渡
* @value zoom-out 由大到小过渡
* @property {Number} duration 过渡动画持续时间
* @property {Object} style-custom 组件样式,同 css 样式,注意带’-‘连接符的属性需要使用小驼峰写法如:`backgroundColor:red`
*/
// #ifdef APP-NVUE
const animation = uni.requireNativePlugin('animation')
// #endif
interface propsType {
show?: boolean
modeClass?: any
duration?: number
styleCustom?: any
}
const props = withDefaults(defineProps<propsType>(), {
show: false,
modeClass: [],
duration: 300,
styleCustom: {},
})
const isShow = ref<boolean>(false)
const transform = ref<string>('')
const ani = ref<AnyObject>({
in: '',
active: '',
})
watch(
() => props.show,
(newVal: boolean) => {
if (newVal) {
open()
} else {
close()
}
}
)
const stylesObject = computed(() => {
let oldStyle = {
'transition-duration': props.duration / 1000 + 's',
}
let styles = Object.assign(props.styleCustom, oldStyle)
let transfrom = ''
for (let i in styles) {
let line = toLine(i)
transfrom += line + ':' + styles[i] + ';'
}
return transfrom
})
const emit = defineEmits<{
(e: 'click', data: any): void
(e: 'change', data: any): void
}>()
function change(event: AnyObject) {
// 阻止继续冒泡.
event.stopPropagation()
emit('click', {
detail: isShow.value,
})
}
function open() {
clearTimeout(timer)
isShow.value = true
transform.value = ''
ani.value.in = ''
for (let i in getTranfrom(false)) {
if (i === 'opacity') {
ani.value.in = 'fade-in'
} else {
transform.value += `${getTranfrom(false)[i]} `
}
}
nextTick(() => {
setTimeout(() => {
_animation(true)
}, 50)
})
}
function close(type?: any) {
clearTimeout(timer)
_animation(false)
}
let timer: any = null
const anis = ref<any>(null)
function _animation(type: any) {
let styles = getTranfrom(type)
// #ifdef APP-NVUE
if (!anis) return
animation.transition(
anis.value,
{
styles,
duration: props.duration, //ms
timingFunction: 'ease',
needLayout: false,
delay: 0, //ms
},
() => {
if (!type) {
isShow.value = false
}
emit('change', {
detail: isShow.value,
})
}
)
// #endif
// #ifndef APP-NVUE
transform.value = ''
for (let i in styles) {
if (i === 'opacity') {
ani.value.in = `fade-${type ? 'out' : 'in'}`
} else {
transform.value += `${styles[i]} `
}
}
timer = setTimeout(() => {
if (!type) {
isShow.value = false
}
emit('change', {
detail: isShow.value,
})
}, props.duration)
// #endif
}
function getTranfrom(type: any) {
let styles: any = {
transform: '',
}
props.modeClass.forEach((mode: any) => {
switch (mode) {
case 'fade':
styles.opacity = type ? 1 : 0
break
case 'slide-top':
styles.transform += `translateY(${type ? '0' : '-100%'}) `
break
case 'slide-right':
styles.transform += `translateX(${type ? '0' : '100%'}) `
break
case 'slide-bottom':
styles.transform += `translateY(${type ? '0' : '100%'}) `
break
case 'slide-left':
styles.transform += `translateX(${type ? '0' : '-100%'}) `
break
case 'zoom-in':
styles.transform += `scale(${type ? 1 : 0.8}) `
break
case 'zoom-out':
styles.transform += `scale(${type ? 1 : 1.2}) `
break
}
})
return styles
}
function _modeClassArr(type: any) {
let mode = props.modeClass
if (typeof mode !== 'string') {
let modestr = ''
mode.forEach((item: any) => {
modestr += item + '-' + type + ','
})
return modestr.substr(0, modestr.length - 1)
} else {
return mode + '-' + type
}
}
function toLine(name: any) {
return name.replace(/([A-Z])/g, '-$1').toLowerCase()
}
</script>
<style lang="scss" scoped>
.view {
/* #ifndef APP-NVUE */
position: relative;
display: flex;
flex-direction: column;
/* #endif */
}
.wrap-transition {
transition-timing-function: ease;
transition-duration: 0.4s;
transition-property: transform, opacity;
}
.fade-in {
opacity: 0;
}
.fade-active {
opacity: 1;
}
.slide-top-in {
transform: translateY(-100%);
}
.slide-top-active {
transform: translateY(0);
}
.slide-right-in {
transform: translateX(100%);
}
.slide-right-active {
transform: translateX(0);
}
.slide-bottom-in {
transform: translateY(100%);
}
.slide-bottom-active {
transform: translateY(0);
}
.slide-left-in {
transform: translateX(-100%);
}
.slide-left-active {
transform: translateX(0);
opacity: 1;
}
.zoom-in-in {
transform: scale(0.8);
}
.zoom-out-active {
transform: scale(1);
}
.zoom-out-in {
transform: scale(1.2);
}
</style>

View File

@@ -0,0 +1,98 @@
<template>
<view>
<text @click="onClick" :style="textStyle">{{ text }}</text>
</view>
</template>
<script lang="ts" setup>
import { styleInto } from '../../js/api'
import { computed } from 'vue'
/**
* text 文本
* @description 文本组件
* @tutorial https://dnvue.dengqichang.cn/component/basic_component/n-text.html
* @property {String, Number} text 文本内容
* @property {String, Number} size 字号(rpx)
* @property {String} color 文本颜色
* @property {String, Number} lines 超出行省略
* @property {String} align 文本位置
* @value left 左侧
* @value center 中间
* @value right 右侧
* @property {String, Number} leading 行高
* @property {Boolean} weight 文本加粗
* @property {String} decoration 文本修饰
* @value none 默认值,定义标准的文本。
* @value line-through 定义穿过文本下的一条线
* @value underline 定义文本下的一条线
* @property {String, Number} width 宽度
* @property {Object} style-custom 组件自定义样式,同 css 样式。注意带’-‘连接符的属性需要使用小驼峰写法如:`backgroundColor:red`
* @event {Function()} click 点击事件
*/
interface propsType {
text?: string | number
size?: string | number
color?: string
lines?: string | number
align?: string
leading?: string | number
weight?: boolean
decoration?: string
width?: string | number
styleCustom?: any
}
const props = withDefaults(defineProps<propsType>(), {
text: '',
size: 30,
color: '#333333',
lines: '',
align: 'left',
leading: '',
weight: false,
decoration: 'none',
width: '',
styleCustom: {},
})
const textStyle = computed(() => {
let oldStyle = {
fontSize: `${props.size}rpx`,
textAlign: props.align,
fontWeight: props.weight ? 'bold' : 'normal',
textDecoration: props.decoration,
color: props.color,
}
let style = Object.assign(props.styleCustom, oldStyle)
/* 超出省略 */
if (!!props.lines) {
let lines_temp = {
textOverflow: 'ellipsis',
lines: props.lines,
overflow: 'hidden',
display: '-webkit-box',
'-webkit-box-orient': 'vertical',
'-webkit-line-clamp': props.lines,
}
style = Object.assign(style, lines_temp)
}
/* 行高 */
if (!!props.leading) {
style.lineHeight = `${props.leading}rpx`
}
/* 宽度 */
if (props.width !== '') {
style.width = `${props.width}rpx`
}
return styleInto(style)
})
const emit = defineEmits<{
(e: 'click', data: any): void
}>()
function onClick(e: any) {
emit('click', e)
}
</script>
<style lang="scss">
</style>

View File

@@ -0,0 +1,463 @@
<template>
<varsion-popup
:show="show"
direction="center"
:mask-close="release.isForceUpdate"
>
<view class="view box-size">
<image :src="defaultBg" class="box-size absolute"></image>
<view class="view box-size absolute desc line-4">
<view class="find-new-version">发现新版本V{{ release.version }}</view>
<varsion-text
:color="textColor"
:text="release.description"
:lines="lines"
/>
</view>
<view
class="absolute footer"
:style="{ marginTop: `${release.isForceUpdate ? 540 : 520}rpx` }"
>
<varsion-button
size="32"
:disabled="!btnVisible"
@click="handleUpdate"
:color="btnTextColor"
:background="btnBgColor"
:width="400"
:radius="40"
:text="btnText"
></varsion-button>
<view
v-if="!release.isForceUpdate && btnVisible"
class="items-center-close"
>
<view class="blose-btn" @click="close">
<jx-icon icon="shanchu" :size="90" color="#eee" />
</view>
</view>
<view v-if="!btnVisible" style="margin-top: 10rpx"
><progress :percent="percent" :color="btnBgColor"></progress
></view>
</view>
</view>
</varsion-popup>
</template>
<script lang="ts" setup>
import { checkUpdate, downloadFile } from '../../js/api.js'
import varsionButton from '../varsion-button/varsion-button.nvue'
import varsionText from '../varsion-text/varsion-text.nvue'
import varsionPopup from '../varsion-popup/varsion-popup.nvue'
import defaultBgImg from '../../js/img'
import { computed, onMounted, ref } from 'vue'
import { store } from '@/store'
/**
* version-update 版本更新
* @description 版本更新组件
* @property {String} id 应用id
* @property {String} version 是否手动传入版本号而不使用系统自动获取的版本
* @property {Boolean} loading 是否显示加载
* @property {String} loadingText 加载中文本,默认'检查更新中'
* @property {String} loadingMask 加载点击遮罩关闭功能是否关闭
* @property {String, Number} loadingDelay 加载框多久出现默认1500ms
* @property {String, Number} lines 超出行省略
*
* @property {String, Number} btnBgColor 按钮背景颜色
* @property {String, Number} btnTextColor 按钮文字颜色
* @property {String, Number} secondaryBtnText 暂不更新按钮文字,默认以后再说
* @property {String, Number} secondaryBtnTextColor 暂不更新按钮文字颜色
*
* @property {String, Number} textColor 更新说明文字颜色
* @property {String, Number} bgImage 自定义背景图
*
* @property {String, Number} errTimes 安装错误次数超过此值提示打开浏览器下载,一般若由高版本降回低版本会出现无法安装的情况
* @property {String, Number} auto 是否自动检查新版本默认true
*
* @event {Function()} check 检查事件,获取到版本数据就会触发,适合需要自定义更新弹窗出现逻辑的
* @event {Function()} finish 完成事件,获取到版本且不用更新触发
* @event {Function()} error 错误事件,发生错误触发
*/
interface propsType {
id: string
apiUrl?: string
pageUrl?: string
loading?: boolean
loadingText?: string
loadingMask?: boolean
loadingDelay?: string | number
lines?: number
version?: string
bgImage?: string
textColor?: string
btnBgColor?: string
btnTextColor?: string
secondaryBtnText?: string
secondaryBtnTextColor?: string
errToast?: boolean
errTimes?: number
auto?: boolean
uniqueId?: string
}
const props = withDefaults(defineProps<propsType>(), {
id: '',
apiUrl: 'https://wx.jxc4.com/v2/version/GetVersionController',
pageUrl: 'http://www.jxc4.com/managerApp/downApp.html',
loading: true,
loadingText: '检查更新中',
loadingMask: true,
loadingDelay: 1500,
lines: 5,
textColor: '#1e1e1e',
btnBgColor: '#04c260',
btnTextColor: '#FFFFFF',
secondaryBtnText: '以后再说',
secondaryBtnTextColor: '#afafaf',
errToast: true,
errTimes: 2,
auto: true,
})
function close() {
show.value = false
emit('close', '')
}
const show = ref<boolean>(false)
const init = ref<boolean>(false)
const release = ref<AnyObject>({
needUpdate: true,
isHBuildUpdate: false,
isForceUpdate: true,
version: '0.1.0',
description: '',
pkgUrl: '',
wgtUrl: '',
})
const btnVisible = ref<boolean>(true)
const btnText = ref<string>('立即升级')
const percent = ref<number>(0)
const tempPath = ref<string>('')
const installFlag = ref<boolean>(false)
const defaultBg = ref<string>(defaultBgImg)
const nowVersion = ref<string>('')
const openCount = ref<number>(0)
const config = computed(() => {
return {
id: props.id,
apiUrl: props.apiUrl,
uniqueId: props.uniqueId,
loading: props.loading,
loadingText: props.loadingText,
loadingMask: props.loadingMask,
loadingDelay: props.loadingDelay,
}
})
const downUrl = computed(() => {
if (!release.value.needUpdate) {
return undefined
}
if (!release.value.isHBuildUpdate) {
return release.value.wgtUrl
}
return release.value.pkgUrl
})
const isHot = computed(() => {
return !release.value.isHBuildUpdate
})
const sysInfo = ref<any>('')
onMounted(() => {
if (percent.value == 100) {
btnText.value = '马上安装'
}
if (!props.id) {
uni.showToast({
title: '请传入应用id',
icon: 'none',
duration: 4000,
})
return
}
if (props.auto) {
init.value = true
}
uni.getSystemInfo({
success: (info) => {
sysInfo.value = info
nowVersion.value = sysInfo.value.appWgtVersion || sysInfo.value.appVersion
check()
},
})
})
const emit = defineEmits<{
(e: 'check', data: any): void
(e: 'finish', data: any): void
(e: 'error', data: any): void
(e: 'close', data: any): void
}>()
function check() {
checkUpdate(props.version || nowVersion.value, sysInfo.value, config.value)
.then((res) => {
if(sysInfo.value.platform === 'ios' && res.appleId.length){
let str = res.appleId
res.appleId = str.split(',')[0]
res.version = str.split(',')[1]
}
release.value = res
emit('check', res)
if (res.needUpdate) {
if (init.value) {
show.value = true
}
} else {
if (res.isTest) {
console.log('测试版' + (props.version || nowVersion.value))
}
emit('finish', res)
}
init.value = true
})
.catch((err) => {
emit('error', err)
if (props.errToast) {
uni.showToast({
title: err,
icon: 'none',
duration: 4000,
})
}
})
}
function handleUpdate() {
if (
sysInfo.value.uniPlatform === 'web' ||
sysInfo.value.uniPlatform === 'h5'
) {
uni.showToast({
icon: 'none',
title: '非app无法安装',
})
btnVisible.value = true
return
}
// 如果是ios并且非热更新
if (sysInfo.value.platform === 'ios' && !isHot.value) {
if (release.value.appleId) {
plus.runtime.launchApplication(
{
action: `https://apps.apple.com/cn/app/%E4%BA%AC%E8%A5%BF%E8%8F%9C%E5%B8%82%E5%95%86%E5%AE%B6%E7%89%88/${release.value.appleId}`,
},
(e) => {
uni.jxConfirm({
title: '跳转到appStore失败',
content: '请向app反馈错误信息' + e.message,
confirmText: '复制错误信息',
success: () => {
uni.setClipboardData({
data: e.message,
success: () => {},
})
},
})
}
)
} else {
uni.showToast({
title: '未配置appleId无法跳转到appStore请向app反馈',
icon: 'none',
duration: 4000,
})
}
return
}
if (tempPath.value !== '') {
openFile()
return
}
if (btnVisible.value) {
btnVisible.value = false
downloadFile({
url: downUrl.value,
success: (filePath: any) => {
percent.value = 100
tempPath.value = filePath
store.commit('serveInfo/setAppFilePath', filePath)
btnText.value = '马上安装'
openFile()
},
fail: (e: any) => {
console.error('下载文件', e)
installFail()
btnVisible.value = true
},
progress: (progress: any) => {
percent.value = progress
if (progress == 100) {
btnText.value = '马上安装'
}
let port = uni.getSystemInfoSync().platform
switch (port) {
case 'android':
const notify = uni.requireNativePlugin('Ba-Notify')
notify.show({
extend: progress,
channelID: '6',
channelName: '进度通知',
ID: 6,
notifyType: 6,
ticker: 'Ticker',
title: '京西菜市更新',
content: '正在下载',
isSound: false,
isVibrate: false,
maxProgress: 100,
progress: progress, //当前进度
indeterminate: false, //是否模糊进度显示
finishText: '下载完成',
})
break
case 'ios':
console.log('iOS不支持此功能')
break
}
},
})
}
}
function openFile() {
btnVisible.value = true
if (!installFlag.value) {
installFlag.value = true
uni.showToast({
icon: 'none',
title: isHot.value ? '正在安装中' : '正在打开安装程序',
success: () => {
uni.navigateBack()
},
})
if (isHot.value) {
//热更新
plus.runtime.install(
tempPath.value,
{
force: false,
},
() => {
uni.hideToast()
setTimeout(() => {
plus.runtime.restart()
}, 100)
},
(e) => {
console.error('热更新失败', e)
uni.hideToast()
installFail()
}
)
} else {
setTimeout(() => {
uni.openDocument({
filePath: tempPath.value,
fail: (e) => {
console.error('打开apk失败', e)
installFail()
},
complete: () => {
uni.hideToast()
installFlag.value = false
openCount.value++
if (openCount.value > props.errTimes) {
installFail()
}
},
})
}, 500)
}
}
}
function installFail() {
uni.jxConfirm({
title: '温馨提醒',
content:
'请问是否出现安装包损坏或其他原因导致无法正常安装新版本的情况?请前往浏览器下载最新版本手动安装',
confirmText: '立刻前往',
success: () => {
plus.runtime.openURL(props.pageUrl, () => {
openUrlFail()
})
},
})
}
function openUrlFail() {
uni.jxConfirm({
title: '温馨提醒',
content: '打开浏览器失败,请复制下载地址,手动打开手机浏览器输入地址下载',
confirmText: '复制',
success: () => {
uni.setClipboardData({
data: props.pageUrl,
success: () => {},
})
},
})
}
</script>
<style lang="scss" scoped>
@import '../../css/index.scss';
.box-size {
width: 500rpx;
height: 650rpx;
border-radius: 0 0 10rpx 10rpx;
}
.desc {
margin-top: 250rpx;
padding: 0 30rpx;
width: 431rpx;
}
.find-new-version {
text-align: center;
margin-bottom: 20rpx;
font-weight: bold;
}
.desc-text {
line-height: 44rpx;
font-size: 30rpx;
}
.items-center-close {
align-items: center !important;
/* #ifndef APP-NVUE */
position: absolute;
display: flex;
flex-direction: column;
width: 500rpx;
bottom: -200rpx;
margin-left: -50rpx;
/* #endif */
.blose-btn {
text-align: center;
}
}
.footer {
margin-left: 50rpx;
}
</style>

View File

@@ -0,0 +1,239 @@
<template>
<view class="upload-pic">
<view class="pic-title">{{ title }}</view>
<view class="pic-wrapper" :style ="{'justify-content' :type === 'invoiceImg' ? 'center': '' }">
<view class="left" @tap="btnShow = true">
<!-- 操作面板 -->
<view v-if="type === 'invoiceImg' && !img" :class="{'isInvoice' : type === 'invoiceImg' }">点击上传</view>
<view class="upload-btn" :class="{ active: btnShow }">
<text @tap.stop="updateImg" class="upload-img">{{
img ? '修改' : '上传'
}}</text>
<text @tap.stop="deleteImg" class="delete" v-if="img"> </text>
<text @tap.stop="btnShow = false" class="upload-cancel"> </text>
</view>
<!-- 获取到的图片 -->
<img class="img" :src="img" v-if="img" />
<!-- 正面 -->
<img
src="https://image.jxc4.com/image/d40844356c5d03975cca9f9bff6e3aeb.png"
v-if="type === 'idCardFront' && !img"
/>
<!-- 背面 -->
<img
class="img"
src="https://image.jxc4.com/image/388f6e26316128c33591f6b1ce6aaed0.png"
v-if="type === 'idCardBack' && !img"
/>
<!-- 手持 -->
<img
class="img"
src="https://image.jxc4.com/image/1f173d964970abb13921431a2c2cde02.png"
v-if="type === 'idCardHand' && !img"
/>
<!-- 营业执照 -->
<img
class="img"
src="https://image.jxc4.com/image/06ba0d91dd8bae128776358af0e3b0b1.png"
v-if="type === 'licence' && !img"
/>
<img
class="img"
src="https://image.jxc4.com/image/ab82b2445366d3579b7064987787f3b6.png"
v-if="type === 'licence2Image' && !img"
/>
</view>
<view
class="right"
v-if="type !== 'invoiceImg'"
:class="{
'card-front': type === 'idCardFront',
'card-back': type === 'idCardBack',
'card-hand': type === 'idCardHand',
licence: type === 'licence',
licence2: type === 'licence2Image',
}"
></view>
</view>
</view>
</template>
<script lang="ts" setup>
/**
* @dsec 京西上传图片
* @param {title}-title 文字提示
* @param {type}-上传类型
* @param {img}-回显图片地址
* @return {imgChange}-type: delet 删除图片 type: upload上传图片
*/
import { onShow } from '@dcloudio/uni-app'
import { ref } from 'vue'
/**
* props
*/
interface UploadImgType {
title: string
type: string
img: string
}
defineProps<UploadImgType>()
/**
* emit
*/
interface EmitType {
img: string
type: string
}
const emit = defineEmits<{
(e: 'imgChange', data: EmitType): void
}>()
/**
* 遮罩层
*/
const btnShow = ref<boolean>(false)
onShow(() => {
btnShow.value = false
})
/**
* 删除图片
*/
function deleteImg() {
uni.jxConfirm({
title: '提示',
content: '确定要删除此图片吗',
success: () => {
emit('imgChange', { img: '', type: 'delet' })
btnShow.value = false
},
})
}
/**
* 修改图片
*/
function updateImg() {
uni.jxConfirm({
title: '相机/相册权限说明',
content: '便于您使用该功能拍照上传您的照片/图片用于同步第三方平台信息等场景中使用相机或读取相册文件内容',
success() {
uni.chooseImage({
count: 1,
sizeType: ['original'],
sourceType: ['album', 'camera'],
success(res) {
emit('imgChange', { img: res.tempFilePaths[0], type: 'upload' })
btnShow.value = false
},
})
}
})
}
</script>
<style lang="scss" scoped>
.isInvoice {
width: 340rpx;
height: 255rpx;
display: flex;
justify-content: center;
align-items: center;
}
.upload-pic {
padding: 20rpx;
.pic-title {
font-size: 34rpx;
font-weight: 400;
padding-bottom: 20rpx;
}
.pic-wrapper {
display: flex;
justify-content: space-between;
.left,
.right {
width: 340rpx;
height: 255rpx;
}
.left {
border: 1rpx dotted rgba(204, 204, 204, 1);
overflow: hidden;
position: relative;
.img {
width: 100%;
height: 100%;
}
}
.right {
border: 1rpx solid rgba(204, 204, 204, 1);
}
}
.upload-btn {
position: absolute;
z-index: 999;
background: rgba(black, 0.1);
left: 0;
right: 0;
top: 0;
bottom: 0;
display: flex;
flex-flow: column;
align-items: center;
justify-content: center;
transition: all 0.2s ease-out;
transform: scale(0);
}
.active {
transform: scale(1);
background: rgba(black, 0.5);
}
.upload-img,
.upload-cancel,
.delete {
color: white;
font-size: 36rpx;
padding: 10rpx 0;
width: 100%;
text-align: center;
font-weight: 500;
}
.card-front {
background: url(https://image.jxc4.com/3a286c49546a99e0f407d16de94d95c4.png)
center center no-repeat;
background-size: cover;
}
.card-back {
background: url(https://image.jxc4.com/52f76d4e63391befba9e16869ac1242c.png)
center center no-repeat;
background-size: cover;
}
.card-hand {
background: url(https://image.jxc4.com/24231d9fbe5b7c1479bd3c7f82e08835.png)
center center no-repeat;
background-size: cover;
}
.licence {
background: url(https://image.jxc4.com/6ba62da13b7e71134af379b8e177a52a.png)
center center no-repeat;
background-size: cover;
}
.licence2 {
background: url(https://image.jxc4.com/a8488f4de2066bf08028b5c562927916.png)
center center no-repeat;
background-size: cover;
}
.upload-wrapper {
height: calc(100vh - 300rpx);
}
}
</style>

View File

@@ -0,0 +1,665 @@
import merchant from "@/api/https/merchant";
import { setStorage, jx_default_storage_plugin, getStorage, cleatStorage } from "@/utils/storage";
import toast from "@/utils/toast";
import { timeFormatD } from "@/utils/tools";
import { store as newStore, store } from '@/store'
import configCms from "@/utils/configCms";
import Bluetooth from '@/utils/bluetoothPrinter/bluetooth'
import util from '@/utils/bluetoothPrinter/util'
import login from "@/api/https/login";
import { computed } from "vue";
import { emojiAnanlyze } from '@/utils/emoji'
/*************************************************
* 全局通用方法
* @param data 事实订单数据
*/
function useGlobalFunc() {
const bluetooth = new Bluetooth()
const playVoid = uni.createInnerAudioContext() // 创建音频实例
/*************************************************
* 退出登录
*/
function logOutFn() {
cleatStorage('token')
cleatStorage('userID')
cleatStorage('userType')
cleatStorage('storeID')
cleatStorage('storeName')
cleatStorage('userID2')
cleatStorage('mobile')
}
/*************************************************
* 获取实时订单数据
* @time 2023年2月1日 11点17分
* @param {data} 请求data数据
* @return {res} code:响应状态 data:响应数据 desc:错误信息
*/
async function globGetToDay(data: AnyObject) {
let orderNumber = await merchant.get_store_order_sale_info(data);
if (orderNumber.code == 0) {
return orderNumber.data
} else {
toast("实时订单数据异常", 2);
}
}
/*************************************************
* 查看详情图片
* @time 2023-02-01 11:18:09
* @param {}-
* @return {*}
*/
async function previewImage(url: string | Array<string>,index?:number) {
new Promise((resolve, reject) => {
uni.previewImage({
current: index ? index : typeof url === 'string' ? url : url[0],
urls: Array.isArray(url) ? url : [url],
longPressActions: {
itemList: ['保存图片'],
success(res) {
uni.showModal({
title: '相册权限使用说明',
content: '便于您保存图片与运营进行交流等场景中写入相册文件内容',
complete: (result) => {
if (result.confirm) {
uni.saveImageToPhotosAlbum({
filePath: Array.isArray(url) ? url[res.index] : url,
complete(r) {
if (r.errMsg === 'saveImageToPhotosAlbum:ok') {
toast('保存成功')
} else {
toast('保存失败')
}
}
})
}
}
})
}
},
success: (res: any) => {
resolve(res)
},
fail: (err: any) => {
toast(err)
reject(err)
}
})
})
}
/*************************************************
* 存储用户信息
* @param {object} [data] 用户信息数据
*/
let serveInfoTimer: any = null
async function setUserInfo(data: AnyObject) {
setStorage("token", data.token);
setStorage("userID", data.userID);
setStorage("userID2", data.userID2);
setStorage("mobile", data.mobile);
jx_default_storage_plugin()
// 防止ios app 出现认证信息还没有缓存就已经跳转请求了
let storeRes = await login.get_my_store_list({ version: '1.3.5' })
let dataList = storeRes.data || []
if (dataList.length == 0) {
return uni.jxAlert({
title: '提示',
content: '该账号未绑定门店请联系运营绑定加盟联系电话18048531223'
})
}
if (dataList.length == 1) {
let data = dataList[0]
setStorage("storeID", data.id);
setStorage('storeName', data.name)
uni.switchTab({ url: '/pages/merchant/index' })
return
}
clearTimeout(serveInfoTimer)
serveInfoTimer = setTimeout(() => {
uni.navigateTo({
url: "/subPages/switchStore/switchStore",
animationType: 'slide-in-top',
animationDuration: 500
})
}, 0)
}
/*************************************************
* app 微信登录
* @bangding {Function} 绑定
* @seccess {Function} 登录成功
*/
type appWxLoginType = {
bangding?: Function
success?: Function
}
function appWxLogin(options: appWxLoginType) {
if (plus.runtime.isApplicationExist({ pname: 'com.tencent.mm', action: 'weixin://' })) { // 判断用户是否安装了微信
// 微信开放平台的应用标识
// 预登录
let weixinService: AnyObject
plus.oauth.getServices((services) => {
if (services && services.length) {
for (var i = 0, len = services.length; i < len; i++) {
if (services[i].id === 'weixin') {
weixinService = services[i]
break
}
}
// 如果没有获取到微信服务,则退出授权
if (!weixinService) {
return uni.jxAlert({
title: '登录失败',
content: '请先下载微信',
})
}
// 进行微信授权,拿到 code
weixinService.authorize(async (event: AnyObject) => {
//此处获取code的关键
let data = {
authType: "weixinapp",
authSecret: event.code,
}
// event.code 发给后端验证,验证成功后处理业务
let res = await login.applets_login(data)
console.log('ZSW-res', res);
if (res.code == 0) {
// 第一次登录绑定手机号码
if (res.data.tokenType == 2) {
options.bangding && options.bangding(res.data.token)
}
// 登录成功
if (res.data.tokenType != 2) {
options.success && options.success(res.data)
}
} else {
if ((res.desc).indexOf('row') == -1) {
uni.jxAlert({
title: '提示',
content: `登录失败:${res.desc || res.data}`
})
} else {
uni.jxAlert({
title: '提示',
content: `登录失败:对不起该账号未绑定门店,请联系官方客服进行绑定!`
})
}
}
})
} else {
uni.jxAlert({
title: '提示',
content: '本机不支持微信登录',
})
}
})
} else {
uni.jxAlert({
title: '提示',
content: '请先下载微信',
})
}
}
/*************************************************
* 全局判断是否有新信息有信息就在tabar显示
*/
async function newMessage() {
let data = {
storeIDs: JSON.stringify([+getStorage('storeID')]),
fromReadCount: 0,
toReadCount: 0,
offset: 0,
pageSize: -1,
fromTime:
timeFormatD(+new Date() - 7 * 24 * 60 * 60 * 1000) + ' 00:00:00',
toTime: timeFormatD(+new Date()) + ' 23:59:59',
}
let msgRes = await merchant.Get_store_message_statuses(data)
if (msgRes.code == 0) {
let num = msgRes.data.totalCount
// 没有信息,移除
if (num == 0) {
store.commit('storeInfo/setIsNewMessage', false)
uni.removeTabBarBadge({ index: 3 })
} else {
store.commit('storeInfo/setIsNewMessage', true)
// 有信息显示
uni.setTabBarBadge({
index: 3,
text: num > 100 ? '99+' : '' + num,
})
}
}
}
/**************************************************************
* 复制订单信息内容
* @param {String} data 需要复制的内容
* @param {String} [text] 复制成功提示内容(非必填)
* @param {string} [errorT] 复制失败提示内容(非必填)
*/
function copyInfo(data: string, text = '复制成功', errorT = '复制失败') {
uni.setClipboardData({
data: data,
success() {
toast(text)
},
fail() {
toast(errorT)
}
})
}
/************************************************************
* 拨打电话
* @param {string} phoneNumber 将要拨号的手机号
* @param {String} [text] 拨号成功提示内容(非必填)
* @param {string} [errorT] 拨号失败提示内容(非必填)
*/
function phoneCall(phoneNumber: string, text = '拨号完成', errorT = '取消拨号') {
uni.jxConfirm({
title: '拨打电话权限说明',
content: '便于您快速地跳到拨号界面与运营进行交流',
success() {
uni.makePhoneCall({
phoneNumber: phoneNumber,
success() {
console.log(text)
},
fail() {
toast(errorT)
}
})
}
})
}
/*************************************************
* 打开微信小程序
* @param {string} [url] 跳转地址
* @param {string} [id] 小程序原始ID
*/
function openWeixin(url: string, id = 'gh_e9161397303e') {
if (plus.runtime.isApplicationExist({ pname: 'com.tencent.mm', action: 'weixin://' })) { // 判断用户是否安装了微信
// 跳转到微信小程序进行物料申请
plus.share.getServices(function (res) {
var sweixin = null;
for (var i = 0; i < res.length; i++) {
var t: AnyObject = res[i];
if (t.id == 'weixin') {
sweixin = t;
}
}
if (sweixin) {
sweixin.launchMiniProgram({
id: id, //这里写你的小程序原始id以gh开头
type: 0, //这里是不同的环境( 0-正式版; 1-测试版; 2-体验版。 默认值为0。
path: url, //这里是指 定页的路径,如需传参直接字符串拼接(首页可以省略)
});
}
}, function (res) {
uni.jxAlert({
title: '提示',
content: '打开小程序失败',
})
});
} else {
uni.jxAlert({
title: '温馨提示',
content: '请先下载微信',
})
}
}
/*************************************************
* 判断门店是否在营业中
* @param {any} [newTime] 需要判断的时间
*/
function isTrades(newTime: any): boolean {
let storeInfo = newStore.state.storeInfo.allStoreInfo
let businessTime: Array<any> = []
businessTime[0] = storeInfo.openTime1
businessTime[1] = storeInfo.closeTime1
businessTime[2] = storeInfo.openTime2
businessTime[3] = storeInfo.closeTime2
// 获取当前时间进行比较
let honer = newTime.getHours()
let minutes = newTime.getMinutes() < 10 ? '0' + newTime.getMinutes() : newTime.getMinutes()
let time: number = +(String(honer) + String(minutes))
if (
(time >= businessTime[0] && time <= businessTime[1]) || (time >= businessTime[2] && time <= businessTime[3])
) {
return true // 未休息
} else {
return false // 休息中
}
}
/*************************************************
* 获取当前app是否选哟更新
* @return {Boolean} isUpdate 是否需要进行更行
*/
async function watchVersion(fn: Function) {
let res = await merchant.get_app_varsion({ appId: configCms.appId })
let systemInfo = uni.getSystemInfoSync()
let version = ''
let versions:AnyObject = {}
if(systemInfo.platform === 'android'){
versions = JSON.parse(res.data[0].value).update
version = versions.version
}else{
version = JSON.parse(res.data[0].value).other.appName.split(',')[1]
}
let versionInfo = compareVersions(version,systemInfo.appVersion)
if (versionInfo) {
fn && fn(true, versions)
} else {
fn && fn(false, versions)
}
}
function compareVersions(v1: string, v2: string) {
var regEx = /(\.0)+[^\.]*$/
var v1parts = v1.replace(regEx, '').split('.')
var v2parts = v2.replace(regEx, '').split('.')
for (var i = 0; i < v1parts.length; ++i) {
if (v2parts.length == i) {
return true
}
if (v1parts[i] == v2parts[i]) {
continue
} else if (v1parts[i] > v2parts[i]) {
return true
} else {
return false
}
}
if (v1parts.length != v2parts.length) {
return false
}
return false
}
/*************************************************
* 格式化今日订单数据
*/
function wholeCalcPrice(calcData: AnyObject) {
if (calcData.isPointStore) {
if (calcData.isNotQuote || calcData.isZero) {
return calcData.actualPayPrice
? (calcData.actualPayPrice / 100).toFixed(2)
: 0;
} else {
if (calcData.isUpperfif) {
return calcData.earningPrice
? (calcData.earningPrice / 100).toFixed(2)
: 0;
} else {
return "请按平台查看";
}
}
} else {
if (calcData.isUpperfif || calcData.isZero) {
return calcData.earningPrice
? (calcData.earningPrice / 100).toFixed(2)
: 0;
} else {
return "请按平台查看";
}
}
}
/*************************************************
* 格式化今日订单数据
*/
function singleCalcPrice(calcData: AnyObject) {
if (calcData.vendorPayPercentage != 0) {
if (calcData.vendorPayPercentage < 50) {
return (calcData.actualPayPrice / 100).toFixed(2)
} else {
return (calcData.earningPrice / 100).toFixed(2)
}
} else {
if (calcData.isPointStore) {
return (calcData.actualPayPrice / 100).toFixed(2)
} else {
return (calcData.earningPrice / 100).toFixed(2)
}
}
}
/*************************************************
* 查询打印机状态并连接
*/
function setPrinterStatus() {
// 获取打印机信息
let data: any = getStorage('commitBTDevCharact')
setInterval(() => {
let isPlay = store.state.storeInfo.isConnectPrinter
// 判断打印机是否在线
util.notifyBLEState(data.deviceId, data.serviceId, data.uuid)
.then(async (res) => {
if (res != 12) {
console.log('连接失败')
await bluetooth.reconnect()
if (!isPlay) return
playVoidFn()
store.commit('storeInfo/setIsConnectPrinter', false)
} else {
console.log('连接正常')
store.commit('storeInfo/setIsConnectPrinter', true)
}
}).catch(async () => {
console.log('连接失败')
await bluetooth.reconnect()
if (!isPlay) return
playVoidFn()
store.commit('storeInfo/setIsConnectPrinter', false)
})
}, 1000 * 20)
}
// 播放音频
function playVoidFn() {
playVoid.src = '/static/audio/close_printer.mp3'
playVoid.stop()
playVoid.play()
}
// ******************** 判断是否有淘鲜达 *****************************
//#region
const storeMaps = computed(() => {
return store.state.storeInfo.allStoreInfo
})
function isTxd() {
let state = false
storeMaps.value.StoreMaps.forEach((item: AnyObject) => {
if (item.vendorID == 16) {
state = true
}
})
return state
}
//#endregion
/**
* 查询美团/饿百的IM状态
*/
const getMtStoreIMStatus = async () => {
let mtStore = isExistPlatformID(1)
let ebStore = isExistPlatformID(3)
let data = []
if (mtStore && mtStore.length > 0) {
data.push({
vendorID: 1,
vendorOrgCode: mtStore[0].vendorOrgCode + '',
vendorStoreID: mtStore[0].vendorStoreID + ''
})
}
if (ebStore && ebStore.length > 0) data.push({
vendorID: 3,
vendorOrgCode: ebStore[0].vendorOrgCode + '',
vendorStoreID: ebStore[0].vendorStoreID + ''
})
if (data.length === 0) return
let res = await merchant.get_mt_store_im_status({ data: JSON.stringify(data) })
let arr: any = []
if (res.code === '0') {
res.data.forEach((item: AnyObject) => {
if (item.errMsg && item.errMsg) arr.push({
...item,
vendorID: +item.errMsg.substring(0, 1)
})
else arr.push({ ...item })
})
}
store.commit('storeInfo/setImOnlineStatus', arr)
}
/**
* 是否存在某个平台
*/
function isExistPlatformID(platformID: number) {
return storeMaps.value.StoreMaps.filter((item: AnyObject) => item.vendorID == platformID)
}
/**
* 是否含有聊天表情
*/
function isCloudEmoji(emoji: string) {
let emojiArr = emoji.match(/\[(.+?)\]/g)
return emojiArr && emojiArr.length > 0 ? true : false
}
interface emojiType {
type: string,
text: string,
emoji: string
}
/**
* 解析emoji数据
*/
function analyEmoji(emoji: string) {
if (!isCloudEmoji(emoji)) {
return [
{
type: 'text',
text: emoji,
emoji: ''
}
]
}
// emoji = '[大哭][大哭][大哭][大哭][心碎][心碎][心碎]11111顶顶顶顶呃零零零零[流泪]iiiihdhggydgjfg kevbuygbhjbnb'
let arr: emojiType[] = []
let emojiArr: string[] = emoji.match(/\[(.+?)\]/g) || []
if (emojiArr && emojiArr.length > 0) {
emojiArr.map((item, index) => {
let emojiImg = emojiAnanlyze(item) // 返回的emoji解析数据
if (emojiImg === item) emojiImg = 'unknown:' + emoji // 未知表情
let indexOf = emoji.indexOf(item) // item在聊天emoji中的位置
if (indexOf === 0) {
// emoji
arr.push({
type: 'emoji',
text: '',
emoji: emojiImg
})
// emoji之后的文字
let afterSymbol = emoji.substring(indexOf + item.length, indexOf + item.length + 1)
if (afterSymbol !== '[' && afterSymbol.length > 0 && index === emojiArr.length - 1) {
arr.push({
type: 'text',
text: emoji.substring(indexOf + item.length),
emoji: ''
})
}
} else {
// emoji之前的文字
arr.push({
type: 'text',
text: emoji.substring(0, indexOf),
emoji: ''
})
// emoji
arr.push({
type: 'emoji',
text: '',
emoji: emojiImg
})
// emoji之后的文字
let afterSymbol = emoji.substring(indexOf + item.length, indexOf + item.length + 1)
if (afterSymbol !== '[' && afterSymbol.length > 0 && index === emojiArr.length - 1) {
arr.push({
type: 'text',
text: emoji.substring(indexOf + item.length),
emoji: ''
})
}
}
emoji = emoji.replace(emoji.substring(0, indexOf + item.length), '') // 清除已处理完的数据
})
}
return arr || []
}
return {
logOutFn, // 全局公用方法
globGetToDay, // 获取实时订单数据
previewImage, // 查看详情图
setUserInfo, // 储存用户信息
appWxLogin, // app 微信登录
openWeixin, // 打开微信小程序
watchVersion, // 检查是否有新版本
newMessage, // 展示新信息
copyInfo, // 复制信息
phoneCall, // 拨打电话
isTrades, // 判断是否是在营业时间
wholeCalcPrice, // 格式化今日订单数据
singleCalcPrice, // 格式化今日订单数据
setPrinterStatus, // 查询打印机状态并连接
isTxd, // 判断是否有淘鲜达
getMtStoreIMStatus, // 获取美团IM单聊状态
isExistPlatformID, // 是否含有平台门店
analyEmoji, // 解析emoji表情
isCloudEmoji // 是否含有emoji
}
}
export default useGlobalFunc

View File

@@ -0,0 +1,288 @@
/**
* 订单管理hooks
*/
import { getStorage } from "@/utils/storage"
import toast from "@/utils/toast"
import util from "@/utils/bluetoothPrinter/util"
import Bluetooth from '@/utils/bluetoothPrinter/bluetooth'
import printerTemplate from '@/utils/bluetoothPrinter/printerTemplate'
import configCms from "@/utils/configCms"
import order from "@/api/https/order"
import merchant from "@/api/https/merchant"
function useOrderInfo() {
const bluetooth = new Bluetooth()
/**************************************************************
* 复制订单信息内容
* @param {String} data 需要复制的内容
* @param {String} [text] 复制成功提示内容(非必填)
* @param {string} [errorT] 复制失败提示内容(非必填)
*/
function copyInfo(data: string, text = '复制成功', errorT = '复制失败') {
uni.setClipboardData({
data: data,
success() {
toast(text, 1)
},
fail() {
toast(errorT)
}
})
}
/************************************************************
* 拨打电话
* @param {string} phoneNumber 将要拨号的手机号
* @param {String} [text] 拨号成功提示内容(非必填)
* @param {string} [errorT] 拨号失败提示内容(非必填)
*/
function phoneCall(phoneNumber: string, text = '拨号完成', errorT = '取消拨号') {
uni.makePhoneCall({
phoneNumber: phoneNumber,
success() {
console.log(text)
},
fail() {
toast(errorT)
}
})
}
/************************************************************
* 跳转到详情页
* @param {string} vendorOrderID 订单id
* @param {string} vendorID 品牌id
*/
function orderDetail(vendorOrderID: string, vendorID: string) {
uni.navigateTo({ url: `/subPages/orderChild/orderDetail/orderDetail?vendorOrderID=${vendorOrderID}&vendorID=${vendorID}` })
}
/*************************************************************
* 跳转到配送管理页面
* @param {string} vendorOrderID 订单id
*/
function deliverManager(vendorOrderID: string) {
uni.navigateTo({ url: `/subPages/orderChild/deliverManager/deliverManager?orderId=${vendorOrderID}` })
}
/************************************************************
* 打印订单
* @param {string} vendorOrderID 订单号
* @param {string} vendorID 品牌ID
*/
async function printerOrder(vendorOrderID: string, vendorID: string) {
if (getStorage('defaultPrinter') == '0') {
// 蓝牙打印机
bluetoothPrinter(vendorOrderID)
} else if (getStorage('defaultPrinter') == '1') {
// 网络打印机
internetPrinter(vendorOrderID, vendorID)
} else {
// 手动选择
uni.jxConfirm({
title: '选择设备',
content: '请选择打印设备进行打印',
confirmText: '网络打印',
cancelText: '蓝牙打印',
isReturn: 1,
success: () => {
internetPrinter(vendorOrderID, vendorID)
},
fail: () => {
bluetoothPrinter(vendorOrderID)
}
})
}
}
/**
* 网络打印
* @param {string} vendorOrderID 订单号
*/
async function internetPrinter(vendorOrderID: string, vendorID: string) {
let res = await order.get_printer_status({
storeID: getStorage('storeID'),
})
if (res.code == 0) {
if (res.data.printerStatus == 2) {
let data = {
vendorOrderID,
vendorID,
}
let pOorder = await order.print_order(data)
if (pOorder.code == 0) {
toast('订单发送成功', 1)
} else {
toast('订单发送失败', 2)
}
} else {
let data = {
vendorOrderID,
vendorID,
}
let pOorder = await order.print_order(data)
if (pOorder.code == 0) {
uni.jxAlert({
title: '提示',
content: '打印机已离线,但订单已推动成功'
})
} else {
toast('订单发送失败', 2)
}
}
} else {
toast('获取打印机数据异常', 2)
}
}
/**
* 蓝牙打印
*/
async function bluetoothPrinter(vendorOrderID: any, type = 1) {
if (getStorage('deviceName')) {
let data: any
if (type == 1) {
data = {
vendorOrderID: vendorOrderID
}
} else {
data = vendorOrderID
}
let orderRes = await order.get_orders(data)
if (orderRes.code == 0) {
getPrinterSku(orderRes.data.data[0]) // 获取订单数据
} else {
toast('测试订单数据异常')
}
} else {
toast('未连接打印机')
}
}
// 获取订单数据
let timer1: any = null
async function getPrinterSku(orderInfo: AnyObject) {
let data = {
vendorOrderID: orderInfo.vendorOrderID,
vendorID: orderInfo.vendorID
}
let skuRes = await merchant.get_order_sku_info(data)
if (skuRes.code) {
let data = {
orderInfo: orderInfo,
skus: skuRes.data,
}
let datas: any = getStorage('commitBTDevCharact')
getBlechData()
util.notifyBLEState(datas.deviceId, datas.serviceId, datas.uuid)
.then(async (res) => {
if (res == 12) {
toast('正在打印订单')
bluetooth.notifyBLECharacteristicValue() // 订阅蓝牙 notify
clearTimeout(timer1)
timer1 = setTimeout(() => {
writeBLECharacteristicValue(data) // 向打印机写入数据
clearTimeout(timer1)
}, 500)
} else {
toast('打印机异常请检查')
}
})
.catch(async (error) => {
toast(error)
})
return
} else {
toast('订单商品数据异常')
}
}
// 获取写入标识数据
function getBlechData() {
let datas: any = getStorage('commitBTDevCharact')
bluetooth.deviceId = datas.deviceId
bluetooth.serviceId = datas.serviceId
bluetooth.writeId = datas.uuid
}
//写入控制命令
async function writeBLECharacteristicValue(data: AnyObject) {
let printerCenter = await printerTemplate(data)
printbuffs(printerCenter)
}
// 分包向打印机发送数据
function printbuffs(buffer: any) {
// 1.并行调用多次会存在写失败的可能性
// 2.建议每次写入不超过20字节
// 分包处理,延时调用
const maxChunk = 20
const delay = 20
for (
let i = 0, j = 0, length = buffer.byteLength;
i < length;
i += maxChunk, j++
) {
let subPackage = buffer.slice(
i,
i + maxChunk <= length ? i + maxChunk : length
)
setTimeout(printbuff, j * delay, subPackage)
}
}
// 写入数据
function printbuff(buffer: any) {
bluetooth.writeBLECharacteristicValue(buffer)
}
/************************************************************
* 转换厂商
*/
function waybillVendor(
waybillVendorID: number,
status: number,
waybillStatus: number
) {
if (waybillVendorID == -1) {
if (status < 25 && waybillStatus == 0) {
return '暂无配送员'
} else if (waybillStatus >= 20) {
return '商家自送'
} else {
return '暂无配送信息'
}
} else {
return (configCms as AnyObject).serveInfo.vendorName[waybillVendorID]
}
}
/************************************************************
* 售后详情
*/
function afterSalesDetaile(afsOrderID: number | string) {
uni.navigateTo({
url: `/subPages/orderChild/afterSalesOrderDetail/afterSalesOrderDetail?afsOrderID=${afsOrderID}`,
})
}
return {
copyInfo, // 复制内容
phoneCall, // 拨号
orderDetail, // 查看订单详情
deliverManager, // 配送管理
printerOrder, // 打印订单
waybillVendor, // 转换厂商
afterSalesDetaile, // 售后详情
bluetoothPrinter, // 打印订单
}
}
export default useOrderInfo

133
src/env.d.ts vendored Normal file
View File

@@ -0,0 +1,133 @@
/// <reference types="vite/client" />
/************************************************************
* vue 文件验证
* @auto zsw
* @time 2023年1月6日
* @emaile 2966211270@qq.com
* @param {}
* @return {}
*/
declare module '*.vue' {
import { DefineComponent } from 'vue'
const component: DefineComponent<{}, {}, any>
export default component
}
/**********************************************************
* nvue 文件验证
* @auto zsw
* @time 2023年1月6日
* @emaile 2966211270@qq.com
* @param {}
* @return {}
*/
declare module '*.nvue' {
import { DefineComponent } from 'vue'
const component: DefineComponent<{}, {}, any>
export default component
}
/**********************************************************
* ASE加密/解密文件验证
*/
declare module 'crypto-js' {
const content: any
export = content
}
/************************************************************
* 自定义挂载 uniapp 全局属性,自定义更改原生 modal 弹窗
* @auto zsw
* @time 2023年1月6日
* @emaile 2966211270@qq.com
* @param {jxConfirm} 双按钮仿 ios module
* @param {jxAlert} 单按钮仿 ios module
* @return {}
*/
declare module 'uview-plus' {
interface alertType {
/**
* 提示标题(必填)
*/
title: string
/**
* 提示内容(必填)
*/
content: string
/**
* 确定按钮
*/
confirmText?: string
/**
* 是否允许安卓按钮返回
* 默认0
* 0不允许手势返回
* 1允许使手势返回
*/
isReturn?: 0 | 1
/**
* 成功回调
*/
success?: Function
}
interface confirmType {
/**
* 提示标题(必填)
*/
title: string
/**
* 提示内容(必填)
*/
content: string
/**
* 确定按钮
*/
confirmText?: string
/**
* 取消按钮
*/
cancelText?: string
/**
* 是否允许安卓按钮返回
* 默认0
* 0不允许手势返回
* 1允许使手势返回
*/
isReturn?: 0 | 1
/**
* 成功回调
*/
success?: Function
/**
* 取消回调
*/
fail?: Function
}
interface globalAlertType {
data: AnyObject
success?: Function
}
export function install(): void
global {
interface Uni {
/**
* 双按钮模态弹窗
*/
jxConfirm: ((options: confirmType) => void)
/**
* 单按钮模态弹窗
*/
jxAlert: ((options: alertType) => void)
/**
* 可覆盖tabBar弹窗
*/
globalAlert: ((options: globalAlertType) => void)
}
}
}

22
src/main.ts Normal file
View File

@@ -0,0 +1,22 @@
import { createSSRApp } from "vue";
import App from "./App.vue";
import { store, key } from "./store";
import { blockExit } from './utils/android_ios'
export function createApp() {
const app = createSSRApp(App);
app.use(store, key)
app.config.errorHandler = (err, vm, info) => {
console.log(err, '错误信息')
console.log(vm, 'vue实例')
console.log(info, '错误位置')
}
return {
app
}
}
/*************************************************
* 双击返回不退出应用
*/
blockExit()

284
src/manifest.json Normal file
View File

@@ -0,0 +1,284 @@
{
"name" : "京西菜市商家版",
"appid" : "__UNI__F9A47D3",
"description" : "1、商户通过京西平台同时管理美团、饿了么、京东等多个外卖平台实现一键上架、下架、修改、删除多个平台商品2、商户通过京西平台可以同时对、美团专送、达达、顺丰同城等多个专送平台召唤偶骑手",
"versionName" : "1.8.9",
"versionCode" : 189,
"transformPx" : false,
"uni-app" : {
"debug" : true
},
/* 5+App */
"app-plus" : {
"compatible" : {
"ignoreVersion" : true
},
"usingComponents" : true,
"nvueStyleCompiler" : "uni-app",
"compilerVersion" : 3,
"splashscreen" : {
"alwaysShowBeforeRender" : true,
"waiting" : true,
"autoclose" : true,
"delay" : 0
},
/* */
"modules" : {
"Bluetooth" : {},
"Camera" : {},
"iBeacon" : {},
"Share" : {},
"Maps" : {},
"OAuth" : {},
"Push" : {},
"Barcode" : {}
},
/* */
"distribute" : {
/* android */
"android" : {
"permissions" : [
"<uses-feature android:name=\"android.hardware.camera\"/>",
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\" />",
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\" />",
"<uses-permission android:name=\"android.permission.BIND_ACCESSIBILITY_SERVICE\"/>",
"<uses-permission android:name=\"android.permission.BLUETOOTH\"/>",
"<uses-permission android:name=\"android.permission.BLUETOOTH_ADMIN\"/>",
"<uses-permission android:name=\"android.permission.BROADCAST_STICKY\"/>",
"<uses-permission android:name=\"android.permission.CALL_PHONE\"/>",
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
"<uses-permission android:name=\"android.permission.INSTALL_PACKAGES\"/>",
"<uses-permission android:name=\"android.permission.INSTALL_SHORTCUT\"/>",
"<uses-permission android:name=\"android.permission.INTERNET\"/>",
"<uses-permission android:name=\"android.permission.MODIFY_AUDIO_SETTINGS\"/>",
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
"<uses-permission android:name=\"android.permission.RECEIVE_BOOT_COMPLETED\"/>",
"<uses-permission android:name=\"android.permission.SYSTEM_ALERT_WINDOW\"/>",
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
"<uses-permission android:name=\"android.permission.GET_TASKS \"/>",
"<uses-permission android:name=\"android.permission.QUERY_ALL_PACKAGES \"/>",
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
"<uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\"/>",
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>",
"<uses-permission android:name=\"android.permission.WRITE_SYNC_SETTINGS\"/>",
"<uses-permission android:name=\"android.permission.RECEIVE_USER_PRESENT\"/>",
"<uses-permission android:name=\"android.permission.BADGE_ICON\"/>"
],
"abiFilters" : [ "armeabi-v7a", "arm64-v8a", "x86" ],
"minSdkVersion" : 23,
"targetSdkVersion" : 30
},
/* ios */
"ios" : {
"dSYMs" : false,
"privacyDescription" : {
"NSPhotoLibraryUsageDescription" : "读取相册图片二维码进行扫码识别",
"NSPhotoLibraryAddUsageDescription" : "保存门店海报图片",
"NSBluetoothPeripheralUsageDescription" : "获取蓝牙连接蓝牙打印机打印订单",
"NSBluetoothAlwaysUsageDescription" : "获取蓝牙连接蓝牙打印机打印订单",
"NSCameraUsageDescription" : "扫描商品二维码或者条形码识别商品"
},
"capabilities" : {
"entitlements" : {
"com.apple.developer.associated-domains" : [ "applinks:www.jxc4.com" ]
}
},
"UIBackgroundModes" : ""
},
/* SDK */
"sdkConfigs" : {
"share" : {
"weixin" : {
"appid" : "wx18111a41fd17f24f",
"UniversalLinks" : "https://www.jxc4.com"
}
},
"ad" : {},
"payment" : {},
"geolocation" : {},
"oauth" : {
"weixin" : {
"appid" : "wx18111a41fd17f24f",
"UniversalLinks" : "https://www.jxc4.com"
}
},
"push" : {
"unipush" : {
"icons" : {
"small" : {
"hdpi" : "D:/wtq/交接文档new (2)/交接文档new/商家版备份文件(无关)/push图标/36x36.png",
"ldpi" : "D:/wtq/交接文档new (2)/交接文档new/商家版备份文件(无关)/push图标/18x18.png",
"mdpi" : "D:/wtq/交接文档new (2)/交接文档new/商家版备份文件(无关)/push图标/24x24.png",
"xhdpi" : "D:/wtq/交接文档new (2)/交接文档new/商家版备份文件(无关)/push图标/48x48.png",
"xxhdpi" : "D:/wtq/交接文档new (2)/交接文档new/商家版备份文件(无关)/push图标/72.png"
}
}
}
},
"maps" : {
"amap" : {
"appkey_ios" : "2ca84776c658dffc3598151eb6a99836",
"appkey_android" : "71502439293566d209ec9754f8d50d76"
}
}
},
"icons" : {
"android" : {
"hdpi" : "unpackage/res/icons/72x72.png",
"xhdpi" : "unpackage/res/icons/96x96.png",
"xxhdpi" : "unpackage/res/icons/144x144.png",
"xxxhdpi" : "unpackage/res/icons/192x192.png"
},
"ios" : {
"appstore" : "unpackage/res/icons/1024x1024.png",
"ipad" : {
"app" : "unpackage/res/icons/76x76.png",
"app@2x" : "unpackage/res/icons/152x152.png",
"notification" : "unpackage/res/icons/20x20.png",
"notification@2x" : "unpackage/res/icons/40x40.png",
"proapp@2x" : "unpackage/res/icons/167x167.png",
"settings" : "unpackage/res/icons/29x29.png",
"settings@2x" : "unpackage/res/icons/58x58.png",
"spotlight" : "unpackage/res/icons/40x40.png",
"spotlight@2x" : "unpackage/res/icons/80x80.png"
},
"iphone" : {
"app@2x" : "unpackage/res/icons/120x120.png",
"app@3x" : "unpackage/res/icons/180x180.png",
"notification@2x" : "unpackage/res/icons/40x40.png",
"notification@3x" : "unpackage/res/icons/60x60.png",
"settings@2x" : "unpackage/res/icons/58x58.png",
"settings@3x" : "unpackage/res/icons/87x87.png",
"spotlight@2x" : "unpackage/res/icons/80x80.png",
"spotlight@3x" : "unpackage/res/icons/120x120.png"
}
}
},
"splashscreen" : {
"useOriginalMsgbox" : true,
"androidStyle" : "default",
"iosStyle" : "storyboard",
"android" : {
"hdpi" : "D:/wtq/交接文档new (2)/交接文档new/交接文档new/京西菜市商家版/素材/Android启动图/480x762.png",
"xhdpi" : "D:/wtq/交接文档new (2)/交接文档new/交接文档new/京西菜市商家版/素材/Android启动图/720x1242.png",
"xxhdpi" : "D:/wtq/交接文档new (2)/交接文档new/交接文档new/京西菜市商家版/素材/Android启动图/1080x1882.png"
},
"ios" : {
"storyboard" : "D:/wtq/交接文档new (2)/交接文档new/交接文档new/京西菜市商家版/素材/ios启动图.zip"
}
}
},
"nativePlugins" : {
"DCloud-PushSound" : {
"__plugin_info__" : {
"name" : "DCloud-PushSound",
"description" : "自定义推送铃声",
"platforms" : "Android,iOS",
"url" : "",
"android_package_name" : "",
"ios_bundle_id" : "",
"isCloud" : false,
"bought" : -1,
"pid" : "",
"parameters" : {}
}
},
"Ba-Notify" : {
"__plugin_info__" : {
"name" : "应用消息通知插件(多种样式,新增支持常驻通知模式) Ba-Notify",
"description" : "Ba-Notify 是一款功能全面的uniapp消息通知插件可在状态栏显示各种样式的消息通知。包含普通、常驻、大图、多行、进度、按钮等通知支持检查、设置、清除通知支持根据渠道和ID分类管管理",
"platforms" : "Android",
"url" : "https://ext.dcloud.net.cn/plugin?id=9231",
"android_package_name" : "jxcs.Android",
"ios_bundle_id" : "",
"isCloud" : true,
"bought" : 1,
"pid" : "9231",
"parameters" : {}
}
},
"J-FrontService" : {
"__plugin_info__" : {
"name" : "常驻通知栏保活插件(支持Android和IOS)",
"description" : "Android、IOS后台保活插件",
"platforms" : "Android,iOS",
"url" : "https://ext.dcloud.net.cn/plugin?id=10479",
"android_package_name" : "",
"ios_bundle_id" : "com.jxc4.www",
"isCloud" : true,
"bought" : 1,
"pid" : "10479",
"parameters" : {}
}
},
"RC-NoticeMonitoring" : {
"__plugin_info__" : {
"name" : "安卓通知栏监听 电池优化 屏幕唤醒",
"description" : "安卓通知栏监听,电池白名单,屏幕唤醒",
"platforms" : "Android",
"url" : "https://ext.dcloud.net.cn/plugin?id=8998",
"android_package_name" : "jxcs.Android",
"ios_bundle_id" : "",
"isCloud" : true,
"bought" : 1,
"pid" : "8998",
"parameters" : {}
}
}
}
},
/* */
"quickapp" : {},
/* */
"mp-weixin" : {
"appid" : "wx08a5c2a8581414ff",
"setting" : {
"urlCheck" : false,
"minified" : true,
"postcss" : true
},
"usingComponents" : true,
"nvueCompiler" : "weex",
"lazyCodeLoading" : "requiredComponents",
"plugins" : {
"chatGroupPlugin" : {
"version" : "1.1.2",
"provider" : "wxaae6519cee98d824"
}
}
},
"mp-alipay" : {
"usingComponents" : true
},
"mp-baidu" : {
"usingComponents" : true
},
"mp-toutiao" : {
"usingComponents" : true
},
"uniStatistics" : {
"enable" : false
},
"vueVersion" : "3",
"fallbackLocale" : "zh-Hans",
"locale" : "zh-Hans",
"_spaceID" : "mp-6a99ccda-c7f6-4ef9-8870-35401c55287e",
"h5" : {
"unipush" : {
"enable" : true
}
},
"app-harmony" : {
"distribute" : {
"modules" : {}
}
}
}
/* ios */

19
src/package.json Normal file
View File

@@ -0,0 +1,19 @@
{
"id": "xing-virtual-list",
"name": "简单易用的高性能不定高项虚拟列表",
"version": "1.1",
"description": "简单易用不定高虚拟列表scroll-view 高度可以传入任意 css",
"keywords": [
"虚拟列表",
"简单易用",
"高性能",
"virtual",
"list"
],
"dcloudext": {
"category": [
"前端组件",
"通用组件"
]
}
}

441
src/pages.json Normal file
View File

@@ -0,0 +1,441 @@
{
"easycom": {
"autoscan": true,
"custom": {
"^uni-(.*)": "@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue"
}
},
"pages": [
{
"path": "pages/merchant/index",
"style": {
"navigationBarTitleText": "商家中心",
"enablePullDownRefresh": true,
"navigationStyle": "custom",
"navigationBarBackgroundColor": "#4eb331",
"navigationBarTextStyle": "white"
}
},
{
"path": "pages/goods-manager/main",
"style": {
"navigationBarTitleText": "商品管理",
"navigationStyle": "custom",
"navigationBarBackgroundColor": "#4eb331",
"navigationBarTextStyle": "white"
}
},
{
"path": "pages/order-manager/main",
"style": {
"navigationBarTitleText": "订单管理",
"navigationStyle": "custom"
}
},
{
"path": "pages/message/index",
"style": {
"navigationBarTitleText": "客户消息",
"enablePullDownRefresh": true
}
},
{
"path": "components/dialog/dialogCom",
"style": {
"navigationStyle": "custom",
"backgroundColor": "transparent",
"backgroundColorTop": "transparent",
"backgroundColorBottom": "transparent",
"app-plus": {
"animationType": "fade-in",
"background": "transparent",
"popGesture": "none",
"animationDuration": "150"
}
}
},
{
"path": "components/globalAlert/globalAlert",
"style": {
"navigationStyle": "custom",
"backgroundColor": "transparent",
"backgroundColorTop": "transparent",
"backgroundColorBottom": "transparent",
"app-plus": {
"animationType": "fade-in",
"background": "transparent",
"popGesture": "none",
"animationDuration": "300"
}
}
}
],
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "京西菜市",
"navigationBarBackgroundColor": "#fff"
},
"subPackages": [
{
"root": "subPages/login",
"pages": [
{
"path": "addAuth/addAuth",
"style": {
"navigationBarTitleText": "绑定手机号"
}
},
{
"path": "index",
"style": {
"navigationBarTitleText": "登录",
"navigationStyle": "custom",
"navigationBarTextStyle": "black",
"navigationBarBackgroundColor": "#fff"
}
},
{
"path": "bindSNS/bindSNS",
"style": {
"navigationBarTitleText": "登录"
}
},
{
"path": "wxLogin/wxLogin",
"style": {
"navigationBarTitleText": "登录",
"navigationStyle": "custom",
"navigationBarTextStyle": "black",
"navigationBarBackgroundColor": "#fff"
}
}
]
},
{
"root": "subPages/agreement",
"pages": [
{
"path": "jxcs",
"style": {
"navigationBarTitleText": "京西菜市"
}
},
{
"path": "updateVersion",
"style": {
"navigationBarTitleText": "检查更新"
}
}
]
},
{
"root": "subPages/switchStore",
"pages": [
{
"path": "switchStore",
"style": {
"navigationBarTitleText": "选择门店",
"enablePullDownRefresh": true,
"navigationBarBackgroundColor": "#4eb331",
"navigationBarTextStyle": "white"
}
}
]
},
{
"root": "subPages/orderChild",
"pages": [
{
"path": "getPhone/getPhone",
"style": {
"navigationBarTitleText": "联系平台"
}
},
{
"path": "orderDetail/orderDetail",
"style": {
"navigationBarTitleText": "订单详情"
}
},
{
"path": "deliverManager/deliverManager",
"style": {
"navigationBarTitleText": "配送管理",
"enablePullDownRefresh": true
}
},
{
"path": "afterSalesOrderDetail/afterSalesOrderDetail",
"style": {
"navigationBarTitleText": "售后详情"
}
},
{
"path": "createAfterSales/createAfterSales",
"style": {
"navigationBarTitleText": "创建售后单"
}
},
{
"path": "seeMap/seeMap",
"style": {
"navigationBarTitleText": "查看地图"
}
},
{
"path": "complaint/complaint",
"style": {
"navigationBarTitleText": "投诉骑手"
}
}
]
},
{
"root": "subPages/merchantChild",
"pages": [
{
"path": "helpCenter/helpCenter",
"style": {
"navigationBarTitleText": "帮助中心"
}
},
{
"path": "orderRealTime/orderRealTime",
"style": {
"navigationBarTitleText": "营业数据"
}
},
{
"path": "orderRealTimeJxgy/orderRealTimeJxgy",
"style": {
"navigationBarTitleText": "营业数据"
}
},
{
"path": "platformM/platformM",
"style": {
"navigationBarTitleText": "已开通店铺"
}
},
{
"path": "modifyPrice/modifyPrice",
"style": {
"navigationBarTitleText": "调价包"
}
},
{
"path": "bill/bill",
"style": {
"navigationBarTitleText": "我的账单"
}
},
{
"path": "billDetaile/billDetaile",
"style": {
"navigationBarTitleText": "账单详情"
}
},
{
"path": "evaluateM/evaluateM",
"style": {
"navigationBarTitleText": "评价管理"
}
},
{
"path": "storeScore/storeScore",
"style": {
"navigationBarTitleText": "门店评分"
}
},
{
"path": "storeScoreDetaile/storeScoreDetaile",
"style": {
"navigationBarTitleText": "评分详情"
}
},
{
"path": "waitGoods/waitGoods",
"style": {
"navigationBarTitleText": "待配商品"
}
},
{
"path": "waitGoodsDetaile/waitGoodsDetaile",
"style": {
"navigationBarTitleText": "商品详情",
"enablePullDownRefresh": true
}
},
{
"path": "shareStore/shareStore",
"style": {
"navigationBarTitleText": "扫码进店"
}
},
{
"path": "enterGroupChat/enterGroupChat",
"style": {
"navigationBarTitleText": "进入群聊",
"mp-weixin": {
"usingComponents": {
"cell": "plugin://chatGroupPlugin/cell"
}
}
}
},
{
"path": "message/message",
"style": {
"navigationBarTitleText": "消息列表"
}
},
{
"path": "messageDetail/messageDetail",
"style": {
"navigationBarTitleText": "最新消息"
}
},
{
"path": "activity/activity",
"style": {
"navigationBarTitleText": "活动信息"
}
},
{
"path": "setUp/setUp",
"style": {
"navigationBarTitleText": "设置"
}
},
{
"path": "printerSetUp/printerSetUp",
"style": {
"navigationBarTitleText": "蓝牙打印机设置"
}
},
{
"path": "businessLicense/businessLicense",
"style": {
"navigationBarTitleText": "营业资质"
}
},
{
"path": "backstageApp/backstageApp",
"style": {
"navigationBarTitleText": "来单通知"
}
},
{
"path": "useInfo/useInfo",
"style": {
"navigationBarTitleText": "个人信息"
}
},
{
"path": "payeeInfo/payeeInfo",
"style": {
"navigationBarTitleText": "收款信息"
}
},
{
"path": "invoice/invoice",
"style": {
"navigationBarTitleText": "发票管理"
}
},
{
"path": "accountBalance/accountBalance",
"style": {
"navigationBarTitleText": "配送余额"
}
},
{
"path": "setNotice/setNotice",
"style": {
"navigationBarTitleText": "设置来单提示"
}
},
{
"path": "setBusinessTime/setBusinessTime",
"style": {
"navigationBarTitleText": "修改营业时间"
}
},
{
"path": "setBusinessStatus/setBusinessStatus",
"style": {
"navigationBarTitleText": "营业状态"
}
},
{
"path": "setInvoiceEB/setInvoiceEB",
"style": {
"navigationBarTitleText": "发票设置"
}
},
{
"path": "platformDetail/index",
"style": {
"navigationBarTitleText": "平台管理"
}
}
]
},
{
"root": "subPages/shoppingChild",
"pages": [
{
"path": "createGoods/createGoods",
"style": {
"navigationBarTitleText": "创建商品",
"navigationBarBackgroundColor": "#4eb331",
"navigationBarTextStyle": "white"
}
}
]
},
{
"root": "subPages/messageChild",
"pages": [
{
"path": "msgChat/msgChat",
"style": {
"navigationBarTitleText": "消息"
}
}
]
}
],
"tabBar": {
"color": "#7A7E83",
"selectedColor": "#4eb331",
"borderStyle": "black",
"backgroundColor": "#ffffff",
"list": [
{
"pagePath": "pages/order-manager/main",
"text": "订单管理",
"iconPath": "./static/image/tabBarIcon/order.png",
"selectedIconPath": "./static/image/tabBarIcon/order-active.png"
},
{
"pagePath": "pages/goods-manager/main",
"text": "商品管理",
"iconPath": "./static/image/tabBarIcon/shopping.png",
"selectedIconPath": "./static/image/tabBarIcon/shopping-active.png"
},
{
"pagePath": "pages/message/index",
"text": "消息",
"iconPath": "./static/image/tabBarIcon/msg.png",
"selectedIconPath": "./static/image/tabBarIcon/msg-active.png"
},
{
"pagePath": "pages/merchant/index",
"text": "商家中心",
"iconPath": "./static/image/tabBarIcon/merchant.png",
"selectedIconPath": "./static/image/tabBarIcon/merchant-active.png"
}
]
}
}

View File

@@ -0,0 +1,305 @@
.skuName-cell {
box-sizing: border-box;
background: white;
padding: 19rpx;
border-radius: 10rpx;
margin: 15rpx 15rpx;
box-shadow: 0rpx 2rpx 10rpx rgb(207, 207, 207);
.skuName {
display: flex;
align-items: flex-start;
position: relative;
.skuName-img {
position: relative;
view {
position: absolute;
z-index: 9;
left: 0;
top: 0;
width: 182rpx;
height: 182rpx;
border-radius: 10rpx;
background: rgba(0, 0, 0, .4);
text-align: center;
line-height: 182rpx;
color: #fff;
font-weight: bold;
}
.imglabel {
width: 180rpx;
height: 180rpx;
border-radius: 10rpx;
border: 1rpx solid rgb(218, 218, 218);
}
}
.skuName-info {
display: flex;
flex-direction: column;
justify-content: space-between;
margin-left: 17rpx;
width: 100%;
height: 180rpx;
.input-price {
position: absolute;
border: 1rpx solid rgba(0, 0, 0, 0.1);
background: white;
border-radius: 8rpx;
padding: 20rpx;
top: 60rpx;
color: #333;
}
.skuName-name {
color: #333;
font-size: 32rpx;
line-height: 1;
display: flex;
align-items: flex-start;
}
.skuName-monthsale {
font-size: 28rpx;
color: #999;
line-height: 1;
margin-top: 7rpx;
}
.skuName-failsync {
font-size: 28rpx;
color: #F60D58;
line-height: 1;
margin-top: 7rpx;
margin-bottom: -30rpx;
}
.skuName-price {
display: flex;
color: #F60D58;
line-height: 1;
.icon-modify {
margin-left: 15rpx;
}
}
.skuName-tips {
font-size: 28rpx;
line-height: 1;
color: #333;
}
.red {
color: #F60D58;
}
.green {
color: $jx-primary;
}
}
}
// sku
.skus {
border-top: 1rpx dashed #ccc;
display: flex;
flex-flow: row wrap;
// justify-content: flex-end;
// padding-top: 16rpx;
// overflow: hidden;
margin-top: 10rpx;
align-items: flex-start;
.sku-cell:nth-of-type(even) {
margin-left: 10rpx;
}
}
// 价格审核中样式
.check-display {
color: #f44;
font-size: 24rpx;
font-weight: bold;
animation: rubberBand 1s infinite alternate;
}
}
.skus-wrapper-new {
border-top: 1rpx solid rgb(219, 219, 219);
.error {
text-align: center;
font-size: 24rpx;
font-weight: bold;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.mt {
color: #f29a40;
}
.eb {
color: #51a7fc;
}
.sku-cell2 {
padding: 10rpx 0 0 0;
border-bottom: 1rpx solid rgb(219, 219, 219);
position: relative;
}
.isSale2 {}
.cell-top {
display: flex;
align-items: center;
.price {
color: #333;
width: 23%;
flex-shrink: 0;
text-align: center;
display: flex;
justify-content: center;
flex-flow: column;
.sku-spec {
font-size: 26rpx;
}
.sku-price {
font-size: 26rpx;
}
}
.promotion-price {
color: #F60D58;
}
.btn-group {
width: 78%;
flex-shrink: 0;
display: flex;
justify-content: space-around;
.btn {
box-sizing: border-box;
flex: 1;
height: 80rpx;
text-align: center;
font-size: 24rpx;
border-radius: 10rpx;
color: $jx-primary;
border: 2rpx solid $jx-primary;
display: flex;
justify-content: center;
align-items: center;
box-sizing: border-box;
margin-right: 8rpx;
}
.tmpSaleNo {
box-sizing: border-box;
display: flex;
flex-direction: column;
font-size: 28rpx;
line-height: 1.02;
margin: 0;
}
.onActive {
background: $jx-primary;
color: white;
}
}
}
.cell-bottom {
font-size: 28rpx;
text-align: center;
color: #666;
padding: 5rpx 0;
}
.sku-autoSaleAt {
font-size: 26rpx;
text-align: center;
color: #F25340;
padding: 5rpx 0;
text {
font-weight: bold;
}
}
}
.checkBoxWrap {
display: flex;
width: 100%;
justify-content: flex-end;
padding-top: 15rpx;
}
.aduit-type {
font-size: 28rpx;
text-align: center;
color: $jx-primary;
}
.aduit-btn-group {
display: flex;
align-items: center;
justify-content: center;
padding-top: 20rpx;
.btn {
font-size: 28rpx;
padding: 20rpx 40rpx;
background: $jx-primary;
border-radius: 10rpx;
color: white;
margin: 0 20rpx;
}
.refuse {
background: #f44;
}
}
@keyframes rubberBand {
from {
transform: scale3d(1, 1, 1);
}
30% {
transform: scale3d(1.01, 0.75, 1);
}
40% {
transform: scale3d(0.95, 1.25, 1);
}
50% {
transform: scale3d(1.02, 0.85, 1);
}
65% {
transform: scale3d(0.98, 1.05, 1);
}
75% {
transform: scale3d(1.01, 0.95, 1);
}
to {
transform: scale3d(1, 1, 1);
}
}

View File

@@ -0,0 +1,177 @@
import shopping from "@/api/https/shopping"
import { store } from "@/store"
import { getStorage } from "@/utils/storage"
import toast from "@/utils/toast"
import { jx_throttles, timeFormatD } from "@/utils/tools"
import { computed } from "@vue/reactivity"
import configCms from "@/utils/configCms"
interface propType {
skuName: AnyObject
isAudit: boolean
isHot: boolean
showMountTab: boolean
}
/*************************************************
* 商品列表
*/
function goodsListFn(props: Readonly<propType>) {
/*************************************************
* 列表判断条件
*/
const isNewPriceDisplay: any = computed(() => {
store.getters['storeInfo/isNewPriceDisplay']
})
/*************************************************
* 获取userType
*/
const userType = computed(() => {
return +getStorage('userType')
})
/*************************************************
* 修改商品售卖状态
*/
function updateSaleStatus(sku: AnyObject, skuName: AnyObject, status: number) {
if (+sku.storeSkuStatus === +status && !sku.autoSaleAt) return false
let data = {
sku,
skuName,
status
}
updateSaleStatusThrottles(data)
}
const updateSaleStatusThrottles = jx_throttles({
time: 500,
success: async (e: AnyObject) => {
let data = {
storeIDs: JSON.stringify([getStorage('storeID')]),
payload: JSON.stringify([
{
nameID: e.skuName.id,
skus: [
{
skuID: e.sku.id,
isSale: +e.status === 0 ? -1 : +e.status,
},
],
},
]),
}
let res = await shopping.update_stores_skus(data)
if (res.code == 0) {
changeSaleStatus(e.sku, e.skuName, e.status)
if (e.sku.autoSaleAt) e.sku.autoSaleAt = 0
} else {
toast('修改失败', 2)
}
},
fail: (t: number) => {
toast(`操作太快`)
}
})
/*************************************************
* 修改商品临时不可售
*/
function tmpSaleNo(sku: AnyObject, skuName: AnyObject) {
if (sku.storeSkuStatus === 0 && sku.autoSaleAt) return false
let data = {
sku,
skuName,
}
tmpSaleNoThrottles(data)
}
const tmpSaleNoThrottles = jx_throttles({
time: 500,
success: async (e: AnyObject) => {
let autoSaleAt = computedAutoSaleAt()
let data = {
storeIDs: JSON.stringify([getStorage('storeID')]),
payload: JSON.stringify([{
skuID: e.sku.id,
isSale: -1,
isAsync: false,
}]),
autoSaleAt: autoSaleAt
}
let res = await shopping.update_stores_skus_sale(data)
// let res:AnyObject = {
// code: "-105",
// desc: "本地数据修改成功,但同步失败,请根据错误提示处理!,同步错误信息:[{\"商品ID\":0,\"分类名\":\"\",\"门店ID\":804947,\"平台名\":\"抖店平台\",\"平台商品ID\":\"\",\"商品nameID\":0,\"平台价\":0,\"同步类型\":\"异常同步错误\",\"错误信息\":\"门店:804947修改没有创建的商品:22807\"},{\"商品ID\":22807,\"分类名\":\"\",\"门店ID\":804947,\"平台名\":\"京东到家\",\"平台商品ID\":\"2792687352\",\"商品nameID\":8643,\"平台价\":0,\"同步类型\":\"更新商品状态\",\"错误信息\":\"未查询到到家商品编码\"}]",
// data: ""
// }
// if (res.code === '0') {
// changeSaleStatus(e.sku, e.skuName, 0)
// e.sku.autoSaleAt = autoSaleAt
// } else {
// if(res.code === '-105' && res.desc.includes('本地数据修改成功,但同步失败,请根据错误提示处理')) toast(res.desc)
// else toast('修改失败', 2)
// }
if (res.code == 0) {
changeSaleStatus(e.sku, e.skuName, 0)
e.sku.autoSaleAt = autoSaleAt
} else {
let findIndex = res.desc.indexOf('[')
let str = ''
if(findIndex!== -1){
JSON.parse(res.desc.substring(findIndex)).forEach((element:AnyObject) => {
str = str.length >0 ? str + '\n' + element['平台名'] + ':【' + element['错误信息'] + '】': str + element['平台名'] +':【' + element['错误信息']+'】'
});
}
if(res.code === '-105' && res.desc.includes('本地数据修改成功,但同步失败,请根据错误提示处理')) toast(`${str}`)
else toast('修改失败', 2)
}
},
fail: (t: number) => {
toast(`操作太快`)
}
})
/*************************************************
* 计算自动可售时间
*/
function computedAutoSaleAt() {
let now = +new Date()
let autoTime = +new Date(`${timeFormatD(+new Date())} ${autoSaleAt.value}`)
if (now < autoTime) {
return `${timeFormatD(+new Date())} ${autoSaleAt.value}`
} else {
return `${timeFormatD(+new Date() + 24 * 3600 * 1000)} ${autoSaleAt.value}`
}
}
// 自动可售时间
const autoSaleAt = computed(() => {
let { autoSaleAt = '' } = configCms.serveInfo
return autoSaleAt
})
/*************************************************
* 修改商品可售状态
*/
async function changeSaleStatus(sku: AnyObject, skuName: AnyObject, status: number) {
if (props.isAudit) return false
sku.storeSkuStatus = +status
// 计算可售不可售图标
if (skuName.skus.some((item: AnyObject) => item.storeSkuStatus)) {
skuName.skuAllnoSale = false
} else {
skuName.skuAllnoSale = true
}
}
return {
isNewPriceDisplay, // 列表判断条件
userType, // 获取userType
updateSaleStatus, // 修改商品售卖状态
tmpSaleNo, // 临时不可售
}
}
export default goodsListFn

View File

@@ -0,0 +1,263 @@
<template>
<view class="skuName-cell">
<!-- skuName -->
<view class="skuName">
<!-- 图片 -->
<view class="skuName-img" @tap="previewImg(skuName)">
<view v-show="skuName.skuAllnoSale">不可售</view>
<image
class="imglabel"
mode="scaleToFill"
lazy-load
:src="skuName.img"
/>
</view>
<!-- 图片 -->
<!-- 其他信息 -->
<view class="skuName-info">
<!-- 名称 -->
<view class="skuName-name">
{{ skuName.prefix ? '[' + skuName.prefix + ']' : ''
}}{{ skuName.name }}
</view>
<view @tap.stop="copyInfo(''+ skuName.id, '复制nameID成功')" style="color:#818181;">
<text>{{ skuName.id }}</text>
<jx-icon icon="fuzhi" color="#818181" style="margin-left: 10rpx;"></jx-icon>
</view>
<!-- 价格 改价 -->
<view class="skuName-price" @tap="openPriceDialog(skuName)">
<jx-price
:price="skuName.unitPrice"
color="#F60D58"
sizeM="22rpx"
sizeN="38rpx"
/>
<view class="icon-modify" v-if="!isAudit">
<jx-icon icon="shuxie" color="#999" :size="38" />
</view>
</view>
<!-- 提示信息 -->
<view>
<view class="skuName-tips" v-if="skuName.unit === '份'">
该价格为每斤价格
</view>
<view class="skuName-tips green" v-if="skuName.unit !== '份'">
该价格为每{{ skuName.unit }}价格
</view>
<!-- 审核状态 -->
<view class="check-display" v-show="skuName.auditUnitPrice">
审核中价格<jx-price
:price="skuName.auditUnitPrice"
color="#f44"
size="24rpx"
/>
</view>
</view>
</view>
<!-- 其他信息 -->
</view>
<!-- skuName -->
<!-- sku2 -->
<view class="skus-wrapper-new" v-if="!isAudit">
<view v-for="(sku, j) in skuName.skus" :key="j" class="sku-cell2">
<!-- 异常商品 -->
<view
class="error mt"
v-if="
sku.mtwmID !== '' &&
(sku.mtwmSyncStatus & 16) === 16 &&
(sku.mtwmSyncStatus & 2) !== 2 &&
(sku.mtwmSyncStatus & 4) !== 4
"
>美团:该商品无法修改价格,请联系运营修改</view
>
<view
class="error eb"
v-if="
sku.ebaiID !== '' &&
(sku.ebaiSyncStatus & 16) === 16 &&
(sku.ebaiSyncStatus & 2) !== 2 &&
(sku.ebaiSyncStatus & 4) !== 4
"
>饿佰:该商品无法修改价格,请联系运营修改</view
>
<view class="cell-top">
<view class="price">
<view class="sku-spec">
{{ sku.specQuality }}{{ sku.specUnit }}
</view>
<view
class="sku-price"
:class="{ 'promotion-price': !isNewPriceDisplay && sku.actPrice }"
>
<jx-price
:price="sku.comparePrice"
sizeM="22rpx"
sizeN="28rpx"
color="#000"
/>
</view>
</view>
<view class="btn-group">
<view
class="btn"
:class="{ onActive: sku.storeSkuStatus }"
@tap="updateSaleStatus(sku, skuName, 1)"
>
可售
</view>
<view
class="btn"
:class="{ onActive: !sku.storeSkuStatus && !sku.autoSaleAt }"
@tap="updateSaleStatus(sku, skuName, 0)"
>
不可售
</view>
<view
v-if="!isHot"
class="btn tmpSaleNo"
:class="{ onActive: !sku.storeSkuStatus && sku.autoSaleAt }"
@tap="tmpSaleNo(sku, skuName)"
>
<text>临时</text>
<text>不可售</text>
</view>
</view>
</view>
<!-- 库存以及位置码 -->
<view style="display: flex;color:#666;margin-top:20rpx;justify-content: center">
<view @tap="openDialog(skuName,sku,'stock')">
库存:{{sku.stock}}
<jx-icon icon="shuxie" color="#999" :size="24" />
</view>
<view style="margin-left: 20rpx;" @tap="openDialog(skuName,sku,'locationCode')">
货架码:{{sku.locationCode && sku.locationCode !== 'EMPTY_VALUE' ? sku.locationCode : ''}}
<jx-icon icon="shuxie" color="#999" :size="24" />
</view>
</view>
<view class="cell-bottom">{{ sku.comment ? sku.comment : '' }}</view>
<view class="sku-autoSaleAt" v-if="sku.autoSaleAt">
该规格将在 <text>{{ sku.autoSaleAt }}</text> 可售
</view>
</view>
<view v-if="showMountTab" class="checkBoxWrap">
<label @tap="handleSale(skuName)">
<checkbox color="#4eb331" style="transform: scale(0.8)" />选中商品
</label>
</view>
</view>
<!-- 待审核商品操作面板 -->
<view class="aduit-wall" v-else>
<view class="aduit-type">{{
skuName.type === 1 ? '【价格】正在审核中' : '【新建】正在审核中'
}}</view>
<!-- ((userType & 4) === 4) 运营 -->
<view class="aduit-btn-group" v-if="(+getStorage('userType') & 4) === 4">
<view class="btn refuse" @tap="toExamine(skuName, -1)">拒绝</view>
<view class="btn" @tap="toExamine(skuName, 1)">批准</view>
</view>
<view class="aduit-btn-group" v-else>
<view class="btn" @tap="phoneCall(storeInfo.marketManName)"
>联系运营加快审核</view
>
</view>
</view>
</view>
</template>
<script lang="ts" setup >
import useGlobalFunc from '@/composables/useGlobalFunc'
import { store } from '@/store'
import { getStorage } from '@/utils/storage'
import { computed } from 'vue'
import goodsListFn from './right-main'
import useOrderInfo from '@/composables/useOrderInfo'
const { copyInfo } = useOrderInfo()
const { phoneCall } = useGlobalFunc()
/*************************************************
* 接收数据
*/
interface propType {
skuName: AnyObject
isAudit: boolean
isHot: boolean
showMountTab: boolean
}
const prop = defineProps<propType>()
const {
isNewPriceDisplay, // 列表判断条件
updateSaleStatus, // 修改商品售卖状态
tmpSaleNo, // 临时不可售
} = goodsListFn(prop)
const {
previewImage, // 预览图片
} = useGlobalFunc()
const emit = defineEmits<{
(e: 'handleSale', data: AnyObject): void
(e: 'openPriceDialog', data: AnyObject): void
(e: 'openDialog', data: AnyObject): void
(e: 'toExamine', data: AnyObject): void
}>()
function handleSale(skuName: AnyObject) {
emit('handleSale', skuName)
}
/*************************************************
* 预览图片
*/
function previewImg(skuName:AnyObject) {
let arr = [skuName.img,skuName.img2,skuName.img3,skuName.img4,skuName.img5].filter(item => { return item && item.length > 0 })
previewImage(arr)
}
/*************************************************
* 修改操作
*/
function openPriceDialog(skuName: AnyObject) {
if (prop.isAudit) return
emit('openPriceDialog', skuName)
}
function openDialog(skuName: AnyObject,sku:AnyObject,type:String) {
let payload = {
nameID:skuName.id,
Skus:[{
skuID:sku.id,
stock:sku.stock,
locationCode:sku.locationCode && sku.locationCode !== 'EMPTY_VALUE' ? sku.locationCode : ''
}]
}
emit('openDialog', {payload,type,name:skuName.name})
}
/*************************************************
* 拒绝改价
*/
function toExamine(skuName: AnyObject, type: any) {
let data = {
status: type,
nameID: skuName.nameID,
storeID: getStorage('storeID'),
auditPrice: skuName.auditUnitPrice,
}
emit('toExamine', data)
}
/***************************************************************
* 获取门店信息
*/
const storeInfo = computed(() => {
return store.state.storeInfo.allStoreInfo
})
</script>
<style lang="scss" scoped>
@import './right-main.scss';
</style>

View File

@@ -0,0 +1,217 @@
<template>
<view class="filter-root"
:class="{'filter-fill':isCheckoutFilter}">
<template v-if="isCheckoutFilter">
<view
class="item item-fill"
:class="{ active: filteActive2 == item.lable }"
v-for="(item, index) in filterData2"
:key="index"
@tap="fliterFn2(item.lable, item.status)"
>{{ item.title }}</view
>
</template>
<template v-else>
<view
class="item item-fill"
:class="{ active: filteActive == item.lable }"
v-for="(item, index) in filterData"
:key="index"
@tap="fliterFn(item, item.status)"
>{{ item.title }}</view
>
</template>
</view>
</template>
<script lang="ts" setup >
import { ref, watch } from 'vue'
import { jx_throttles } from '@/utils/tools'
import toast from '@/utils/toast'
interface propsType {
isCheckoutFilter: boolean
updateStateOk: boolean
}
const props = defineProps<propsType>()
/*************************************************
* 参数1
*/
const filterData = ref<Array<AnyObject>>([
{
title: '全部',
name:'all',
lable: 2,
status: -1,
},
{
title: '可售',
name:'status',
lable: 1,
status: 1,
},
{
title: '不可售',
name:'status',
lable: 0,
status: 0,
},
{
title: '有库存', //库存 1 全查~ 2 有~ 3 无~
name:'stock',
lable:4,
status: 2,
},
{
title: '无库存',
name:'stock',
lable:5,
status: 3,
},
// {
// title: '有货架码',
// name:'locationCode',
// lable:6,
// status:false // 实际上是全部查,感觉没用
// },
{
title: '无货架码',
name:'locationCode',
lable:7,
status:true
},
{
title: '批量',
name:'',
lable: 3,
status: -1,
},
])
/*************************************************
* 参数2
*/
const filterData2 = ref<Array<AnyObject>>([
{
title: '全部',
lable: 2,
status: -1,
},
{
title: '批量',
lable: 3,
status: -1,
},
])
/*************************************************
* emit
*/
const emit = defineEmits<{
(e: 'updateIsSale', data: AnyObject): void
(e: 'updateTowFilter', data: AnyObject): void
}>()
/*************************************************
* 筛选1
*/
const filteActive = ref<number>(2)
function fliterFn(item: AnyObject, status: number) {
if (filteActive.value == item.lable) return
fliterFnThrottles(item, status)
}
const fliterFnThrottles = jx_throttles({
time: 2000,
success: (item: AnyObject, status: number | boolean) => {
filteActive.value = item.lable
filteActive2.value = item.lable
let data = {
status: status,
lable: item.lable,
name:item.name
}
emit('updateIsSale', data)
},
fail: () => {
toast('老板要点慢点哦')
},
})
/*************************************************
* 筛选2
*/
const filteActive2 = ref<number>(2)
function fliterFn2(lable: number, status: number) {
if (filteActive2.value == lable) return
filteActive2.value = lable
filteActive.value = lable
let data = {
status: status,
lable: lable,
}
emit('updateTowFilter', data)
}
watch(
() => props.updateStateOk,
(val) => {
if (val) {
filteActive2.value = 2
filteActive.value = 2
}
}
)
</script>
<style lang="scss" scoped>
.filter-root {
display: flex;
overflow-x: auto; /* 允许水平方向滚动 */
white-space: nowrap; /* 防止子元素换行 */
align-items: center;
// justify-content: space-around;
box-sizing: border-box;
width: 100%;
border-left: 1rpx solid rgb(223, 223, 223);
height: 90rpx;
background-color: #fff;
box-shadow: 10rpx 0rpx 10rpx rgb(207, 207, 207);
border-bottom: 1rpx solid rgb(224, 224, 224);
padding: 0 10rpx;
.filter-fill{
justify-content: space-around;
}
.item {
flex: 1;
height: 60rpx;
border-radius: 10rpx;
border: 2rpx solid $jx-primary;
color: $jx-primary;
padding: 0 10rpx;
line-height: 60rpx;
text-align: center;
transition: all 0.2s;
margin-left: 10rpx;
}
.item-filter{
width: fit-content;
}
.item-fill{
flex: 1;
}
.item:nth-child(1) {
margin: 0 !important;
}
.active {
background-color: $jx-primary;
color: #fff;
}
}
</style>

View File

@@ -0,0 +1,129 @@
<template>
<view class="search-root">
<view class="add-shopping" @tap="createGoods">
<jx-icon icon="jiahao" color="#4eb331" />
<text>新建</text>
</view>
<uni-search-bar
cancelButton="none"
clearButton="auto"
placeholder="请输入关键字 例如:精华液"
@confirm="confirm"
@input="input"
@clear="clear"
v-model="text"
/>
</view>
</template>
<script lang="ts" setup >
import toast from '@/utils/toast'
import { jx_trembling } from '@/utils/tools'
import { ref, watch } from 'vue'
/*************************************************
* props
*/
interface propsType {
isFilter: string | number
}
const props = defineProps<propsType>()
const text = ref<string>('')
let isInput = false
watch(
() => props.isFilter,
(val) => {
if (val == 'hot' || val == 'audit') {
isInput = true
} else {
isInput = false
}
}
)
/*************************************************
* emit
*/
const emit = defineEmits<{
(e: 'serachShopping', data: string): void
(e: 'clearInpu', data: string): void
(e: 'createGoods'): void
}>()
/*************************************************
* 确定搜索
*/
let watchTimer: any = null
function confirm(e: AnyObject) {
if (isInput) {
let watchTimer = setTimeout(() => {
text.value = ''
clearTimeout(watchTimer)
}, 500)
return toast('该分类暂不支持搜索')
}
emit('serachShopping', e.value)
}
/*************************************************
* 输入框加载
*/
function input(e: string) {
if (isInput) {
let watchTimer = setTimeout(() => {
text.value = ''
clearTimeout(watchTimer)
}, 500)
return toast('该分类暂不支持搜索')
}
trembling(e)
}
const trembling = jx_trembling((e: string) => {
emit('serachShopping', e)
}, 1000)
/*************************************************
* 清空输入框
*/
function clear(e: AnyObject) {
if (isInput) return
emit('clearInpu', e.value)
}
/*************************************************
* 新建商品
*/
function createGoods() {
emit('createGoods')
}
</script>
<style lang="scss">
.search-root {
box-sizing: border-box;
background-color: $jx-primary;
padding: 0 20rpx 2rpx 20rpx;
height: 92rpx;
display: flex;
align-items: center;
justify-content: space-between;
.add-shopping {
width: 80rpx;
height: 80rpx;
background-color: #fff;
font-size: 20rpx;
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
border-radius: 50%;
color: $jx-primary;
line-height: 1;
padding: 0;
}
}
</style>

View File

@@ -0,0 +1,45 @@
// 一级
.one-item {
background-color: #fff;
height: 90rpx;
overflow: hidden;
transition: all 0.4s;
border-bottom: 1rpx solid #f1f1f1;
// 二级名字
.one-item-name {
display: flex;
height: 90rpx;
line-height: 90rpx;
.iconfont {
display: inline-block;
transform: rotate(0deg);
transition: all 0.2s;
}
.noe-seat {
display: inline-block;
width: 30rpx;
height: 90rpx;
border-left: 7rpx solid transparent;
transition: none;
}
}
// 二级内容
.tow-item {
display: flex;
height: 90rpx;
line-height: 90rpx;
transition: none;
// 二级左侧竖杠
.tow-seat {
display: inline-block;
width: 30rpx;
height: 90rpx;
border-left: 7rpx solid transparent;
}
}
}

View File

@@ -0,0 +1,83 @@
import { getStorage } from "@/utils/storage"
import { onLoad } from "@dcloudio/uni-app"
import { ref } from "vue"
import shopping from "@/api/https/shopping"
/*************************************************
* 商品分类栏目
*/
function leftBarFn(props: AnyObject) {
onLoad(async () => {
await GetStoreCategoryMap()
})
/*************************************************
* @info 左侧tab数据
* 获取列表数据
*/
const cat = ref<Array<AnyObject>>([])
async function GetStoreCategoryMap() {
let data = {
storeID: getStorage('storeID'),
parentID: -1,
}
let res = await shopping.getStore_category_map(data)
if (res.code == 0) {
handledata(res.data, true)
} else {
cat.value = []
handleOriginData()
}
}
/*************************************************
* 处理列表数据
*/
const _isMap = ref<boolean>(false)
function handledata(curdeData: Array<AnyObject>, isMap: boolean) {
let data = curdeData
let catData: Array<AnyObject> = []
data.forEach((item: AnyObject) => {
if (item.name !== '3件9.9') {
item.name = item.name.slice(0, 4)
}
catData.push(item)
})
//把sku分类过滤掉
if (!isMap) catData = catData.filter((item) => item.type === 0)
let catLevel1 = catData.filter((item) => item.level === 1)
let catLevel2 = catData.filter((item) => item.level === 2)
// 组合分类
let catData2: Array<AnyObject> = []
let catData3: AnyObject
catLevel1.forEach((level1: AnyObject) => {
isMap
? (catData3 = catLevel2.filter(
(level2) => level2.parentID === level1.categoryID
))
: (catData3 = catLevel2.filter((level2) => level2.parentID === level1.id))
level1.children = catData3
_isMap.value = isMap
catData2.push(level1)
})
let lastData = props.dafauleData.concat(catData2)
cat.value = lastData
}
async function handleOriginData() {
let res = await shopping.get_categories()
if (res.code == 0) {
handledata(res.data, false)
}
}
return {
cat, // 右侧菜单数据
GetStoreCategoryMap, // 获取数据
}
}
export default leftBarFn

View File

@@ -0,0 +1,139 @@
<template>
<view
v-for="(item, index) in cat"
:key="index"
class="one-item"
:class="{
'one-item-active':
index == oneActive && item.children.length != 0 && isOpen,
'item-name': oneActive == index && item.children.length == 0,
}"
>
<!-- 第一层 -->
<view
:class="{
'never-pen-active': index == oneActive && item.children.length != 0,
}"
class="one-item-name"
@tap="oneItemFn(item, index)"
>
<text class="iconfont icon-jiantou1" v-if="item.children.length != 0" />
<text class="noe-seat noe-seat-active" v-else></text>
<text>{{ item.name }}</text>
</view>
<!-- 第二层 -->
<view
class="tow-item"
:class="{ 'tow-item-active': towActive == childIndex }"
v-for="(childItem, childIndex) in item.children"
:key="childIndex"
@tap="towItemFn(childItem, childIndex)"
>
<text class="tow-seat tow-seat-active"></text>{{ childItem.name }}</view
>
</view>
</template>
<script lang="ts" setup >
import { Ref, ref } from 'vue'
import leftBarFn from './left-bar'
/*************************************************
* 接收数据
*/
interface propsType {
dafauleData: Array<AnyObject>
}
const props = defineProps<propsType>()
const {
cat, // 右侧菜单数据
GetStoreCategoryMap, // 获取数据
} = leftBarFn(props)
/*************************************************
* emit
*/
const eimt = defineEmits<{
(e: 'oneMenuClick', data: string | number): void
}>()
/*************************************************
* 一级菜单点击
*/
const isOpen = ref<boolean>(false)
const oneActive = ref<number>(0) // 高亮
const oneHeight: Ref<string> = ref('0px') // 高度
function oneItemFn(item: AnyObject, index: number) {
if (oneActive.value == index) {
isOpen.value = !isOpen.value
} else {
isOpen.value = true
}
oneActive.value = index // 一级菜单
oneHeight.value = `${(item.length + 1) * 90}rpx` // 动态高度
towActive.value = -1 // 默认二级菜单
if (!isOpen.value) return
eimt('oneMenuClick', item.categoryID)
}
/*************************************************
* 二级菜单点击
*/
const towActive = ref<number>(-1) // 高亮
function towItemFn(childItem: AnyObject, index: number) {
if (towActive.value == index) return
towActive.value = index
eimt('oneMenuClick', childItem.categoryID)
}
/*************************************************
* 导出子组件方法
*/
defineExpose({
GetStoreCategoryMap,
})
</script>
<style lang="scss" scoped>
@import './left-bar.scss';
// 一级展开动画
.one-item-active {
height: v-bind(oneHeight) !important;
background-color: rgb(236, 252, 233);
// 三角图标动画
.icon-jiantou1 {
display: inline-block;
transform: rotate(90deg) !important;
}
}
// 一级选中高亮
.never-pen-active {
background-color: $jx-primary;
color: #fff;
border-bottom: 1rpx solid #fff;
}
// 一级展开背景
.item-name {
color: $jx-primary;
.noe-seat-active {
border-left: 7rpx solid $jx-primary !important;
}
}
// 二级高亮
.tow-item-active {
color: $jx-primary;
background-color: #fff;
// 二级选中高亮
.tow-seat-active {
border-left: 7rpx solid $jx-primary !important;
}
}
</style>

View File

@@ -0,0 +1,132 @@
.status_bar {
height: var(--status-bar-height);
width: 100%;
background-color: $jx-primary;
}
.MountWrap {
display: flex;
z-index: 99;
box-sizing: border-box;
justify-content: space-between;
position: fixed;
width: 100%;
bottom: 0;
left: 0;
background-color: $jx-primary;
padding: 20rpx 25rpx;
.onActive {
width: 44%;
background-color: #fff;
color: $jx-primary;
text-align: center;
border-radius: 10rpx;
padding: 10rpx 0;
}
}
.createGoods {
padding: 10rpx 80rpx;
border-radius: 10rpx;
background-color: $jx-primary;
color: #fff;
text-align: center;
margin-top: 20rpx;
}
.jx-popup-update {
box-sizing: border-box;
padding: 20rpx;
background-color: #fff;
border-radius: 0 0 15rpx 15rpx;
.text {
display: block;
width: 100%;
text-align: center;
margin-bottom: 25rpx;
padding-bottom: 10rpx;
border-bottom: 2rpx solid rgb(234, 234, 234);
}
.tip-new{
padding: 2rpx 0;
height: 66rpx;
line-height: 66rpx;
text-align: left;
border-bottom:1px dashed #999;
.money {
color: $jx-primary;
}
}
.ipt-box{
margin: 10rpx 0;
// height: 86rpx;
// line-height: normal;
}
.tip {
padding: 10rpx 0;
.money {
color: $jx-primary;
}
}
.ipt {
border: 2rpx solid rgb(209, 209, 209);
text-align: center;
border-radius: 5rpx;
height: 86rpx;
line-height: normal;
// -webkit-appearance: none;
// border-radius: 0
}
.title {
width: 100%;
text-align: center;
margin-bottom: 20rpx;
}
.btn-root {
display: flex;
justify-content: space-between;
margin: 40rpx 0 0rpx 0;
.btn-esc,
.btn-ok {
text-align: center;
width: 100%;
padding: 15rpx 0;
border-radius: 10rpx;
border: 2rpx solid $jx-primary;
color: $jx-primary;
}
.btn-ok {
background-color: $jx-primary;
color: #fff;
margin-left: 10rpx;
}
.btn-esc {
margin-right: 10rpx;
}
}
.delete {
margin-top: 50rpx;
margin-bottom: 20rpx;
background-color: $jx-warring;
text-align: center;
color: #fff;
padding: 20rpx;
border-radius: 15rpx;
}
}

View File

@@ -0,0 +1,714 @@
import { onLoad, onShow } from '@dcloudio/uni-app'
import { getStorage } from '@/utils/storage'
import { computed, onBeforeUnmount, ref } from 'vue'
import { store } from '@/store'
import { timeFormatD, timeFormatHMS } from '@/utils/tools'
import toast from '@/utils/toast'
import merchant from "@/api/https/merchant"
import shopping from "@/api/https/shopping"
/*************************************************
* 商品管理
*/
function shoppingMangerFn() {
/*************************************************
* 数据归位,元神显现
*/
function dataHoming() {
skuNames.value = []
page.value = 1
totalCount.value = 0
}
/*************************************************
* 下拉刷新数据重现
*/
const leftBarRef = ref<any>(null)
let onPullDownRefreshTimer: any = ''
const triggered = ref<boolean>(false)
function refresherrefresh() {
triggered.value = true
clearTimeout(onPullDownRefreshTimer)
onPullDownRefreshTimer = setTimeout(() => {
triggered.value = false
dataHoming()
oneMenuClick(isFilter.value)
if (isFilter.value == 'hot') return
leftBarRef.value.GetStoreCategoryMap()
}, 500)
}
/*************************************************
* 获取数据
*/
let oldStoreID: any = 0
onShow(() => {
if (oldStoreID != getStorage('storeID') && oldStoreID != 0) {
triggered.value = true
}
oldStoreID = getStorage('storeID')
})
/*************************************************
* 默认数据
*/
const dafauleData: Array<AnyObject> = [
{
categoryID: 'all',
children: [],
level: 1,
name: '所有分类',
},
{
categoryID: 'act',
children: [],
level: 1,
name: '活动商品',
},
{
categoryID: 'hot',
children: [],
level: 1,
name: '畅销推荐',
},
{
categoryID: 'audit',
children: [],
level: 1,
name: '待审商品',
},
]
/*************************************************
* @info 右侧主体数据
* 获取商品数据
*/
const statusBarHeight = ref<string>('0px') // 状态栏高度
onLoad(async () => {
// 获取状态栏高度
uni.getSystemInfo({
success: (res: any) => {
statusBarHeight.value = res.statusBarHeight + 'px'
}
})
await getSkuNames()
})
const keyword = ref<string>('')
const categoryID = ref<string>('') // 分类id
const isAct = ref<boolean>(false) // 是否是活动商品
const totalCount = ref<number>(0) // 总条数
const skuNames = ref<Array<AnyObject>>([]) // 商品数据
const isAudit = ref<boolean>(false) // 商品列表判断条件
const isHot = ref<boolean>(false) // 商品列表判断条件
async function getSkuNames() {
isLoad.value = true
let data:AnyObject = {
categoryID: categoryID.value,
isFocus: true,
keyword: keyword.value,
offset: pageSize.value * (page.value - 1),
pageSize: pageSize.value,
isAct: isAct.value,
status: -1,
storeID: getStorage('storeID')
}
if(allSaleStatus.value && allSaleStatus.value.name !== 'all') data[allSaleStatus.value.name] = allSaleStatus.value.status
keyFilter(data)
let res = await shopping.get_stores_skus_for_store(data)
if (res.code == 0) {
totalCount.value = res.data.totalCount
let filterData = mapskuName(res.data.skuNames || [])
skuNames.value = skuNames.value.concat(filterData)
if (filterData.length == 0) return toast('该分类未找到商品')
} else {
dataHoming()
toast('分类查询错误')
}
isLoad.value = false
}
/*************************************************
* 过滤对象空字段
*/
function keyFilter(obj: AnyObject) {
for (let key in obj) {
if ('' + obj[key] == "" || '' + obj[key] == undefined) {
delete obj[key]
}
}
return obj
}
/*************************************************
* 列表判断条件
*/
const isNewPriceDisplay = ref<boolean>(
store.getters['storeInfo/isNewPriceDisplay']
)
/*************************************************
* 格式化数据
*/
function mapskuName(skuNames: Array<AnyObject>) {
let arr = skuNames.map((skuName) => {
skuName.auditUnitPrice = skuName.auditUnitPrice
// 是否全部不可售
if (skuName.skus.some((item: AnyObject) => item.storeSkuStatus)) {
skuName.skuAllnoSale = false
} else {
skuName.skuAllnoSale = true
}
// skus
skuName.skus = skuName.skus.map((sku: AnyObject) => {
// 价格异常请参考老版本或者在git进行查看
sku.comparePrice = sku.price
sku.autoSaleAt =
+new Date(sku.autoSaleAt) > 0 ? timeFormatHMS(sku.autoSaleAt) : 0
return sku
})
return skuName
})
return arr
}
/*************************************************
* 页面触底,加载更多数据
*/
const page = ref<number>(1) // 第几页
const pageSize = ref<number>(20) // 每页条数
const isLoad = ref<boolean>(false) // 加载图
function scrolltolower() {
page.value++
if (pageSize.value * (page.value - 1) > totalCount.value || totalCount.value < pageSize.value) {
isLoad.value = false
} else {
if (isLoad.value) return
if (isFilter.value == 'hot') return
if (isFilter.value == 'audit') return GetStoreSkuAudit()
getSkuNames()
}
}
/*************************************************
* 点击菜单获取数据
*/
const isCheckoutFilter = ref<boolean>(false)
const isFilter = ref<string | number>('')
function oneMenuClick(catID: string | number) {
isAct.value = false
isHot.value = false
isCheckoutFilter.value = false
categoryID.value = ''
keyword.value = ''
isFilter.value = catID
isAudit.value = false
dataHoming()
if (catID == 'all') { // 全部商品
isAct.value = false
getSkuNames()
} else if (catID == 'act') { // 活动商品
isAct.value = true
getSkuNames()
} else if (catID == 'hot') { // 畅销商品
isHot.value = true
isCheckoutFilter.value = true
getTopSkus()
} else if (catID == 'audit') { // 待审核商品
isCheckoutFilter.value = true
isAudit.value = true
GetStoreSkuAudit()
} else {
categoryID.value = catID as string
getSkuNames()
}
}
/*************************************************
* 畅销推荐
*/
async function getTopSkus() {
isLoad.value = true
let data = {
storeID: getStorage('storeID')
}
let res = await shopping.get_top_skus_by_city_code(data)
if (res.code == 0) {
let data = res.data || []
if (data.length > 0) {
totalCount.value = data.length
skuNames.value = mapskuName(data)
} else {
dataHoming()
toast('暂无畅销商品')
}
} else {
toast('分类查询错误')
dataHoming()
}
isLoad.value = false
}
/*************************************************
* 待审核商品
*/
async function GetStoreSkuAudit() {
isLoad.value = true
let data = {
storeIDs: JSON.stringify([getStorage('storeID')]),
applyTimeStart: timeFormatD(+new Date() - 1000 * 60 * 60 * 24 * 30) + ' 00:00:00',
applyTimeEnd: timeFormatD(+new Date()) + ' 23:59:59',
statuss: JSON.stringify([0]),
types: JSON.stringify([1, 2]),
offset: pageSize.value * (page.value - 1),
pageSize: pageSize.value,
}
let res = await shopping.get_store_sku_audit(data)
if (res.code == 0) {
totalCount.value = res.data.totalCount
let newData = res.data.data || []
let filterSkuName = mapAuditSkuName(newData)
skuNames.value = skuNames.value.concat(filterSkuName)
if (newData.length == 0) return toast('暂无待审核商品')
} else {
toast('分类查询错误')
dataHoming()
}
isLoad.value = false
}
/*************************************************
* 过滤待审核商品
*/
function mapAuditSkuName(data: AnyObject) {
let arr = data.map((item: any) => ({
auditUnitPrice: item.unitPrice,
unitPrice: item.originPrice,
skuAllnoSale: false,
nameID: item.nameID,
img: item.img,
unit: item.unit,
type: item.type,
prefix: item.prefix,
name: item.skuName,
}))
return arr
}
/*************************************************
* @info 过滤类数据
*/
const showMountTab = ref<boolean>(false)
/*************************************************
* 头部数据过滤
*/
const allSaleStatus = ref<AnyObject>()
async function updateIsSale(data: AnyObject) {
allSaleStatus.value = data
data.lable == 3
? (showMountTab.value = true)
: (showMountTab.value = false)
if (data.lable == 3) return
dataHoming()
await getSkuNames()
}
async function updateTowFilter(data: AnyObject) {
if (data.lable == 3) {
return showMountTab.value = true
} else {
showMountTab.value = false
}
if (isFilter.value == 'hot') {
oneMenuClick(isFilter.value)
}
if (isFilter.value == 'audit') {
oneMenuClick(isFilter.value)
}
}
/*************************************************
* @info 搜索框操作
*/
async function serachShopping(text: string) {
dataHoming()
keyword.value = text
await getSkuNames()
}
async function clearInpu() {
dataHoming()
keyword.value = ''
await getSkuNames()
}
/*************************************************
* 批量操作
*/
let picked: Array<AnyObject> = []
function handleSale(skuName: AnyObject) {
if (picked && picked.some((item) => item.nameID == skuName.id)) {
picked = picked.filter((item) => {
return item.nameID != skuName.id
})
} else {
picked.push({ nameID: Number(skuName.id) })
picked = distinct(picked, 'nameID')
}
}
function distinct(arr: any, key: string) {
let set = new Set()
return arr.reduce(
(p: any, c: any) => (set.has(c[key]) ? p : (set.add(c[key]), [...p, c])),
[]
)
}
/*************************************************
* 批量可售与不可售
*/
let handleChangeSaleTimer: any = null
const updateStateOk = ref<boolean>(false)
async function handleChangeSale(type: number) {
if (picked.length == 0) return toast('未选择商品')
picked.forEach((item: AnyObject) => {
item['isSale'] = type
})
let data = {
storeIDs: JSON.stringify([getStorage('storeID')]),
payload: JSON.stringify(picked),
}
let res = await shopping.update_stores_skus(data)
if (res.code == 0) {
toast('修改成功')
let data = {
status: -1,
lable: 2,
}
updateStateOk.value = true
handleChangeSaleTimer = setTimeout(() => {
updateIsSale(data)
clearTimeout(handleChangeSaleTimer)
}, 1000)
} else {
toast('修改失败', 2)
updateStateOk.value = false
}
}
/*************************************************
* 去创建商品
*/
function createGoods() {
uni.navigateTo({ url: '/subPages/shoppingChild/createGoods/createGoods' })
}
/*************************************************
* 改价还是折扣从vuex 里面读取)
*/
const isPointStore = computed(() => {
return store.getters['storeInfo/isPointStore']
})
// skuName
const skuName = ref<AnyObject>({
unit: '',
auditUnitPrice: ''
})
function openPriceDialog(skuNames: AnyObject) {
skuName.value = skuNames
popup.value.open()
}
// 当前修改价格
const currentValue = ref<string>('')
// 审核价格
const auditUnitPrice = computed(() => {
let price = skuName.value.auditUnitPrice
if (price) {
return +((price * 1) / 100).toFixed(2)
} else {
return +'0.00'
}
})
// 弹窗实例
const popup = ref<any>(null)
// 确定修改价格
function handleConfirm() {
if (isNaN(+currentValue.value)) return toast('请输入格式正确的价格')
if (+currentValue.value < 0.01) return toast('请输入大于等于1分钱的价格')
if (
currentValue.value.toString().indexOf('.') > -1 &&
currentValue.value.toString().split('.')[1].length > 2
) {
return toast('最多只能有两位小数')
}
let updatePrice = Math.round(+currentValue.value * 100)
if (updatePrice == skuName.value.unitPrice) {
return toast('没有修改价格')
}
if (updatePrice > skuName.value.unitPrice * 1.3 ||
updatePrice < skuName.value.unitPrice * 0.7) {
uni.jxConfirm({
title: '提示',
content: `修改幅度超过30%,新价格为¥${(updatePrice / 100).toFixed(2)},是否确定修改?`,
success: () => {
updatePriceFn(updatePrice, skuName.value.id, skuName.value.unitPrice)
}
})
} else {
updatePriceFn(updatePrice, skuName.value.id, skuName.value.unitPrice)
}
}
/**
* 验证通过开始修改价格
*/
let updatePriceFnTimer: any = null
async function updatePriceFn(price: string | number, id: number, originalUnitPrice: number) {
let data = {
storeIDs: JSON.stringify([+getStorage('storeID')]),
payload: JSON.stringify([
{
nameID: skuName.value.id,
unitPrice: price,
},
]),
}
popup.value.close() // 关闭 popup
// 修改价格
let updatePrice = await shopping.update_stores_skus(data)
if (updatePrice.code == 0) {
// 获取单个门店serverSkuName
let storeData = {
storeIDs: JSON.stringify([+getStorage('storeID')]),
isFocus: true,
nameIDs: JSON.stringify([id]),
fromStatus: 0,
toStatus: 1,
}
const serverSkuName = await merchant.get_stores_skus(storeData)
if (serverSkuName.code == 0) {
let skuNameData = serverSkuName.data.skuNames || []
if (skuNameData.length > 0) {
let index = skuNames.value.findIndex((item: any) => item.id == id)
if (index !== -1) skuNames.value[index] = mapskuName(skuNameData)[0]
}
}
// 判断提示
if (isPointStore.value || store.state.storeInfo.allStoreInfo.storeLevel == 'E') {
toast('修改成功')
currentValue.value = ''
} else {
currentValue.value = ''
toast(
+price < originalUnitPrice ? '修改成功' : '提交成功, 请等待审核'
)
}
} else {
toast('修改失败', 2)
}
}
/*************************************************
* 修该库存或货架码
*/
const popupDialog = ref<any>(null)
const skuNameItem = ref<AnyObject>({
payload:{
nameID:0,
Skus:[],
},
name:'',
type:'price'
})
const stockOrCode = ref('')
// 打开dialog 修改库存以及货架码
function openDialog(payload: AnyObject) {
skuNameItem.value = payload
const sku = payload.payload.Skus[0]
if(payload.type === 'stock') stockOrCode.value = sku.stock + ''
if(payload.type === 'locationCode') stockOrCode.value = sku.locationCode
popupDialog.value.open()
}
async function sureStockOrCode() {
const nameID = skuNameItem.value.payload.nameID
const skuID = skuNameItem.value.payload.Skus[0].skuID
let data:AnyObject = {
storeIDs: JSON.stringify([+getStorage('storeID')])
}
if(skuNameItem.value.type === 'stock') {
data.payload = JSON.stringify([{
nameID: nameID,
Skus:[
{
skuID: skuID,
stock: +stockOrCode.value
}
]
}])
}else{
data.payload = JSON.stringify([{
nameID: nameID,
Skus:[
{
skuID:skuID,
locationCode: ''+ stockOrCode.value ? '' + stockOrCode.value : 'EMPTY_VALUE'
}
]
}])
}
popupDialog.value.close() // 关闭 popupDialog
let res = await shopping.update_stores_skus(data)
if (res.code == 0) {
let storeData = {
storeIDs: JSON.stringify([+getStorage('storeID')]),
isFocus: true,
nameIDs: JSON.stringify([skuNameItem.value.payload.nameID]),
fromStatus: 0,
toStatus: 1,
}
const serverSkuName = await merchant.get_stores_skus(storeData)
if (serverSkuName.code == 0) {
let skuNameData = serverSkuName.data.skuNames || []
if (skuNameData.length > 0) {
let index = skuNames.value.findIndex((item: any) => item.id == skuNameItem.value.payload.nameID)
if (index !== -1) {
skuNames.value[index] = mapskuName(skuNameData)[0]
}
}
}
toast('修改成功')
}
}
/*************************************************
* 删除商品
*/
function handleDelete() {
uni.jxConfirm({
title: '提示',
content: `确认删除《${skuName.value.name}》吗?`,
confirmText: '确认',
success: async () => {
popup.value.close() // 关闭 popup
let data = {
storeIDs: JSON.stringify([getStorage('storeID')]),
payload: JSON.stringify([{ nameID: skuName.value.id, isFocus: -1 }]),
}
let res = await shopping.update_stores_skus(data)
if (res.code == 0) {
toast('删除成功')
skuNames.value = skuNames.value.filter((item) => item.id != skuName.value.id)
if (skuNames.value.length == 0) return dataHoming()
} else {
toast('删除失败', 2)
}
}
})
}
const toExamineData = ref<AnyObject>({}) // 审核商品数据
const toExaminePopup = ref<any>(null) // 审核弹窗实例
const toExamineValue = ref<string | number>('') // 审核输入框
/*************************************************
* 审核商品
*/
function toExamine(res: AnyObject) {
toExamineData.value = res
if (res.status == 1) {
toExamineValue.value = res.auditPrice / 100
} else {
toExamineValue.value = ''
}
toExaminePopup.value.open()
}
/*************************************************
* 改价审核操作
*/
async function toExamineConfirm() {
toExaminePopup.value.close()
let data = {
status: toExamineData.value.status,
isAsync: false,
isContinueWhenError: true,
payload: JSON.stringify([{
storeID: toExamineData.value.storeID,
nameID: toExamineData.value.nameID,
...(toExamineData.value.status == 1
? { auditPrice: Math.floor(+toExamineValue.value * 100) }
: { remark: toExamineValue.value })
}])
}
let res = await shopping.store_sku_price_audit(data)
if (res.code == 0) {
toast('操作成功')
skuNames.value = skuNames.value.filter((item) => item.nameID != toExamineData.value.nameID)
if (skuNames.value.length == 0) return dataHoming()
} else {
toast(res.desc || res.data)
}
}
/*************************************************
* 善后工作
*/
onBeforeUnmount(() => {
clearTimeout(handleChangeSaleTimer)
clearTimeout(updatePriceFnTimer)
clearTimeout(onPullDownRefreshTimer)
})
return {
dafauleData, // 左侧tablist 数据
totalCount, // 商品总条数
skuNames, // 商品列表数据
skuNameItem, // 商品数据2
isAudit, // 商品列表判断条件
isHot, // 商品列表判断条件
showMountTab, // 批量操作判断
scrolltolower, // 页面触底
isLoad, // 加载动画
updateIsSale, // 过滤筛选
updateTowFilter, // 过滤筛选
serachShopping, // 搜索框确定
clearInpu, // 清空搜索框
oneMenuClick, // 一级菜单点击事件
isCheckoutFilter, // 切换过滤选项
isFilter, // 判断条件
handleSale, // 批量可售与不可售
handleChangeSale, // 批量可售与不可售
updateStateOk, // 批量操作成功
createGoods, // 去创建商品
isPointStore, // 判断扣点还是折扣
skuName, // 当前修改的价格
auditUnitPrice, // 正在审核的价格
currentValue, // 当前修改价格
popup, // 弹窗实例
stockOrCode, // stock locationCode
popupDialog, // 弹窗 stock locationCode
handleConfirm, // 确定修改价格
openPriceDialog, // 获取修改数据
openDialog, // 获取修改数据2
sureStockOrCode, // 确认框 stock locationCode
handleDelete, // 删除商品
refresherrefresh, // 下拉刷新
triggered, // 下拉刷新标识
leftBarRef, // 右侧导航栏实例
statusBarHeight, // 状态栏高度
toExamine, // 审核商品
toExamineData, // 审核商品数据
toExaminePopup, // 改价审核实例
toExamineConfirm, // 确定操作审核
toExamineValue, // 审核输入内容
}
}
export default shoppingMangerFn

View File

@@ -0,0 +1,252 @@
<template>
<view class="status_bar"></view>
<view>
<shopping-search
class="shopping-cel"
:isFilter="isFilter"
@serachShopping="serachShopping"
@clearInpu="clearInpu"
@createGoods="createGoods"
/>
</view>
<view class="main-center-root">
<view class="left-bar-root">
<scroll-view
scroll-y
:style="{ height: `calc(100vh - 92rpx - ${statusBarHeight})` }"
>
<left-bar
ref="leftBarRef"
:dafauleData="dafauleData"
@oneMenuClick="oneMenuClick"
/>
</scroll-view>
</view>
<view class="right-center">
<shopping-filter
@updateIsSale="updateIsSale"
@updateTowFilter="updateTowFilter"
:isCheckoutFilter="isCheckoutFilter"
:updateStateOk="updateStateOk"
/>
<scroll-view
scroll-y
:style="{ height: `calc(100vh - 182rpx - ${statusBarHeight})` }"
refresher-enabled
:refresher-triggered="triggered"
@scrolltolower="scrolltolower"
@refresherrefresh="refresherrefresh"
>
<right-main
v-for="item in skuNames"
:key="item.id"
:skuName="item"
:isAudit="isAudit"
:isHot="isHot"
:showMountTab="showMountTab"
@handleSale="handleSale"
@openPriceDialog="openPriceDialog"
@openDialog="openDialog"
@toExamine="toExamine"
/>
<jx-load-more
v-show="totalCount >= 4"
:isLoad="isLoad"
tip="没有更多商品了"
/>
<jx-empty
class="jx-empty"
v-show="totalCount == 0"
title="该分类暂无商品"
>
<view class="createGoods" @tap="createGoods">去创建商品</view>
</jx-empty>
</scroll-view>
</view>
</view>
<view v-if="showMountTab" class="MountWrap">
<view class="btn onActive" @tap="handleChangeSale(1)">可售</view>
<view class="btn onActive" @tap="handleChangeSale(-1)">不可售</view>
</view>
<!-- 修改价格 -->
<uni-popup ref="popup" type="top">
<view class="status_bar"></view>
<view class="jx-popup-update">
<text class="text">{{ isPointStore ? '改价' : '提交改价审核' }}</text>
<view class="tip">
当前价格每<text style="color: #f60d58">{{
skuName.unit === '份' ? '斤' : skuName.unit
}}</text
>:
<jx-price :price="skuName.unitPrice" color="#4eb331" />
</view>
<view class="tip audit" v-if="auditUnitPrice > 0">
正在审核¥<text>{{ auditUnitPrice }}</text>
</view>
<input
class="ipt"
type="digit"
v-model="currentValue"
placeholder="请输入修改价格"
/>
<view class="btn-root">
<view class="btn-esc" @tap="popup.close()">取消</view>
<view class="btn-ok" @tap="handleConfirm">确定修改</view>
</view>
<view class="delete">
<view class="delete-text" @tap="handleDelete"
>删除{{ skuName.name }}</view
>
</view>
</view>
</uni-popup>
<!-- 审核商品 -->
<uni-popup ref="toExaminePopup" type="top">
<view class="status_bar"></view>
<view class="jx-popup-update">
<text class="text">{{
toExamineData.status == 1 ? '同意申请' : '拒绝申请'
}}</text>
<view class="tip audit"
>商户申请价格¥{{ toExamineData.auditPrice / 100 }}</view
>
<input
class="ipt"
type="digit"
v-model="toExamineValue"
:placeholder="
toExamineData.status == 1 ? '请输入审核价格' : '请输入拒绝原因'
"
/>
<view class="btn-root">
<view class="btn-esc" @tap="toExaminePopup.close()">取消</view>
<view class="btn-ok" @tap="toExamineConfirm">确定</view>
</view>
</view>
</uni-popup>
<!-- 修改库存以及商品 -->
<uni-popup ref="popupDialog" type="top">
<view class="jx-popup-update" >
<view class="text">
{{ skuNameItem.type === 'stock' ? '修改库存' : '修改货架码' }}
</view>
<view class="tip-new">{{ skuNameItem.name }}</view>
<view class="ipt-box">
<input
class="ipt"
:type="skuNameItem.type === 'stock' ? 'number' : 'text'"
v-model="stockOrCode"
:placeholder="
skuNameItem.type === 'stock' ? '请输入商品库存' : '请输入商品货架码'
"
/>
</view>
<view class="btn-root">
<view class="btn-esc" @tap="popupDialog.close()">取消</view>
<view class="btn-ok" @tap="sureStockOrCode">确定</view>
</view>
</view>
</uni-popup>
<!-- 公共组件 -->
<jx-loading />
<jx-login-empty title="马上登录,管理商品" />
</template>
<script lang="ts" setup>
import shoppingSearch from './childPages/shopping-search/shopping-search.vue'
import leftBar from './component/left-bar/left-bar.vue'
import rightMain from './childPages/right-main/right-main.vue'
import shoppingFilter from './childPages/shopping-filter/shopping-filter.vue'
import shoppingMangerFn from './main'
const {
dafauleData, // 左侧tablit数据
totalCount, // 商品总条数
skuNames, // 商品列表数据
skuNameItem, // 商品数据2
isAudit, // 商品列表判断条件
isHot, // 商品列表判断条件
showMountTab, // 批量操作判断
scrolltolower, // 页面触底
isLoad, // 加载动画
updateIsSale, // 过滤筛选
updateTowFilter, // 过滤筛选
serachShopping, // 搜索框确定
clearInpu, // 清空搜索框
oneMenuClick, // 一级菜单点击事件
isCheckoutFilter, // 切换过滤选项
isFilter, // 判断条件
handleSale, // 批量可售与不可售
handleChangeSale, // 批量可售与不可售
updateStateOk, // 批量操作成功
createGoods, // 去创建商品
isPointStore, // 判断扣点还是折扣
skuName, // 当前修改的价格
auditUnitPrice, // 正在审核的价格
currentValue, // 当前修改价格
popup, // 弹窗实例
stockOrCode, // stock locationCode
popupDialog, // 弹窗 stock locationCode
handleConfirm, // 确定修改价格
openPriceDialog, // 获取修改数据
openDialog, // 获取修改数据2
sureStockOrCode, // 确认框 stock locationCode
handleDelete, // 删除商品
refresherrefresh, // 下拉刷新
triggered, // 下拉刷新标识
leftBarRef, // 右侧导航栏实例
statusBarHeight, // 状态栏高度
toExamine, // 审核商品
toExamineData, // 审核商品数据
toExaminePopup, // 改价审核实例
toExamineConfirm, // 确定操作审核
toExamineValue, // 审核输入内容
} = shoppingMangerFn()
</script>
<style lang="scss">
page {
background-color: #fff;
}
</style>
<style lang="scss" scoped>
@import './main.scss';
.shopping-cel {
:deep(.uni-searchbar) {
padding: 0 !important;
width: 610rpx !important;
height: 70rpx;
.uni-searchbar__box {
border-radius: 7rpx !important;
height: auto !important;
}
}
}
.main-center-root {
box-sizing: border-box;
display: flex;
justify-content: space-between;
.left-bar-root {
width: 200rpx;
box-shadow: 0rpx 10rpx 10rpx rgb(207, 207, 207);
}
.right-center {
width: calc(100vw - 200rpx);
}
}
</style>

197
src/pages/merchant/index.ts Normal file
View File

@@ -0,0 +1,197 @@
import { computed, onBeforeUnmount, ref } from 'vue'
import { timeFormatD } from '@/utils/tools'
import { getStorage } from '@/utils/storage'
import { onLoad, onPullDownRefresh } from '@dcloudio/uni-app'
import { store } from '@/store'
import useGlobalFunc from '@/composables/useGlobalFunc'
import merchant from "@/api/https/merchant"
/*************************************************
* 商家中心
*/
const merchantFn = function () {
const { logOutFn, getMtStoreIMStatus } = useGlobalFunc()
/*************************************************
* 下拉刷新
*/
let onPullDownRefreshTimer: any = null
onPullDownRefresh(() => {
clearTimeout(onPullDownRefreshTimer)
onPullDownRefreshTimer = setTimeout(async () => {
uni.stopPullDownRefresh()
await getSaleInfo()
await getStoreVendorMaps(-1)
await getCid()
await getMtStoreIMStatus() // 获取美团门店的im状态
clearTimeout(onPullDownRefreshTimer)
}, 1000)
})
/*************************************************
* cid通知提示
*/
let cidNotice = ref<boolean>(false)
async function getCid() {
let infoRes = await merchant.get_self_info()
if (infoRes.code == 0) {
if (getStorage('cid') == infoRes.data.c_id) {
cidNotice.value = false
} else {
cidNotice.value = true
}
}
}
/*************************************************
* 页面加载获取数据
*/
onLoad(async () => {
await getStoreVendorMaps(-1)
await getSaleInfo()
await getCid()
})
const saleInfo = ref({
earningPrice: 0,
count: 0,
})
/*************************************************
* 获取今日营业数据
*/
async function getSaleInfo() {
let fromTime = `${timeFormatD()} 00:00:00`
let toTime = `${timeFormatD()} 23:59:59`
let data = {
storeIDs: `[${parseInt(getStorage('storeID'))}]`,
fromTime,
toTime,
statuss:JSON.stringify([110]) // 只统计已完成的订单,不包含取消单
}
await merchant.get_store_order_sale_info(data).then((res) => {
let json = {
earningPrice: 0,
shopPrice: 0,
realEarningPrice: 0,
count: 0,
actualPayPrice: 0,
actualFee: 0
}
if (res.code == 0) {
let data = res.data || []
data.forEach((item: AnyObject) => {
if (item.status === 110) {
json.actualPayPrice += item.actualPayPrice
json.realEarningPrice += item.realEarningPrice
json.earningPrice += item.earningPrice
json.shopPrice += item.shopPrice
json.count += item.count
json.actualFee += item.actualFee
}
})
json.actualFee = +(json.actualFee / 100).toFixed(2)
saleInfo.value = json
} else {
saleInfo.value = json
}
})
}
/*************************************************
* 获取门店信息数据
*/
const _vendorPayPercentage = ref<number>(0)
const isNotQuote = ref<boolean>(true)
const isZero = ref<boolean>(true)
const isUpperfif = ref<boolean>(false)
const isShowShop = ref<boolean>(false)
async function getStoreVendorMaps(vendorID: number) {
let data = {
storeID: getStorage('storeID'),
vendorID: vendorID
}
let res = await merchant.get_store_vendor_maps(data)
if (res.code == 0) {
let data = res.data
_vendorPayPercentage.value = data[0].vendorPayPercentage
isNotQuote.value = true
isNotQuote.value = data.some((item: AnyObject) => {
return item.vendorPayPercentage != 0 && item.vendorPayPercentage <= 50
})
isZero.value = data.every((item: AnyObject) => {
return item.vendorPayPercentage == 0
})
isUpperfif.value = data.every((item: AnyObject) => {
return item.vendorPayPercentage > 50
})
if (isNotQuote.value) {
isShowShop.value = data.every((v: AnyObject) => {
return v.vendorPayPercentage > 50
})
}
} else {
_vendorPayPercentage.value = 0
}
}
// 系统信息
function getMsg() {
uni.removeTabBarBadge({ index: 3 })
store.commit('storeInfo/setIsNewMessage', false)
uni.navigateTo({
url: '/subPages/merchantChild/message/message',
})
}
const isMsg = computed(() => {
return store.state.storeInfo.isNewMessage
})
/*************************************************
* 退出登录
*/
function goLogin() {
uni.showActionSheet({
title: '退出后不会删除任何数据',
itemColor: '#e70808',
itemList: ['重新登录'],
popover: {
width: 5000,
},
success: function (res) {
logOutFn();
// uni.navigateTo({ url: '/subPages/login/wxLogin/wxLogin' })
uni.reLaunch({ url: '/subPages/login/wxLogin/wxLogin' })
}
});
}
/*************************************************
* 做收尾工作
*/
onBeforeUnmount(() => {
clearTimeout(onPullDownRefreshTimer)
})
return {
saleInfo, // 今日订单数据
_vendorPayPercentage, // 供应商百分比
isShowShop, // 是否为出售金额
isNotQuote,
isZero,
isUpperfif,
getMsg,
isMsg,
goLogin,
cidNotice,
}
}
export default merchantFn

View File

@@ -0,0 +1,147 @@
<template>
<view>
<view class="status_bar"></view>
<!-- 用户信息 -->
<user-info />
<!-- 实时订单数据 -->
<template v-if="getStorage('terrace') == 'jxcs' || getStorage('terrace') == 'gblm'">
<!-- 京西菜市 -->
<order-data
:showMore="true"
:saleInfo="saleInfo"
:_vendorPayPercentage="_vendorPayPercentage"
:isShowShop="isShowShop"
:isNotQuote="isNotQuote"
:isZero="isZero"
:isUpperfif="isUpperfif"
:isOut="true"
/>
</template>
<template v-else>
<!-- 京西果园 -->
<order-data-jxgy :showMore="true" :saleInfo="saleInfo" />
</template>
<!-- 选项内容 -->
<options />
<!-- 新信息 -->
<view class="tip-root">
<!-- 信息 -->
<view class="new-msg" v-if="isMsg" @tap="getMsg">
<image
src="https://image.jxc4.com/image/e17593d0abe4daa160a9d67f46732f7b.png"
mode="scaleToFill"
/>
<view class="msg">
<view class="title">新系统消息</view>
<view>请查收您的系统信息</view>
</view>
<view class="btn">立即查看</view>
</view>
<!-- 通知 -->
<view class="notice" v-if="cidNotice" @tap="goLogin">
<text>订单通知提醒已被其他设备抢走-请重新登录</text>
<jx-icon icon="gengduo" color="red"></jx-icon>
</view>
</view>
<!-- 公共组件 -->
<jx-loading />
<!-- 未登录无网络 -->
<jx-login-empty title="马上登录,开始使用" />
</view>
</template>
<script lang="ts" setup>
import userInfo from './userInfo/userInfo.vue'
import orderData from './orderData/orderData.vue'
import orderDataJxgy from './orderDataJxgy/orderDataJxgy.vue'
import options from './options/options.vue'
import merchantFn from './index'
import { getStorage } from '@/utils/storage'
const {
saleInfo, //今日订单数据
_vendorPayPercentage, // 供应商百分比
isShowShop, // 是否为出售金额
isNotQuote,
isZero,
isUpperfif,
getMsg,
isMsg,
goLogin,
cidNotice,
} = merchantFn()
</script>
<style lang="scss" scoped>
.status_bar {
height: calc(var(--status-bar-height) + 20rpx);
width: 100%;
background-color: $jx-primary;
}
.new-msg {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10rpx 20rpx;
width: 710rpx;
overflow: hidden;
background-color: rgba($color: #000000, $alpha: 0.65);
color: #fff;
border-radius: 15rpx;
box-sizing: border-box;
margin-bottom: 20rpx;
image {
width: 120rpx;
height: 120rpx;
}
.msg {
.title {
font-weight: bold;
font-size: 35rpx;
}
}
.btn {
padding: 7rpx 22rpx;
border-radius: 50rpx;
background-image: linear-gradient(135deg, #f72a6c, #f16692);
animation: btnANimation 1s ease-in-out infinite alternate;
}
}
@keyframes btnANimation {
0% {
transform: scale(0.95);
}
100% {
transform: scale(1.05);
}
}
.notice {
display: flex;
justify-content: space-between;
box-sizing: border-box;
width: 100%;
padding: 20rpx;
background-color: #fef5f6;
color: #e91d37;
font-size: 28rpx;
}
.tip-root {
position: fixed;
width: 100%;
bottom: 0rpx;
left: 0rpx;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
</style>

View File

@@ -0,0 +1,114 @@
.options-root {
position: relative;
background-color: #fff;
margin-top: 20rpx;
box-sizing: border-box;
padding: 20rpx;
:deep(.popupAnimation) {
z-index: 1000000;
}
.grid-item-box {
position: relative;
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
.image {
width: 75rpx;
height: 75rpx;
margin-bottom: 10rpx;
}
.text {
font-size: 26rpx;
}
// ************* 角标内容 ************
// 我的账单
.bill-new {
position: absolute;
top: 15rpx;
right: 15rpx;
background-color: $jx-warring;
color: #fff;
font-size: 24rpx;
padding: 0 15rpx 5rpx 15rpx;
border-radius: 20rpx;
animation: bill-new-animation 0.5s ease-in-out infinite alternate;
}
// 消息通知
.msg-count {
position: absolute;
top: 20rpx;
right: 35rpx;
color: #fff;
background-color: $jx-warring;
font-size: 24rpx;
min-width: 18rpx;
min-height: 20rpx;
line-height: 20rpx;
text-align: center;
line-height: 1;
padding: 4rpx 8rpx 5rpx 8rpx;
border-radius: 100rpx;
}
// 差评管理
.evaluate-number {
position: absolute;
top: 20rpx;
right: 30rpx;
color: #fff;
background-color: $jx-warring;
font-size: 24rpx;
line-height: 1;
padding: 4rpx 8rpx 5rpx 8rpx;
border-radius: 100rpx;
min-width: 30rpx;
text-align: center;
max-height: 35rpx;
}
// 发现新版本
.newVarsion {
position: absolute;
top: 15rpx;
right: 30rpx;
display: inline-block;
background-color: $jx-warring;
width: 30rpx;
height: 30rpx;
border-radius: 50%;
font-size: 24rpx;
line-height: 30rpx;
text-align: center;
color: #fff;
padding: 5rpx;
animation: bill-new-animation 0.5s ease-in-out infinite alternate;
}
}
.v {
position: absolute;
bottom: 5rpx;
right: 20rpx;
color: rgb(232, 232, 232);
}
}
@keyframes bill-new-animation {
0% {
transform: scale(0.95);
}
100% {
transform: scale(1.05);
}
}

View File

@@ -0,0 +1,274 @@
/**
* options 选项
*/
import toast from "@/utils/toast"
import { store } from '@/store'
import { timeFormatD } from "@/utils/tools"
import { getStorage } from "@/utils/storage"
import { onLoad, onPullDownRefresh } from "@dcloudio/uni-app"
import { Ref, ref, onBeforeUnmount,watch } from "vue"
import merchant from "@/api/https/merchant"
import useGlobalFunc from '@/composables/useGlobalFunc'
import order from "@/api/https/order"
function options() {
const { openWeixin, watchVersion } = useGlobalFunc()
/**
* 进入群聊
*/
function getGroupChat() {
openWeixin('subPages/merchantChild/enterGroupChat/enterGroupChat')
}
/**
* 注册时间
*/
async function getSelfInfo() {
let infoRes = await merchant.get_self_info()
if (infoRes.code == 0) {
let time1 = Math.floor((+new Date() - +new Date(infoRes.data.createdAt)) / 1000 / 24 / 3600)
let time2 = Math.floor((+new Date() - +new Date(store.state.storeInfo.createStoreTimer)) / 1000 / 24 / 3600)
uni.jxAlert({
title: '回首过往',
content: `门店ID:${getStorage('storeID')}\r\n\r\n您注册于${timeFormatD(infoRes.data.createdAt)}\r\n来到京西${time1}\r\n\r\n门店创建于${timeFormatD(store.state.storeInfo.createStoreTimer)}\r\n在平台经营${time2}`
})
} else toast('注册数据异常', 2)
}
/**
* 物料申请
*/
function moveToWM() {
let tel = store.state.storeInfo.allStoreInfo.marketManPhone ? store.state.storeInfo.allStoreInfo.marketManPhone : "18048531223"
if (getStorage('terrace') != 'jxcs') {
// 果园禁止物料跳转
uni.jxAlert({
title: '物料申请',
content: `非常抱歉,无法进入物料商城,请联系运营${tel}`
})
return
} else {
if (store.state.storeInfo.allStoreInfo.packageSwitch === 1) {
uni.jxAlert({
title: '物料申请',
content: `非常抱歉,无法进入物料商城,请联系运营${tel}`
})
return
}
}
if (store.state.storeInfo.storeStatus === -2) {
uni.jxAlert({
title: '物料申请',
content: '门店已被禁用,请联系运营'
})
}
openWeixin(`pages/index/index?storeID=666666&fromStoreID=${getStorage('storeID')}&storeType=c4`, 'gh_0d7e2243b51f')
}
/**
* 查询是否有新账单
*/
const isInstallWx = ref<boolean>(false) // 是否安装微信
onLoad(async () => {
if (plus.runtime.isApplicationExist({ pname: 'com.tencent.mm', action: 'weixin://' })) {
isInstallWx.value = true
} else {
isInstallWx.value = false
}
await handleMsg()
await tmpGetJxBadCommentsNo()
await getMessageData()
})
// 处理新账单
const billUrl: Ref<string | undefined | object[]> = ref('')
const newBillShow: Ref<boolean> = ref(false) // 是否有新帐单
function handleMsg() {
getStoreBills((url: Array<object> | string) => {
if (typeof (url) == 'string') {
billUrl.value = url
// 保存新账单url地址 存vuex
store.commit('serveInfo/setOrderUrl', url)
// 查询本地账单地址
if (getStorage('newBillUrl') !== billUrl.value) {
// 有新账单
newBillShow.value = true
} else {
// 没有新帐单
newBillShow.value = false
}
}
})
}
// 查询新订单
interface BillListType {
billName: string
billTitle: string
date: string
id: number
shopName: string
storeId: string
url: string
}
const billList = ref<Array<BillListType>>([])
async function getStoreBills(fn: Function) {
let data = {
storeID: getStorage('storeID')
}
let newOrderRes = await merchant.get_store_bills(data)
if (newOrderRes.code == 0) {
let newMsg: Array<object> | string = []
if (newOrderRes.data != null) {
billList.value = newOrderRes.data.slice(0, 5)
billList.value = billList.value.map((bill) => {
let time = bill.date
bill.date = timeFormatD(time)
return bill
})
newMsg = newOrderRes.data[0].url.trim()
fn && fn(newMsg)
} else {
billList.value = []
fn && fn(newMsg)
}
} else {
toast('账单数据异常', 2)
}
}
/**
* 是否有新信息
*/
const msgCount = ref<number>(0)
async function getMessageData() {
let data = {
storeIDs: JSON.stringify([+getStorage('storeID')]),
fromReadCount: 0,
toReadCount: 0,
offset: 0,
pageSize: -1,
fromTime:
timeFormatD(+new Date() - 7 * 24 * 60 * 60 * 1000) + ' 00:00:00',
toTime: timeFormatD(+new Date()) + ' 23:59:59',
}
let msgRes = await merchant.Get_store_message_statuses(data)
if (msgRes.code == 0) {
msgCount.value = msgRes.data.totalCount
} else {
toast('消息数据异常')
}
}
/**
* 获取差评数量
*/
let badCommentCount: Ref<number | string> = ref(0)
async function tmpGetJxBadCommentsNo() {
let data = {
jxStoreId: getStorage('storeID')
}
let evaluateMRes = await merchant.tmp_get_jx_bad_comments_no(data)
if (evaluateMRes.code == 0) {
badCommentCount.value = evaluateMRes.data ? evaluateMRes.data : 0
} else toast('差评数据异常', 2)
}
watch(() => store.getters['storeInfo/imMtStatus'],
(val) => {
if(val && val.length>0) getInvoiceInfo()
})
/**
* 发票数量
*/
const invoiceCount:Ref<number | string> = ref(0)
async function getInvoiceInfo() {
// if(store.getters['storeInfo/imEbStatus'] && store.getters['storeInfo/imEbStatus'].length>0){
// // 存在饿百门店
// }
// 美团们门店
if(store.getters['storeInfo/imMtStatus'] && store.getters['storeInfo/imMtStatus'].length>0) {
let data:AnyObject = {
storeId: getStorage('storeID'),
startTime: `${timeFormatD(+new Date() - 7 * 24 * 60 * 60 * 1000)}` + ' 00:00:00',
endTime:`${timeFormatD()}` + ' 23:59:59',
pageSize: -1,
offset: 0
}
let res = await order.query_mt_invoice(data)
invoiceCount.value = res.data.totalCount
}
}
/**
* 打开小程序
*/
function openAppOrApplet() {
openWeixin('pages/merchant/index')
}
/*************************************************
* 下拉刷新
*/
let onPullDownRefreshTimer: any = null
onPullDownRefresh(() => {
clearTimeout(onPullDownRefreshTimer)
onPullDownRefreshTimer = setTimeout(async () => {
uni.stopPullDownRefresh()
await tmpGetJxBadCommentsNo()
await getMessageData()
await handleMsg()
await getInvoiceInfo()
}, 1000)
})
/**
* 版本更新
*/
const isVarsion = ref<boolean>(false)
function isUpdate(type: number) {
watchVersion((res: boolean) => {
if (res) {
uni.globalAlert({
data: {
type: 3,
},
})
isVarsion.value = true
} else {
isVarsion.value = false
if (type == 1) toast('已经是最新版')
}
})
}
onBeforeUnmount(() => {
clearTimeout(onPullDownRefreshTimer)
})
return {
getGroupChat, // 跳转加入群聊
getSelfInfo, // 获取门店来京西的时间
moveToWM, // 物料申请
newBillShow, // 是否有新账单
billList, // 账单列表
msgCount, // 是否有信息
badCommentCount, // 获取差评数量
invoiceCount, // 发票数量
openAppOrApplet, // app or 小程序
isVarsion, // 是否现实新版本
isUpdate, // 版本更新
isInstallWx, // 是否安装微信
}
}
export default options

View File

@@ -0,0 +1,315 @@
<template>
<view class="options-root">
<uni-grid :column="4" :highlight="true" :showBorder="false">
<!-- grid -->
<uni-grid-item
v-for="(item, i) in newGrindListData"
:key="i"
@tap="grindData(item.id)"
>
<view class="grid-item-box">
<image :src="item.icon" mode="scaleToFill" class="image" />
<text class="text">{{ item.title }}</text>
<!-- ***** 角标内容 ****** -->
<!-- 我的账单 -->
<text class="bill-new" v-if="item.id == 4 && newBillShow">new</text>
<!-- 信息通知 -->
<text class="msg-count" v-if="item.id == 6 && msgCount > 0">{{
msgCount
}}</text>
<!-- 差评管理 -->
<text
class="evaluate-number"
v-if="item.id == 5 && +badCommentCount > 0"
>
{{ +badCommentCount < 99 ? badCommentCount : '99+' }}
</text>
<!-- 发票数量 -->
<text
class="evaluate-number"
v-if="item.id == 22 && +invoiceCount > 0"
>
{{ +invoiceCount < 99 ? invoiceCount : '99+' }}
</text>
<!-- 发现新版本 -->
<text v-if="item.id == 17 && isVarsion" class="newVarsion"></text>
</view>
</uni-grid-item>
<template v-if="isInstallWx">
<jx-ios-android isShow="ios">
<uni-grid-item>
<view class="grid-item-box" @tap="moveToWM">
<image
src="/static/merchant-icon/7.png"
mode="scaleToFill"
class="image"
/>
<text class="text">物料申请</text>
</view>
</uni-grid-item>
</jx-ios-android>
</template>
</uni-grid>
<!-- 版本 -->
<text class="v">𝑽 {{ oldVersion }}</text>
</view>
</template>
<script lang="ts" setup>
import options from './options'
import { computed, ref } from 'vue'
const {
getGroupChat, // 跳转加入群聊
getSelfInfo, // 获取门店来京西的时间
moveToWM, // 物料申请
newBillShow, // 是否有新订单
msgCount, // 是否有信息
billList, // 账单列表
badCommentCount, // 差评数量
invoiceCount, // 发票数量数量
openAppOrApplet, // app or 小程序
isVarsion, // 是否现实新版本
isUpdate, // 版本更新
isInstallWx, // 是否安装微信
} = options()
const oldVersion = ref<string>(uni.getSystemInfoSync().appVersion) // 版本号
// 不用展示信息的图标
// 未下载微信不展示
const grindListData = ref([
{
id: 1,
icon: '/static/merchant-icon/1.png',
title: '加入群聊',
isIos: true,
},
{
id: 2,
icon: '/static/merchant-icon/2.png',
title: '营业资质',
isIos: false,
},
{
id: 3,
icon: '/static/merchant-icon/3.png',
title: '我的店铺',
isIos: false,
},
{
id: 4,
icon: '/static/merchant-icon/4.png',
title: '我的账单',
isIos: false,
},
{
id: 5,
icon: '/static/merchant-icon/5.png',
title: '差评管理',
isIos: false,
},
{
id: 6,
icon: '/static/merchant-icon/6.png',
title: '消息通知',
isIos: false,
},
{
id: 7,
icon: '/static/merchant-icon/7.png',
title: '物料申请',
isIos: true,
},
{
id: 16,
icon: '/static/merchant-icon/8.png',
title: '扫码进店',
isIos: false,
},
{
id: 8,
icon: '/static/merchant-icon/9.png',
title: '待配商品',
isIos: false,
},
{
id: 9,
icon: '/static/merchant-icon/10.png',
title: '门店评分',
isIos: false,
},
{
id: 10,
icon: '/static/merchant-icon/11.png',
title: '帮助中心',
isIos: false,
},
{
id: 11,
icon: '/static/merchant-icon/12.png',
title: '官方客服',
isIos: false,
},
{
id: 12,
icon: '/static/merchant-icon/13.png',
title: '设置',
isIos: false,
},
{
id: 13,
icon: '/static/merchant-icon/14.png',
title: '活动信息',
isIos: false,
},
{
id: 14,
icon: '/static/merchant-icon/15.png',
title: '注册时间',
isIos: false,
},
{
id: 15,
icon: '/static/merchant-icon/17.png',
title: '打开小程序',
isIos: true,
},
{
id: 18,
icon: '/static/merchant-icon/19.png',
title: '个人信息',
isIos: false,
},
{
id: 22,
icon: '/static/merchant-icon/22.png',
title: '发票管理',
isIos: false,
},
{
id: 20,
icon: '/static/merchant-icon/21.png',
title: '收款信息',
},
{
id: 19,
icon: '/static/merchant-icon/20.png',
title: '配送余额',
isIos: false,
},
{
id: 17,
icon: '/static/merchant-icon/18.png',
title: '检查更新',
isIos: false,
},
])
/*************************************************
* 格式化数据IOS不展示
*/
const newGrindListData: AnyObject = computed(() => {
if (uni.getSystemInfoSync().platform == 'ios') {
return grindListData.value.filter((res: any) => res.isIos == false)
} else {
let brand = uni.getSystemInfoSync().brand
if (brand == 'huawei' || brand == 'honor') {
return grindListData.value.filter((res: any) => res.id != 17)
} else {
return grindListData.value
}
}
})
function grindData(title: number) {
switch (title) {
case 1:
getGroupChat() // 加入群聊
break
case 2:
uni.navigateTo({
url: '/subPages/merchantChild/businessLicense/businessLicense',
}) // 营业资质
break
case 3:
uni.navigateTo({ url: '/subPages/merchantChild/platformM/platformM' }) // 我的店铺
break
case 4:
uni.navigateTo({
url: `/subPages/merchantChild/bill/bill?billList=${JSON.stringify(
billList.value
)}`,
}) // 我的账单
break
case 5:
uni.navigateTo({
url: `/subPages/merchantChild/evaluateM/evaluateM?number=${badCommentCount.value}`,
}) // 差评管理
break
case 6:
uni.navigateTo({
url: '/subPages/merchantChild/message/message',
}) // 消息通知
break
case 7:
moveToWM()
break
case 8:
uni.navigateTo({
url: '/subPages/merchantChild/waitGoods/waitGoods',
}) // 待配商品
break
case 9:
uni.navigateTo({
url: '/subPages/merchantChild/storeScore/storeScore',
}) // 门店评分
break
case 10:
uni.navigateTo({ url: '/subPages/merchantChild/helpCenter/helpCenter' }) // 帮助中心
break
case 11:
uni.navigateTo({ url: '/subPages/orderChild/getPhone/getPhone' }) // 联系客服
break
case 12:
uni.navigateTo({ url: '/subPages/merchantChild/setUp/setUp' }) // 设置
break
case 13:
uni.navigateTo({ url: '/subPages/merchantChild/activity/activity' }) // 活动信息
break
case 14:
getSelfInfo() // 注册时间
break
case 15:
openAppOrApplet() // 打开 app or 小程序
break
case 16:
uni.navigateTo({ url: '/subPages/merchantChild/shareStore/shareStore' }) // 扫码进店
break
case 17:
isUpdate(1) // 检查更新
break
case 18:
uni.navigateTo({ url: '/subPages/merchantChild/useInfo/useInfo' }) // 个人信息
break
case 19:
uni.navigateTo({
url: '/subPages/merchantChild/accountBalance/accountBalance',
}) // 配送余额
break
case 20:
uni.navigateTo({ url: '/subPages/merchantChild/payeeInfo/payeeInfo' }) // 收款信息
break
case 22:
uni.navigateTo({
url: '/subPages/merchantChild/invoice/invoice'
}) // 发票信息
break
}
}
</script>
<style lang="scss" scoped>
@import './options.scss';
</style>

View File

@@ -0,0 +1,49 @@
.order-data-root {
box-sizing: border-box;
background-color: #fff;
padding: 20rpx;
}
.title-root {
display: flex;
justify-content: space-between;
margin-bottom: 10rpx;
.see-more {
color: #cfcccc;
}
.text {
margin-right: 15rpx;
}
}
.order-money {
display: flex;
justify-content: space-between;
.money,
.order {
border-right: 1rpx solid #e0e0e0;
}
.money,
.order,
.order1 {
width: 354rpx;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.number {
font-weight: bold;
font-size: 40rpx;
padding: 30rpx 0;
}
}
.afterNumber::before{
content: '-';
}
}

View File

@@ -0,0 +1,147 @@
<template>
<view class="order-data-root" @tap="getOrderRealTime">
<view class="title-root">
<view>
<text class="text">今日完成实时数据</text>
<jx-icon icon="wenhaoxiao" color="#cfcccc" @tap.stop="explain" />
</view>
<view class="see-more" v-if="showMore">
<text>更多</text>
<jx-icon icon="gengduo" color="#cfcccc" />
</view>
</view>
<view class="order-money">
<view class="money">
<text class="number">{{ price }}</text>
<text>{{ vendorTitle }}</text>
</view>
<view class="order">
<text class="number">{{ count }}</text>
<text>有效订单量</text>
</view>
<view class="order1">
<text class="number" :class="{'afterNumber': +actualFee > 0}">{{ actualFee }}</text>
<text>运费</text>
</view>
</view>
</view>
</template>
<script lang="ts" setup>
import jxIcon from '@/components/jx-icon/jx-icon.vue'
import { computed, Ref } from 'vue'
import useGlobalFunc from '@/composables/useGlobalFunc'
import { store } from '@/store'
const { wholeCalcPrice, singleCalcPrice } = useGlobalFunc()
interface propsType {
saleInfo: AnyObject
showMore?: boolean
_vendorPayPercentage: number | string
isNotQuote: boolean
isShowShop?: boolean
isZero: boolean
isUpperfif: boolean
isOut?: boolean
isAllplatfrom?: boolean
}
const props = defineProps<propsType>()
/*************************************************
* 判断门店是否为折扣
*/
const isPointStore = computed(() => {
return store.getters['storeInfo/isPointStore']
})
/*************************************************
* 收入说明
*/
const vendorTitle = computed(() => {
if (isPointStore.value) {
return '实际支付'
} else {
if (props._vendorPayPercentage != 0 && +props._vendorPayPercentage < 50) {
//扣点
return '实际支付'
} else {
//报价
return '实际收入'
}
}
})
/*************************************************
* 订单数量
*/
const count: Ref<number | string> = computed(() => {
return props.saleInfo.count || '0'
})
/*************************************************
* 扣除运费
*/
const actualFee: Ref<number | string> = computed(() => {
return props.saleInfo.actualFee || '0'
})
/*************************************************
* 门店收益
*/
const price = computed(() => {
if (count.value) {
if (props.isAllplatfrom || props.isOut) {
//全平台
let calcData = {
vendorPayPercentage: props._vendorPayPercentage,
actualPayPrice: props.saleInfo.actualPayPrice,
shopPrice: props.saleInfo.shopPrice,
isPointStore: isPointStore.value,
isUpperfif: props.isUpperfif,
isZero: props.isZero,
isNotQuote: props.isNotQuote,
earningPrice: props.saleInfo.earningPrice,
}
return wholeCalcPrice(calcData)
} else {
//单平台
let calcData = {
vendorPayPercentage: props._vendorPayPercentage,
actualPayPrice: props.saleInfo.actualPayPrice,
shopPrice: props.saleInfo.shopPrice,
isPointStore: isPointStore.value,
earningPrice: props.saleInfo.earningPrice,
}
return singleCalcPrice(calcData)
}
} else {
return 0
}
})
/**
* 打开说明窗口
*/
function explain() {
uni.jxAlert({
title: '说明',
content: `实际收入: 从当日0时到当前时间的实际获得不再扣点已扣除售后退款\r\n有效订单: 统计时间内,已支付订单中未被取消的订单数量`,
})
}
/**
* 跳转到营业数据
*/
function getOrderRealTime() {
if (props.showMore != true) return
uni.navigateTo({
url: `/subPages/merchantChild/orderRealTime/orderRealTime?_vendorPayPercentage=${props._vendorPayPercentage}&isShowShop=${props.isShowShop}&isNotQuote=${props.isNotQuote}&isZero=${props.isZero}&isUpperfif=${props.isUpperfif}`,
})
}
</script>
<style lang="scss" scoped>
@import './orderData.scss';
</style>

View File

@@ -0,0 +1,45 @@
.order-data-root {
box-sizing: border-box;
background-color: #fff;
padding: 20rpx;
}
.title-root {
display: flex;
justify-content: space-between;
margin-bottom: 10rpx;
.see-more {
color: #cfcccc;
}
.text {
margin-right: 15rpx;
}
}
.order-money {
display: flex;
justify-content: space-between;
.money,
.order {
border-right: 1rpx solid #e0e0e0;
}
.money,
.order,
.order1 {
width: 354rpx;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.number {
font-weight: bold;
font-size: 40rpx;
padding: 30rpx 0;
}
}
}

View File

@@ -0,0 +1,88 @@
<template>
<view class="order-data-root" @tap="getOrderRealTime">
<view class="title-root">
<view>
<text class="text">今日完成实时数据</text>
<jx-icon icon="wenhaoxiao" color="#cfcccc" @tap.stop="explain" />
</view>
<view class="see-more" v-if="showMore">
<text>更多</text>
<jx-icon icon="gengduo" color="#cfcccc" />
</view>
</view>
<view class="order-money">
<view class="money">
<text class="number">{{ price }}</text>
<text>门店收益</text>
</view>
<view class="order">
<text class="number">{{ count }}</text>
<text>有效订单量</text>
</view>
<view class="order1">
<text class="number">-{{ actualFee }}</text>
<text>运费</text>
</view>
</view>
</view>
</template>
<script lang="ts" setup>
import jxIcon from '@/components/jx-icon/jx-icon.vue'
import { computed, Ref } from 'vue'
interface propsType {
saleInfo: AnyObject
showMore?: boolean
}
const props = defineProps<propsType>()
/*************************************************
* 扣除运费
*/
const actualFee: Ref<number | string> = computed(() => {
return props.saleInfo.actualFee || '0'
})
/*************************************************
* 门店收益
*/
const price = computed(() => {
return props.saleInfo.realEarningPrice
? (props.saleInfo.realEarningPrice / 100).toFixed(2)
: '0.00'
})
/*************************************************
* 有效订单量
*/
const count = computed(() => {
return props.saleInfo.count || '0'
})
/**
* 打开说明窗口
*/
function explain() {
uni.jxAlert({
title: '说明',
content: `实际收入: 从当日0时到当前时间的实际获得不再扣点已扣除售后退款\r\n有效订单: 统计时间内,已支付订单中未被取消的订单数量`,
})
}
/**
* 跳转到营业数据
*/
function getOrderRealTime() {
if (props.showMore != true) return
uni.navigateTo({
url: '/subPages/merchantChild/orderRealTimeJxgy/orderRealTimeJxgy',
})
}
</script>
<style lang="scss" scoped>
@import './orderDataJxgy.scss';
</style>

View File

@@ -0,0 +1,200 @@
.merchant-root {
position: sticky;
top: 0;
z-index: 9;
box-sizing: border-box;
background-color: #4eb331;
z-index: 1;
.store-timer {
text-align: center;
color: #fcff06;
height: 0rpx;
line-height: 50rpx;
overflow: hidden;
transition: all 0.5s;
.text {
margin-left: -60rpx;
}
}
.store-active {
height: 50rpx;
}
.info-root {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0rpx 20rpx 20rpx 20rpx;
.user-infor-root {
display: flex;
align-items: center;
image {
box-sizing: border-box;
width: 140rpx;
height: 140rpx;
border-radius: 50%;
border: 4rpx solid #fff;
background-color: #fff;
}
.isHeight {
height: 190rpx;
}
.storeName-style-timer {
display: flex;
flex-direction: column;
color: #fff;
width: 380rpx;
margin-left: 25rpx;
.timer-root {
margin-top: 5rpx;
line-height: 1;
padding: 10rpx 10rpx;
background-color: rgba(0, 0, 0, 0.15);
border-radius: 10rpx;
}
.name,
.state,
.timer-root {
display: inline-block;
max-width: 380rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
margin-bottom: 10rpx;
}
.state,
.timer {
font-size: 28rpx;
}
.state {
display: flex;
align-items: center;
.tip{
display: flex;
line-height: 46rpx;
.title{
font-size: 24rpx;
}
}
.do-business-root {
display: flex;
align-items: center;
justify-content: center;
background: #3e8f27;
border-radius: 80rpx;
color: #cccccc;
margin-right: 10rpx;
transition: all 0.4s;
.text {
padding: 0 15rpx;
}
}
.business-active {
background-color: #ffad49;
color: #fff;
}
}
}
}
.esc-switchSoter {
width: 152rpx;
button {
font-size: 24rpx;
color: #4eb331;
white-space: nowrap;
}
.swithcStore-btn {
margin-top: 20rpx;
}
}
}
}
.jx-popup-update {
box-sizing: border-box;
padding: 20rpx;
background-color: #fff;
border-radius: 0 0 15rpx 15rpx;
.status_bar {
height: var(--status-bar-height);
width: 100%;
background-color: $jx-primary;
}
.text {
display: block;
width: 100%;
text-align: center;
margin-bottom: 25rpx;
padding-bottom: 10rpx;
border-bottom: 2rpx solid rgb(209, 209, 209);
}
// .tip {
// padding: 10rpx 0;
// .money {
// color: $jx-primary;
// }
// }
.ipt {
border: 2rpx solid rgb(209, 209, 209);
text-align: center;
height: 140rpx;
border-radius: 5rpx;
padding-bottom: 20rpx;
}
.btn-root {
display: flex;
justify-content: space-between;
margin: 40rpx 0 0rpx 0;
.btn-esc,
.btn-ok {
text-align: center;
width: 100%;
padding: 15rpx 0;
border-radius: 10rpx;
border: 2rpx solid $jx-primary;
color: $jx-primary;
}
.btn-ok {
background-color: $jx-primary;
color: #fff;
margin-left: 10rpx;
}
.btn-esc {
margin-right: 10rpx;
}
}
// .delete {
// margin-top: 50rpx;
// margin-bottom: 20rpx;
// background-color: $jx-warring;
// text-align: center;
// color: #fff;
// padding: 20rpx;
// border-radius: 15rpx;
// }
}

View File

@@ -0,0 +1,158 @@
/**
* 用户信息类
*/
import { getStorage, setStorage } from "@/utils/storage";
import { onPullDownRefresh, onShow, onLoad } from "@dcloudio/uni-app";
import { computed, onBeforeUnmount, ref } from "vue";
import { timeFormatD } from "@/utils/tools";
import { store } from "@/store";
import useGlobalFunc from "@/composables/useGlobalFunc";
function userInfo() {
// vuex
const { newMessage, logOutFn, isTxd, getMtStoreIMStatus } = useGlobalFunc()
/**
* 门店自动营业时间
*/
const newAutoEnableAt = ref<string>('')
const switchOpenTime = computed(() => {
if (newAutoEnableAt.value) {
let now = +new Date(timeFormatD(+new Date()));
let time = +new Date(timeFormatD(newAutoEnableAt.value));
let num = time - now;
if (num < 0) {
return "营业时间错误请联系运营";
} else {
let day = num / 1000 / 3600 / 24;
if (day < 1) return "门店将在今天自动营业";
else if (day >= 1 && day < 2) return "门店将在明天自动营业";
else if (day >= 2 && day < 3) return "门店将在后天自动营业";
else return `将在 ${timeFormatD(newAutoEnableAt.value)} 自动营业`;
}
} else {
return "";
}
})
/**
* 下拉刷新
*/
let onPullDownRefreshTimer: any = null
onPullDownRefresh(async () => {
await getStores()
clearTimeout(onPullDownRefreshTimer)
onPullDownRefreshTimer = setTimeout(() => {
uni.stopPullDownRefresh()
}, 1000)
})
/**
* 用户头像、门店名字
*/
interface StoreInfoType {
avatar: string;
storeName: string;
}
const storeInfo = ref<StoreInfoType>({
avatar: "https://image.jxc4.com/image/70143fcf48aefe74537533f35a0a8153.jpg",
storeName: "",
});
let oldStoreID: any = 0
onShow(async () => {
getStores()
storeInfo.value.storeName = getStorage("storeName")
if (oldStoreID != getStorage('storeID') && oldStoreID != 0) {
uni.startPullDownRefresh({})
}
oldStoreID = getStorage('storeID')
});
onLoad(async () => {
await getStores()
await newMessage() // 商家中心有新信息了
})
const businessHours = ref<AnyObject>({})
async function getStores() {
await store.dispatch('storeInfo/getOneStore',getStorage("storeID"))
businessHours.value = store.getters['storeInfo/businessHours'] // 营业时间
newAutoEnableAt.value = store.getters['storeInfo/newAutoEnableAt'] // 手机门店休息时间
await getMtStoreIMStatus() // 获取门店的IM单聊开关状态
await newMessage() // 商家中心有新信息了
}
/*************************************************
* 去修改营业时间
*/
function setTime() {
uni.navigateTo({ url: `/subPages/merchantChild/setBusinessTime/setBusinessTime` })
}
/**
* 退出登录
*/
let goLoginTime: any = null
function goLogin() {
uni.showActionSheet({
title: '退出后不会删除任何数据',
itemColor: '#e70808',
itemList: ['退出登录'],
popover: {
width: 5000,
},
success: function (res) {
logOutFn();
// uni.navigateTo({ url: '/subPages/login/wxLogin/wxLogin' })
uni.reLaunch({ url: '/subPages/login/wxLogin/wxLogin' })
},
fail: () => {
console.log('ZSW-取消退出');
}
});
}
/**
* 切换门店
*/
function switchStore() {
uni.navigateTo({ url: "/subPages/switchStore/switchStore" });
}
/**
* 跳转到设置营业状态页面
*/
function jumpBusinessStatus() {
uni.navigateTo({
url: '/subPages/merchantChild/setBusinessStatus/setBusinessStatus'
})
}
/*************************************************
* 做收尾工作
*/
onBeforeUnmount(() => {
clearTimeout(onPullDownRefreshTimer)
clearTimeout(goLoginTime)
})
return {
storeInfo, // 用户信息
businessHours, // 营业时间段
goLogin, // 退出登录
switchStore, // 切换门店
switchOpenTime, // 门店休息到那天
setTime, // 去修改营业时间
jumpBusinessStatus, // 跳转到营业状态页面
store
}
}
export default userInfo

View File

@@ -0,0 +1,83 @@
<template>
<view class="merchant-root">
<view class="store-timer" :class="{ 'store-active': switchOpenTime != '' }">
<text class="text">{{ switchOpenTime }}</text>
</view>
<view class="info-root">
<view class="user-infor-root">
<image
@longtap=""
:src="storeInfo.avatar"
mode="scaleToFill"
@tap="previewImage(storeInfo.avatar)"
/>
<view class="storeName-style-timer">
<view class="name">{{ storeInfo.storeName }}</view>
<view class="state">
<view class="tip" @tap="jumpBusinessStatus">
<view class="title">营业状态</view>
<view
class="do-business-root business-active"
>
<text class="text">{{store.getters['storeInfo/storeStatus'] === 1?'营业中':store.getters['storeInfo/storeStatus'] === 0?'临时休息':store.getters['storeInfo/storeStatus'] === -1?'休息':store.getters['storeInfo/storeStatus'] === -2?'禁用':'未知'}}</text>
<jx-icon icon="shuxie" color="#fff"/>
</view>
</view>
</view>
<!-- 营业时间段 -->
<view
class="timer-root"
v-if="
businessHours.timer != '00:00' && businessHours.timer2 != '00:00'
"
@tap="setTime"
>
<view class="timer">
营业时间段{{ businessHours.timer1 }}至{{ businessHours.timer2 }}
<jx-icon icon="shuxie" color="#fff" />
</view>
<view
class="timer"
v-if="
businessHours.timer3 != '00:00' &&
businessHours.timer4 != '00:00'
"
>
营业时间段{{ businessHours.timer3 }}至{{ businessHours.timer4 }}
<jx-icon icon="shuxie" color="#fff" />
</view>
</view>
</view>
</view>
<view class="esc-switchSoter">
<button class="esc-btn" @tap="goLogin">退出登录</button>
<button class="swithcStore-btn" @tap="switchStore">切换门店</button>
</view>
</view>
</view>
</template>
<script lang="ts" setup>
import jxIcon from '@/components/jx-icon/jx-icon.vue'
import userInfo from './userInfo'
import useGlobalFunc from '@/composables/useGlobalFunc'
const { previewImage } = useGlobalFunc()
const {
storeInfo, // 用户信息
businessHours, // 营业时间段
goLogin, // 退出登录
switchStore, // 切换门店
switchOpenTime, // 门店休息到哪天
setTime, // 去修改营业时间
jumpBusinessStatus, // 跳转到营业状态页面
store
} = userInfo()
</script>
<style lang="scss" scoped>
@import './userInfo.scss';
</style>

227
src/pages/message/index.ts Normal file
View File

@@ -0,0 +1,227 @@
import toast from '@/utils/toast'
import { onPullDownRefresh, onShow } from '@dcloudio/uni-app'
import { computed, ref } from 'vue'
import { store } from "@/store"
import { Decrypt, timeFormatDHM } from '@/utils/tools'
import message from "@/api/https/message"
// import { msgInfo } from '@/api/mockData/index'
import order from '@/api/https/order'
import useGlobalFunc from "@/composables/useGlobalFunc";
import { setStorage, getStorage,cleatStorage } from "@/utils/storage";
/*************************************************
* IM消息
*/
const messageFn = function () {
// vuex
const { getMtStoreIMStatus } = useGlobalFunc()
// 用户列表
const userListData = ref<Array<AnyObject>>([])
/*************************************************
* 获取用户列表
*/
onShow(async () => {
if(getStorage('storeMessge')){
if(store.state.storeInfo.allStoreInfo.id !== getStorage('storeID')) await store.dispatch('storeInfo/getOneStore',getStorage("storeID"))
await getMtStoreIMStatus() // 获取美团im单聊状态
await getMTUserList() // 获取用户列表
cleatStorage('storeMessge')
}
uni.hideTabBarRedDot({ index: 2 })
if (isFirstLogin.value) return
userListData.value = []
getMTUserList()
})
const isFirstLogin = computed(() => {
// 是否没有登陆的状态
return store.state.serveInfo.isFirstLogin
})
/**
* 整理参数信息,避免请求出错
*/
async function dataParams() {
let arr:any = []
let brr = store.getters['storeInfo/platformInfo']
if(brr && brr.length>0){
let mtVendorIDInfo = brr.find((item:AnyObject) => item.vendorID === 1)
let ebVendorIDInfo = brr.find((item:AnyObject) => item.vendorID === 3)
if(mtVendorIDInfo){
arr.push({
vendorStoreID: mtVendorIDInfo.vendorStoreID,
vendorID: "1",
appID: mtVendorIDInfo.vendorOrgCode
})
}
if(ebVendorIDInfo){
arr.push({
vendorStoreID: ebVendorIDInfo.vendorStoreID,
vendorID: "3",
appID: ebVendorIDInfo.vendorOrgCode
})
}
}
return arr
}
// 获取美团IM
async function getMTUserList() {
let arr = await dataParams()
if(!(arr && arr.length>0)) return
let data = {
payLoad:JSON.stringify(arr)
}
let venderIDInfo = arr.find((item:AnyObject) => item.vendorID === '1')
let ebStore = arr.find((item:AnyObject) => item.vendorID === '3')
let res = await message.get_IM_user_list(data)
// res = msgInfo.userList // 模拟数据
if (res.code == 0) {
if (JSON.stringify(res.data) === '{}') return
let platformID = venderIDInfo.appID // 美团账号
let newArr: any = []
let fmtUserList = venderIDInfo ? res.data[`${venderIDInfo.appID}:${venderIDInfo.vendorStoreID}:1`] || [] : [] // 美团
let febUserList = ebStore && JSON.stringify(ebStore) !== '{}' ? res.data[`${ebStore.appID}:${ebStore.vendorStoreID}:3`] || [] : [] // 饿百
// let febUserList = res.data[`${ebStore.appID}:${ebStore.vendorStoreID}:3`] || []
let reverseList = fmtUserList.reverse()
let reverseListEb = febUserList.reverse()
// 格式化数据
reverseList.map((element: any) => {
let resData = JSON.parse(element)
let latestMsgHandler = ''
try {
JSON.parse(Decrypt(resData.latestMsg, platformID))
latestMsgHandler = typeof JSON.parse(Decrypt(resData.latestMsg, platformID)) === 'number' ? Decrypt(resData.latestMsg, platformID) : '【订单】'
} catch (error) {
let msg = Decrypt(resData.latestMsg, platformID)
if (msg == '') {
latestMsgHandler = '【商品】'
} else {
if (!(msg.includes('https') || msg.includes('http'))) {
latestMsgHandler = msg
} else {
if (msg.indexOf('.amr') == -1) {
latestMsgHandler = '【图片】'
} else {
latestMsgHandler = '【语音】'
}
}
}
}
// if (resData.userID != 0) {
// 只展示12个小时以内的消息
let userList = {
...resData,
latestMsg: latestMsgHandler,
latestTime: timeFormatDHM(+new Date(resData.latestTime * 1000)),
orderInfo: {},
orderDesc: ''
}
newArr.push(userList)
// 获取订单信息
// if (userList.orderID) getOrderInfo(userList.orderID, index)
if (userList.orderID) getOrderInfo(userList.orderID, newArr.length - 1)
// }
})
// 饿百
reverseListEb.map((element: any, index: number) => {
let resData = JSON.parse(element)
// let isAddUserLiset = JSON.parse(resData.latestMsg).data && JSON.parse(JSON.parse(resData.latestMsg).data).title.includes('本次服务已经完成,会话暂停') ? false : true
let latestMsgHandler = JSON.parse(resData.latestMsg).text ? JSON.parse(resData.latestMsg).text : JSON.parse(resData.latestMsg).duration ? '【语音】' : '【图片】'
if (JSON.parse(resData.latestMsg).elements && JSON.parse(resData.latestMsg).elements.length > 0) {
let findItem = JSON.parse(resData.latestMsg).elements.filter((item: { elementType: number }) => item.elementType === 1)
latestMsgHandler = findItem && findItem.length > 0 ? JSON.parse(findItem[0].elementContent).text.replace('@商家', '') : latestMsgHandler
}
// 饿百参考文档https://open-retail.ele.me/#/apidoc/me.ele.retail:im.message.send-3?aopApiCategory=IM_all&type=api_menu && isAddUserLiset
if ((new Date().getTime() - resData.latestTime * 1000) <= (3600 * 1000 * 12 * 1)) {
let userList = {
...resData,
latestMsg: latestMsgHandler,
latestTime: timeFormatDHM(+new Date(resData.latestTime * 1000)),
orderInfo: {},
orderDesc: ''
}
newArr.push(userList)
// 获取订单信息
// if (userList.orderID) getOrderInfo(userList.orderID, index)
if (userList.orderID) getOrderInfo(userList.orderID, newArr.length - 1 )
}
})
userListData.value = newArr
} else {
toast('获取信息异常')
userListData.value.length == 0
}
}
/**
* 获取订单信息
*/
async function getOrderInfo(orderId: string, index: number) {
let res = await order.get_orders({ vendorOrderID: orderId })
if (res.code === '0') {
userListData.value[index].orderInfo = res.data.data[0]
userListData.value[index].orderDesc = ` #${res.data.data[0].orderSeq}`
}
}
/**
* 下拉刷新
*/
let onPullDownRefreshTimer: any = null
onPullDownRefresh(() => {
clearTimeout(onPullDownRefreshTimer)
onPullDownRefreshTimer = setTimeout(async () => {
getMtStoreIMStatus() // 获取美团im单聊状态
// 获取用户列表
getMTUserList()
clearTimeout(onPullDownRefreshTimer)
}, 500)
})
/*************************************************
* 进入聊天页面
*/
function charItem(item: AnyObject) {
item.latestMsg = ""
uni.navigateTo({
url: `/subPages/messageChild/msgChat/msgChat?data=${JSON.stringify(item)}`,
})
}
/*************************************************
* 进入设置页面
*/
function jumpToSetUp() {
uni.navigateTo({
url: `/subPages/merchantChild/setUp/setUp`,
})
}
return {
charItem, // 进入聊天页面
userListData, // 用户列表
jumpToSetUp, // 跳到设置页面
store
}
}
export default messageFn

View File

@@ -0,0 +1,76 @@
<template>
<!-- 美团授权已过期 -->
<!-- <jx-empty v-if="imOnlineStatus === -1" title="美团授权已过期" /> -->
<!-- IM状态 -->
<view v-if="store.getters['storeInfo/imStatus']" style="position:absolute;bottom:0;width:100%">
<view class="notice" @tap="jumpToSetUp">
<text>{{store.getters['storeInfo/imStatus']}}IM单聊状态已经关闭</text>
<jx-icon icon="gengduo" color="red"></jx-icon>
</view>
<!-- IM状态已经关闭是否打开 -->
</view>
<!-- 用户列表 -->
<template v-if="userListData.length > 0">
<uni-list :border="false">
<view class="chat-border" v-for="item in userListData" :key="item.userID">
<uni-list-chat
:clickable="true"
@click="charItem(item)"
:avatar-circle="true"
:title="
item.vendorID == 1
? `【美团${item.orderDesc}】${item.userID === '0' ? '群发消息' : item.userID}`
: `【饿了么】${item.userID}`
"
:avatar="
item.vendorID == 1
? 'https://image.jxc4.com/image/75654ab606494a0efdb0cf7d7ad060d9.png'
: 'https://image.jxc4.com/image/6c2f1dfd95890df8ef5e27bde15c4e7f.png'
"
:note="item.latestMsg"
:time="item.latestTime"
badge-positon="left"
:badge-text="item.NewMessageNum"
/>
</view>
</uni-list>
</template>
<jx-empty v-else title="暂无消息" />
<!-- 公共组件 -->
<jx-login-empty title="马上登录,查看消息" />
<jx-loading />
</template>
<script lang="ts" setup >
import messageFn from './index'
const {
charItem, // 聊天详情
userListData, // 用户列表
jumpToSetUp, // 跳到设置页面
store
} = messageFn()
</script>
<style lang="scss" scoped>
.chat-border:nth-child(1) {
border-top: 2rpx solid rgb(230, 230, 230);
}
.chat-border {
border-bottom: 2rpx solid rgb(230, 230, 230);
}
.notice {
display: flex;
justify-content: space-between;
box-sizing: border-box;
width: 100%;
padding: 20rpx;
background-color: #fef5f6;
color: #e91d37;
font-size: 28rpx;
}
</style>

View File

@@ -0,0 +1,73 @@
.abnormal-order {
background-color: #fff;
margin-bottom: 25rpx;
padding-bottom: 1rpx;
.address {
display: flex;
justify-content: space-between;
padding: 15rpx;
font-size: 32rpx;
border-bottom: 2rpx dashed #e7e7e7;
color: #999999;
font-size: 28rpx;
}
.abnormal-op {
height: 90rpx;
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 32rpx;
padding: 0 20rpx;
background: linear-gradient(to right, #e8edd8, white);
.title {
color: #333;
font-weight: bold;
}
.op {
display: flex;
align-items: center;
.btn-cancel,
.btn-confirm {
color: #fff;
background-color: $jx-primary;
padding: 7rpx 30rpx;
border-radius: 7rpx;
}
.btn-cancel {
margin-right: 40rpx;
background-color: #F60D58;
}
}
}
.abnormal-dealed {
height: 90rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 32rpx;
background: white;
color: #333;
text {
font-weight: bold;
display: inline-block;
margin-left: 10rpx;
}
.agree {
color: green;
}
.refuse {
color: red;
}
}
}

View File

@@ -0,0 +1,90 @@
<template>
<view
class="abnormal-order position-relative"
@tap="orderDetail(item.vendorOrderID, item.vendorID)"
>
<order-list-top :item="item" />
<template v-if="getStorage('terrace') == 'jxcs' || getStorage('terrace') == 'gblm'">
<!-- 京西菜市 -->
<order-money :item="item" />
</template>
<template v-else>
<!-- 京西果园 -->
<order-money-jxgy :item="item" />
</template>
<!-- 地址 -->
<view class="divider"></view>
<view class="address">地址{{ item.consigneeAddress }}</view>
<view v-if="item.lockStatus === -5">
<view class="abnormal-op" @tap.stop v-if="(item.flag & 6) === 0">
<view class="title">用户申请取消订单</view>
<view class="op">
<view class="btn-cancel" @tap.stop="fnCancelOrder(0)">拒绝</view>
<view class="btn-confirm" @tap.stop="fnCancelOrder(1)">同意</view>
</view>
</view>
<view class="abnormal-dealed" v-if="(item.flag & 6) !== 0">
用户申请取消订单
<text class="agree" v-if="(item.flag & 6) === 2">[已同意]</text>
<text class="refuse" v-if="(item.flag & 6) === 6">[已拒绝]</text>
</view>
</view>
<template v-if="item.status === 17 && item.lockStatus === 0">
<bottom-component
title="骑手申请取消配送"
@handleCancel="fnCancelDeliver(0)"
@handleConfirm="fnCancelDeliver(1)"
confirmText="同意"
:order="item"
/>
</template>
<template v-if="item.status === 18 && item.lockStatus === 0">
<bottom-component
title="骑手取货失败"
@handleConfirm="fnCallNew"
confirmText="重新召唤骑手"
:order="item"
/>
</template>
<template v-if="item.status === 22 && item.lockStatus === 0">
<bottom-component
title="用户拒收"
@handleConfirm="fnGoodsReturn()"
confirmText="确认退回"
:order="item"
/>
</template>
</view>
</template>
<script lang="ts" setup >
import orderListTop from '../component/orderListTop.vue'
import orderMoney from '../component/orderMoney.vue'
import orderMoneyJxgy from '../component/orderMoneyJxgy.vue'
import { getStorage } from '@/utils/storage'
import bottomComponent from './bottom-component.vue'
import abonmrmalFn from './abonmrmal-order'
import useOrderInfo from '@/composables/useOrderInfo'
interface PropsType {
item: AnyObject
}
const props = defineProps<PropsType>()
const {
fnCancelOrder, // 是否统一用户取消订单
fnCancelDeliver, // 骑手申请取消
fnCallNew, // 重新召唤骑手
fnGoodsReturn, // 是否退回商品
} = abonmrmalFn(props)
const {
orderDetail, // 订单详情
} = useOrderInfo()
</script>
<style lang="scss" scoped>
@import './abnormal-order.scss';
</style>

View File

@@ -0,0 +1,158 @@
import { store } from "@/store"
import toast from "@/utils/toast"
import order from "@/api/https/order"
/*************************************************
* 异常订单处理
*/
function abonmrmalFn(props: { item: AnyObject }) {
// 是否拒绝用户退款
function fnCancelOrder(num: number) {
let data = {
vendorOrderID: props.item.vendorOrderID,
vendorID: props.item.vendorID,
acceptIt: Boolean(num),
reason: '理由暂无'
}
// let data = {
// afsOrderID: props.item.afsOrderID,
// vendorID: props.item.vendorID,
// approveType: num,
// reason: '理由暂无'
// }
// 拒绝退款
if (num == 0) {
uni.jxConfirm({
title: '提示',
content: '是否拒绝用户取消该订单',
success: async () => {
let res = await order.agree_or_refuse_cancel(data)
// let res = await order.agree_orRefuse_refund(data)
if (res.code == 0) {
toast('拒绝成功', 1)
store.commit('serveInfo/setUpdateOrder', Date.now())
} else {
toast('决绝失败', 2)
}
}
})
}
// 同意退款
if (num == 1) {
uni.jxConfirm({
title: '提示',
content: '是否同意用户取消该订单',
success: async () => {
let res = await order.agree_or_refuse_cancel(data)
// let res = await order.agree_orRefuse_refund(data)
if (res.code == 0) {
toast('同意成功', 1)
store.commit('serveInfo/setUpdateOrder', Date.now())
} else {
toast('同意失败', 2)
}
}
})
}
}
/*************************************************
* 骑手申请取消
*/
function fnCancelDeliver(num: number) {
let data = {
vendorOrderID: props.item.vendorOrderID,
vendorID: props.item.vendorID,
acceptIt: Boolean(num),
reason: '理由暂无'
}
//
if (num == 0) {
uni.jxConfirm({
title: '提示',
content: '拒绝后只能由该配送员完成本订单',
success: async () => {
let res = await order.accept_or_refuse_failed_get_order(data)
if (res.code == 0) {
store.commit('serveInfo/setUpdateOrder', Date.now())
fnCallNew()
} else {
toast('操作失败', 2)
}
}
})
}
if (num == 1) {
uni.jxConfirm({
title: '提示',
content: '是否同意取消该订单配送',
success: async () => {
let res = await order.accept_or_refuse_failed_get_order(data)
if (res.code == 0) {
store.commit('serveInfo/setUpdateOrder', Date.now())
fnCallNew()
} else {
toast('操作失败', 2)
}
}
})
}
}
// 重新召唤骑手
async function fnCallNew() {
let data = {
vendorOrderID: props.item.vendorOrderID,
vendorID: props.item.vendorID
}
uni.jxConfirm({
title: '提示',
content: '是否重新召唤骑手进行配送',
success: async () => {
let res = await order.callP_m_courier(data)
if (res.code == 0) {
toast('操作成功')
store.commit('serveInfo/setUpdateOrder', Date.now())
} else {
toast('操作失败')
}
}
})
}
/*************************************************
* 是否收到退货
*/
function fnGoodsReturn() {
let data = {
vendorOrderID: props.item.vendorOrderID,
vendorID: props.item.vendorID,
}
uni.jxConfirm({
title: '提示',
content: '确认已经收到退回的货物',
success: async () => {
let res = await order.confirm_receive_goods(data)
if (res.code == 0) {
toast('操作成功')
store.commit('serveInfo/setUpdateOrder', Date.now())
} else {
toast('操作失败')
}
}
})
}
return {
fnCancelOrder, // 是否统一用户取消订单
fnCancelDeliver, // 骑手申请取消
fnCallNew, // 重新召唤骑手
fnGoodsReturn, // 是否退回商品
}
}
export default abonmrmalFn

View File

@@ -0,0 +1,124 @@
<template>
<view>
<view
class="abnormal-op"
v-if="
(order.status === 17 && (order.flag & 24) === 0) ||
(order.status === 22 && (order.flag & 32) === 0) ||
(order.status === 18 && (order.flag & 64) === 0)
"
>
<view class="title">{{ title }}</view>
<view class="op">
<view class="btn-confirm" @click.stop="handleConfirm">{{
confirmText
}}</view>
</view>
</view>
<view
class="abnormal-dealed"
v-if="
(order.status === 17 && (order.flag & 24) !== 0) ||
(order.status === 22 && (order.flag & 32) !== 0) ||
(order.status === 18 && (order.flag & 64) !== 0)
"
>
{{ title }}
<text class="agree" v-if="(order.flag & 24) === 8">[已同意]</text>
<text class="refuse" v-if="(order.flag & 24) === 24"
>[已拒绝]请联系:18048531223</text
>
<text
class="agree"
v-if="(order.flag & 32) === 32 || (order.flag & 64) === 64"
>[已发单]</text
>
<text><slot></slot></text>
</view>
</view>
</template>
<script lang="ts" setup>
interface propsType {
title: string
confirmText: string
order: AnyObject
}
defineProps<propsType>()
const emits = defineEmits<{
(e: 'handleCancel'): void
(e: 'handleConfirm'): void
}>()
// 点击取消
function handleCancel() {
emits('handleCancel')
}
// 点击确定
function handleConfirm() {
emits('handleConfirm')
}
</script>
<style lang="scss" scoped>
.abnormal-op {
height: 90rpx;
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 32rpx;
padding: 0 20rpx;
background: linear-gradient(to right, #e8edd8, white);
.title {
color: #333;
font-weight: bold;
}
.op {
display: flex;
align-items: center;
.btn-cancel,
.btn-confirm {
color: #fff;
background-color: $jx-primary;
padding: 7rpx 30rpx;
border-radius: 7rpx;
}
.btn-cancel {
margin-right: 40rpx;
background-color: #f60d58;
}
}
}
.abnormal-dealed {
height: 90rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 32rpx;
background: white;
color: #333;
text {
font-weight: bold;
display: inline-block;
margin-left: 10rpx;
}
.agree {
color: green;
}
.refuse {
color: red;
}
}
</style>

View File

@@ -0,0 +1,195 @@
%globalStyle {
border-bottom: 2rpx dashed #e7e7e7;
padding: 15rpx;
}
.after-sales-root {
background-color: #fff;
.top-title {
@extend %globalStyle;
border-bottom: 6rpx dashed #e7e7e7;
display: flex;
justify-content: space-between;
font-size: 30rpx;
padding: 25rpx 15rpx;
.order {
color: rgb(0, 0, 0);
}
.success {
color: rgb(0, 0, 0);
}
.warring {
color: $jx-warring;
}
}
.platform {
display: flex;
align-items: center;
@extend %globalStyle;
.brand {
display: inline-block;
width: 40rpx;
height: 40rpx;
flex-shrink: 0;
background-size: 100%;
background-repeat: no-repeat;
border-radius: 15rpx;
}
.orderSeq{
color: #999;
}
.num {
font-size: 30rpx;
color: #999;
margin-left: 15rpx;
}
}
.detaile-text {
@extend %globalStyle;
background-color: #fcf1f0;
color: $jx-warring;
}
.after-text {
@extend %globalStyle;
font-size: 34rpx;
color: #666;
.mode {
font-weight: bold;
}
}
.created-time {
@extend %globalStyle;
font-size: 32rpx;
color: #999;
}
.shopping-count {
@extend %globalStyle;
font-size: 32rpx;
color: #999;
}
.detail-btn {
box-sizing: border-box;
padding: 20rpx;
margin: 15rpx;
text-align: center;
color: #fff;
background-image: linear-gradient(135deg, #4eb331, #85c972);
border-radius: 10rpx;
}
.tips-text {
text-align: center;
color: #f72a6c;
text {
display: inline-block;
padding: 15rpx;
}
}
.operation-btn {
@extend %globalStyle;
.text {
color: #f72a6c;
font-size: 24rpx;
width: 100%;
}
.btn-root {
display: flex;
justify-content: space-between;
box-sizing: border-box;
.reject,
.resolve {
width: 100%;
padding: 20rpx;
text-align: center;
border-radius: 10rpx;
margin-top: 15rpx;
color: #fff;
}
.reject {
margin-right: 15rpx;
background-image: linear-gradient(135deg, #85c972, $jx-primary);
}
.resolve {
margin-left: 15rpx;
background-image: linear-gradient(135deg, #ff6a20, #ec903f);
}
}
}
.confirm-goods {
@extend %globalStyle;
.text {
padding: 20rpx;
text-align: center;
background-image: linear-gradient(135deg, #f72a6c, #f16692);
border-radius: 10rpx;
color: #fff;
}
}
}
.reson-root {
padding: 15rpx;
background-color: #fff;
width: 600rpx;
border-radius: 10rpx;
.title {
text-align: center;
}
.textarea {
box-sizing: border-box;
margin: 15rpx 0;
width: 100%;
max-height: 200rpx;
background-color: rgb(243, 243, 243);
padding: 10rpx;
border-radius: 10rpx;
}
.btn-root {
width: 100%;
display: flex;
justify-content: space-between;
border-top: 1rpx solid rgb(223, 223, 223);
.cancal,
.confirm {
width: 100%;
padding: 20rpx 0 10rpx 0;
text-align: center;
}
.cancal {
color: #666;
}
.confirm {
border-left: 1rpx solid rgb(223, 223, 223);
}
}
}

View File

@@ -0,0 +1,286 @@
<template>
<view
class="after-sales-root position-relative"
@tap="afterSalesDetaile(item.afsOrderID)"
>
<!-- 订单号 -->
<view class="top-title">
<view
class="order"
@tap.stop="copyInfo(item.afsOrderID, '售后单号复制成功')"
>
<text>售后单号{{ item.afsOrderID }}</text>
<jx-icon icon="fuzhi" color="#ffffff"></jx-icon>
</view>
<text :class="item.status == 180 ? 'success' : 'warring'">{{
status
}}</text>
</view>
<!-- 订单平台 -->
<view
class="platform"
@tap.stop="copyInfo(item.vendorOrderID, '订单号复制成功')"
>
<text class="brand" :class="`icon-${item.vendorID}`"></text>
<text class="orderSeq">#{{ item.orderSeq }}</text>
<text class="num">订单号{{ item.vendorOrderID }}</text>
<jx-icon icon="fuzhi" color="#818181"></jx-icon>
</view>
<!-- 原因描述 -->
<view class="detaile-text">{{ item.reasonDesc || '用户未评价' }}</view>
<!-- 售后方式 -->
<view class="after-text">
<text>售后方式</text>
<text class="mode">{{ afsAppealTypeName }}</text>
</view>
<!-- 申请时间 -->
<view class="created-time"
>申请时间{{ timeFormatHMS(item.afsCreatedAt) || '无' }}</view
>
<!-- 商品数量 -->
<view class="shopping-count" v-if="item.skus != null"
>{{ item.skus.length || 0 }}&nbsp;{{ count }}件商品</view
>
<!-- 驳回理由 -->
<view class="shopping-count" v-if="item.refuseReason">
<text>驳回理由:&emsp;{{ item.refuseReason }}</text>
</view>
<!-- 操作按钮 -->
<view
class="operation-btn"
v-if="item.status === 155 && (item.flag & 3) === 0"
>
<text class="text"
>若退款造成的损失较大建议联系顾客自行上门取回退货</text
>
<view class="btn-root">
<view class="reject" @tap.stop="popup.open()">驳回</view>
<view class="resolve" @tap.stop="handleAgree">同意</view>
</view>
</view>
<!-- 商家确认收到货 -->
<view
class="confirm-goods"
v-if="item.status === 165 && (item.flag & 4) === 0"
>
<view class="text" @tap.stop="confirmGoods">商家确认收货</view>
</view>
<!-- 查看详情 -->
<view class="detail-btn">查看详情</view>
<!-- 提示内容 -->
<view class="tips-text">
<!-- 已进行审核操作 -->
<template v-if="item.status === 155 && (item.flag & 3) !== 0">
<text v-if="(item.flag & 3) === 1">同意售后</text>
<text v-if="(item.flag & 3) === 3">驳回售后</text>
</template>
<!-- 确认收货 -->
<template v-if="item.status === 165 && (item.flag & 4) !== 0">
<text>已确认收货</text>
</template>
</view>
</view>
<uni-popup ref="popup" type="center">
<view class="reson-root">
<view class="title">驳回原因</view>
<textarea
class="textarea"
v-model.trim="reason"
placeholder="请输入驳回原因"
></textarea>
<view class="btn-root">
<view class="cancal" @tap="cancel">取消</view>
<view class="confirm" @tap="handleRefuse">确定</view>
</view>
</view>
</uni-popup>
</template>
<script lang="ts" setup>
import order from '@/api/https/order'
import useOrderInfo from '@/composables/useOrderInfo'
import toast from '@/utils/toast'
import { timeFormatHMS } from '@/utils/tools'
import { computed, ref } from 'vue'
import { store } from '@/store'
const {
copyInfo, // 复制内容
afterSalesDetaile, // 售后详情
} = useOrderInfo()
interface PropsType {
item: any
}
const props = defineProps<PropsType>()
/**
* 售后状态
*/
const status = computed(() => {
switch (props.item.status) {
case 155:
return '待审核'
case 160:
return '已审核'
case 165:
return '退货待确认'
case 167:
return '退货已收到'
case 180:
return '售后成功'
case 190:
return '售后失败'
default:
return '未知'
}
})
/**
* 售后方式
*/
const afsAppealTypeName = computed(() => {
switch (props.item.appealType) {
case 1:
return '仅退款'
case 2:
return '退货退款'
case 3:
return '重发商品'
default:
return '未知'
}
})
/**
* 商品数量
*/
const count = computed(() => {
let num = 0
props.item.skus.forEach((item: any) => {
num += item.count
})
return num
})
/**
* 驳回售后
*/
const popup = ref<any>(null)
const reason = ref<string>('')
async function agreeOrRefuse(type: number) {
// if (props.item.vendorID == 3) {
// // 饿百订单
// if (type === 1) {
// // 同意
// let data = {
// vendorOrderID: props.item.vendorOrderID,
// vendorID: props.item.vendorID,
// acceptIt: Boolean(1), // 拒绝为0同意为1
// reason: type === 1 ? '同意退款' : reason.value,
// }
// let res = await order.agree_or_refuse_cancel(data)
// judge(res)
// } else {
// // type ===3 驳回
// let data = {
// vendorOrderID: props.item.vendorOrderID,
// vendorID: props.item.vendorID,
// acceptIt: Boolean(1), // 拒绝为0同意为1
// reason: type === 1 ? '同意退款' : reason.value,
// }
// let res = await order.agree_or_refuse_cancel(data)
// judge(res)
// }
// } else {
// // 非饿百订单
// 退货退款
let data = {
afsOrderID: props.item.afsOrderID,
vendorID: props.item.vendorID,
approveType: type,
reason: type === 1 ? '同意退款' : reason.value,
}
let res = await order.agree_orRefuse_refund(data)
judge(res)
// }
}
async function handleRefuse() {
if (reason.value) {
agreeOrRefuse(3)
} else {
toast('请输入驳回原因')
}
}
/**
* 判断驳回信息
*/
function judge(res: AnyObject) {
if (res.code == 0) {
toast('操作成功', 1)
cancel()
// 刷新订单
store.commit('serveInfo/setUpdateOrder', Date.now())
} else {
uni.jxAlert({
title: '错误',
content: res.desc,
})
}
}
/**
* 关闭驳回弹窗
*/
function cancel() {
reason.value = ''
popup.value.close()
}
/**
* 同意售后
*/
function handleAgree() {
uni.jxConfirm({
title: '提示',
content: '是否同意处理该售后单',
success: () => {
agreeOrRefuse(1)
},
})
}
/**
* 商家确认收货
*/
function confirmGoods() {
uni.jxConfirm({
title: '提示',
content: '是否已经收到货',
success: async () => {
let data = {
afsOrderID: props.item.afsOrderID,
vendorID: props.item.vendorID,
}
let res = await order.confirm_received_return_goods(data)
judge(res)
},
})
}
</script>
<style lang="scss" scoped>
@import './after-sales-order.scss';
</style>

View File

@@ -0,0 +1,129 @@
<template>
<view
class="compelet-root position-relative"
@tap="orderDetail(item.vendorOrderID, item.vendorID)"
>
<order-list-top :item="item" />
<template v-if="getStorage('terrace') == 'jxcs' || getStorage('terrace') == 'gblm'">
<!-- 京西菜市 -->
<order-money :item="item" />
</template>
<template v-else>
<!-- 京西果园 -->
<order-money-jxgy :item="item" />
</template>
<!-- 地址 -->
<view class="address">地址{{ item.buyerComment.includes('支付方式') ? store.getters['storeInfo/storeAddress'] : item.consigneeAddress }}</view>
<!-- 配送信息 -->
<view class="distribution-msg" v-if="!item.buyerComment.includes('支付方式')">
<text class="vender-name">{{ wbVendor }}</text>
<text class="distribution-name">{{ item.courierName }}</text>
<text
v-if="item.courierMobile.split(',')[1]"
class="distribution-mobile"
@tap.stop="phoneCall(item.courierMobile)"
>{{
item.courierMobile.split(',')[0] +
'转' +
item.courierMobile.split(',')[1]
}}</text
>
<text
v-else
class="distribution-mobile"
@tap.stop="phoneCall(item.courierMobile)"
>{{ item.courierMobile }}</text
>
<jx-icon
v-show="item.courierMobile != ''"
icon="24gf-telephone"
color="#999999"
@tap.stop="phoneCall(item.courierMobile)"
:size="38"
style="margin-left: 10rpx"
/>
</view>
<!-- 查看详情 -->
<view class="detail-btn">查看详情</view>
</view>
</template>
<script lang="ts" setup>
import useOrderInfo from '@/composables/useOrderInfo'
import { computed } from 'vue'
import orderListTop from '../component/orderListTop.vue'
import orderMoney from '../component/orderMoney.vue'
import orderMoneyJxgy from '../component/orderMoneyJxgy.vue'
import { getStorage } from '@/utils/storage'
import { store } from '@/store'
const {
orderDetail, // 订单详情
phoneCall, // 复制手机号
waybillVendor, // 转换厂商
} = useOrderInfo()
interface PropsType {
item: any
}
const props = defineProps<PropsType>()
/**
* 转换快递厂商
*/
const wbVendor = computed(() => {
return waybillVendor(
props.item.waybillVendorID,
props.item.status,
props.item.waybillStatus
)
})
</script>
<style lang="scss" scoped>
:deep(.order-totalCount) {
border: none !important;
}
.compelet-root {
background-color: #fff;
padding-bottom: 1rpx;
.address {
display: flex;
justify-content: space-between;
padding: 15rpx;
font-size: 32rpx;
color: #000000;
background-color: rgba($color: #908f96, $alpha: 0.15);
border-radius: 10rpx;
}
.detail-btn {
background-color: #fff;
padding: 20rpx;
text-align: center;
color: #fff;
background-image: linear-gradient(135deg, #4eb331, #85c972);
margin: 15rpx 15rpx 25rpx 15rpx;
border-radius: 10rpx;
}
.distribution-msg {
padding: 15rpx;
border-bottom: 2rpx dashed #e7e7e7;
.vender-name {
color: #999999;
margin-right: 25rpx;
}
.distribution-name {
margin-right: 25rpx;
}
.distribution-mobile {
color: #999999;
}
}
}
</style>

View File

@@ -0,0 +1,504 @@
<template>
<!-- 订单信息 -->
<view class="order-info">
<view class="order">
<view class="h-number index-color">
<text class="brand" :class="`icon-${item.vendorID}`"></text>
<text class="num-root">
<text>#</text>
<text class="num">{{ item.orderSeq }}</text>
</text>
</view>
<view class="timer" v-if="!item.buyerComment.includes('支付方式')">预计{{ expectedDeliveredTime }}前送达</view>
</view>
<view v-if="isSrestPickTime" v-html="restPickTime"></view>
<view v-if="isCancelTime">
<view v-if="item.lockStatus === -5 && (item.flag & 6) === 0">
<text class="rest-time canceltime"
>{{ cancelTime
}}<text v-if="cancelTime !== '已超时'">分钟</text></text
>
</view>
<text class="order-delivered">{{ abnormalStatus }}</text>
</view>
<!-- 状态展示 -->
<text class="compelet" v-if="item.status === 110">已完成</text>
<text class="cancel" v-else-if="item.status === 115">已取消</text>
<text class="fail" v-else-if="item.status === 120">已失败</text>
</view>
<!-- 用户名字 -->
<view class="order-title" v-if="!item.buyerComment.includes('支付方式')">
<!-- <view class="title-left"> -->
<view >
<text class="name">{{ item.consigneeName.slice(0, 1) }}...</text>
<!-- <img src="https://image.jxc4.com/jxapp/z_send_normal.png" alt="" class="connectUser" @tap.stop="connectUser(item)"> -->
</view>
<view class="see-map" @tap.stop="callPhone(item)">拨打电话</view>
<view class="see-map" @tap.stop="connectUser(item)">发消息</view>
<!-- <view class="phone">
<view>
<text v-if="item.consigneeMobile">临1</text>
<text
class="phone-number"
@tap.stop="phoneCall(item.consigneeMobile)"
v-if="item.consigneeMobile.split(',')[1]"
>{{
item.consigneeMobile.split(',')[0] +
'转' +
item.consigneeMobile.split(',')[1]
}}</text
>
<text
v-else
class="phone-number"
@tap.stop="phoneCall(item.consigneeMobile)"
>{{ item.consigneeMobile }}</text
>
<br />
真实号
<text v-if="item.consigneeMobile2">临2</text>
<text
class="phone-number"
@tap.stop="phoneCall(item.consigneeMobile2)"
v-if="item.consigneeMobile2.split(',')[1]"
>{{
item.consigneeMobile2.split(',')[0] +
'转' +
item.consigneeMobile2.split(',')[1]
}}</text
>
<text
v-else
:class="item.consigneeMobile2 ? 'phone-number' : ''"
@tap.stop="phoneCall(item.consigneeMobile2)"
>{{ item.consigneeMobile2 }}</text
>
</view>
<img src="https://image.jxc4.com/jxapp/z_send_normal.png" alt="" class="connectUser" @tap.stop="connectUser(item)">
</view>
</view> -->
<!-- style="height:25px;line-height:25px;margin:auto 10px;" -->
<view class="see-map" @tap.stop="seeMap">查看地图</view>
</view>
<!-- 订单号 -->
<view class="order-number" @tap.stop="copyInfo(orderNum, '复制订单号成功')">
<text class="number">订单号{{ orderNum }}</text>
<text class="copy">复制</text>
</view>
</template>
<script lang="ts" setup>
import useOrderInfo from '@/composables/useOrderInfo'
import { store } from '@/store'
import { isNullDate } from '@/utils/tools'
import { onShow } from '@dcloudio/uni-app'
import { computed, ref } from 'vue'
import { setStorage } from "@/utils/storage";
import toast from "@/utils/toast";
const {
copyInfo, // 复制内容
phoneCall, // 拨号
} = useOrderInfo()
interface PropsType {
item: any
}
let props = defineProps<PropsType>()
/**
* 拨打电话
*/
function callPhone(item:AnyObject) {
// let itemList = [item.consigneeMobile,item.consigneeMobile2]
let itemList:string[] = []
if(item.consigneeMobile) itemList.push('临1' + item.consigneeMobile.split(',')[0] +'转' + item.consigneeMobile.split(',')[1])
if(item.consigneeMobile2) itemList.push('临2' + item.consigneeMobile2.split(',')[0] +'转' + item.consigneeMobile2.split(',')[1])
if(itemList.length === 0) return toast('该订单暂无联系方式', 2)
uni.showActionSheet({
// title: '退出后不会删除任何数据',
itemColor: '#4eb331',
itemList,
popover: {
width: 5000,
},
success: function (res) {
if(res.tapIndex === 0) phoneCall(item.consigneeMobile)
if(res.tapIndex === 1) phoneCall(item.consigneeMobile2)
}
});
}
/*************************************************
* 联系用户
*/
function connectUser(item:AnyObject) {
if(item.vendorID === 1){
if(store.getters['storeInfo/imMtStatus'][0].imStatus !== 1) return toast('美团IM状态已关闭', 1)
setStorage('vendorUserInfo',{
venderOrderID:item.vendorOrderID,
// venderOrderID:0,
orderSeq:item.orderSeq,
vendorOrgCode:item.vendorOrgCode,
vendorStoreID:item.vendorStoreID,
userID:item.vendorUserID,
// userID:'11555078706',
vendorID:item.vendorID
})
uni.navigateTo({ url: '/subPages/messageChild/msgChat/msgChat' })
}else{
// 饿百
toast('暂不支持聊天', 2)
}
}
/*************************************************
* 查看地图
*/
function seeMap() {
uni.navigateTo({
url: `/subPages/orderChild/seeMap/seeMap?vendorOrderID=${props.item.vendorOrderID}&vendorID=${props.item.vendorID}`,
})
}
/**
* 是否显示已超时
*/
const isCancelTime = computed(() => {
return (
(props.item.status === 17 ||
props.item.status === 18 ||
props.item.status === 22) &&
props.item.lockStatus !== -5
)
})
/**
* 是否显示预计送达时间
*/
const isSrestPickTime = computed(() => {
return (
(props.item.status === 10 ||
props.item.status === 15 ||
props.item.status === 20) &&
props.item.lockStatus === 0
)
})
/**
* 订单号转换
*/
const orderNum = computed(() => {
return props.item.vendorID === 3
? props.item.vendorOrderID2
: props.item.vendorOrderID
})
/**
* 异常订单转换
*/
const abnormalStatus = computed(() => {
let order = props.item
if (order.lockStatus === -5) {
return '申请取消'
} else if (order.status === 17) {
return '待审核'
} else if (order.status === 18) {
return '取货失败'
} else if (order.status === 22) {
return '投递失败'
} else {
return '未知'
}
})
/**
* 待接单预计超时时间
*/
const cancelTime = ref<any>()
const timer = ref<any>()
onShow(() => {
if (props.item.lockStatus === -5) {
let { purchaseVendorInfo } = store.state.serveInfo.sysInfo as any
let { userApplyCancelWaitMinute } = purchaseVendorInfo[props.item.vendorID]
let cancelTime1 =
new Date(props.item.lockStatusTime).getTime() +
userApplyCancelWaitMinute * 60 * 1000 -
new Date().getTime()
cancelTime.value =
cancelTime1 > 0 ? `${new Date(cancelTime1).getMinutes()}` : '已超时'
timer.value = setInterval(() => {
cancelTime1 =
new Date(props.item.lockStatusTime).getTime() +
userApplyCancelWaitMinute * 60 * 1000 -
new Date().getTime()
cancelTime.value =
cancelTime1 > 0 ? `${new Date(cancelTime1).getMinutes()}` : '已超时'
}, 1000)
}
})
/**
* 预计送达时间
*/
const expectedDeliveredTime = computed(() => {
let timer: any = ''
if (isNullDate(props.item.expectedDeliveredTime)) {
// 预计送达时间无的情况
timer = new Date(
new Date(props.item.orderCreatedAt).getTime() + 60 * 60 * 1000
)
} else {
timer = new Date(props.item.expectedDeliveredTime)
}
return `${
timer.getHours() < 10 ? '0' + timer.getHours() : timer.getHours()
}:${timer.getMinutes() < 10 ? '0' + timer.getMinutes() : timer.getMinutes()}`
})
/**
* 剩余拣货时间 || 剩余用户自己取消订单时间
*/
const restPickTime = computed(() => {
// 拣货结束时间time1 = 预计送达时间 - 30分钟
let time1: any = ''
if (isNullDate(props.item.pickDeadline)) {
// 没有拣货时间
if (isNullDate(props.item.expectedDeliveredTime)) {
// 预计送达时间为空
time1 = new Date(props.item.orderCreatedAt).getTime() + 30 * 60 * 1000
} else {
// 预计送达时间有
time1 =
new Date(props.item.expectedDeliveredTime).getTime() - 30 * 60 * 1000
}
} else {
// 有拣货时间
time1 = new Date(props.item.pickDeadline).getTime()
}
let restTime = (time1 - new Date().getTime()) / 1000 / 60 // 分钟
restTime = Math.floor(restTime)
// 送达时间
let time2: any = ''
if (isNullDate(props.item.expectedDeliveredTime)) {
// 时间是空
time2 =
new Date(props.item.orderCreatedAt).getTime() +
60 * 60 * 1000 -
new Date().getTime()
} else {
time2 =
new Date(props.item.expectedDeliveredTime).getTime() -
new Date().getTime()
}
let arrivedTime = Math.floor(time2 / 1000 / 60)
switch (props.item.status) {
case 10:
if (props.item.lockStatus === 0) {
if (restTime < 0) {
// 超时
return `<span class="order-bg-cs">&nbsp;</span>`
} else if (restTime < 5) {
// 小于5分钟
return `<span class="rest-time picktime3">${restTime}分钟</span>`
} else if (restTime < 10) {
// 小于10分钟
return `<span class="rest-time picktime2">${restTime}分钟</span>`
} else if (restTime > 60 && props.item.businessType === 2) {
// 预订单
return `<span class="order-bg-dsd">&nbsp;</span>`
} else {
// 通常
return `<span class="rest-time picktime1">${restTime}分钟</span>`
}
} else {
return `<span class="order-delivered">已锁定</span>`
}
case 15:
return sendTime(arrivedTime)
case 20:
return sendTime(arrivedTime)
case 105:
return `<span class="order-delivered">已送达</span>`
case 110:
return `<span class="order-delivered">已送达</span>`
case 115:
return `<span class="order-delivered">已取消</span>`
case 120:
return `<span class="order-delivered">已失败</span>`
default:
return ''
}
})
function sendTime(time: any) {
if (time < 0) {
// 超时
return `<span class="order-bg-cs">&nbsp;</span>`
} else if (time < 5) {
// 小于5分钟
return `<span class="rest-time arrived3">${time}分钟</span>`
} else if (time < 20) {
// 小于20分钟
return `<span class="rest-time arrived2">${time}分钟</span>`
} else if (time > 60 && props.item.businessType === 2) {
// 预订单
return `<span class="order-bg-dsd">&nbsp;</span>`
} else {
// 通常
return `<span class="rest-time arrived1">${time}分钟</span>`
}
}
/**
* 判断是否显示已完成,预计送达文字
*/
const isShow = computed(() => {
if (
props.item.status == 110 ||
props.item.status == 115 ||
props.item.status == 120
) {
return false
} else {
return true
}
})
</script>
<style lang="scss" scoped>
// 表哦提
.order-info {
display: flex;
align-items: center;
justify-content: space-between;
padding: 20rpx 15rpx;
background-color: #fff;
border-bottom: 6rpx dashed #e7e7e7;
.order {
.timer {
margin-top: 6rpx;
color: rgb(0, 0, 0);
}
}
.index-color {
color: rgb(0, 0, 0);
}
.h-number {
display: flex;
align-items: center;
.brand {
display: inline-block;
width: 60rpx;
height: 60rpx;
flex-shrink: 0;
background-size: 100%;
background-repeat: no-repeat;
border-radius: 15rpx;
}
.num-root {
margin-left: 5rpx;
}
.num {
font-size: 50rpx;
font-weight: bold;
}
}
.compelet {
color: #000;
font-weight: bold;
}
.cancel {
color: #f60d58;
font-weight: bold;
}
.fail {
color: $jx-warring;
font-weight: bold;
}
}
// 顶部标题
.order-title {
display: flex;
justify-content: space-between;
background-color: #ffffff;
// padding: 15rpx;
padding: 10rpx;
border-bottom: 2rpx dashed #e7e7e7;
text-align: center;
align-items: center;
.name {
color: #999999;
// margin-right: 20rpx;
}
// .title-left {
// display: flex;
// align-items: center;
// .name {
// color: #999999;
// margin-right: 20rpx;
// }
// .phone {
// color: #999999;
// display: flex;
// align-items: center;
// border:1px solid red;
// .phone-number {
// // margin-right: 10rpx;
// }
// .connectUser{
// width: 38rpx;
// height: 38rpx;
// }
// }
// }
}
.order-number {
display: flex;
justify-content: space-between;
white-space: nowrap;
padding: 15rpx;
border-bottom: 2rpx dashed #e7e7e7;
color: #999999;
.copy {
font-size: 26rpx;
padding: 4rpx 12rpx;
border-radius: 5rpx;
border: 2rpx solid #999999;
color: #999999;
}
}
.see-map {
font-size: 28rpx;
padding: 7rpx 12rpx;
border-radius: 5rpx;
background-color: rgba($color: $jx-primary, $alpha: 0.15);
color: $jx-primary;
height:25px;
line-height:25px;
margin:auto 10px;
}
</style>

View File

@@ -0,0 +1,79 @@
<template>
<view class="order-totalCount">
<text class="totalCount"
>{{ item.skuCount }}{{ item.goodsCount }}件商品</text
>
<view>
{{
item.vendorPayPercentage != 0
? item.vendorPayPercentage < 50
? '实际支付:'
: '实际收入:'
: isPointStore
? '实际支付:'
: '实际收入:'
}}<jx-real-income :orderData="item" color="#585858" />
</view>
<!-- 预定单 -->
<view class="preIcon" v-if="item.businessType === 2">预订单</view>
</view>
</template>
<script lang="ts" setup>
import { store } from '@/store'
import { computed } from 'vue'
interface PropsType {
item: any
}
defineProps<PropsType>()
const isPointStore = computed(() => {
return store.getters['storeInfo/isPointStore']
})
</script>
<style lang="scss" scoped>
// 商品数量
.order-totalCount {
display: flex;
align-items: center;
padding: 15rpx;
border-bottom: 2rpx dashed #e7e7e7;
color: #585858;
.play-money {
margin-left: 30rpx;
}
.totalCount {
margin-right: 25rpx;
}
}
.preIcon {
position: absolute;
top: 0;
right: 0;
padding: 4rpx 20rpx 6rpx 20rpx;
font-size: 26rpx;
color: #fff;
border-radius: 0 0 0 10rpx;
background-color: #ff702c;
}
@keyframes enlarge {
0% {
transform: scale(0.9);
}
50% {
transform: scale(1.1);
}
100% {
transform: scale(0.9);
}
}
</style>

View File

@@ -0,0 +1,63 @@
<template>
<view class="order-totalCount">
<text class="totalCount"
>{{ item.skuCount }}{{ item.goodsCount }}件商品</text
>
<view>
门店收益:<jx-real-income-jxgy :order="item" color="#585858" />
</view>
<!-- 预定单 -->
<view class="preIcon" v-if="item.businessType === 2">预订单</view>
</view>
</template>
<script lang="ts" setup>
interface PropsType {
item: AnyObject
}
defineProps<PropsType>()
</script>
<style lang="scss" scoped>
// 商品数量
.order-totalCount {
display: flex;
align-items: center;
padding: 15rpx;
color: #585858;
.play-money {
margin-left: 30rpx;
}
.totalCount {
margin-right: 25rpx;
}
}
.preIcon {
position: absolute;
top: 0;
right: 0;
padding: 4rpx 20rpx 6rpx 20rpx;
font-size: 26rpx;
color: #fff;
border-radius: 0 0 0 10rpx;
background-color: #ff702c;
}
@keyframes enlarge {
0% {
transform: scale(0.9);
}
50% {
transform: scale(1.1);
}
100% {
transform: scale(0.9);
}
}
</style>

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