This commit is contained in:
wtq
2025-11-14 10:30:53 +08:00
commit 6bc72db0ee
348 changed files with 53952 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*

27
.hbuilderx/launch.json Normal file
View File

@@ -0,0 +1,27 @@
{
// 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"
},
{
"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/

357
README.md Normal file
View File

@@ -0,0 +1,357 @@
# 京西菜市商家版
- 开发:
张树伟
- 日期:
2022年12月05日
- 项目说明:
京西果园商家版本,兼容《微信小程序》
- 技术栈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
## 果园小程序
- 分支名字:果园小程序
- 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-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 # 商家中心页面
│ │ └── 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 # 商品详情页面
│ │ │
│ │ ├── 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

59
dfslkf Normal file
View File

@@ -0,0 +1,59 @@
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>

7014
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

72
package.json Normal file
View File

@@ -0,0 +1,72 @@
{
"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",
"@rollup/plugin-commonjs": "^25.0.1",
"add": "^2.0.6",
"crypto-js": "^4.1.1",
"js-md5": "^0.7.3",
"vue": "3.2.45",
"vue-i18n": "9.2.2",
"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",
"sass": "^1.56.1",
"typescript": "^4.8.4",
"vite": "3.2.4"
}
}

144
src/App.ts Normal file
View File

@@ -0,0 +1,144 @@
/**
* 全局文件配置
*/
import { store } from '@/store'
import { setStorage, getStorage } from "@/utils/storage";
import Bluetooth from '@/utils/bluetoothPrinter/bluetooth'
import useGlobalFunc from './composables/useGlobalFunc';
import { onShow, onLaunch } from '@dcloudio/uni-app';
function App() {
// const bluetooth = new Bluetooth()
const bluetooth: any = getStorage('deviceName') ? new Bluetooth() : null
const { setPrinterStatus } = useGlobalFunc()
/**
* 小程序冷启动
*/
onLaunch(async (params: any) => {
// 订单管理-新订单通知
if (params.query && params.query.jxStoreId) {
setStorage("storeID", +params.query.jxStoreId)
if (getStorage('token')) await store.dispatch('storeInfo/getOneStore', +params.query.jxStoreId)
}
})
/*************************************************
* 页面出现 热启动
*/
let reconnectTime1: any = null
onShow(async (params: any) => {
// 订单管理-新订单通知
if (params.query && params.query.jxStoreId) {
setStorage("storeID", +params.query.jxStoreId)
if (getStorage('token')) await store.dispatch('storeInfo/getOneStore', +params.query.jxStoreId)
}
if (getStorage('deviceName')) {
reconnectTime1 = setTimeout(async () => {
await bluetooth.reconnect()
clearTimeout(reconnectTime1)
}, 1500)
}
})
/**
* 获取设备信息
*/
async function SystemInfo() {
uni.getSystemInfo({
success(res) {
// 保存本机系统信息
// 详细字段信息参考 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) => {
store.commit('serveInfo/setIsNetWorkS', res.isConnected)
})
}
/**
* 微信小程序更新机制
*/
function autoUpdate() {
// 获取小程序更新机制兼容
if (uni.canIUse('getUpdateManager')) {
const updateManager = uni.getUpdateManager()
// 检查是否有新版本发布
updateManager.onCheckForUpdate(function (res) {
if (res.hasUpdate) {
//小程序有新版本,则静默下载新版本,做好更新准备
updateManager.onUpdateReady(function () {
uni.jxAlert({
title: '更新提示',
content: '应用已经升级到新版本了请及时更新',
success: () => {
updateManager.applyUpdate()
}
})
})
// 新的版本下载失败
updateManager.onUpdateFailed(function () {
uni.showModal({
title: '温馨提示',
content: '新版本已经上线,请您删除当前小程序,重新搜索打开',
})
})
}
})
} else {
// 提示用户在最新版本的客户端上体验
uni.showModal({
title: '温馨提示',
content: '当前微信版本过低,可能无法使用该功能,请升级到最新版本后重试。'
})
}
}
/*************************************************
* 判断用户是否为IOS系统
* @param {}
* @return {boolean} // 是否为IOS系统
*/
function isIosSystem() {
setStorage('isIosSystem', true)
}
/*************************************************
* 打印机检测
*/
let reconnectTime: any = null
function onPrinterChange() {
if (getStorage('deviceName')) {
setPrinterStatus()
reconnectTime = setTimeout(async () => {
await bluetooth.reconnect()
clearTimeout(reconnectTime)
}, 1500)
}
}
return {
SystemInfo, // 获取本机系统信息
onNetWorkStatusChange, // 监听网络状态
autoUpdate, // 小程序更新
isIosSystem, // 是否为IOS
onPrinterChange, // 监听打印机状态
}
}
export default App

33
src/App.vue Normal file
View File

@@ -0,0 +1,33 @@
<script setup lang="ts">
import jxMOdal from '@/components/dialog/dialogUtil'
import { onLaunch } from '@dcloudio/uni-app'
import App from './App'
import { store } from "@/store";
const {
autoUpdate, // 小程序更新
} = App()
const {
SystemInfo, //获取本机设备信息
onNetWorkStatusChange, // 监听网络状态
isIosSystem, // 是否为IOS
onPrinterChange, // 监听打印机状态
} = App()
onLaunch(() => {
SystemInfo() // 获取本机设备信息
uni['jxAlert'] = jxMOdal.alert // 全局挂载 jxMOdal
uni['jxConfirm'] = jxMOdal.confirm // 全局挂载 jxMOdal
onNetWorkStatusChange() // 监听网络状态
isIosSystem() // 是否为IOS
onPrinterChange() // 监听打印机状态
autoUpdate() // 检查版本更新
store.dispatch('serveInfo/get_services')
})
</script>
<style>
@import './static/font/iconfont.css';
page {
background-color: #efefef;
}
</style>

3
src/androidPrivacy.json Normal file
View File

@@ -0,0 +1,3 @@
{
"prompt" : "none"
}

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

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

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

@@ -0,0 +1,112 @@
/*************************************************
*@description: 登录模块
*@return {*}
*@param {}-
*/
import { setLoading } from '@/utils/tools'
import request from '../request'
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: (params: AnyObject): Promise<AnyObject> => {
setLoading('登录中...')
return 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

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

@@ -0,0 +1,267 @@
/**
* @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

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

@@ -0,0 +1,49 @@
/**
* @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

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

@@ -0,0 +1,519 @@
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_s_to_u_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 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)
},
/**
* @Title 查询门店发票设置
* @Description 查询门店发票设置
* @Param token header string true "认证token"
*
* @Param vendorId formData string true "平台ID"
* @Param vendorStoreID formData string true "平台门店ID"
*/
query_invoice_setting: async (params: AnyObject): Promise<AnyObject> => {
return await request.api('/v2/order/QueryInvoiceSetting', 'GET', params)
},
/**
* @Title 查询门店开票申请 饿百
* @Description 批量更新店铺开票申请
* @Param token header string true "认证token"
* @Param vendorId formData string true "平台ID"
* @Param vendorStoreID formData string true "平台门店ID"
* @Param storeID formData int true "京西门店ID"
*/
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

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

@@ -0,0 +1,26 @@
/**
* 模拟后端返回的数据
*/
// 聊天消息
export const msgInfo = {
// 用户列表
userList: {
code: '0',
data: {
'4123:18936290:1': ['{"vendorID":1,"userID":"11555094096","orderID":"1100741210767960587","NewMessageNum":0,"latestMsg":"Vn/zZZLHq/i1ZVdIsiIpxRWO3yUqTe4GVRjOZVDVP5Q=","latestTime":1695691485}']
},
desc: ''
},
// 聊天详情
chatDetail: {
code: '0',
data: {
'4123:18936290:1:11555094096': [
// '{"sendType":"mt","msgContent":{"app_id":5873,"app_poi_code":"18003191","msg_id":1400636412362739712,"msg_content":"Vn/zZZLHq/i1ZVdIsiIpxRWO3yUqTe4GVRjOZVDVP5Q=","msg_source":2,"msg_type":1,"cts":1695691485,"open_user_id":1100739340156553913,"order_id":1100741210767960587,"group_id":0,"app_spu_codes":""}}'
'{"sendType":"mt","msgContent":{"app_id":5873,"app_poi_code":"18003191","msg_id":1400636412362739712,"msg_content":"0S489X84oStvm5vg3jJdG5XRPCX/MD5D5+JlrOLi4bMae3ppvVn6Rp7yMP6qrckY","msg_source":2,"msg_type":1,"cts":1695691485,"open_user_id":1100739340156553913,"order_id":1100741210767960587,"group_id":0,"app_spu_codes":""}}'
]
},
desc: ''
}
}

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

@@ -0,0 +1,234 @@
/**
*@description: 请求接口配置文件
*@return {*}
*@param
*/
import urlConfig from "./config";
import toast from "@/utils/toast";
import { cleatStorage, getStorage } from "@/utils/storage";
import { store } from "@/store";
import { addTask, jx_trembling } from "@/utils/tools";
import configCms from "@/utils/configCms";
import log from '@/utils/log'
// 定义请求类型
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) => { })
}
timeouts = timeout
// store.commit('storeInfo/jxLoadingFn', false) // 关闭自定义加载图vuex)
clearTimeout(timer)
timer = setTimeout(() => {
// 显示自定义加载图(vuex)
// store.commit('storeInfo/jxLoadingFn', true)
// uni.showNavigationBarLoading()
// 最大时间加载图
tremblingJxLoadingFn()
}, 600)
if (url == '/v2/cms/GetNewOrderMsg') store.commit('storeInfo/jxLoadingFn', false)
return new Promise((resolve, reject) => {
requestTask = uni.request({
url: baseURL + url,
method: method,
data: data,
timeout: timeout,
header: {
'content-type': contentType,
'token': getStorage('token') ? getStorage('token') : 'jxcs'
},
success: (res) => {
//#region
let logData = {
'日志记录时间': Date(),
'调用接口': url,
'请求方法': method,
'请求参数': data,
'请求超时时间': timeout,
'请求域名': baseURL,
'登录类型': getStorage('loginType') ? getStorage('loginType') : '未获取到用户登录类型',
'用户TOKEN': getStorage('token') ? getStorage('token') : '未获取到用户TOKEN',
'权限ID': getStorage('userType') ? getStorage('userType') : '未获取到用户权限ID',
'用户ID': getStorage('userID') ? getStorage('userID') : '未获取到用户ID',
'用户ID2': getStorage('userID2') ? getStorage('userID2') : '未获取到用户ID2',
'用户手机号': getStorage('mobile') ? getStorage('mobile') : '未获取到用户手机号',
'店铺ID': getStorage('storeID') ? getStorage('storeID') : '未获取到店铺ID',
'店铺名字': getStorage('storeName') ? getStorage('storeName') : '未获取到店铺名字',
'网络状态码': res.statusCode,
'服务端数据': res.data
}
//#endregion
// store.commit('storeInfo/jxLoadingFn', false) // 关闭自定义加载图vuex)
if (res.statusCode >= 200 && res.statusCode < 300) {
log.info(JSON.stringify(logData))
// 通过token 验证 通过store 验证
if ((res.data as AnyObject).code == '-2') {
uni.jxAlert({
title: '提示',
content: '登录信息已过期',
confirmText: '重新登录',
success: () => {
cleatStorage()
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) {
log.warn(JSON.stringify(logData))
toast('客户端出错', 2)
reject('客户端出错')
} else if (res.statusCode >= 500) {
log.warn(JSON.stringify(logData))
toast('服务端出错', 2)
reject('服务端出错')
} else {
log.warn(JSON.stringify(logData))
toast('网络请求出错', 2)
}
},
fail: (error) => {
if (error.errMsg == 'request:fail abort') {
// 中断请求
return false
}
toast('网络请求超时', 2)
console.log('jx-网络请求超时', error);
reject(`网络请求超时 -- request.ts, ${error}`)
//#region
let logData = {
'日志记录时间': Date(),
'调用接口': url,
'请求方法': method,
'请求参数': data,
'请求超时时间': timeout,
'请求域名': baseURL,
'登录类型': getStorage('loginType') ? getStorage('loginType') : '未获取到用户登录类型',
'用户TOKEN': getStorage('token') ? getStorage('token') : '未获取到用户TOKEN',
'权限ID': getStorage('userType') ? getStorage('userType') : '未获取到用户权限ID',
'用户ID': getStorage('userID') ? getStorage('userID') : '未获取到用户ID',
'用户ID2': getStorage('userID2') ? getStorage('userID2') : '未获取到用户ID2',
'用户手机号': getStorage('mobile') ? getStorage('mobile') : '未获取到用户手机号',
'店铺ID': getStorage('storeID') ? getStorage('storeID') : '未获取到店铺ID',
'店铺名字': getStorage('storeName') ? getStorage('storeName') : '未获取到店铺名字',
'请求错误信息': error
}
log.error(JSON.stringify(logData)) // 普通请求日志
//#endregion
},
complete: () => {
uni.stopPullDownRefresh()
// uni.hideNavigationBarLoading()
// 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)
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', getStorage('token') ? false : true)
return false
}
// 门店防抖节流
const rulerStoreID = jx_trembling(() => {
uni.navigateTo({ url: "/subPages/switchStore/switchStore" })
}, 1000)
export default request

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,202 @@
<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
uni.vibrateShort({})
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.vibrateShort({})
uni.navigateBack()
uni.$emit('jx_dialog', type)
}
</script>
<style lang="scss">
$btncolor: #51b535;
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.4);
.dialog-content {
background-color: #ffffff;
width: 560rpx;
border-radius: 15rpx;
animation: centerScale 0.3s;
@keyframes centerScale {
0% {
transform: scale(1.3);
}
100% {
transform: scale(1);
}
}
.head-content {
display: flex;
align-items: center;
justify-content: center;
color: #343434;
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;
color: #636463;
display: flex;
justify-content: center;
align-items: 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: rgb(77, 77, 77);
font-weight: bold;
}
}
}
}
}
.active1 {
background-color: #dddddd;
}
}
</style>

View File

@@ -0,0 +1,42 @@
import dialog from "./dialog"
const jxMOdal = {
/**
* 弹出提示
*/
alert(options: any) {
uni.showModal({
title: options.title,
content: options.content,
confirmText: options.confirmText || '确定',
showCancel: false,
confirmColor: "#51b535",
success: options.success
})
},
/**
* 确认提示框
*/
confirm(options: any) {
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,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: 999999;
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,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,113 @@
<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
>
</view>
<view class="login-empty" v-else-if="store.state.serveInfo.isFirstLogin">
<jx-empty :title="title" color="#9b9b9b">
<view>
<view style="color: #f56c6c;font-size: 24rpx;text-align: center;">(仅限京西商家用户登录使用)</view>
<view
class="first-login"
hover-class="hoverLogin"
hover-start-time="0"
hover-stay-time="1200"
@tap="firstLogin"
>立即登录</view
>
</view>
</jx-empty>
</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,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,103 @@
<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
}
const props = withDefaults(defineProps<PropsType>(), {
color: '#000',
isTip: true,
})
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);
}
.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,232 @@
<template>
<view class="upload-pic">
<view class="pic-title" :style ="{'justify-content':type === 'invoiceImg' ? 'center': '' }">{{ title }}</view>
<view class="pic-wrapper">
<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.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 {
height: 130px;
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,597 @@
import merchant from "@/api/https/merchant";
import { store } from "@/store";
import { setStorage, jx_default_storage_plugin, getStorage, cleatStorage } from "@/utils/storage";
import toast from "@/utils/toast";
import { timeFormatD } from "@/utils/tools";
import { utilsMd5 } from '@/utils/md5.js'
import Bluetooth from '@/utils/bluetoothPrinter/bluetooth'
import { store as newStore } from '@/store'
import util from '@/utils/bluetoothPrinter/util'
import login from "@/api/https/login";
import order from "@/api/https/order";
import { computed } from "vue";
import { emojiAnanlyze } from '@/utils/emoji'
/**
* 今日营业数据
* @param data 事实订单数据
*/
function useGlobalFunc() {
const bluetooth: any = getStorage('deviceName') ? new Bluetooth() : null
/*************************************************
* 获取实时订单数据
* @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);
}
}
/*************************************************
* 退出登录
*/
function logOutFn() {
cleatStorage('token')
cleatStorage('userID')
cleatStorage('userType')
cleatStorage('storeID')
cleatStorage('storeName')
cleatStorage('userID2')
cleatStorage('mobile')
cleatStorage('isAgreement')
cleatStorage('loginType')
store.commit('serveInfo/setIsFirestLogin', true)
}
/*************************************************
* 查看详情图片
* @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],
success: (res: any) => {
resolve(res)
},
fail: (err: any) => {
toast(err)
reject(err)
}
})
})
uni.vibrateShort({})
}
/*************************************************
* 存储用户信息
* @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);
setStorage("loginType", data.authBindInfo.type);
jx_default_storage_plugin()
// 防止ios app 出现认证信息还没有缓存就已经跳转请求了
if (getStorage("storeID")) {
await store.dispatch('storeInfo/getOneStore', getStorage("storeID"))
uni.switchTab({ url: '/pages/order-manager/main' })
} else {
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" })
}, 0)
}
}
/*************************************************
* app 微信登录
* @bangding {Function} 绑定
* @seccess {Function} 登录成功
*/
/*************************************************
* 全局判断是否有新信息有信息就在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)
}
})
uni.vibrateShort({})
}
/************************************************************
* 拨打电话
* @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)
}
})
uni.vibrateShort({})
}
const businessKey = 'XKJPOIHJ233adf01KJIXlIeQDSDKFJAD' // 商户秘钥
/*************************************************
* 统一微信支付功能
* 说明app暂未申请支付功能仅支持小程序支付
* @param {number} [chargeMoney] 支付金额
* @param {number | string} [storeID] 门店ID
* @param {Function} [fn] 支付回调,成功或失败都会调用
* @param {string} [vendorOrderID] 订单id
*
*/
async function globalPlayMoney(orderPayType: number, chargeMoney: number, StoreID: number | string, code: string, fn: Function, vendorOrderID = '') {
let tempMoney = +chargeMoney * 100
// 创建订单
let data = {
orderType: orderPayType,
storeID: StoreID,
price: tempMoney,
vendorOrderID: vendorOrderID
}
let orderNum = await order.create_store_acct_order(data)
// 支付订单
let data1 = {
// subAppID: 'wx08a5c2a8581414ff',
subAppID: 'wx2d6949f724b2541d',
payType: orderPayType,
vendorOrderID: orderNum.data,
vendorPayType: 'W06',
code: `weixinappcs_${code}`
}
let orderInfo = await order.pay4_user(data1)
let newOrderInfo = orderInfo.data
// 调用微信支付
handleCreatePay(newOrderInfo.vendorOrderID, newOrderInfo.prepayID, JSON.parse(newOrderInfo.codeURL), fn)
}
// 微信支付
function handleCreatePay(orderInfo: any, prepayID: number | string, codeURL: AnyObject, fn: Function) {
let token = ''
token = getStorage('token')
let timeStamp: string
let randomNum: number
let strPay: string
let nonceStr: string
let packageA: string
let paySign: string
let signType = 'MD5'
if (codeURL) {
// 通联收银 payType 2
timeStamp = codeURL.timeStamp
nonceStr = codeURL.nonceStr
packageA = codeURL.package
signType = codeURL.signType
paySign = codeURL.paySign
} else {
timeStamp = Math.round(new Date().getTime() / 1000).toString()
randomNum = (Math.random() * 5) + 1
strPay = timeStamp + token + randomNum
nonceStr = utilsMd5.hex_md5(strPay)
packageA = `prepay_id=${prepayID}`
paySign = utilsMd5.hex_md5(`appId=wx4b5930c13f8b1170&nonceStr=${nonceStr}&package=${packageA}&signType=MD5&timeStamp=${timeStamp}&key=${businessKey}`)
}
uni.requestPayment({
provider: 'wxpay',
orderInfo: orderInfo,
timeStamp: timeStamp,
nonceStr: nonceStr,
package: packageA,
signType: signType,
paySign: paySign,
success: () => {
toast('充值成功', 1)
},
fail: () => {
toast('取消充值', 2)
},
complete: () => {
fn && fn()
}
})
}
/*************************************************
* 打开微信小程序
* @param {string} [url] 跳转地址
* @param {string} [id] 小程序原始ID
*/
/*************************************************
* 判断门店是否在营业中
* @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 是否需要进行更行
*/
/*************************************************
* 格式化今日订单数据
*/
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)
}
}
}
/*************************************************
* 查询打印机状态并连接
*/
const playVoid = uni.createInnerAudioContext()
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 * 10)
}
// 播放音频
function playVoidFn() {
playVoid.src = 'https://image.jxc4.com/image/ee1174253ee2919a23d7ea5277b2141b.jpg'
playVoid.stop()
playVoid.play()
}
/*************************************************
* 提示用户未勾选
*/
let time: any = null
function isUserAgreementFn() {
store.commit('serveInfo/setIsAgreementIf', false)
clearTimeout(time)
time = setTimeout(() => {
uni.vibrateShort({})
store.commit('serveInfo/setIsAgreementIf', true)
}, 200)
}
// ******************** 判断是否有淘鲜达 *****************************
//#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: 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 && storeMaps.value.StoreMaps.length > 0 ? 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 // 未知表情
if (emojiImg === item) emojiImg = 'unknown:' + item // 未知表情
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 {
globGetToDay, //获取实时订单数据
previewImage, // 查看详情图
setUserInfo, // 储存用户信息
newMessage, // 展示新信息
copyInfo, // 复制信息
phoneCall, // 拨打电话
globalPlayMoney, // 统一支付
isTrades, // 判断是否是在营业时间
wholeCalcPrice, // 格式化今日订单数据
singleCalcPrice, // 格式化今日订单数据
setPrinterStatus, // 查询打印机状态并连接
logOutFn, // 退出登录
isUserAgreementFn, // 提示用户未勾选
isTxd, // 判断是否有淘鲜达
getMtStoreIMStatus, // 获取美团IM单聊状态
analyEmoji, // 解析emoji表情
isCloudEmoji // 是否含有emoji
}
}
export default useGlobalFunc

View File

@@ -0,0 +1,287 @@
/**
* 订单管理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 merchant from "@/api/https/merchant"
import order from "@/api/https/order"
function useOrderInfo() {
const bluetooth: any = getStorage('deviceName') ? new Bluetooth() : null
/**************************************************************
* 复制订单信息内容
* @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)
}
})
uni.vibrateShort({})
}
/************************************************************
* 拨打电话
* @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)
}
})
uni.vibrateShort({})
}
/************************************************************
* 跳转到详情页
* @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

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

@@ -0,0 +1,134 @@
/// <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)
/*************************************************************
* 允许uni 使用 showShareImageMenu 微信分享功能
*/
}
}
}

15
src/main.ts Normal file
View File

@@ -0,0 +1,15 @@
import { createSSRApp } from "vue";
import App from "./App.vue";
import { store, key } from "./store";
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
}
}

174
src/manifest.json Normal file
View File

@@ -0,0 +1,174 @@
{
"name": "京西菜市商家版",
"appid": "__UNI__F9A47D3",
"description": "1、商户通过京西平台同时管理美团、饿了么、京东等多个外卖平台实现一键上架、下架、修改、删除多个平台商品2、商户通过京西平台可以同时对、美团专送、达达、顺丰同城等多个专送平台召唤偶骑手",
"versionName": "1.3.0",
"versionCode": 130,
"transformPx": false,
/* 5+App */
"app-plus": {
"compatible": {
"ignoreVersion": true
},
"usingComponents": true,
"nvueStyleCompiler": "uni-app",
"compilerVersion": 3,
"splashscreen": {
"alwaysShowBeforeRender": false,
"waiting": false,
"autoclose": true,
"delay": 0
},
/* */
"modules": {},
/* */
"distribute": {
/* android */
"android": {
"permissions": [],
"abiFilters": [
"armeabi-v7a",
"arm64-v8a",
"x86"
],
"minSdkVersion": 23,
"targetSdkVersion": 28,
"autoSdkPermissions": false
},
/* ios */
"ios": {
"dSYMs": false,
"privacyDescription": {
"NSPhotoLibraryUsageDescription": "",
"NSPhotoLibraryAddUsageDescription": "",
"NSBluetoothPeripheralUsageDescription": "",
"NSBluetoothAlwaysUsageDescription": "",
"NSCameraUsageDescription": ""
},
"capabilities": {
"entitlements": {
"com.apple.developer.associated-domains": []
}
},
"UIBackgroundModes": ""
},
/* SDK */
"sdkConfigs": {
"share": {
"weixin": {
"appid": "wx18111a41fd17f24f",
"UniversalLinks": "https://www.jxc4.com"
}
},
"ad": {},
"payment": {
"weixin": {
"__platform__": [
"android"
],
"appid": "wx18111a41fd17f24f",
"UniversalLinks": "https://www.jxc4.com"
}
},
"geolocation": {
"system": {
"__platform__": [
"ios"
]
}
},
"oauth": {
"weixin": {
"appid": "wx18111a41fd17f24f",
"UniversalLinks": "https://www.jxc4.com"
}
},
"push": {
"unipush": {}
}
},
"icons": {
"android": {
"hdpi": "",
"xhdpi": "",
"xxhdpi": "",
"xxxhdpi": ""
},
"ios": {
"appstore": "",
"ipad": {
"app": "",
"app@2x": "",
"notification": "",
"notification@2x": "",
"proapp@2x": "",
"settings": "",
"settings@2x": "",
"spotlight": "",
"spotlight@2x": ""
},
"iphone": {
"app@2x": "",
"app@3x": "",
"notification@2x": "",
"notification@3x": "",
"settings@2x": "",
"settings@3x": "",
"spotlight@2x": "",
"spotlight@3x": ""
}
}
},
"splashscreen": {
"useOriginalMsgbox": false,
"androidStyle": "common",
"iosStyle": "common",
"android": {
"hdpi": "D:/桌面/京西/新商家版/图标(1)/480x762.png",
"xhdpi": "D:/桌面/京西/新商家版/图标(1)/720x1242.png",
"xxhdpi": "D:/桌面/京西/新商家版/图标(1)/1080x1882.png"
}
}
},
"nativePlugins": {}
},
/* */
"quickapp": {},
/* */
"mp-weixin": {
"appid": "wx2d6949f724b2541d",
"setting": {
"urlCheck": false
},
"usingComponents": true,
"lazyCodeLoading": "requiredComponents",
"plugins": {
"chatGroupPlugin": {
"version": "1.1.2",
"provider": "wxaae6519cee98d824"
}
},
"permission": {
"scope.userLocation": {
"desc": "你的位置信息将用于搜索附近的蓝牙打印机设备"
}
}
},
"mp-alipay": {
"usingComponents": true
},
"mp-baidu": {
"usingComponents": true,
"appid": "wx2d6949f724b2541d"
},
"mp-toutiao": {
"usingComponents": true
},
"uniStatistics": {
"enable": false
},
"vueVersion": "3",
"fallbackLocale": "zh-Hans",
"locale": "zh-Hans",
"_spaceID": "mp-6a99ccda-c7f6-4ef9-8870-35401c55287e"
}

401
src/pages.json Normal file
View File

@@ -0,0 +1,401 @@
{
"lazyCodeLoading": "requiredComponents",
"easycom": {
"autoscan": true,
"custom": {
"^uni-(.*)": "@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue"
}
},
"pages": [
{
"path": "pages/merchant/index",
"style": {
"navigationBarTitleText": "商家中心",
"enablePullDownRefresh": true,
"navigationBarBackgroundColor": "#4eb331",
"navigationBarTextStyle": "white"
}
},
{
"path": "pages/goods-manager/main",
"style": {
"navigationBarTitleText": "商品管理",
"navigationBarBackgroundColor": "#4eb331",
"navigationBarTextStyle": "white"
}
},
{
"path": "pages/message/index",
"style": {
"navigationBarTitleText": "客户消息",
"enablePullDownRefresh": true
}
},
{
"path": "pages/order-manager/main",
"style": {
"navigationBarTitleText": "订单管理"
}
}
],
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "京西菜市",
"navigationBarBackgroundColor": "#fff",
"backgroundColor": "#F8F8F8",
"rpxCalcBaseDeviceWidth": 750
},
"subPackages": [
{
"root": "subPages/login",
"pages": [
{
"path": "index",
"style": {
"navigationBarTitleText": "登录"
}
},
{
"path": "bindSNS/bindSNS",
"style": {
"navigationBarTitleText": "绑定"
}
},
{
"path": "wxLogin/wxLogin",
"style": {
"navigationBarTitleText": "登录"
}
}
]
},
{
"root": "subPages/agreement",
"pages": [
{
"path": "privacy",
"style": {
"navigationBarTitleText": "京西菜市隐私协议"
}
},
{
"path": "user",
"style": {
"navigationBarTitleText": "京西菜市用户协议"
}
},
{
"path": "about",
"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": "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": "商品详情"
}
},
{
"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": "useInfo/useInfo",
"style": {
"navigationBarTitleText": "个人信息"
}
},
{
"path": "payeeInfo/payeeInfo",
"style": {
"navigationBarTitleText": "收款信息"
}
},
{
"path": "invoice/invoice",
"style": {
"navigationBarTitleText": "发票管理"
}
},
{
"path": "accountBalance/accountBalance",
"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": "消息"
}
},
{
"path": "appPlay/appPlay",
"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"
}
]
},
"condition": {
"current": 0,
"list": [
{
"name": "订单管理-新订单通知",
"path": "pages/order-manager/main?jxStoreId=800422"
}
]
}
}

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,255 @@
<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 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}}
<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'
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,219 @@
<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-filter"
: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 toast from '@/utils/toast'
import { jx_throttles } from '@/utils/tools'
import { ref, watch } from 'vue'
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 | boolean) {
if (filteActive.value == item.lable) return
fliterFn_throttles(item, status)
}
const fliterFn_throttles = 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,128 @@
<template>
<view class="search-root">
<view class="add-shopping" @tap="createGoods">
<jx-icon icon="jiahao" color="#4eb331"></jx-icon>
<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 shopping from "@/api/https/shopping"
import { getStorage } from "@/utils/storage"
import { onLoad } from "@dcloudio/uni-app"
import { ref } from "vue"
/*************************************************
* 商品分类栏目
*/
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,111 @@
.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(209, 209, 209);
}
.tip {
padding: 2rpx 0;
height: 66rpx;
line-height: 66rpx;
text-align: left;
border-bottom:1px dashed #999;
.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,741 @@
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 shopping from '@/api/https/shopping'
import merchant from '@/api/https/merchant'
/*************************************************
* 商品管理
*/
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 右侧主体数据
* 获取商品数据
*/
onLoad(async () => {
if (!getStorage('token')) return
store.commit('storeInfo/jxLoadingFn', true)
await getSkuNames()
store.commit('storeInfo/jxLoadingFn', false)
})
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,
// locationCode2: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') {
console.log('allSaleStatus',allSaleStatus.value)
data[allSaleStatus.value.name] = allSaleStatus.value.status
}
keyFilter(data)
let res = await shopping.get_stores_skus_for_store({...data,keyword: keyword.value }) // 关键字查询
let res1:AnyObject = {}
if(keyword.value) res1 = await shopping.get_stores_skus_for_store({...data,locationCode2:keyword.value}) // 货架码查询
if (res.code == 0) {
let totalCount1 = res.data.totalCount
let skuNameArr = res.data.skuNames || []
if(JSON.stringify(res1) !== '{}' && res1.code == 0) {
skuNameArr = mergeUnique(skuNameArr,res1.data.skuNames)
totalCount1 = skuNameArr.length
}
totalCount.value = totalCount1
let filterData = mapskuName(skuNameArr)
skuNames.value = skuNames.value.concat(filterData)
if (filterData.length == 0) return toast('该分类未找到商品')
} else {
dataHoming()
toast('分类查询错误')
}
isLoad.value = false
}
/*************************************************
* 去重合并数组
*/
function mergeUnique(...arrays:any[]) {
const uniqueObjects = new Set();
arrays.forEach(array => {
if(array){
array.forEach((obj:any) => {
uniqueObjects.add(JSON.stringify(obj));
});
}
});
return Array.from(uniqueObjects).map((json:any) => JSON.parse(json));
}
/*************************************************
* 过滤对象空字段
*/
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, // 右侧导航栏实例
toExamine, // 审核商品
toExamineData, // 审核商品数据
toExaminePopup, // 改价审核实例
toExamineConfirm, // 确定操作审核
toExamineValue, // 审核输入内容
}
}
export default shoppingMangerFn

View File

@@ -0,0 +1,244 @@
<template>
<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)">
<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)"
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="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="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, // 右侧导航栏实例
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>

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

@@ -0,0 +1,176 @@
import { computed, onBeforeUnmount, ref } from 'vue'
import { timeFormatD } from '@/utils/tools'
import { getStorage, setStorage } from '@/utils/storage'
import { onLoad, onPullDownRefresh } from '@dcloudio/uni-app'
import merchant from '@/api/https/merchant'
import { store } from '@/store'
import useGlobalFunc from '@/composables/useGlobalFunc'
/*************************************************
* 商家中心
*/
const merchantFn = function () {
const { getMtStoreIMStatus } = useGlobalFunc()
/*************************************************
* 下拉刷新
*/
let onPullDownRefreshTimer: any = null
onPullDownRefresh(() => {
clearTimeout(onPullDownRefreshTimer)
onPullDownRefreshTimer = setTimeout(async () => {
if (!getStorage('token')) return
store.commit('storeInfo/jxLoadingFn', true)
await getSaleInfo()
await getStoreVendorMaps(-1)
await getMtStoreIMStatus() // 获取美团门店的im状态
uni.stopPullDownRefresh()
clearTimeout(onPullDownRefreshTimer)
store.commit('storeInfo/jxLoadingFn', false)
}, 500)
})
/*************************************************
* 页面加载获取数据
*/
const popup = ref<any>(null)
onLoad(async () => {
if (!getStorage('token')) return
store.commit('storeInfo/jxLoadingFn', true)
await getStoreVendorMaps(-1)
await getSaleInfo()
store.commit('storeInfo/jxLoadingFn', false)
if (getStorage('isDownApp') != 'true') {
setTimeout(() => {
popup.value.open()
}, 800)
}
})
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 && JSON.stringify(res.data) !== '[]') {
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 closeDownApp() {
setStorage('isDownApp', 'true')
popup.value.close()
}
/*************************************************
* 做收尾工作
*/
onBeforeUnmount(() => {
clearTimeout(onPullDownRefreshTimer)
})
return {
saleInfo, // 今日订单数据
_vendorPayPercentage, // 供应商百分比
isShowShop, // 是否为出售金额
isNotQuote,
isZero,
isUpperfif,
getMsg,
isMsg,
popup,
closeDownApp,
}
}
export default merchantFn

View File

@@ -0,0 +1,156 @@
<template>
<!-- 用户信息 -->
<user-info />
<!-- 实时订单数据 -->
<order-data
:showMore="true"
:saleInfo="saleInfo"
:_vendorPayPercentage="_vendorPayPercentage"
:isShowShop="isShowShop"
:isNotQuote="isNotQuote"
:isZero="isZero"
:isUpperfif="isUpperfif"
:isOut="true"
/>
<!-- 选项内容 -->
<options />
<!-- 新信息 -->
<view class="new-msg" v-if="isMsg" @tap="getMsg">
<image
class="img"
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>
<!-- 下载App -->
<uni-popup ref="popup" type="center">
<view class="down-app-root">
<uni-title type="h2" title="果园商家App上线" align="center" />
<view class="info"
>京西菜市商家版App全新上架系统更加稳定功能更加齐全订单通知更加及时请往手机自带应用商店搜索京西菜市进行安装使用</view
>
<uni-title type="h3" title="苹果搜索【京西菜市】" />
<image
class="img"
src="https://image.jxc4.com/image/a9879811d0bebfa8fd9d25240fccbcde.tem.jpg"
mode="widthFix"
/>
<uni-title type="h3" title="安卓搜索【京西菜市】" />
<image
class="img"
src="https://image.jxc4.com/image/b77cc513274b89da69a9119fef43c24e.tem.jpg"
mode="widthFix"
/>
<view class="btn" @tap="closeDownApp">我知道了</view>
</view>
</uni-popup>
<!-- 公共组件 -->
<jx-loading />
<!-- 未登录无网络 -->
<jx-login-empty title="马上登录,开始使用" />
</template>
<script lang="ts" setup>
import userInfo from './userInfo/userInfo.vue'
import orderData from './orderData/orderData.vue'
import options from './options/options.vue'
import merchantFn from './index'
const {
saleInfo, //今日订单数据
_vendorPayPercentage, // 供应商百分比
isShowShop, // 是否为出售金额
isNotQuote,
isZero,
isUpperfif,
getMsg,
popup,
isMsg,
closeDownApp,
} = merchantFn()
</script>
<style lang="scss" scoped>
.new-msg {
position: fixed;
bottom: 20rpx;
left: 20rpx;
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;
.img {
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);
}
}
.down-app-root {
background-color: #fff;
width: 600rpx;
box-sizing: border-box;
padding: 25rpx 35rpx;
border-radius: 20rpx;
.info {
font-size: 28rpx;
color: rgb(146, 146, 146);
}
.img {
width: 100%;
margin-bottom: 25rpx;
border-radius: 5rpx;
box-shadow: 0 0 5rpx rgb(199, 199, 199);
}
.btn {
background: linear-gradient(0, #7ecf68, #51b535);
color: #fff;
padding: 15rpx 0;
border-radius: 100rpx;
text-align: center;
}
}
</style>

View File

@@ -0,0 +1,106 @@
.options-root {
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;
}
}
}
@keyframes bill-new-animation {
0% {
transform: scale(0.95);
}
100% {
transform: scale(1.05);
}
}

View File

@@ -0,0 +1,299 @@
/**
* 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 order from "@/api/https/order"
function options() {
/**
* 进入群聊
*/
function getGroupChat() {
uni.navigateTo({
url: '/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"
uni.jxAlert({
title: '物料申请',
content: `非常抱歉,无法进入物料商城,请联系运营${tel}`
})
}
/**
* 查询是否有新账单
*/
onLoad(async () => {
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) {
if (evaluateMRes.data) {
badCommentCount.value = evaluateMRes.data
} else {
badCommentCount.value = 0
}
} else toast('差评数据异常', 2)
}
watch(() => store.getters['storeInfo/imMtStatus'],
(val) => {
if(val && val.length>0) getInvoiceInfo('mt')
})
/**
* 发票数量 美团
*/
const invoiceCount:Ref<number | string> = ref(0)
async function getInvoiceInfo(type:string,ebStore?:any) {
if(type === 'mt'){
// 美团们门店
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)
if(res.code === '0') invoiceCount.value = res.data.totalCount
}
}else if(type === 'eb'){
// console.log('get_invoice_info',ebStore)
// let res = await order.get_invoice_info({
// vendorId:'3',
// vendorStoreID:'' + ebStore.vendorStoreID,
// storeID:+ebStore.storeID
// })
// console.log('饿百数据列表信息',res.data)
// if(res.code === '0') invoiceCount.value = Number(invoiceCount.value) + res.total_count
}
}
/**
* 打开 app or 小程序
*/
function openAppOrApplet() {
uni.jxAlert({
title: '提示',
content: '下载链接复制成功,请到浏览器进行下载,或者到手机应用商店搜索【京西菜市】进行下载!',
success: () => {
uni.setClipboardData({
data: 'https://www.jxc4.com/managerApp/downApp.html'
})
}
})
}
/*************************************************
* 下拉刷新
*/
let onPullDownRefreshTimer: any = null
onPullDownRefresh(() => {
clearTimeout(onPullDownRefreshTimer)
onPullDownRefreshTimer = setTimeout(async () => {
await tmpGetJxBadCommentsNo()
await getMessageData()
await handleMsg()
await getInvoiceInfo('mt')
// await getInvoiceInfo('eb')
uni.stopPullDownRefresh()
}, 1000)
})
/**
* 版本更新
*/
const isVarsion = ref<boolean>(false)
onBeforeUnmount(() => {
clearTimeout(onPullDownRefreshTimer)
})
/*************************************************
* 微信小程序版本更新
*/
function autoUpdate() {
// 获取小程序更新机制兼容
if (uni.canIUse('getUpdateManager')) {
const updateManager = uni.getUpdateManager()
// 检查是否有新版本发布
updateManager.onCheckForUpdate(function (res) {
if (res.hasUpdate) {
isVarsion.value = true
//小程序有新版本,则静默下载新版本,做好更新准备
updateManager.onUpdateReady(function () {
uni.jxAlert({
title: '更新提示',
content: '应用已经升级到新版本了请及时更新',
success: () => {
updateManager.applyUpdate()
}
})
})
// 新的版本下载失败
updateManager.onUpdateFailed(function () {
uni.showModal({
title: '温馨提示',
content: '新版本已经上线,请您删除当前小程序,重新搜索打开',
})
})
} else {
isVarsion.value = false
toast('已经是最新版')
}
})
} else {
// 提示用户在最新版本的客户端上体验
uni.showModal({
title: '温馨提示',
content: '当前微信版本过低,可能无法使用该功能,请升级到最新版本后重试。'
})
}
}
return {
getGroupChat, // 跳转加入群聊
getSelfInfo, // 获取门店来京西的时间
moveToWM, // 物料申请
newBillShow, // 是否有新订单
billList, // 账单列表
msgCount, // 是否有信息
badCommentCount, // 获取差评数量
invoiceCount, // 发票数量
openAppOrApplet, // app or 小程序
isVarsion, // 是否现实新版本
autoUpdate, // 检查微信更新
}
}
export default options

View File

@@ -0,0 +1,261 @@
<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>
</uni-grid>
</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, // 是否现实新版本
autoUpdate, // 检查微信更新
} = options()
// 不用展示信息的图标
// 未下载微信不展示
const grindListData = ref([
{
id: 1,
icon: '/static/merchant-icon/1.png',
title: '加入群聊',
},
{
id: 2,
icon: '/static/merchant-icon/2.png',
title: '营业资质',
},
{
id: 3,
icon: '/static/merchant-icon/3.png',
title: '平台管理',
},
{
id: 4,
icon: '/static/merchant-icon/4.png',
title: '我的账单',
},
{
id: 5,
icon: '/static/merchant-icon/5.png',
title: '差评管理',
},
{
id: 6,
icon: '/static/merchant-icon/6.png',
title: '消息通知',
},
{
id: 7,
icon: '/static/merchant-icon/7.png',
title: '物料申请',
},
{
id: 16,
icon: '/static/merchant-icon/8.png',
title: '扫码进店',
},
{
id: 8,
icon: '/static/merchant-icon/9.png',
title: '待配商品',
},
{
id: 9,
icon: '/static/merchant-icon/10.png',
title: '门店评分',
},
{
id: 10,
icon: '/static/merchant-icon/11.png',
title: '帮助中心',
},
{
id: 11,
icon: '/static/merchant-icon/12.png',
title: '官方客服',
},
{
id: 12,
icon: '/static/merchant-icon/13.png',
title: '设置',
},
{
id: 13,
icon: '/static/merchant-icon/14.png',
title: '活动信息',
},
{
id: 14,
icon: '/static/merchant-icon/15.png',
title: '注册时间',
},
{
id: 15,
icon: '/static/merchant-icon/16.png',
title: '下载App',
},
{
id: 18,
icon: '/static/merchant-icon/19.png',
title: '个人信息',
},
{
id: 20,
icon: '/static/merchant-icon/21.png',
title: '收款信息',
},
{
id: 19,
icon: '/static/merchant-icon/20.png',
title: '配送余额',
},
{
id: 17,
icon: '/static/merchant-icon/18.png',
title: '检查更新',
},
])
/*************************************************
* 格式化数据,没有下载微信有些数据不展示
*/
const newGrindListData = computed(() => {
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:
autoUpdate()
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,151 @@
<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"
></jx-icon>
</view>
<view class="see-more" v-if="showMore">
<text>更多</text>
<jx-icon icon="gengduo" color="#cfcccc"></jx-icon>
</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,194 @@
.merchant-root {
box-sizing: border-box;
background-color: #4eb331;
position: sticky;
top: 0;
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 {
width: 140rpx;
height: 140rpx;
border-radius: 50%;
background-color: #fff;
border: 4rpx solid #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;
.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,177 @@
/**
* 用户信息类
*/
import { getStorage, setStorage } from "@/utils/storage";
import { onPullDownRefresh, onShow, onLoad } from "@dcloudio/uni-app";
import { computed, onBeforeUnmount, ref } from "vue";
import toast from "@/utils/toast";
import { timeFormatD } from "@/utils/tools";
import useGlobalFunc from "@/composables/useGlobalFunc";
import { listenOrder } from '@/utils/bluetoothPrinter/printerOrder'
import merchant from "@/api/https/merchant";
import { store } from "@/store";
function userInfo() {
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/542e220faa4a996467050ed23fecf67a.jpg",
storeName: "",
});
let oldStoreID: any = 0
onShow(async () => {
getStores()
await listenOrder()
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() // 商家中心有新信息了
await listenOrder() // 小程序监听新订单
}
/*************************************************
* 去修改营业时间
*/
function setTime() {
uni.navigateTo({ url: `/subPages/merchantChild/setBusinessTime/setBusinessTime` })
}
/**
* 退出登录
*/
let goLoginTime: any = null
function goLogin() {
uni.vibrateShort({})
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-取消退出');
},
complete: () => {
uni.vibrateShort({})
}
});
}
function downApp() {
uni.jxAlert({
title: '提示',
content: '下载链接复制成功,请到浏览器进行下载,或者到手机应用商店搜索【京西菜市】进行下载!',
success: () => {
uni.setClipboardData({
data: 'https://www.jxc4.com/managerApp/downApp.html'
})
}
})
}
/**
* 切换门店
*/
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, // 跳转到营业状态页面
downApp,
store
}
}
export default userInfo

View File

@@ -0,0 +1,97 @@
<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.timer1 != '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>
<!-- app下载通告栏 -->
<uni-notice-bar
:speed="50"
show-icon
scrollable
background-color="#fcefee"
color="#e70808"
moreColor="#e70808"
showGetMore
@click="downApp"
text="京西菜市商家版App全新上架系统更加稳定功能更加齐全订单通知更加及时请往手机自带应用商店搜索【京西菜市】进行安装使用"
/>
</view>
</template>
<script lang="ts" setup>
import userInfo from './userInfo'
import useGlobalFunc from '@/composables/useGlobalFunc'
const { previewImage } = useGlobalFunc()
const {
storeInfo, // 用户信息
businessHours, // 营业时间段
goLogin, // 退出登录
switchStore, // 切换门店
switchOpenTime, // 门店休息到哪天
setTime, // 去修改营业时间
jumpBusinessStatus, // 跳转到营业状态页面
downApp,
store
} = userInfo()
</script>
<style lang="scss" scoped>
@import './userInfo.scss';
</style>

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

@@ -0,0 +1,212 @@
import toast from '@/utils/toast'
import { onPullDownRefresh, onShow } from '@dcloudio/uni-app'
import { computed, ref } from 'vue'
import { store } from "@/store"
import { Decrypt, Encrypt, 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"
/*************************************************
* IM消息
*/
const messageFn = function () {
// vuex
const { getMtStoreIMStatus } = useGlobalFunc()
// 用户列表
const userListData = ref<Array<AnyObject>>([])
/*************************************************
* 获取用户列表
*/
onShow(() => {
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 // 模拟数据
// console.log('获取用户列表', res)
if (res.code == 0) {
if (JSON.stringify(res.data) === '{}') return
let platformID = venderIDInfo.appID // 美团账号
let newArr: any = []
// let fmtUserList = res.data[`${venderIDInfo.appID}:${venderIDInfo.MT}:1`] || [] // 美团
// let febUserList = ebStore && JSON.stringify(ebStore) !== '{}' ? res.data[`${ebStore.vendorOrgCode}:${ebStore.vendorStoreID}:3`] : [] // 饿百
let fmtUserList = venderIDInfo ? res.data[`${venderIDInfo.appID}:${venderIDInfo.vendorStoreID}:1`] || [] : [] // 美团
let febUserList = ebStore && JSON.stringify(ebStore) !== '{}' ? res.data[`${ebStore.appID}:${ebStore.vendorStoreID}:3`] || [] : [] // 饿百
let reverseList = fmtUserList && fmtUserList.length > 0 ? fmtUserList.reverse() : []
let reverseListEb = febUserList && febUserList.length > 0 ? febUserList.reverse() : []
reverseList.map((element: any) => {
let resData = JSON.parse(element)
// 判断是否需要显示列表
if (Decrypt(resData.latestMsg, platformID).indexOf('[自动回复]') == -1) {
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.indexOf('https') == -1) latestMsgHandler = msg
else latestMsgHandler = msg.indexOf('.amr') == -1 ? '【图片】' : '【语音】'
}
}
// if (resData.userID != 0) {
// 只展示6个小时以内的消息
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 && resData.userID != 0 && 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,78 @@
<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 > -->
<!-- 用户列表 -->
<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="暂无消息" />
<!-- </template> -->
<!-- 公共组件 -->
<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,76 @@
.position-relative {
position: relative;
}
.abnormal-order {
background-color: #fff;
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,80 @@
<template>
<view
class="abnormal-order position-relative"
@tap="orderDetail(item.vendorOrderID, item.vendorID)"
>
<order-list-top :item="item" />
<order-money :item="item" />
<!-- 地址 -->
<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 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,199 @@
%globalStyle {
border-bottom: 2rpx dashed #e7e7e7;
padding: 15rpx;
}
.position-relative {
position: relative;
}
.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: #000;
}
.success {
color: $jx-primary;
}
.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;
color: $jx-warring;
background-image: linear-gradient(90deg, #fffefd, #fceceb);
}
.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,285 @@
<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>
</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 useOrderInfo from '@/composables/useOrderInfo'
import toast from '@/utils/toast'
import { timeFormatHMS } from '@/utils/tools'
import { computed, ref } from 'vue'
import { store } from '@/store'
import order from '@/api/https/order'
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,120 @@
<template>
<view
class="compelet-root position-relative"
@tap="orderDetail(item.vendorOrderID, item.vendorID)"
>
<order-list-top :item="item" />
<order-money :item="item" />
<!-- 地址 -->
<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 { 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>
.position-relative {
position: relative;
}
.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;
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,500 @@
<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>
</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"></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"></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="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;
// .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,45 @@
.jx-tabs {
border-top: 1rpx solid #f8f8f8;
background-color: #fff;
border-bottom: 1rpx solid rgb(214, 214, 214);
}
.tab-scroll {
white-space: nowrap;
width: 100%;
height: 95rpx;
line-height: 94rpx;
}
.scroll-item {
position: relative;
display: inline-block;
width: 150rpx;
text-align: center;
text-align: center;
font-size: 33rpx;
transition: all 0.2s;
.badge {
position: absolute;
right: -5rpx;
top: 4rpx;
border-radius: 100rpx 100rpx 100rpx 0;
font-size: 28rpx;
min-width: 40rpx;
min-height: 40rpx;
padding: 3rpx;
box-sizing: border-box;
text-align: center;
line-height: 40rpx;
color: #fff;
background-color: #f60d58;
}
}
.jxTabsActive {
color: #4eb331;
font-weight: bold;
font-size: 37rpx;
}

View File

@@ -0,0 +1,161 @@
/**
* 订单木块方法
*/
import { Ref, ref } from "vue";
import { getStorage } from '@/utils/storage'
import { onShow } from "@dcloudio/uni-app";
import order from '@/api/https/order'
function tabFn() {
onShow(async () => {
await getOrderCount()
})
/**
* tab 菜单栏数据
*/
const currentStatus: Ref<number> = ref(2);
interface OrderStatusType {
id: number;
status: number | Array<number>;
name: string;
count: number;
}
const orderStatus = ref<OrderStatusType[]>([
{
id: 1,
status: [3],
name: "待接单",
count: 0,
},
{
id: 2,
status: [10],
name: "待拣货",
count: 0,
},
{
id: 3,
status: [15],
name: "待配送",
count: 0,
},
{
id: 4,
status: [20],
name: "配送中",
count: 0,
},
{
id: 5,
status: [5, 10, 15, 20, 17, 18, 22],
name: "异常单",
count: 0,
},
{
id: 6,
status: [155, 160, 165, 167, 180, 190],
name: "售后单",
count: 0,
},
{
id: 7,
status: [110, 115, 120],
name: "已完成",
count: 0,
},
]);
/**
* tab 点击事件
*/
const scrollLeft: Ref<number> = ref(0); // 滚动到左边距离
const record: Ref<number> = ref(1); // 记录值
function clickTab(id: number, recordID: number, e: AnyObject) {
currentStatus.value = id;
// 判断左右滑动
let { offsetLeft } = e.target;
if (id > recordID) {
scrollLeft.value = offsetLeft - 75;
} else {
scrollLeft.value = offsetLeft - 75 * 3;
}
record.value = id; // 赋值记录纸
// 更新条数
getOrderCount()
}
/**
* 请求订单数量信息
*/
async function getOrderCount() {
let orderData = {
storeID: getStorage('storeID'),
lastHours: new Date().getHours() * 1 + 48
}
// 订单数量
let orderCount = await order.Get_store_rder_count_info(orderData)
// 售后单量
let afsCount = await order.Get_store_afs_order_countinfo(orderData)
if (orderCount.code == 0 && afsCount.code == 0) {
// 没有数据默认一个空数组
let data = orderCount.data || []
let data2 = afsCount.data || []
// 判断显示条数
if (data.length > 0) {
// 3 待接单
orderStatus.value[0].count = data.filter((item: any) => item.status === 3 && item.lockStatus === 0).length > 0 ? data.filter((item: any) => item.status === 3 && item.lockStatus === 0)[0].count : 0
orderStatus.value[0].count += data.filter((item: any) => item.status === 3 && item.lockStatus === -20).length > 0 ? data.filter((item: any) => item.status === 3 && item.lockStatus === 0)[0].count : 0
// 10 带拣货
orderStatus.value[1].count = data.filter((item: any) => item.status === 10 && item.lockStatus === 0).length > 0 ? data.filter((item: any) => item.status === 10 && item.lockStatus === 0)[0].count : 0
orderStatus.value[1].count += data.filter((item: any) => item.status === 10 && item.lockStatus === -20).length > 0 ? data.filter((item: any) => item.status === 10 && item.lockStatus === 0)[0].count : 0
// 15 带配送
orderStatus.value[2].count = data.filter((item: any) => item.status === 15 && item.lockStatus === 0).length > 0 ? data.filter((item: any) => item.status === 15 && item.lockStatus === 0)[0].count : 0
orderStatus.value[2].count += data.filter((item: any) => item.status === 15 && item.lockStatus === -20).length > 0 ? data.filter((item: any) => item.status === 15 && item.lockStatus === -20)[0].count : 0
// 20 配送中
orderStatus.value[3].count = data.filter((item: any) => item.status === 20 && item.lockStatus === 0).length > 0 ? data.filter((item: any) => item.status === 20 && item.lockStatus === 0)[0].count : 0
orderStatus.value[3].count += data.filter((item: any) => item.status === 20 && item.lockStatus === -20).length > 0 ? data.filter((item: any) => item.status === 20 && item.lockStatus === -20)[0].count : 0
// 17 异常单
orderStatus.value[4].count = data.filter((item: any) => item.status === 17 && item.lockStatus === 0).length > 0 ? data.filter((item: any) => item.status === 17 && item.lockStatus === 0)[0].count : 0
// 18 已完成
orderStatus.value[4].count += data.filter((item: any) => item.status === 18 && item.lockStatus === 0).length > 0 ? data.filter((item: any) => item.status === 18 && item.lockStatus === 0)[0].count : 0
// 22 已完成
orderStatus.value[4].count += data.filter((item: any) => item.status === 22 && item.lockStatus === 0).length > 0 ? data.filter((item: any) => item.status === 22 && item.lockStatus === 0)[0].count : 0
orderStatus.value[4].count += data.filter((item: any) => item.lockStatus === -5 && item.status < 100).length > 0 ? data.filter((item: any) => item.lockStatus === -5 && item.status < 100)[0].count : 0
} else {
orderStatus.value[0].count = 0
orderStatus.value[1].count = 0
orderStatus.value[2].count = 0
orderStatus.value[3].count = 0
orderStatus.value[4].count = 0
}
// 售后单
if (data2.length > 0) {
orderStatus.value[5].count = data2.find((item: any) => item.status === 155) ? data2.find((item: any) => item.status === 155).count : 0
orderStatus.value[5].count += data2.find((item: any) => item.status === 165) ? data2.find((item: any) => item.status === 155).count : 0
} else {
orderStatus.value[5].count = 0
}
}
}
/**
* 导出数据
*/
return {
currentStatus, // 高亮初始值
orderStatus, // tab 菜单栏数据
scrollLeft, // 滚动到左边距离
record, // 记录值
clickTab, // tab 点击事件
getOrderCount, // 获取数据
}
}
export default tabFn

View File

@@ -0,0 +1,51 @@
<template>
<view class="jx-tabs">
<scroll-view
class="tab-scroll"
scroll-x="true"
scroll-with-animation
:scroll-left="scrollLeft"
>
<view
v-for="item in orderStatus"
:key="item.id"
class="scroll-item"
:class="{ jxTabsActive: currentStatus == item.id }"
@tap="tabEmit(item.id, item, record, $event)"
>{{ item.name }}
<text class="badge" v-if="item.count != 0">{{ item.count }}</text>
</view>
</scroll-view>
</view>
</template>
<script lang="ts" setup>
import tabFn from './jx-tab'
const {
currentStatus, // 高亮初始值
orderStatus, // tab 菜单栏数据
scrollLeft, // 滚动到左边距离
record, // 记录值
clickTab, // tab 点击事件
getOrderCount, // 获取数据
} = tabFn()
const emit = defineEmits<{
(e: 'jxTab', target: AnyObject): void
}>()
let recordNum: number = 2
function tabEmit(id: number, item: AnyObject, recordID: number, e: AnyObject) {
if (recordNum == id) return false
recordNum = id
emit('jxTab', item)
clickTab(id, recordID, e)
}
defineExpose({
getOrderCount,
})
</script>
<style lang="scss" scoped>
@import './jx-tab.scss';
</style>

View File

@@ -0,0 +1,56 @@
.switch-filter {
background-color: #fff;
.condition {
text-align: center;
color: #999999;
}
box-sizing: border-box;
border-radius: 10rpx;
padding: 20rpx 40rpx 10rpx 40rpx;
.item {
display: flex;
margin-top: 35rpx;
.root {
display: flex;
align-items: center;
text {
padding: 0 10rpx;
}
}
.title {
color: #999999;
}
.value {
padding: 5rpx 15rpx;
border: 1rpx solid #bebebe;
border-radius: 10rpx;
}
}
.btnRoot {
display: flex;
justify-content: space-between;
margin-top: 30rpx;
border-top: 1rpx solid #999999;
.cancel,
.confirm {
color: #696969;
text-align: center;
width: 100%;
padding: 20rpx;
}
.confirm {
color: #000;
border-left: 1rpx solid #999999;
}
}
}

View File

@@ -0,0 +1,275 @@
<template>
<uni-popup ref="popup" type="top">
<view class="switch-filter">
<view class="condition">查询条件</view>
<view class="item" v-if="orderState == 7">
<text class="title">时间类型</text>
<picker
class="value"
mode="selector"
:value="isDateFinishSearch"
:range="dateFinish"
range-key="name"
@change="pickerChange1"
>{{ dateFinish[isDateFinishSearch].name }}</picker
>
</view>
<view class="item">
<text class="title">查询时间</text>
<view class="root">
<picker
class="value"
mode="date"
:value="date1"
start="2010-01-01"
:end="endDate"
@change="dateChange1"
>{{ date1 }}</picker
>
<text></text>
<picker
class="value"
mode="date"
:value="date2"
start="2010-01-01"
:end="endDate"
@change="dateChange2"
>{{ date2 }}</picker
>
</view>
</view>
<view class="item">
<text class="title">外卖平台</text>
<picker
class="value"
mode="selector"
:value="vendor"
:range="vendorArr"
range-key="name"
@change="dateChange3"
>{{ vendorArr[vendor].name }}</picker
>
</view>
<view class="item" v-if="orderState == 7">
<text class="title">配送方式</text>
<picker
class="value"
mode="selector"
:value="waybillVendor"
:range="waybillVendorArr"
range-key="name"
@change="dateChange4"
>{{ waybillVendorArr[waybillVendor].name }}</picker
>
</view>
<view class="item" v-if="orderState == 6">
<text class="title">售后方式</text>
<picker
class="value"
mode="selector"
:value="appealTypes1"
:range="appealTypesArr"
range-key="name"
@change="dateChange5"
>{{ appealTypesArr[appealTypes1].name }}</picker
>
</view>
<view class="item" v-if="orderState == 6">
<text class="title">售后状态</text>
<picker
class="value"
mode="selector"
:value="afsStatus1"
:range="afsStatusArr"
range-key="name"
@change="dateChange6"
>{{ afsStatusArr[afsStatus1].name }}</picker
>
</view>
<view class="btnRoot">
<text class="cancel" @tap="popup.close()">取消</text>
<text class="confirm" @tap="confirm">确定</text>
</view>
</view>
</uni-popup>
</template>
<script lang="ts" setup>
import { timeFormatD } from '@/utils/tools'
import { ref,watch } from 'vue'
/**
* 筛选条件实例
*/
const popup = ref<any>(null)
interface propsType {
orderState: number,
orderStateInfo:AnyObject
}
const props = defineProps<propsType>()
/**
* 创建时间
*/
const isDateFinishSearch = ref<number>(0)
type dateFinishType = {
key: number
name: string
}
const dateFinish = ref<Array<dateFinishType>>([
{ key: 0, name: '创建时间' },
{ key: 1, name: '完成时间' },
])
function pickerChange1(e: AnyObject) {
isDateFinishSearch.value = +e.detail.value
}
/**
* 起始时间,结束时间
*/
const date1 = ref<string>(
timeFormatD(+new Date(new Date().getTime() - 1000 * 60 * 60 * 24 * 7))
// timeFormatD(+new Date(new Date().getTime() - 1000 * 60 * 60 * 24 * 2))
)
watch(
() => props.orderStateInfo,
(val) => {
if (val && val.id === 6 && val.count) {
afsStatus1.value = 1
date1.value = timeFormatD(+new Date(new Date().getTime() - 1000 * 60 * 60 * 24 * 2))
}else {
afsStatus1.value = 0
date1.value = timeFormatD(+new Date(new Date().getTime() - 1000 * 60 * 60 * 24 * 7))
}
}
)
const date2 = ref<string>(timeFormatD(+new Date()))
const endDate = ref<string>('')
function dateChange1(e: AnyObject) {
date1.value = e.detail.value
}
function dateChange2(e: AnyObject) {
date2.value = e.detail.value
}
/**
* 外卖平台
*/
const vendor = ref<number>(0)
type vendorArrType = {
id: number
name: string
}
const vendorArr = ref<Array<vendorArrType>>([
{ id: -1, name: '所有平台' },
{ id: 0, name: '京东到家' },
{ id: 1, name: '美团外卖' },
{ id: 3, name: '饿百新零售' },
{ id: 5, name: '京东商城' },
{ id: 9, name: '京西商城' },
])
function dateChange3(e: AnyObject) {
vendor.value = e.detail.value
}
/**
* 配送方式
*/
// const waybillVendor = ref<number>(0)
const waybillVendor = ref<number>(1)
const waybillVendorArr = ref<Array<vendorArrType>>([
{ id: -1, name: '所有配送' },
{ id: 0, name: '京东到家专送' },
{ id: 1, name: '美团专送' },
{ id: 3, name: '饿百专送' },
{ id: 101, name: '达达众包' },
{ id: 102, name: '美团配送' },
{ id: 103, name: '蜂鸟配送' },
{ id: 105, name: 'UU跑腿' },
{ id: 106, name: '顺丰同城' },
])
function dateChange4(e: AnyObject) {
waybillVendor.value = e.detail.value
}
/**
* 售后方式
*/
const appealTypes1 = ref<number>(0)
const appealTypesArr = ref<Array<vendorArrType>>([
{ id: -1, name: '全部方式' },
{ id: 1, name: '仅退款' },
{ id: 2, name: '退货退款' },
{ id: 3, name: '重发商品' },
])
function dateChange5(e: AnyObject) {
appealTypes1.value = e.detail.value
}
/**
* 售后状态
*/
const afsStatus1 = ref<number>(0)
const afsStatusArr = ref<Array<vendorArrType>>([
{ id: -1, name: '全部状态' },
{ id: 155, name: '待审核' },
{ id: 160, name: '已审核' },
{ id: 165, name: '退货待确认' },
{ id: 167, name: '退货已收到' },
{ id: 180, name: '售后成功' },
{ id: 190, name: '售后失败' },
])
function dateChange6(e: AnyObject) {
afsStatus1.value = e.detail.value
}
/**
* 确定筛选条件
*/
type emitType = {
fromTime: string
toTime: string
vendorID: number | string
waybillVendorID?: number | string
isDateFinish?: boolean
appealTypes?: number | string
afsStatus?: number | string
}
const emit = defineEmits<{
(e: 'filterData', data: emitType): void
}>()
function confirm() {
let data = {
fromTime: date1.value,
toTime: date2.value,
vendorID: vendorArr.value[vendor.value].id,
waybillVendorID: waybillVendorArr.value[waybillVendor.value].id,
isDateFinish: Boolean(isDateFinishSearch.value),
appealTypes: appealTypesArr.value[appealTypes1.value].id,
afsStatus: afsStatusArr.value[afsStatus1.value].id,
}
emit('filterData', data)
popup.value.close()
}
/**
* 打开弹窗
*/
function openRef() {
popup.value.open()
}
/**
* 导出外部访问函数
*/
defineExpose({
openRef,
})
</script>
<style lang="scss" scoped>
@import './order-filter.scss';
</style>

View File

@@ -0,0 +1,325 @@
<template>
<view
class="distribution-root position-relative"
@tap="orderDetail(item.vendorOrderID, item.vendorID)"
>
<order-list-top :item="item" />
<order-money :item="item" />
<view class="address">地址{{ item.consigneeAddress }}</view>
<view class="distribution-msg" v-if="item.courierName">
<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
icon="24gf-telephone"
color="#999999"
@tap.stop="phoneCall(item.courierMobile)"
:size="38"
style="margin-left: 10rpx"
/>
</view>
<!-- 自提订单 -->
<view class="self-order self" v-if="item.deliveryType === 'self'"
>[自提订单]</view
>
<!-- 操作按钮 -->
<view class="operation">
<view class="printerBtn" @tap.stop="deliverManager(item.vendorOrderID)"
>配送管理</view
>
<view class="pickingBtn">查看详情</view>
</view>
<!-- 确定自提 -->
<template v-if="isSelfBtn">
<view
class="btn-picked"
v-if="item.vendorID != 9"
@tap.stop="inputTakeCode"
>输入自提码</view
>
<view class="btn-picked" v-else @tap.stop="jxSelfTake('jx')"
>完成自提</view
>
</template>
<!-- 商家自送送达按钮 status 20 -->
<template v-if="isConfrim">
<div class="btn-picked" @tap.stop="handleSelfDelivered">
确认送达
<text v-if="(item.flag & 128) === 128">[已操作]</text>
</div>
</template>
</view>
<!-- 自提码弹窗 -->
<uni-popup ref="popup" type="top">
<view class="takeCode-root">
<view class="title">自提订单</view>
<input
class="ipt"
type="text"
placeholder="请输入自提码"
v-model="takeCode"
/>
<view class="btn-root">
<view class="cancel" @tap.stop="popup.close()">取消</view>
<view class="confirm" @tap.stop="jxSelfTake('noJx')">确定</view>
</view>
</view>
</uni-popup>
</template>
<script lang="ts" setup>
import useOrderInfo from '@/composables/useOrderInfo'
import toast from '@/utils/toast'
import { computed, ref } from 'vue'
import orderListTop from '../component/orderListTop.vue'
import orderMoney from '../component/orderMoney.vue'
import { store } from '@/store'
import order from '@/api/https/order'
const {
orderDetail, // 订单详情
deliverManager, // 配送管理
phoneCall, // 拨打电话
waybillVendor, // 厂商转换
} = useOrderInfo()
interface PropsType {
item: any
type: number
}
const props = defineProps<PropsType>()
/**
* 转换快递厂商
*/
const wbVendor = computed(() => {
return waybillVendor(
props.item.waybillVendorID,
props.item.status,
props.item.waybillStatus
)
})
/**
* 计算属性展示确认送达按钮
*/
const isConfrim = computed(() => {
return (
(props.item.deliveryFlag & 3) === 3 &&
props.item.lockStatus === 0 &&
props.item.deliveryType !== 'self' &&
!props.item.vendorWaybillID
)
})
/**
* 计算属性计算出是否显示自提订单按钮
*/
const isSelfBtn = computed(() => {
return (
props.item.status === 15 &&
props.item.waybillVendorID === -1 &&
props.item.lockStatus === 0 &&
props.item.deliveryType === 'self'
)
})
/**
* 除开京西自提订单
*/
const popup = ref<any>(null)
function inputTakeCode() {
takeCode.value = ''
popup.value.open()
}
/**
* 自提订单 默认京西自提订单
*/
const takeCode = ref<any>() // 自提码
function jxSelfTake(type: string) {
if (type != 'jx' && takeCode.value == '') return toast('请输入自提码')
uni.jxConfirm({
title: '自提订单',
content: '是否完成自提(请确保用户已出示正确订单,以免引起不必要的损失)',
success: async () => {
let data = {
vendorOrderID: props.item.vendorOrderID,
vendorID: props.item.vendorID,
selfTakeCode: type === 'jx' ? '135246' : takeCode.value,
}
let res = await order.confirm_self_take(data)
if (res.code == 0) {
toast('自提成功', 1)
popup.value.close()
// 刷新订单
store.commit('serveInfo/setUpdateOrder', Date.now())
} else {
toast('自提发生异常', 2)
}
},
})
}
/**
* 确认送达
*/
function handleSelfDelivered() {
// if ((props.item.flag & 128) === 128) return false
uni.jxConfirm({
title: '提示',
content: '是否确认送达商品',
success: async () => {
let data = {
vendorOrderID: props.item.vendorOrderID,
vendorID: props.item.vendorID,
}
let res = await order.self_delivered(data)
if (res.code == 0) {
toast('送达成功', 1)
// 刷新订单
store.commit('serveInfo/setUpdateOrder', Date.now())
} else {
toast('送达异常'+ res.desc, 2)
}
},
})
}
</script>
<style lang="scss" scoped>
:deep(.order-totalCount) {
border: none !important;
}
.position-relative {
position: relative;
}
.distribution-root {
position: relative;
background-color: #fff;
padding-bottom: 20rpx;
}
.self {
padding: 15rpx;
border-bottom: 2rpx dashed #e7e7e7;
}
.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;
}
// 操作按钮
.operation {
display: flex;
justify-content: space-between;
box-sizing: border-box;
padding: 15rpx 20rpx 0 20rpx;
.printerBtn,
.pickingBtn {
width: 100%;
padding: 20rpx;
text-align: center;
border-radius: 10rpx;
color: #fff;
}
.printerBtn {
margin-right: 15rpx;
background-image: linear-gradient(135deg, #ec903f, #ff6a20);
}
.pickingBtn {
margin-left: 15rpx;
background-image: linear-gradient(135deg, $jx-primary, #85c972);
}
}
// 自提
.takeCode-root {
box-sizing: border-box;
background-color: rgb(255, 255, 255);
border-radius: 0 0 15rpx 15rpx;
padding: 25rpx;
.title {
width: 100%;
text-align: center;
}
.ipt {
width: 100%;
height: 80rpx;
border: 1rpx solid #cecece;
border-radius: 10rpx;
margin: 20rpx 0;
text-align: center;
}
.btn-root {
display: flex;
justify-content: space-between;
.cancel,
.confirm {
width: 100%;
padding: 15rpx 0;
text-align: center;
border-radius: 10rpx;
}
.cancel {
color: $jx-primary;
border: 1rpx solid $jx-primary;
margin-right: 15rpx;
}
.confirm {
background-color: $jx-primary;
margin-left: 15rpx;
color: #fff;
}
}
}
.distribution-msg {
padding: 15rpx;
border-bottom: 2rpx dashed #e7e7e7;
.distribution-name {
margin-right: 25rpx;
}
.distribution-mobile {
color: #999;
}
}
.vender-name {
color: #999999;
margin-right: 25rpx;
}
</style>

View File

@@ -0,0 +1,107 @@
<template>
<view
class="pending-order-root position-relative"
@tap="orderDetail(item.vendorOrderID, item.vendorID)"
>
<order-list-top :item="item" />
<!-- 商品统计 -->
<orderMoney :item="item" />
<!-- 操作按钮 -->
<view class="operation-btn">
<view
class="refuse"
@tap.stop="
AcceptOrRefuseOrder(item.vendorOrderID, item.vendorID, false)
"
>拒绝接单</view
>
<view
class="need"
@tap.stop="AcceptOrRefuseOrder(item.vendorOrderID, item.vendorID, true)"
>立即接单</view
>
</view>
</view>
</template>
<script lang="ts" setup>
import useOrderInfo from '@/composables/useOrderInfo'
import orderListTop from '../component/orderListTop.vue'
import orderMoney from '../component/orderMoney.vue'
import toast from '@/utils/toast'
import { store } from '@/store'
import order from '@/api/https/order'
const {
orderDetail, // 订单详情
} = useOrderInfo()
interface PropsType {
item: any
}
defineProps<PropsType>()
/**
* 确定接单
*/
async function AcceptOrRefuseOrder(
vendorOrderID: string,
vendorID: string,
isAccept: boolean
) {
let data = {
vendorOrderID,
vendorID,
isAccept,
}
let res = await order.accept_or_refuse_order(data)
if (res.code == 0) {
if (isAccept) {
toast('接单成功', 1)
} else {
toast('拒绝订单成功', 1)
}
// 刷新订单
store.commit('serveInfo/setUpdateOrder', Date.now())
} else {
toast('订单数据异常')
}
}
</script>
<style lang="scss" scoped>
.position-relative {
position: relative;
}
.pending-order-root {
box-sizing: border-box;
background-color: #fff;
// 操作按钮
.operation-btn {
display: flex;
align-items: center;
padding: 20rpx;
justify-content: space-evenly;
border-bottom: 2rpx dashed #e7e7e7;
.refuse,
.need {
padding: 8rpx 35rpx;
border-radius: 7rpx;
color: #fff;
font-size: 28rpx;
}
.refuse {
background-color: #f60d58;
}
.need {
background-color: $jx-primary;
}
}
}
</style>

View File

@@ -0,0 +1,119 @@
<template>
<view
class="pending-picking-root position-relative"
@tap="orderDetail(item.vendorOrderID, item.vendorID)"
>
<order-list-top :item="item" />
<view class="remarks"
>备注{{ item.buyerComment || '该订单用户未进行备注' }}</view
>
<order-money :item="item" />
<!-- 操作按钮 -->
<view class="operation" v-if="item.status === 10 && item.lockStatus === 0">
<view
class="printerBtn"
@tap.stop="printerOrder(item.vendorOrderID, item.vendorID)"
>打印订单</view
>
<view
class="pickingBtn"
@tap.stop="pickingComplete(item.vendorOrderID, item.vendorID)"
>拣货完成</view
>
</view>
<view class="self-order" v-if="item.deliveryType === 'self'"
>[自提订单]</view
>
</view>
</template>
<script lang="ts" setup>
import orderListTop from '../component/orderListTop.vue'
import orderMoney from '../component/orderMoney.vue'
import useOrderInfo from '@/composables/useOrderInfo'
import toast from '@/utils/toast'
import { store } from '@/store'
import order from '@/api/https/order'
const {
orderDetail, // 订单详情
printerOrder, // 打印订单
} = useOrderInfo()
interface PropsType {
item: any
}
defineProps<PropsType>()
/**
* 拣货完成
*/
async function pickingComplete(vendorOrderID: string, vendorID: string) {
let data = {
vendorOrderID,
vendorID,
}
let res = await order.finished_pickup(data)
if (res.code == 0) {
toast('拣货成功', 1)
// 刷新订单
store.commit('serveInfo/setUpdateOrder', Date.now())
} else {
toast('拣货异常', 2)
}
}
</script>
<style lang="scss" scoped>
:deep(.order-number) {
border: none !important;
}
.position-relative {
position: relative;
}
.pending-picking-root {
background-color: #fff;
.remarks {
padding: 15rpx;
color: #999999;
background-color: rgba($color: #908f96, $alpha: 0.15);
border-radius: 10rpx;
}
.divider {
width: 100%;
height: 7rpx;
background: white url('../../../../static/image/global/order-divider.png') 0
0 no-repeat;
background-size: 100%;
}
// 操作按钮
.operation {
display: flex;
justify-content: space-between;
box-sizing: border-box;
padding: 15rpx 20rpx;
.printerBtn,
.pickingBtn {
width: 100%;
padding: 20rpx;
text-align: center;
border-radius: 10rpx;
color: #fff;
}
.printerBtn {
margin-right: 15rpx;
background-image: linear-gradient(135deg, #85c972, $jx-primary);
}
.pickingBtn {
margin-left: 15rpx;
background-image: linear-gradient(135deg, #ff6a20, #ec903f);
}
}
}
</style>

View File

@@ -0,0 +1,413 @@
import useGlobalFunc from '@/composables/useGlobalFunc'
import { store } from '@/store'
import { getStorage } from '@/utils/storage'
import toast from '@/utils/toast'
import { timeFormatD, jx_trembling } from '@/utils/tools'
import { onLoad, onShow } from '@dcloudio/uni-app'
import { watch, ref, onBeforeUnmount } from 'vue'
import order from '@/api/https/order'
// import merchant from '@/api/https/merchant'
/**
* 订单管理方法
* @author zhangshuwie <2966211270@qq.com>
* @param *
* @return 模板使用数据与方法详情内容请查看return
*/
function orderInfoFn() {
const { isTrades } = useGlobalFunc()
/**
* 公共复位函数
*/
function reset() {
orderDataList.value = []
page.value = 1
totalCount.value = 0
}
/*************************************************
* 获取门店信息
*/
async function getStores() {
await store.dispatch('storeInfo/getOneStore',getStorage("storeID"))
}
/**
* tab单击事件
* @param target 点击对应tab获取到的信息
*/
const status = ref<Array<number>>([10]) // 默认显示待拣货
const orderState = ref<number>(2) // 默认显示待拣货
const orderStateInfo = ref()
async function jxTabClick(target: AnyObject) {
orderStateInfo.value = target
await reset()
uni.removeTabBarBadge({ index: 0 })
keyword.value = ''
// 列表展示判断条件
orderState.value = target.id
// 请求数据订单状态
status.value = target.status
// 请求数据
if (target.id == 6) {
// 获取售后单
if (orderStateInfo.value.count) {
allData.value.fromTime = timeFormatD(+new Date(new Date().getTime() - 1000 * 60 * 60 * 24 * 2))
allData.value.afsStatus = '155'
}
await getAfsOrders()
} else {
await getOrderAllInfo()
}
}
/**
* 下拉刷新
*/
let refresherrefreshTimer: any = null
const triggered = ref<boolean>(false)
function refresherrefresh() {
uni.removeTabBarBadge({ index: 0 })
triggered.value = true
clearTimeout(refresherrefreshTimer)
refresherrefreshTimer = setTimeout(async () => {
store.commit('storeInfo/jxLoadingFn', true)
await reset()
await refreshTab()
if (orderState.value == 5) {
totalCount.value = 0
}
if (orderState.value == 6) {
await getAfsOrders()
} else {
await getOrderAllInfo()
}
triggered.value = false
store.commit('storeInfo/jxLoadingFn', false)
}, 500)
}
/**
* 页面触底
*/
const isLoad = ref<boolean>(false)
async function scrolltolower() {
uni.removeTabBarBadge({ index: 0 })
page.value++
if (pageSize.value * (page.value - 1) > totalCount.value || totalCount.value < pageSize.value) {
isLoad.value = false
} else {
if (isLoad.value) return
if (orderState.value == 7) {
await getOrderAllInfo()
} else {
await getAfsOrders()
}
}
}
/**
* 获取订单详情数据
*/
type emitType = {
fromTime: string
toTime: string
vendorID: number | string
waybillVendorID?: number | string
isDateFinish?: boolean
appealTypes?: number | string
afsStatus?: number | string
}
let oldStoreID: any = 0
/*************************************************
* 门店休息情况
*/
const isRest = ref<boolean>(true)
const isStatu = ref<boolean>(false)
onShow(async () => {
if (!store.state.storeInfo.allStoreInfo.id) {
console.log('ZSW-没有门店信息开始获取门店信息');
await getStores()
}
if (oldStoreID != getStorage('storeID') && oldStoreID != 0) {
await reset()
triggered.value = true
}
oldStoreID = getStorage('storeID')
isRest.value = isTrades(new Date()) // 门店是否接受预订单
let storeInfo = store.state.storeInfo.allStoreInfo
isStatu.value = storeInfo.status == 1 ? true : false
uni.removeTabBarBadge({ index: 0 })
})
onLoad(async () => {
store.commit('storeInfo/jxLoadingFn', true)
// 请求数据
await reset()
await getOrderAllInfo()
store.commit('storeInfo/jxLoadingFn', false)
})
const pageSize = ref<number>(33) // 每一页条数
const page = ref<number>(1) // 第多少条
const orderDataList = ref<any>([]) // 订单数据
const totalCount = ref<number>(0) // 订单条数
const allData = ref<emitType>({
fromTime: timeFormatD(+new Date(new Date().getTime() - 1000 * 60 * 60 * 24 * 7)),
toTime: timeFormatD(+new Date()),
vendorID: '',
waybillVendorID: '',
isDateFinish: false,
appealTypes: '',
afsStatus: ''
}) // 已完成数据筛选
async function getOrderAllInfo() {
isLoad.value = true
let time1 = timeFormatD(+new Date(new Date().getTime() - 1000 * 60 * 60 * 24 * 7))
let time2 = timeFormatD(+new Date())
// 待接单、待检货、待配送、配送中、异常单、已完成
let data: any = {
fromDate: time1,
toDate: time2,
storeIDs: JSON.stringify([getStorage('storeID')]),
statuss: JSON.stringify(status.value),
offset: pageSize.value * (page.value - 1),
pageSize: pageSize.value,
isJxFirst: true
}
if (orderState.value == 7) {
data = {
fromDate: allData.value.fromTime ? allData.value.fromTime : time1,
toDate: allData.value.toTime ? allData.value.toTime : time2,
storeIDs: JSON.stringify([getStorage('storeID')]),
statuss: JSON.stringify(status.value),
offset: pageSize.value * (page.value - 1),
pageSize: pageSize.value,
isDateFinish: allData.value.isDateFinish,
vendorIDs: `[${allData.value.vendorID}]`,
waybillVendorIDs: `[${allData.value.waybillVendorID}]`,
isJxFirst: true,
keyword: keyword.value
}
}
let res = await order.get_orders(keyFilter(data))
if (res.code == 0) {
if (page.value <= 1) {
reset()
}
let data: Array<any> = res.data.data || []
if (data.length == 0) toast('暂无该类型订单')
orderDataList.value = orderDataList.value.concat(data)
totalCount.value = res.data.totalCount
} else {
await reset()
totalCount.value = 0
}
isLoad.value = false
}
/*************************************************
* 过滤对象空字段
*/
function keyFilter(obj: AnyObject) {
for (let key in obj) {
// if ((obj[key] == "" || obj[key] == [""] || obj[key] == '[-1]')) {
if ((obj[key] == "" || obj[key] == '[-1]')) {
delete obj[key]
}
}
return obj
}
/*************************************************
* 获取异常单
*/
async function getAfsOrders() {
isLoad.value = true
// 待接单、待捡货、待配送、配送中、异常单、已完成
let data = {
storeIDs: JSON.stringify([getStorage('storeID')]),
fromTime: `${allData.value.fromTime} 00:00:00`,
toTime: `${allData.value.toTime} 23:59:59`,
pageSize: pageSize.value,
offset: pageSize.value * (page.value - 1),
vendorIDs: `[${allData.value.vendorID}]`,
appealTypes: `[${allData.value.appealTypes}]`,
statuss: `[${allData.value.afsStatus}]`,
isDetail: true,
keyword: keyword.value
}
let res = await order.get_afs_orders(keyFilter(data))
if (res.code == 0) {
if (page.value <= 1) {
reset()
}
let data: Array<any> = res.data.data || []
if (data.length == 0) toast("暂无售后订单")
orderDataList.value = orderDataList.value.concat(res.data.data)
totalCount.value = res.data.totalCount
} else {
await reset()
totalCount.value = 0
}
isLoad.value = false
}
/**
* 刷新导航栏
*/
const tabInfo = ref<any>(null)
function refreshTab() {
tabInfo.value.getOrderCount()
}
/**
* 输入确认按钮
*/
const keyword = ref<string>('')
async function searchStore(keywords: string) {
keyword.value = keywords
await reset()
if (orderState.value == 7) {
await getOrderAllInfo()
} else {
await getAfsOrders()
}
}
/**
* 输入框输入值变化
*/
let trembling = jx_trembling(getOrderAllInfo, 800)
let trembling2 = jx_trembling(getAfsOrders, 800)
async function changeIpt(keywords: string) {
keyword.value = keywords
await reset()
if (orderState.value == 7) {
await trembling()
} else {
await trembling2()
}
}
/**
* 清空输入框
*/
async function clearIpt() {
keyword.value = ''
await reset()
if (orderState.value == 7) {
await getOrderAllInfo()
} else {
await getAfsOrders()
}
}
/**
* 已完成和售后单筛选
*/
const active = ref<number>(0)
async function filterData(data: emitType) {
let ruler = (+new Date() - +new Date(data.fromTime)) / 1000 / 60 / 60 / 24
if (orderState.value != 7 && ruler > 59) {
return toast('售后查询不能超过60天')
}
if (orderState.value == 7 && ruler > 180) {
return toast('最大查询天数为180天')
}
allData.value = data
await reset()
if (orderState.value == 7) {
await getOrderAllInfo()
} else {
await getAfsOrders()
}
}
/**
* 筛选条件实例对象
*/
const orderFilterRef = ref<any>(null)
/**
* 监听新订单刷新页面
*/
watch(() => store.state.serveInfo.updateOrder, async () => {
await reset()
await refreshTab()
if (orderState.value == 6) {
await getAfsOrders()
} else {
await trembling()
}
})
/**
* 动态计算scorll-view 高度
*/
const scorllHeight = ref<string>('94rpx')
watch(() => orderState.value, (nweVal) => {
let arr: Array<number> = [1, 2, 4, 5]
if (arr.includes(nweVal)) {
scorllHeight.value = '100rpx'
} else {
scorllHeight.value = '190rpx'
}
})
/*************************************************
* 配送状态筛选
*/
function distributionStatu(type: number) {
active.value = type
}
/*************************************************
* 收尾工作
*/
onBeforeUnmount(() => {
clearTimeout(refresherrefreshTimer)
})
return {
jxTabClick, // 导航栏按钮
orderDataList, // 订单数据
totalCount, // 订单条数
orderState, // 订单列表判断条件
orderStateInfo, // 订单列表信息
tabInfo, // 导航栏实例
searchStore, // 输入库条件筛选
keyword, // 输入库内容
changeIpt, // 输入款输入变化
clearIpt, // 清空输入框
scorllHeight, // 动态计算scorll-view高度
active, // 待配送筛选高亮
orderFilterRef, // 筛选条件实例对象
filterData, // 筛选条件数据
refresherrefresh, // 下拉刷新
triggered, // 下拉加载
scrolltolower, // 页面触底
isLoad, // 触底加载
distributionStatu, // 配送筛选
isRest, // 是否显示休息状态
isStatu, // 门店是否在营业
}
}
export default orderInfoFn

View File

@@ -0,0 +1,439 @@
<template>
<!-- 联系运营 -->
<image
class="icon-phone"
src="https://image.jxc4.com/image/dd78fd0b128be86e681f376e794f8309.png"
mode="scaleToFill"
@tap="getPhone"
@touchmove.stop.prevent="touchM($event, 1)"
@touchstart="touchS()"
@touchend="touchE($event, 1)"
/>
<!-- 当前门店是否休息 -->
<view
v-if="!isStatu"
class="open-status-msg"
@touchmove.prevent="touchM($event, 2)"
@touchstart.prevent="touchS()"
@touchend.prevent="touchE($event, 2)"
><text>本店</text><text>已休息</text></view
>
<view
v-else-if="!isRest"
class="open-status-msg open-to-booking"
@touchmove.prevent="touchM($event, 2)"
@touchstart.prevent="touchS()"
@touchend.prevent="touchE($event, 2)"
><text>接受</text><text>预订单</text></view
>
<!-- tab -->
<view class="jx-tabs-root">
<jx-tab ref="tabInfo" @jxTab="jxTabClick"></jx-tab>
<!-- 售后单已完成 -->
<template v-if="orderState == 6 || orderState == 7">
<view class="filter-root">
<text class="btn" @tap="orderFilterRef.openRef()">更多条件</text>
<uni-search-bar
v-model="keyword"
@confirm="searchStore(keyword)"
@clear="clearIpt"
cancelButton="none"
clearButton="auto"
@input="changeIpt(keyword)"
:placeholder="
orderState == 6 ? '搜索售后单号、订单号、电话' : '搜索订单、电话等'
"
/>
</view>
</template>
<!-- 待配送筛选 -->
<template v-if="orderState == 3">
<view class="filter-order">
<view :class="{ active: active == 0 }" @tap="distributionStatu(0)"
>&emsp;</view
>
<view :class="{ active: active == 1 }" @tap="distributionStatu(1)"
>未抢单</view
>
<view :class="{ active: active == 2 }" @tap="distributionStatu(2)"
>已抢单</view
>
</view>
</template>
</view>
<!-- 列表内容 -->
<scroll-view
class="order-item-main"
scroll-y
:style="{ height: `calc(100vh - ${scorllHeight})` }"
refresher-enabled
:refresher-triggered="triggered"
@refresherrefresh="refresherrefresh"
refresher-background="#efefef"
@scrolltolower="scrolltolower"
>
<!-- 待接单 -->
<template v-if="orderState == 1 && totalCount != 0">
<pending-order
v-for="item in orderDataList"
:key="item.id"
:item="item"
/>
</template>
<!-- 待拣货 -->
<template v-if="orderState == 2 && totalCount != 0">
<pending-picking
v-for="item in orderDataList"
:key="item.id"
:item="item"
/>
</template>
<!-- 待配送 -->
<template v-if="orderState == 3 && totalCount != 0">
<view v-for="item in orderDataList" :key="item.id">
<pending-distribution
v-if="
active === 0 ||
(active === 1 && item.waybillStatus < 10) ||
(active === 2 && item.waybillStatus >= 10 && item.lockStatus !== -5)
"
:item="item"
:type="1"
/>
</view>
<jx-load-more
v-show="totalCount >= 2 && active === 0"
:isLoad="isLoad"
marginTop="25rpx"
/>
</template>
<!-- 配送中 -->
<template v-if="orderState == 4 && totalCount != 0">
<pending-distribution
v-for="item in orderDataList"
:key="item.id"
:item="item"
:type="0"
/>
</template>
<!-- 异常单 -->
<template v-if="orderState == 5 && totalCount != 0">
<view v-for="item in orderDataList" :key="item.id">
<abnormal-order
v-if="
item.lockStatus === -5 ||
((item.status === 17 || item.status === 18) &&
item.lockStatus !== -5) ||
(item.status === 22 && item.lockStatus !== -5)
"
:item="item"
/>
<jx-empty title="暂无异常订单" v-else />
</view>
</template>
<!-- 售后单 -->
<template v-if="orderState == 6 && totalCount != 0">
<after-sales-order
v-for="item in orderDataList"
:key="item.id"
:item="item"
></after-sales-order>
</template>
<!-- 已完成 -->
<template v-if="orderState == 7 && totalCount != 0">
<completed
v-for="item in orderDataList"
:key="item.id"
:item="item"
></completed>
</template>
<!-- 加载更多 -->
<jx-load-more
v-show="totalCount >= 2 && orderState != 3 && orderState != 5"
:isLoad="isLoad"
marginTop="25rpx"
/>
<!-- 空状态 -->
<jx-empty title="暂无订单信息" v-show="totalCount == 0" />
</scroll-view>
<!-- 切换筛选条件 -->
<order-filter
@filter-data="filterData"
ref="orderFilterRef"
:orderState="orderState"
:orderStateInfo="orderStateInfo"
/>
<!-- 公共组件 -->
<jx-login-empty title="马上登录,查看订单" />
<jx-loading />
</template>
<script lang="ts" setup>
import jxTab from './childPages/jx-tab/jx-tab.vue' // 待拣货
import pendingOrder from './childPages/pending-order/pending-order.vue' // 待拣货
import pendingPicking from './childPages/pending-picking/pending-picking.vue' // 待配送
import pendingDistribution from './childPages/pending-distribution/pending-distribution.vue' // 配送中
import afterSalesOrder from './childPages/after-sales-order/after-sales-order.vue' // 售后单
import completed from './childPages/completed/completed.vue'
import orderFilter from './childPages/order-filter/order-filter.vue'
import abnormalOrder from './childPages/abnormal-order/abnormal-order.vue'
import orderInfoFn from './main'
import { ref } from 'vue'
import { jx_throttles } from '@/utils/tools'
const {
jxTabClick, // 导航栏单击事件
orderDataList, // 订单数据
totalCount, // 订单条数
orderState, // 订单列表判断条件
orderStateInfo, // 订单列表信息
tabInfo, // 导航栏实例
searchStore, // 输入库条件筛选
keyword, // 输入库内容
changeIpt, // 输入款输入变化
clearIpt, // 清空输入框
scorllHeight, // 动态计算scorll-view高度
active, // 待配送筛选高亮
orderFilterRef, // 筛选条件实例对象
filterData, // 筛选条件数据
refresherrefresh, // 下拉刷新
triggered, // 刷新状态
scrolltolower, // 页面触底
isLoad, // 触底加载
distributionStatu, // 配送筛选
isRest, // 是否显示休息状态
isStatu, // 门店营业状态
} = orderInfoFn()
/**
* 联系运营页面跳转
*/
function getPhone() {
uni.navigateTo({ url: '/subPages/orderChild/getPhone/getPhone' })
}
/*************************************************
* 开始触摸运营
*/
const isAnmarion = ref<string>('0s')
let windowW = 0
let windowH = 0
function touchS() {
isAnmarion.value = '0s'
windowW = 0
windowH = 0
let sysTem = uni.getSystemInfoSync()
windowW = sysTem.windowWidth
windowH = sysTem.windowHeight
}
/*************************************************
* 移动联系运营
*/
const pageX1 = ref<string>('20rpx')
const pageY1 = ref<string>('450rpx')
const pageX2 = ref<string>('20rpx')
const pageY2 = ref<string>('300rpx')
function touchM(e: AnyObject, type: number) {
touchMThrottles(e, type)
}
const touchMThrottles = jx_throttles({
time: 5,
success(e: AnyObject, type: number) {
let sysTem = e.changedTouches[0]
if (type == 1) {
pageX1.value = sysTem.clientX - 25 + 'px'
pageY1.value = sysTem.clientY - 25 + 'px'
}
if (type == 2) {
pageX2.value = sysTem.clientX - 25 + 'px'
pageY2.value = sysTem.clientY - 25 + 'px'
}
},
})
/*************************************************
* 触摸运营结束
*/
function touchE(e: AnyObject, type: number) {
isAnmarion.value = '0.5s'
let sysTem = e.target
if (type == 1) {
if (sysTem.offsetLeft <= 0 || sysTem.offsetLeft <= windowW / 2 - 25) {
pageX1.value = '10px'
}
if (sysTem.offsetLeft >= windowW || sysTem.offsetLeft >= windowW / 2 - 25) {
pageX1.value = windowW - 60 + 'px'
}
if (sysTem.offsetTop <= 50) {
pageY1.value = '50px'
}
if (sysTem.offsetTop >= windowH - 100) {
pageY1.value = windowH - 60 + 'px'
}
}
if (type == 2) {
let pageX = parseInt(pageX2.value)
let pageY = parseInt(pageY2.value)
if (pageX <= 0 || pageX <= windowW / 2 - 25) {
pageX2.value = '10px'
}
if (pageX >= windowW || pageX >= windowW / 2 - 25) {
pageX2.value = windowW - 60 + 'px'
}
if (pageY <= 50) {
pageY2.value = '50px'
}
if (pageY >= windowH - 100) {
pageY2.value = windowH - 60 + 'px'
}
}
}
</script>
<style lang="scss" scoped>
.open-status-msg {
position: absolute;
z-index: 99999999999;
left: v-bind(pageX2);
top: v-bind(pageY2);
width: 50px;
height: 50px;
font-size: 10px;
padding: 10px;
text-align: center;
box-sizing: border-box;
border-radius: 50%;
color: #fff;
font-weight: bold;
background: rgba(116, 116, 116, 0.75);
text-shadow: 1rpx 1rpx 2rpx #eb6100;
transition: all v-bind(isAnmarion);
text {
display: inline-block;
}
}
.open-to-booking {
text-shadow: 2rpx 2rpx 2rpx $jx-warring;
}
.icon-phone {
position: absolute;
z-index: 99999999999;
left: v-bind(pageX1);
top: v-bind(pageY1);
width: 50px;
height: 50px;
transition: all v-bind(isAnmarion);
}
.filter-root {
box-sizing: border-box;
height: 90rpx;
padding: 15rpx;
background-color: #fff;
display: flex;
align-items: center;
.btn {
padding: 8rpx 0;
width: 160rpx;
text-align: center;
background-color: $jx-primary;
color: #fff;
font-size: 28rpx;
border-radius: 100rpx;
margin-right: 15rpx;
}
:deep(.uni-searchbar) {
padding: 0 !important;
width: 545rpx !important;
.uni-searchbar__box {
border-radius: 100rpx !important;
height: auto !important;
}
}
}
</style>
<style lang="scss">
page {
position: relative;
background-color: #efefef;
width: 100%;
height: 100%;
}
.self-order {
width: 100%;
text-align: center;
color: #ff0000;
font-weight: bold;
padding-bottom: 20rpx;
font-size: 28rpx;
}
.btn-picked {
background: $jx-primary;
color: white;
border-radius: 10rpx;
font-size: 36rpx;
font-weight: 400;
height: 94rpx;
line-height: 94rpx;
text-align: center;
margin: 0rpx 20rpx;
margin-top: 15rpx;
}
.jx-tabs-root {
position: sticky;
top: 0;
box-shadow: 0 5rpx 7rpx #ececec;
}
.filter-order {
height: 90rpx;
box-sizing: border-box;
padding: 15rpx;
display: flex;
justify-content: space-between;
background-color: #fff;
view {
box-sizing: border-box;
width: 230rpx;
padding: 10rpx 20rpx;
border: 1rpx solid #999999;
color: #999999;
border-radius: 10rpx;
text-align: center;
}
.active {
background-color: #82c86f;
border: 1rpx solid #82c86f;
color: #fff;
}
}
.order-item-main {
box-sizing: border-box;
}
</style>

View File

@@ -0,0 +1,103 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>京西菜市用户隐私协议</title>
<style>
.service-wrap{
padding: 20px;
box-sizing: border-box;
}
.paper-title{
/* padding-bottom: 20px; */
text-align: center;
font-size: 24px;
line-height: 80px;
}
pre{
letter-spacing: 1px;
font-size: 16px;
white-space:pre-wrap;
white-space:-moz-pre-wrap;
white-space:-pre-wrap;
white-space:-o-pre-wrap;
word-wrap:break-word;
}
</style>
</head>
<body>
<div class="service-wrap">
<div class="paper-title">京西菜市用户隐私协议</div>
<pre>
京西菜市尊重和保护用户的隐私。本隐私政策将告诉您我们如何收集和使用有关您的信息,以及我们如何保护这些信息的安全。您成为京西菜市用户前务必仔细阅读本隐私条款并同意所有隐私条款。本隐私政策条款在您注册成为京西菜市用户后立即生效,并对您及京西菜市产生约束力。
一、我们可能收集的用户信息
我们提供服务时,可能会收集、储存和使用下列与您有关的信息。如果您不提供相关信息,可能无法注册成为我们的用户或无法享受我们提供的某些服务。
1、您提供的信息
•  您在注册账户或使用我们的服务时,向我们提供的相关个人信息,例如电话号码,昵称。
2、我们获取的您的信息。 您使用服务时我们可能收集如下信息:
设备信息移动设备的设备识别码、IP地址
• 位置信息:手机等设备返回的当前位置信息。
• 地址信息,指您在微信,支付宝等平台存储的常用收件地址信息。
行为信息指您在APP不同页面停留时间关注商品 使用APP直到退出时的行为轨迹。
二、我们可能如何使用用户信息
1、登录验证和防作弊监测
2、推荐附近店铺
3、分析使用我们软件的手机类型地域
4、协助选择收货信息
5、优化APP商品展示。
为了让您有更好的体验、改善我们的服务或您同意的其他用途,在符合相关法律法规的前提下,我们可能将通过以上描述的某一项服务所收集的信息,以汇集信息或者个性化的方式,用于我们京西菜市的其他服务。
三、我们可能与第三方共享的用户信息
在下列情况下,我们可能会共享您的个人信息:
1、我们店铺或骑手在完成定单过程中无法通过您收件预留的信息与您联系我们将您的注册电话或其他联系方式分享给店铺或骑手。
2、您在京西菜市活动中的存在刷补贴等违约行为被我们发现或店铺发起申诉时我们会将您的注册信息分享给对应的负责人
3、应行政、司法部门的要求向该等机构提供您的用户信息
4、您通过京西菜市平台向第三方合作机构申请相关产品服务时我们将根据您的授权向第三方提供您的用户信息
5、我们以及我们的关联公司可能将您的个人信息与我们的关联公司、合作伙伴及第三方服务供应商、承包商及代理例如代表我们发出短信或推送通知的通讯服务提供商、为我们提供位置数据的地图服务供应商分享他们可能并非位于您所在的法域为了我们向您提供或改善我们的服务
• 随着我们业务的持续发展,我们以及我们的关联公司有可能进行合并、收购、资产转让或类似的交易,您的个人信息有可能作为此类交易的一部分而被转移;
• 依据法律要求必须向第三方提供您的用户信息的情形;
四、我们如何保护用户信息
我们使用各种安全技术和程序,以防信息的丢失、不当使用、未经授权阅览或披露。但请您理解,由于技术的限制以及可能存在的各种恶意手段,在互联网行业,即便竭尽所能加强安全措施,也不可能始终保证信息百分之百的安全。您需要了解,您接入我们的服务所用的系统和通讯网络,有可能因我们可控范围外的因素而出现问题。
五、账户注销
当用户需要注销本账号时,可联系 京西菜市 客服人员进行验证注销。
六、隐私政策的修改
由于法律法规的变更,以及为了与互联网的新发展和可能的发展趋势保持同步,我们可能会不定时修改本政策。因此,我们保留自行决定实施此类修改的权利,如该等修订造成您在本《隐私政策》下权利的实质减少,我们将在修订生效前通过在主页上显著位置提示或向您推送通知或以其他方式通知您。在该种情况下,若您继续使用我们的服务,即表示同意受经修订的本《隐私政策》的约束。
</pre>
</div>
</body>
</html>

View File

@@ -0,0 +1,211 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>京西菜市用户协议</title>
<style>
.service-wrap{
padding: 20px;
box-sizing: border-box;
}
.paper-title{
/* padding-bottom: 20px; */
text-align: center;
font-size: 24px;
line-height: 80px;
}
pre{
letter-spacing: 1px;
font-size: 16px;
white-space:pre-wrap;
white-space:-moz-pre-wrap;
white-space:-pre-wrap;
white-space:-o-pre-wrap;
word-wrap:break-word;
}
</style>
</head>
<body>
<div class="service-wrap">
<div class="paper-title">京西菜市用户协议</div>
<pre>
京西菜市帐号使用协议
欢迎您注册、使用京西菜市帐号!
本协议系您与成都若溪科技有限公司就京西菜市帐号的注册和使用而订立的。成都若溪科技有限公司(如下简称“京西菜市”)在此特别提醒您认真阅读、充分理解本协议各条款,特别是涉及服务费用条款,免除或者限制京西菜市责任的条款,对您的权利限制条款,争议解决和法律适用条款等,此类条款将以加粗的形式提示您注意。请您审慎阅读并选择接受或不接受本协议(限制民事行为能力人应在监护人或法定代理人陪同下阅读)。除非您接受本协议所有条款,否则您无权注册、使用京西菜市帐号。您的注册和使用京西菜市帐号行为将视为您已充分理解本协议(即本协议及后续更新版本或开通或使用某项服务的单项协议),并同意接受本协议各项条款的约束。
一、 关于京西菜市帐号
1京西菜市帐号系由京西菜市所有的用于识别您身份的标识。帐号的所有权属于京西菜市您作为初始申请注册人仅拥有您所注册帐号的使用权。
2您可通过京西菜市帐号享受京西菜市及关联公司提供的单项服务包括但不限于京西菜市小程序服务您亦可通过京西菜市帐号向京西菜市购买品鉴券以便您享受京西菜市及关联公司的各种产品和增值服务。
3. 本服务条款的效力范围及于京西菜市及关联公司的一切产品和服务,您在享受任何单项服务时,应当受本服务条款的约束。当您使用京西菜市各单项服务时,您同意以单项服务要求的方式同意该单项服务的服务条款以及京西菜市在该单项服务中发出的各类公告(下列简称为“单项条款”),在此情况下单项条款与本服务条款同时对您产生效力。若单项条款与本服务条款存在同类条款的冲突,则在单项条款约束范围内应以单项条款为准。
二、帐号使用规则
1注册帐号
1.1 您确认,在您开始注册程序使用京西菜市服务前,您应当具备中华人民共和国法律规定的与您行为相适应的民事行为能力。若您不具备前述与您行为相适应的民事行为能力,则您及您的监护人应依照法律规定承担因此而导致的一切后果。
1.2 您应提供及时、详尽及准确的个人资料,并不断更新注册资料,符合及时、详尽、准确的要求。您保证在注册时所提交的所有资料(包括但不限于手机号码、生日等)真实、准确、合法、有效且系您本人的资料。如果因注册信息不真实或更新不及时而引发的相关问题, 京西菜市不负任何责任。您可以通过京西菜市帐号设置页面查询、更正您的信息,您应当通过真实身份信息认证注册帐号,且您提交的帐号名称、头像和简介等注册信息中不得出现违法和不良信息,经京西菜市审核,如存在上述情况,京西菜市将不予注册;同时,在注册后,如发现您以虚假信息骗取帐号名称注册,或您的帐号头像、简介等注册信息存在违法和不良信息的,京西菜市有权不经通知单方采取限期改正、暂停使用、终止帐号等措施。当您按照注册页面提示填写信息、阅读并同意本协议条款且完成全部注册程序后,您可获得京西菜市帐号并成为京西菜市用户。
2.帐号使用
2.1 您应对您帐号项下的所有行为结果负责。
2.2 由于您的京西菜市帐号关联您的个人信息及京西菜市商业信息,您的京西菜市帐号仅限您本人使用。未经京西菜市同意,您直接或间接授权第三方使用您京西菜市帐号或获取您帐号项下信息的行为无效。如京西菜市根据京西菜市各平台规则中约定的违约认定程序及标准判断您京西菜市帐号的使用可能危及您的帐号安全及或京西菜市信息安全的,京西菜市可拒绝提供相应服务或终止本协议。
2.3 若您选择第三方帐号登陆京西菜市的服务,第三方帐号将与您的京西菜市帐号相关联,京西菜市将根据您授权第三方提供的信息而使用您的信息(如头像)。您后续使用该京西菜市帐号的行为受本协议约束。
3.帐号保管和找回
3.1 京西菜市帐号包括帐号名称和手机号,您可使用设置的帐号名称(手机号)登录,您应妥善保管好您的帐号,因您个人原因导致的帐号信息遗失,如需找回京西菜市帐号信息,请按照京西菜市帐号找回流程提供相应的信息,并确保提供的信息合法真实有效,若提供的信息不符合要求,无法通过京西菜市安全验证,京西菜市有权拒绝提供帐号找回服务;
3.2 如果您当前使用的京西菜市帐号并非您初始申请注册的或通过京西菜市提供的其他途径获得的,但您却知悉该京西菜市帐号当前的手机号,您不得用该京西菜市帐号登录或进行任何操作,并请您在第一时间通知京西菜市或者该京西菜市帐号的初始申请注册人。
4帐号转让
4.1 您可在本协议约定的范围内使用京西菜市帐号,您不得恶意注册京西菜市帐号,不得赠与、借用、租用、有偿或无偿转让或售卖京西菜市帐号或者以其他方式许可非初始申请注册人使用京西菜市帐号,京西菜市有权对上述行为进行独立判断并处理,您应当自行承担由此产生的任何责任,同时京西菜市保留追究上述行为人法律责任的权利。且由此产生的一切责任均由您承担。
4.2 京西菜市有权根据法律法规对您采取以下措施:
4.2.1 如您违反法律法规、京西菜市各单项条款或业务规则的规定,京西菜市有权进行独立判断并随时采取限期改正、暂停使用、终止您对京西菜市帐号的使用,且根据实际情况决定是否恢复使用。
4.2.2 如果京西菜市发现您并非该帐号初始申请注册人,京西菜市有权在未经通知的情况下终止您使用该帐号。
4.2.3 京西菜市按照本规则或相关法律法规,限期改正、暂停使用或终止您对京西菜市帐号的使用,而由此给您带来的损失(包括但不限于通信中断,用户资料和相关数据等的清空等),由您自行承担。
5.帐号回收
5.1为了防止资源占用如您连续24个月未使用您的京西菜市帐号或未通过京西菜市认可的其他方式登录过您的帐号京西菜市有权对该帐号进行注销您将不能再通过该帐号登录或使用相关服务。如该帐号有关联的待处理交易或余额等京西菜市会在合理范围内协助您处理请您按照京西菜市提示的方式进行操作。
6. 帐号安全
6.1 您的帐号为您自行设置并由您保管,京西菜市任何时候均不会主动要求您提供您的帐号手机号。建议您采取特定措施保护您的帐号安全,包括但不限于安装防病毒木马软件等措施。
6.2 京西菜市帐号因您主动泄露或因您遭受他人攻击、诈骗等行为导致的损失及后果,京西菜市并不承担责任,您应通过司法、行政等救济途径向侵权行为人追偿。
7.帐号注销
7.1 在需要终止使用京西菜市帐号服务时,符合以下条件的,您可以申请注销您的京西菜市帐号。
7.1.1 您仅能申请注销您本人的帐号,并依照京西菜市的流程进行注销;
7.1.2 您仍应对您在注销帐号前且使用京西菜市服务期间的行为承担相应责任。
7.1.3 您应当知晓您的帐号终止意味着您的用户内容将从我们的活动数据库中删除。
三、用户权利和义务
1.您在使用京西菜市服务时,必须遵守《网络安全法》、《互联网新闻信息服务管理规定》等中华人民共和国相关法律法规的规定,您应同意将不会利用本服务进行任何违法或不正当的活动,包括但不限于下列行为:
1.1上载、展示、张贴、传播或以其他方式传送含有下列内容之一的信息:
1.1.1 反对宪法所确定的基本原则的;
1.1.2 危害 国家安全,泄露国家秘密,颠覆国家政权,破坏国家统一的;
1.1.3 损害国家荣誉和利益的;
1.1.4 煽动民族仇恨、民族歧视、破坏民族团结的;
1.1.5 破坏国家宗教政策,宣扬邪教和封建迷信的;
1.1.6 散布谣言,扰乱社会秩序,破坏社会稳定的;
1.1.7 散布淫秽、色情、赌博、暴力、凶杀、恐怖或者教唆犯罪的;
1.1.8 侮辱或者诽谤他人,侵害他人合法权利的;
1.1.9 含有虚假、有害、胁迫、侵害他人隐私、骚扰、侵害、中伤、粗俗、猥亵、或其他道德上令人反感的内容;
1.1.10 含有中国法律、法规、规章、条例以及任何具有法律效力之规范所限制或禁止的其他内容的;
1.2 不利用京西菜市服务从事以下活动:
1.2.1 未经允许,进入计算机信息网络或者使用计算机信息网络资源的;
1.2.2 未经允许,对计算机信息网络功能进行删除、修改或者增加的;
1.2.3 未经允许,对进入计算机信息网络中存储、处理或者传输的数据和应用程序进行删除、修改或者增加的;
1.2.4 故意制作、传播计算机病毒等破坏性程序的;
1.2.5 进行任何诸如发布广告、销售商品的商业行为,或者进行任何非法的侵害京西菜市利益的行为,如贩卖可币、游戏币、外挂、道具等;
1.2.6 其他危害计算机信息网络安全的行为。
2.您违反本协议或相关的服务条款的规定,导致或产生的任何第三方向京西菜市与合作公司、关联公司主张的任何索赔、要求或损失,包括合理的律师费,您同意赔偿京西菜市与合作公司、关联公司,并使之免受损害。同时,京西菜市有权视您的行为性质,采取包括但不限于删除发布信息内容、暂停使用许可、终止服务、限制使用京西菜市帐号、追究法律责任等措施。同时,京西菜市会视司法部门的要求,协助调查。
3.您不得对京西菜市服务任何部分或京西菜市服务之使用或获得,进行复制、拷贝、出售、转售或用于任何其他商业目的。
4.您须对自己在使用京西菜市服务过程中的行为承担法律责任。您承担法律责任的形式包括但不限于:对受到侵害者进行赔偿,以及在京西菜市首先承担了因您的行为导致的行政处罚或侵权损害赔偿责任后,您应给予京西菜市等额的赔偿。
5.在任何情况下,京西菜市都不对您或任何第三方因本协议产生的任何间接性、后果性、惩戒性的、偶然的、特殊或惩罚性的损害赔偿承担责任。
四 免责声明
1.如发生下述情形,京西菜市不承担任何法律责任:
1.1 依据法律规定或相关政府部门的要求提供您的个人信息;
1.2 由于您的使用不当或其他自身原因而导致任何个人信息的泄露;
1.3 任何由于黑客攻击,电脑病毒的侵入,非法内容信息、骚扰信息的屏蔽,政府管制以及其他任何网络、技术、通信线路、信息安全管理措施等原因造成的服务中断、受阻等不能满足您要求的情形;
1.4 因第三方如运营商的通讯线路故障、技术问题、网络、电脑故障、系统不稳定及其他因不可抗力造成的损失的情形;
1.5 使用京西菜市产品、程序及服务可能存在的来自他人匿名或冒名的含有威胁、诽谤、令人反感或非法内容的信息而招致的风险;
1.6 用户之间通过本网站或京西菜市产品、程序及服务与其他用户交往,因受误导或欺骗而导致或可能导致的任何心理、生理上的伤害以及经济上的损失;
1.7 京西菜市服务明文声明,不以明示、默示或以任何形式对京西菜市及其合作公司服务之及时性、安全性、准确性做出担保。
1.8 您在利用京西菜市帐号所发布的任何内容并不代表和反映京西菜市的任何观点或政策,京西菜市对此不承担任何责任。
1.9 在任何情况下,京西菜市均不对任何间接性、后果性、惩罚性、偶然性、特殊性或刑罚性的损害,包括因您使用京西菜市服务而遭受的利润损失,承担责任。尽管本协议中可能含有相悖的规定,我们对您承担的全部责任,无论因何原因或何种行为方式,始终不超过您在注册期内因使用京西菜市服务而支付给京西菜市的费用(如有)。
2. 您可以选择使用您已有的第三方帐号关联京西菜市帐号,京西菜市对于因第三方原因对您造成的损失不承担任何责任。
五、知识产权
1. 您在京西菜市发布的信息不得侵犯任何第三人的知识产权,未经具有相关所有权人之事先书面同意,您不得以任何方式上传、发布、修改、传播或复制任何受著作权保护的材料、商标或属于其他人的专有信息。如果收到任何著作权人或其合法代表发给京西菜市的适当通知后,我们将在审查的基础上移除该等侵犯他人著作权的内容。
2. 您在使用京西菜市服务时利用京西菜市帐号发表上传的文字、图片、视频、软件以及表演等原创信息的知识产权归您所有,但是您确认您对该等信息的发表、上传行为视同为对京西菜市非独占地、永久地、不可撤销地授予该等信息相关全部知识产权的使用、复制等权利,并且您同意京西菜市可转授权上述权利。
3. 除非经过京西菜市的在先书面同意,您未获得权利使用京西菜市的任何知识产权。您保证、陈述并承诺您尊重京西菜市的知识产权。您不会以自己名义或促使第三方,也不会同意或放任任何第三方,为了其任何营销、广告、促销或其他目的,在任何法域、以任何方式申请与京西菜市或京西菜市关联公司商标相似的商标、域名、无线网站、互联网搜索词或任何商号、服务标志。如出现上述情况,您须将所有相关权利转让给京西菜市,费用由您承担。如因您违反本条款约定而给京西菜市造成损失的,该损失全部由您承担。
六、 修订
1. 鉴于互联网相关技术、市场、业务模式等等的发展迅速,您同意,京西菜市有权随时根据中华人民共和国有关法律、法规的变化、互联网的发展以及公司经营状况和经营策略的调整等不定时地制定、修改本协议及各类规则。如有修订,京西菜市将通过法定程序通知。经修订的协议、规则一经公布,则立即自动生效,且成为本服务协议不可分割的一部分。如您不同意上述修订,则您必须立即停止使用本协议下各项服务。您继续登录或继续使用京西菜市服务,则表明您认可并接受经修订的协议、规则。
七、 终止
7.1 本协议自您接受之日起生效,在您使用京西菜市服务的过程中持续有效,直至依据本协议终止;
7.2 尽管有上述规定,如果您使用京西菜市服务的时间早于您接受本协议的时间,您在此知晓或应当知晓并同意本协议于您第一次使用京西菜市服务时生效,除非依据本协议提前终止。
7.3 我们可能会依据法律的规定,保留您使用京西菜市服务、或者京西菜市帐号的权利;无论是否通知,我们将在任何时间以任何原因终止本协议,包括出于善意地相信您违反了我们可接受使用政策或本协议的其他规定。
7.4 不受前款规定所限,如果您侵犯第三人的著作权且京西菜市接到著作权人或著作权人的合法代理人的通知后,京西菜市保留终止本协议的权利。
八、其他
8.1 反馈
8.1.1 您对京西菜市提出建议(或称“反馈”),即视为您向京西菜市转让“反馈”的全部权利并同意京西菜市有权利以任何合理方式使用此反馈及其相关信息。我们将视此类反馈信息为非保密且非专有;
8.1.2 您已同意您不会向京西菜市提供任何您视为保密和专有的信息;
8.2 隐私政策
8.2.1 请查阅我们的《隐私政策》,《隐私政策》为与本协议效力等同且不可分割的一部分。
8.3 通知
8.3.1 在注册京西菜市帐号时,您应该向京西菜市提供真实有效的联系方式(包括您的手机号码等),对于联系方式发生变更的,您有义务及时更新有关信息,并保持可被联系的状态。京西菜市将向您的上述联系方式的其中之一或其中若干向您送达各类通知,而此类通知的内容可能对您的权利义务产生重大的有利或不利影响,请您务必及时关注。您所提供的手机号码无法使用或者因任何原因我们无法将通知送达给您而产生的风险,由您自行承担。
8.4 适用法律
8.4.1 本协议适用中华人民共和国法律。
8.4.2 如果双方发生纠纷,应本着友好的原则协商解决;如协商不成,应向北京市海淀区人民法院提起诉讼。若单项条款与本服务条款在管辖约定内容上存在冲突,则在单项条款约束范围内应以单项条款为准。
8.5 独立性
8.5.1 若本协议中的某些条款因故无法适用,则本协议的其他条款继续适用且无法适用的条款将会被修改,以便能够依法适用。
</pre>
</div>
</body>
</html>

View File

@@ -0,0 +1,343 @@
@font-face {
font-family: "iconfont";
src: url('/static/font/iconfont.ttf') format('truetype');
}
/* 自定义图标 */
.icon-0 {
background-image: url(https://image.jxc4.com/image/884664b80ffd2eda64a4aab9f4dc402e.png);
}
.icon-1 {
background-image: url(http://image.jxc4.com/image/c4d4a4bf342e301733d16262e0cec2dc.png)
}
.icon-3 {
background-image: url(https://image.jxc4.com/image/9b6dc6f925111cf1d72175df9669c738.png)
}
.icon-4 {
background-image: url(https://image.jxc4.com/image/a8914f97edd3e8efa8aef4122fb86f78.png)
}
.icon-5 {
background-image: url(https://image.jxc4.com/image/e3d7c79e4fe65a687bafbccbad5c2c57.png)
}
.icon-9 {
background-image: url(http://image.jxc4.com/image/02a72aff88e6fb688472d3d34c275ea2.png)
}
.icon-16 {
background-image: url(https://image.jxc4.com/image/db9c805c2747a9f8cced29ef8ea7be75.jpg)
}
.icon-14 {
background-image: url(https://image.jxc4.com/image/32ff8463b62a4195e0a5d979eb0f46f3.png)
}
.icon-6 {
background-image: url(https://image.jxc4.com/image/57ed88f5b1c2122655dada08de40ed61.png);
}
.icon-103 {
background-image: url(http://image.jxc4.com/image/35cb1b9bbf9d78b6bb4b48fdae20d88f.png);
}
.icon-101 {
background-image: url(http://image.jxc4.com/image/223fccabb90ffeb8854e534c6ec1a43c.jpg)
}
.icon-105 {
background-image: url(http://image.jxc4.com/image/f4ef8fd49fc3d07f456c5fe19dc2ac44.jpg)
}
.icon-106 {
background-image: url(http://image.jxc4.com/image/938b1fc6aa3428f95182e30c87b887ab.png)
}
.promtion-sku-icon,
.promtion-sku-icon2,
.promotion-earning-icon {
position: absolute;
left: 0;
top: 20rpx;
width: 30rpx;
height: 30rpx;
background-color: white;
background-repeat: no-repeat;
background-position: center center;
background-size: 100%;
animation: bounce .5s infinite alternate;
}
.promotion-earning-icon {
height: 60rpx;
}
.promtion-sku-icon {
background-image: url(http://image.jxc4.com/image/21a32b90b1de684d70fa16a24b033be7.png);
}
.promtion-sku-icon2 {
background-image: url(http://image.jxc4.com/image/0be36cc81c28da0be8d1152dc3a2f9b5.png);
}
.promotion-earning-icon {
background-image: url(http://image.jxc4.com/image/194cd17fcce1c86e589251e9c9e4d87b.png);
}
/* 订单管理item样式 */
.position-relative {
font-size: 30rpx;
box-sizing: border-box;
position: relative;
border-radius: 10rpx !important;
overflow: hidden;
padding: 0rpx 15rpx;
margin: 35rpx 25rpx 0rpx 25rpx;
}
.promtion-sku-icon2 {
background-image: url(https://image.jxc4.com/image/b593ed3cb0b2bc4f012ad81eeacaf4f6.png);
}
.promtion-sku-icon {
background-image: url(https://image.jxc4.com/image/61daa3ff4294cd271fef44088c94d38c.png);
}
/* 兼容ios样式 */
.rest-time {
display: block;
box-sizing: border-box;
width: 186rpx;
height: 58rpx;
background-size: 100%;
text-align: right;
font-size: 36rpx;
font-weight: bold;
color: #fff;
line-height: 56rpx;
padding-right: 10rpx;
}
/* 已超时 */
.order-bg-cs {
display: block;
width: 186rpx;
height: 58rpx;
background: url(https://image.jxc4.com/image/28c4ddde0d2d427e7dd8ec852cd7984f.tem.png) center center no-repeat;
background-size: 100%;
font-size: 0;
}
/* 预订单 */
.order-bg-dsd {
display: block;
width: 186rpx;
height: 58rpx;
background: url(https://image.jxc4.com/image/96d3ae7a7b3748a9ad2fc4678c528a61.tem.png) center center no-repeat;
background-size: 100%;
font-size: 0;
}
/* time */
.picktime1 {
background: url(https://image.jxc4.com/image/9de64fdcd36aa43cf85c20f5361a486a.tem.png) center center no-repeat;
background-size: 100% 100%;
}
.canceltime {
background: url(https://image.jxc4.com/image/1ba2acde27582db3bcc801fab44729db.tem.png) center center no-repeat;
background-size: 100% 100%;
}
/* time < 10 */
.picktime2 {
background: url(https://image.jxc4.com/image/20b8cfeba3fa10114b7292ee53bde792.tem.png) center center no-repeat;
background-size: 100% 100%;
}
/* time < 5 */
.picktime3 {
background: url(https://image.jxc4.com/image/cd1e46e18fa2b7eeea72c4b5b4828b5b.tem.png) center center no-repeat;
background-size: 100% 100%;
}
/* time */
.arrived1 {
background: url(https://image.jxc4.com/image/68d5fbc3b1d925cb58a6dad714c45adb.tem.png) center center no-repeat;
background-size: 100% 100%;
}
/* time < 20 */
.arrived2 {
background: url(https://image.jxc4.com/image/628846b61f5a0a67aa15b1c6c0ab838f.tem.png) center center no-repeat;
background-size: 100% 100%;
}
/* time < 5 */
.arrived3 {
background: url(https://image.jxc4.com/image/47a56698feaf90e5b8376a4824f98475.tem.png) center center no-repeat;
background-size: 100% 100%;
}
/* 已送达 */
.order-delivered {
display: block;
box-sizing: border-box;
width: 186rpx;
height: 58rpx;
font-size: 36rpx;
font-weight: 500;
color: #4eb331;
text-align: right;
line-height: 58rpx;
}
/* 配送管理 */
.small {
font-size: 24rpx !important;
}
.red {
color: #D34B3B !important;
}
.green {
color: #4EB331 !important;
}
/* 系统图标 */
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-yijianshouquan:before {
content: "\e68f";
}
.icon-yuyin:before {
content: "\e69f";
}
.icon-jiantou_yemian_xiangxia:before {
content: "\eb0a";
}
.icon-erweima:before {
content: "\e60c";
}
.icon-xiangce:before {
content: "\e7f1";
}
.icon-qiehuan:before {
content: "\e607";
}
.icon-zhengque:before {
content: "\e628";
}
.icon-ziyuan:before {
content: "\e60f";
}
.icon-jiantou1:before {
content: "\e605";
}
.icon-jiahao:before {
content: "\eaf3";
}
.icon-24gf-telephone:before {
content: "\e96c";
}
.icon-zhuanfa:before {
content: "\e627";
}
.icon-cangpeitubiao_xiazaipandiandanxiazaidayinmoban:before {
content: "\e623";
}
.icon-shengyin:before {
content: "\e87c";
}
.icon-shijian:before {
content: "\e8a9";
}
.icon-xinxi:before {
content: "\e64e";
}
.icon-fuzhi:before {
content: "\e604";
}
.icon-shanchu:before {
content: "\e603";
}
.icon-xiangyoujiantou:before {
content: "\e65f";
}
.icon-xiangzuojiantou:before {
content: "\e660";
}
.icon-gengduo:before {
content: "\e602";
}
.icon-wenhaoxiao:before {
content: "\e8c8";
}
.icon-duihao:before {
content: "\e684";
}
.icon-shuxie:before {
content: "\e60e";
}
.icon-kongzhuangtai:before {
content: "\e6fe";
}
.icon-sousuo:before {
content: "\e62f";
}
.icon-weixin:before {
content: "\e601";
}
.icon-mima:before {
content: "\e600";
}
.icon-yanzhengma2:before {
content: "\e656";
}
.icon-shoujihao:before {
content: "\e62b";
}

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 501 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 553 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 357 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 422 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 378 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 549 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

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