Compare commits
No commits in common. "main" and "develop" have entirely different histories.
4
.env
4
.env
|
|
@ -1,3 +1 @@
|
|||
|
||||
VITE_APP_VERSION_CODE = 100
|
||||
VITE_APP_VERSION = 1.0.0
|
||||
VITE_COMMON_API_URL=
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
|
||||
VITE_COMMON_API_PREFIX = /api-base
|
||||
|
||||
VITE_COMMON_API_URL = http://store-manage.hmily.club/api
|
||||
VITE_COMMON_API_PREFIX = /api
|
||||
|
||||
VITE_COMMON_URL = http://store-manage.hmily.club
|
||||
VITE_COMMON_API_URL = http://store-manage.hmily.club
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
VITE_COMMON_API_PREFIX = /api-base
|
||||
VITE_COMMON_API_PREFIX = /api
|
||||
|
||||
VITE_COMMON_API_URL = https://store.manage.zlgj168.com/api
|
||||
|
||||
VITE_COMMON_URL = https://store.manage.zlgj168.com
|
||||
VITE_COMMON_API_URL = http://store-manage.hmily.club
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
{ // 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"
|
||||
},
|
||||
"type" : "uniCloud"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
{
|
||||
"i18n-ally.localesPaths": [
|
||||
"src/components/cu-calendars/i18n"
|
||||
]
|
||||
}
|
||||
1344
download.html
1344
download.html
File diff suppressed because it is too large
Load Diff
|
|
@ -1 +0,0 @@
|
|||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1714901800208" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4248" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M521.995587 236.597895a154.138947 154.138947 0 0 0 35.031579-4.850527h5.389474a179.469474 179.469474 0 0 0 35.570526-16.168421h4.850527a209.650526 209.650526 0 0 0 30.72-20.48l3.772631-3.233684a234.442105 234.442105 0 0 0 26.947369-26.947368l3.233684-3.233684a242.526316 242.526316 0 0 0 22.096842-32.336843v-3.772631a232.825263 232.825263 0 0 0 16.168421-36.648421V86.231579a211.267368 211.267368 0 0 0 9.162105-39.882105 188.092632 188.092632 0 0 0 0-42.037895A227.435789 227.435789 0 0 0 512.294535 236.058947zM813.027166 616.016842a218.812632 218.812632 0 0 1-14.551579-86.231579 212.345263 212.345263 0 0 1 10.24-57.667368 215.578947 215.578947 0 0 1 26.408421-53.894737 245.221053 245.221053 0 0 1 71.141053-68.985263 236.597895 236.597895 0 0 0-154.138947-97.549474 250.610526 250.610526 0 0 0-35.031579-4.311579h-65.212632l-15.629474 4.311579-11.856842 3.772632-15.090526 5.389473-10.778947 8.623158-17.785263 7.006316-14.551579 5.928421-10.24 3.772632-12.39579 3.772631h-7.006316a73.296842 73.296842 0 0 1-16.707368 0 77.608421 77.608421 0 0 1-16.168421 0h-5.928421l-11.856842-3.233684-8.623158-3.233684-12.39579-3.233684-20.48-8.084211L436.302956 269.473684l-14.551579-5.389473-9.701053-3.233685-13.473684-4.311579H388.33664l-14.012632-2.694736h-10.778947L350.610324 250.071579A256.538947 256.538947 0 0 0 254.138745 269.473684 291.570526 291.570526 0 0 0 81.13664 554.576842v53.894737c0 4.311579 0 19.402105 3.772632 29.103158s0 10.778947 3.233684 16.168421 3.233684 17.246316 5.389473 25.869474 3.233684 11.317895 4.850527 16.707368 4.311579 16.168421 7.006316 24.252632 4.311579 11.856842 6.467368 17.785263l8.084211 22.635789 7.545263 17.246316c3.233684 7.006316 5.928421 14.551579 9.162105 21.557895l8.08421 16.168421 10.778948 21.018947 9.162105 15.629474 11.317895 19.402105 9.701052 14.551579 11.856843 17.785263 10.24 13.473684 12.395789 15.629474 10.778947 12.39579 12.39579 13.473684 11.317895 10.778947 12.395789 11.317895 11.317895 8.623158 12.395789 9.162105 11.317895 6.467368 11.856842 6.467369 10.778948 3.772631 11.856842 3.772632L350.610324 1024H363.006114a161.684211 161.684211 0 0 0 43.115789-7.545263 331.991579 331.991579 0 0 1 126.652632-34.492632 198.871579 198.871579 0 0 1 26.947368 0h8.623158l14.551579 3.233684 9.162105 2.694737 11.317895 3.772632 9.701053 3.772631 14.012631 5.928422 12.39579 5.389473 8.08421 2.694737 10.778948 3.772632H704.159798a154.138947 154.138947 0 0 0 95.393684-44.193685 551.882105 551.882105 0 0 0 119.107369-165.995789 568.050526 568.050526 0 0 0 24.791578-51.738947 247.915789 247.915789 0 0 1-130.425263-135.27579z" p-id="4249" fill="#ffffff"></path></svg>
|
||||
|
Before Width: | Height: | Size: 2.9 KiB |
|
|
@ -1 +0,0 @@
|
|||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1714899843587" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4297" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M270.1 741.7c0 23.4 19.1 42.5 42.6 42.5h48.7v120.4c0 30.5 24.5 55.4 54.6 55.4 30.2 0 54.6-24.8 54.6-55.4V784.1h85v120.4c0 30.5 24.5 55.4 54.6 55.4 30.2 0 54.6-24.8 54.6-55.4V784.1h48.7c23.5 0 42.6-19.1 42.6-42.5V346.4h-486v395.3zM627.2 141.6l44.9-65c2.6-3.8 2-8.9-1.5-11.4-3.5-2.4-8.5-1.2-11.1 2.6l-46.6 67.6c-30.7-12.1-64.9-18.8-100.8-18.8-35.9 0-70.1 6.7-100.8 18.8l-46.6-67.5c-2.6-3.8-7.6-5.1-11.1-2.6-3.5 2.4-4.1 7.4-1.5 11.4l44.9 65c-71.4 33.2-121.4 96.1-127.8 169.6h486c-6.6-73.6-56.7-136.5-128-169.7zM409.5 244.1c-14.8 0-26.9-12-26.9-26.9 0-14.8 12-26.9 26.9-26.9 14.8 0 26.9 12 26.9 26.9-0.1 14.9-12.1 26.9-26.9 26.9z m208.4 0c-14.8 0-26.9-12-26.9-26.9 0-14.8 12-26.9 26.9-26.9 14.8 0 26.9 12 26.9 26.9-0.1 14.9-12.1 26.9-26.9 26.9zM841.3 344.8c-30.2 0-54.6 24.8-54.6 55.4v216.4c0 30.5 24.5 55.4 54.6 55.4 30.2 0 54.6-24.8 54.6-55.4V400.1c0.1-30.6-24.3-55.3-54.6-55.3zM182.7 344.8c-30.2 0-54.6 24.8-54.6 55.4v216.4c0 30.5 24.5 55.4 54.6 55.4 30.2 0 54.6-24.8 54.6-55.4V400.1c0-30.6-24.5-55.3-54.6-55.3z" p-id="4298" fill="#ee2c37"></path></svg>
|
||||
|
Before Width: | Height: | Size: 1.4 KiB |
|
|
@ -1,169 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>应用名称 - 下载</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background-color: #f4f4f4;
|
||||
}
|
||||
|
||||
.container {
|
||||
height: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.content {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
top: 28%;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #333;
|
||||
text-align: center;
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
p {
|
||||
color: #666;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.download-link {
|
||||
display: block;
|
||||
text-align: center;
|
||||
margin-top: 20px;
|
||||
}
|
||||
a{
|
||||
text-decoration: none;
|
||||
}
|
||||
.btn {
|
||||
height: 60px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-radius: 5px;
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
.btn-icon {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.btn-android {
|
||||
color: #ee2c37;
|
||||
border: 1px solid #ee2c37;
|
||||
background-color: #fff;
|
||||
}
|
||||
.btn-ios{
|
||||
color: #fff;
|
||||
border: 1px solid #fff;
|
||||
background-color: #5895e8;
|
||||
}
|
||||
.btn-text{
|
||||
margin-left: 10px;
|
||||
}
|
||||
.btn-title{
|
||||
font-size: 16px;
|
||||
}
|
||||
.btn-subtitle{
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.download-link a:hover {
|
||||
background-color: #5895e8;
|
||||
}
|
||||
|
||||
.wechat-warning {
|
||||
display: none;
|
||||
color: red;
|
||||
text-align: center;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.logo {
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
margin: 0 auto;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.download-wrap {
|
||||
padding: 0 30px;
|
||||
margin-top: 50px;
|
||||
}
|
||||
|
||||
.w-full {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.h-full {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="content">
|
||||
<div class="logo">
|
||||
<img src="" alt="" srcset="">
|
||||
</div>
|
||||
<h1>托管门店助手</h1>
|
||||
<div class="download-wrap">
|
||||
<a href="链接到你的应用下载地址">
|
||||
<div class="btn btn-android">
|
||||
<div class="btn-icon">
|
||||
<img class="w-full h-full" src="./android-fill.svg" alt="" srcset="">
|
||||
</div>
|
||||
<div class="btn-text">
|
||||
<div class="btn-title">Android.Harmony 版本</div>
|
||||
<div class="btn-subtitle">直接下载安装包</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<br/>
|
||||
<a href="链接到你的应用下载地址">
|
||||
<div class="btn btn-ios">
|
||||
<div class="btn-icon">
|
||||
<img class="w-full h-full" src="./IOS.svg" alt="" srcset="">
|
||||
</div>
|
||||
<div class="btn-text">
|
||||
<div class="btn-title">iPhone 版本</div>
|
||||
<div class="btn-subtitle">下载安装</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <p class="wechat-warning" id="wechatWarning">请使用浏览器打开链接以下载应用。</p> -->
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// 检测是否在微信中打开,并显示相应提示
|
||||
// var userAgent = navigator.userAgent.toLowerCase();
|
||||
// if (userAgent.indexOf('micromessenger') !== -1) {
|
||||
// document.getElementById('downloadButton').style.display = 'none';
|
||||
// document.getElementById('wechatWarning').style.display = 'block';
|
||||
// }
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -1,3 +0,0 @@
|
|||
别名:store_manage
|
||||
密码:123456a
|
||||
包名:com.lottery.store
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -24,8 +24,6 @@
|
|||
"@dcloudio/uni-mp-xhs": "3.0.0-3090920231225001",
|
||||
"@dcloudio/uni-quickapp-webview": "3.0.0-3090920231225001",
|
||||
"@qiun/ucharts": "^2.5.0-20230101",
|
||||
"esbuild-darwin-arm64": "^0.15.18",
|
||||
"luch-request": "^3.1.1",
|
||||
"pinia": "2.0.33",
|
||||
"pinia-plugin-persistedstate": "^3.2.1",
|
||||
"vue": "^3.2.45",
|
||||
|
|
@ -6282,20 +6280,6 @@
|
|||
"@esbuild/win32-x64": "0.16.17"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-darwin-arm64": {
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmmirror.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.18.tgz",
|
||||
"integrity": "sha512-tKPSxcTJ5OmNb1btVikATJ8NftlyNlc8BVNtyT/UAr62JFOhwHlnoPrhYWz09akBLHI9nElFVfWSTSRsrZiDUA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/escalade": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmmirror.com/escalade/-/escalade-3.1.2.tgz",
|
||||
|
|
@ -9428,19 +9412,6 @@
|
|||
"yallist": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/luch-request": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmmirror.com/luch-request/-/luch-request-3.1.1.tgz",
|
||||
"integrity": "sha512-p7+mlcEtgRcd0OfXC4XZbyiwSr1XgCeqNT7LlVUjnk7InYl/8d5Rk7BUqAYNA2WRafI1wRIUQWRWZRpeUwWR0w==",
|
||||
"dependencies": {
|
||||
"@dcloudio/types": "^2.0.16"
|
||||
}
|
||||
},
|
||||
"node_modules/luch-request/node_modules/@dcloudio/types": {
|
||||
"version": "2.6.12",
|
||||
"resolved": "https://registry.npmmirror.com/@dcloudio/types/-/types-2.6.12.tgz",
|
||||
"integrity": "sha512-mrCMwcINy1IFjU9VUqLeWBkj404yWs5paLDttBcA+eqUjanuUQbBcTVPqlrGgkyzLXDcV2oDDZRSNxNpXi4kMQ=="
|
||||
},
|
||||
"node_modules/magic-string": {
|
||||
"version": "0.30.8",
|
||||
"resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.8.tgz",
|
||||
|
|
@ -17073,11 +17044,6 @@
|
|||
"@esbuild/win32-x64": "0.16.17"
|
||||
}
|
||||
},
|
||||
"esbuild-darwin-arm64": {
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmmirror.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.18.tgz",
|
||||
"integrity": "sha512-tKPSxcTJ5OmNb1btVikATJ8NftlyNlc8BVNtyT/UAr62JFOhwHlnoPrhYWz09akBLHI9nElFVfWSTSRsrZiDUA=="
|
||||
},
|
||||
"escalade": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmmirror.com/escalade/-/escalade-3.1.2.tgz",
|
||||
|
|
@ -19479,21 +19445,6 @@
|
|||
"yallist": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"luch-request": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmmirror.com/luch-request/-/luch-request-3.1.1.tgz",
|
||||
"integrity": "sha512-p7+mlcEtgRcd0OfXC4XZbyiwSr1XgCeqNT7LlVUjnk7InYl/8d5Rk7BUqAYNA2WRafI1wRIUQWRWZRpeUwWR0w==",
|
||||
"requires": {
|
||||
"@dcloudio/types": "^2.0.16"
|
||||
},
|
||||
"dependencies": {
|
||||
"@dcloudio/types": {
|
||||
"version": "2.6.12",
|
||||
"resolved": "https://registry.npmmirror.com/@dcloudio/types/-/types-2.6.12.tgz",
|
||||
"integrity": "sha512-mrCMwcINy1IFjU9VUqLeWBkj404yWs5paLDttBcA+eqUjanuUQbBcTVPqlrGgkyzLXDcV2oDDZRSNxNpXi4kMQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"magic-string": {
|
||||
"version": "0.30.8",
|
||||
"resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.8.tgz",
|
||||
|
|
|
|||
|
|
@ -3,12 +3,10 @@
|
|||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"dev:app": "uni -p app",
|
||||
"dev:app:pro": "uni -p app --mode production",
|
||||
"dev:app-android": "uni -p app-android",
|
||||
"dev:app-ios": "uni -p app-ios",
|
||||
"dev:custom": "uni -p",
|
||||
"dev:h5": "uni",
|
||||
"dev:h5:pro": "uni --mode production",
|
||||
"dev:h5:ssr": "uni --ssr",
|
||||
"dev:mp-alipay": "uni -p mp-alipay",
|
||||
"dev:mp-baidu": "uni -p mp-baidu",
|
||||
|
|
@ -58,7 +56,6 @@
|
|||
"@dcloudio/uni-mp-xhs": "3.0.0-3090920231225001",
|
||||
"@dcloudio/uni-quickapp-webview": "3.0.0-3090920231225001",
|
||||
"@qiun/ucharts": "^2.5.0-20230101",
|
||||
"dayjs": "^1.11.11",
|
||||
"luch-request": "^3.1.1",
|
||||
"pinia": "2.0.33",
|
||||
"pinia-plugin-persistedstate": "^3.2.1",
|
||||
|
|
@ -70,7 +67,6 @@
|
|||
"@dcloudio/uni-automator": "3.0.0-3090920231225001",
|
||||
"@dcloudio/uni-cli-shared": "3.0.0-3090920231225001",
|
||||
"@dcloudio/uni-stacktracey": "3.0.0-3090920231225001",
|
||||
"@dcloudio/uni-uts-v1": "3.0.0-3090920231225001",
|
||||
"@dcloudio/vite-plugin-uni": "3.0.0-3090920231225001",
|
||||
"@vue/runtime-core": "^3.2.45",
|
||||
"sass": "^1.71.1",
|
||||
|
|
|
|||
53
src/App.vue
53
src/App.vue
|
|
@ -1,64 +1,15 @@
|
|||
<script>
|
||||
import { useUserStoreWithOut } from '@/store/modules/user'
|
||||
// #ifdef APP-PLUS
|
||||
// 实现,路由拦截。当应用无访问摄像头/相册权限,引导跳到设置界面 https://ext.dcloud.net.cn/plugin?id=5095
|
||||
import interceptorChooseImage from '@/uni_modules/json-interceptor-chooseImage/js_sdk/main.js';
|
||||
interceptorChooseImage()
|
||||
// #endif
|
||||
// import { useUserStoreWithOut } from "@/store/modules/user";
|
||||
export default {
|
||||
onLaunch: function () {
|
||||
const userStore = useUserStoreWithOut()
|
||||
if (userStore.isLogin) {
|
||||
userStore.fetchUserInfo()
|
||||
}
|
||||
// #ifdef APP-PLUS
|
||||
plus.screen.lockOrientation('portrait-primary')
|
||||
plus.navigator.closeSplashscreen()
|
||||
if (userStore.isLogin) {
|
||||
// plus.navigator.closeSplashscreen()
|
||||
} else {
|
||||
// uni.reLaunch({
|
||||
// url: '/pages/login/index',
|
||||
// success: () => {
|
||||
// plus.navigator.closeSplashscreen()
|
||||
// },
|
||||
// })
|
||||
}
|
||||
// #endif
|
||||
console.log('App Launch')
|
||||
},
|
||||
onShow: function () {
|
||||
console.log('App Show')
|
||||
// this.isHaveNetwork()
|
||||
},
|
||||
onHide: function () {
|
||||
console.log('App Hide')
|
||||
},
|
||||
methods: {
|
||||
isHaveNetwork() {
|
||||
uni.getNetworkType({
|
||||
success: (res) => {
|
||||
if (res.networkType == 'none') {
|
||||
uni.showModal({
|
||||
title: '网络不给力~',
|
||||
content: '是否重新连接',
|
||||
showCancel: true,
|
||||
confirmText: '是',
|
||||
cancelText: '不了',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
setTimeout(() => {
|
||||
this.isHaveNetwork() //再次判断
|
||||
}, 200)
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
},
|
||||
fail: (err) => console.error('调用失败'),
|
||||
complete: () => {},
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"prompt" : "none"
|
||||
}
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
<template>
|
||||
<BaesData :data="data" :colums="colums">
|
||||
<template v-slot="{ data, slotName }">
|
||||
<slot :slotName="slotName" :data="data"> </slot>
|
||||
</template>
|
||||
</BaesData>
|
||||
</template>
|
||||
<script setup>
|
||||
import { onBeforeMount } from 'vue'
|
||||
import { http } from '@/utils/request'
|
||||
import { ref } from 'vue'
|
||||
import BaesData from './base-data.vue'
|
||||
const props = defineProps({
|
||||
colums: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
apiUrl: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
data: {
|
||||
type: Object,
|
||||
},
|
||||
params: {
|
||||
type: Object,
|
||||
},
|
||||
method: {
|
||||
type: String,
|
||||
default: 'GET',
|
||||
},
|
||||
header: {
|
||||
type: Object,
|
||||
},
|
||||
})
|
||||
|
||||
const data = ref({})
|
||||
|
||||
onBeforeMount(async () => {
|
||||
init()
|
||||
})
|
||||
|
||||
const init = async () => {
|
||||
if (!props.apiUrl) return
|
||||
try {
|
||||
const resData = await http.request({
|
||||
url: props.apiUrl,
|
||||
method: props.method,
|
||||
data: props.data,
|
||||
params: props.params,
|
||||
header: props.header,
|
||||
})
|
||||
data.value = resData
|
||||
} catch (error) {}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
<template>
|
||||
<!-- <uv-list v-if="colums.length && data && Object.keys(data).length">
|
||||
<template v-for="(item, i) in columsList" :key="i">
|
||||
<slot :slotName="item.dataIndex" :data="item">
|
||||
<uv-list-item :title="item.title" :right-text="item?.value">
|
||||
</uv-list-item>
|
||||
</slot>
|
||||
</template>
|
||||
</uv-list> -->
|
||||
<uv-form labelWidth="160rpx">
|
||||
<template v-for="(item, i) in columsList" :key="i">
|
||||
<slot :slotName="item.dataIndex" :data="item">
|
||||
<uv-form-item :label="item.title" :labelPosition="item.labelPosition">
|
||||
<uv-input inputAlign="right" :border="`none`" v-model="item.value"></uv-input>
|
||||
</uv-form-item>
|
||||
</slot>
|
||||
</template>
|
||||
</uv-form>
|
||||
</template>
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
colums: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
data: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
})
|
||||
|
||||
const columsList = computed(() => {
|
||||
const arr = []
|
||||
props.colums.forEach((e) => {
|
||||
const { dataIndex, format } = e
|
||||
// console.log(props.data)
|
||||
// props.data[dataIndex]
|
||||
let str =getValue(props.data,dataIndex)
|
||||
if (isFunction(format)) {
|
||||
str = format(str)
|
||||
}
|
||||
arr.push({
|
||||
...e,
|
||||
value: str,
|
||||
})
|
||||
})
|
||||
return arr
|
||||
})
|
||||
|
||||
const getValue = (obj, path) => {
|
||||
return path.split('.').reduce((acc, key) => (acc ? acc[key] : undefined), obj)
|
||||
}
|
||||
|
||||
const isFunction = (fn) => {
|
||||
return typeof fn === 'function'
|
||||
}
|
||||
</script>
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
<template>
|
||||
<view class="relative box-content">
|
||||
|
||||
<view>
|
||||
<slot></slot>
|
||||
</view>
|
||||
<uv-badge
|
||||
absolute
|
||||
:offset="[0, 0]"
|
||||
type="error"
|
||||
max="99"
|
||||
:absolute="true"
|
||||
:value="value"
|
||||
:color="color"
|
||||
:bgColor="bgColor"
|
||||
customStyle="transform:translate(50%,-50%);"
|
||||
></uv-badge>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
// import { defineOptions } from 'vue';
|
||||
// defineOptions({ name: 'CuBadge' })
|
||||
|
||||
const props = defineProps({
|
||||
value: {
|
||||
type: [Number, String],
|
||||
},
|
||||
bgColor:{
|
||||
type: String,
|
||||
default: '#ee2c37',
|
||||
},
|
||||
color:{
|
||||
type: String,
|
||||
default: '#ee2c37',
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
@ -1,376 +0,0 @@
|
|||
<template>
|
||||
<view class="uv-calendar-body">
|
||||
<view class="uv-calendar__header">
|
||||
<view class="uv-calendar__header-btn-box" @click.stop="pre">
|
||||
<view class="uv-calendar__header-btn uv-calendar--left"></view>
|
||||
</view>
|
||||
<picker mode="date" :value="getDate" fields="month" @change="bindDateChange">
|
||||
<text class="uv-calendar__header-text">{{ (nowDate.year||'') +' / '+( nowDate.month||'')}}</text>
|
||||
</picker>
|
||||
<view class="uv-calendar__header-btn-box" @click.stop="next">
|
||||
<view class="uv-calendar__header-btn uv-calendar--right"></view>
|
||||
</view>
|
||||
<text class="uv-calendar__backtoday" @click="backToday">{{todayText}}</text>
|
||||
</view>
|
||||
<view class="uv-calendar__box">
|
||||
<view v-if="showMonth" class="uv-calendar__box-bg">
|
||||
<text class="uv-calendar__box-bg-text">{{nowDate.month}}</text>
|
||||
</view>
|
||||
<view class="uv-calendar__weeks uv-calendar__weeks-week">
|
||||
<view class="uv-calendar__weeks-day">
|
||||
<text class="uv-calendar__weeks-day-text">{{SUNText}}</text>
|
||||
</view>
|
||||
<view class="uv-calendar__weeks-day">
|
||||
<text class="uv-calendar__weeks-day-text">{{monText}}</text>
|
||||
</view>
|
||||
<view class="uv-calendar__weeks-day">
|
||||
<text class="uv-calendar__weeks-day-text">{{TUEText}}</text>
|
||||
</view>
|
||||
<view class="uv-calendar__weeks-day">
|
||||
<text class="uv-calendar__weeks-day-text">{{WEDText}}</text>
|
||||
</view>
|
||||
<view class="uv-calendar__weeks-day">
|
||||
<text class="uv-calendar__weeks-day-text">{{THUText}}</text>
|
||||
</view>
|
||||
<view class="uv-calendar__weeks-day">
|
||||
<text class="uv-calendar__weeks-day-text">{{FRIText}}</text>
|
||||
</view>
|
||||
<view class="uv-calendar__weeks-day">
|
||||
<text class="uv-calendar__weeks-day-text">{{SATText}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="uv-calendar__weeks" v-for="(item,weekIndex) in weeks" :key="weekIndex">
|
||||
<view class="uv-calendar__weeks-item" v-for="(weeks,weeksIndex) in item" :key="weeksIndex">
|
||||
<calendar-item class="uv-calendar-item--hook" :weeks="weeks" :rangeInfoText="rangeInfoText(weeks)" :multiple="multiple" :range="range" :calendar="calendar" :selected="selected" :lunar="lunar" :color="color" @change="choiceDate"></calendar-item>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import mpMixin from '@climblee/uv-ui/libs/mixin/mpMixin.js';
|
||||
import mixin from '@climblee/uv-ui/libs/mixin/mixin.js';
|
||||
|
||||
import CalendarItem from './calendar-item.vue';
|
||||
|
||||
import { initVueI18n } from '@dcloudio/uni-i18n';
|
||||
import i18nMessages from './i18n/index.js';
|
||||
const { t } = initVueI18n(i18nMessages);
|
||||
export default {
|
||||
mixins: [mpMixin, mixin],
|
||||
components: {
|
||||
CalendarItem
|
||||
},
|
||||
props: {
|
||||
date: {
|
||||
type: [String,Array],
|
||||
default: ''
|
||||
},
|
||||
nowDate: {
|
||||
type: [String, Object],
|
||||
default: ''
|
||||
},
|
||||
weeks: {
|
||||
type: [Array, Object],
|
||||
default () {
|
||||
return []
|
||||
}
|
||||
},
|
||||
calendar: {
|
||||
type: Object,
|
||||
default () {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
selected: {
|
||||
type: Array,
|
||||
default () {
|
||||
return []
|
||||
}
|
||||
},
|
||||
lunar: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
showMonth: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
color: {
|
||||
type: String,
|
||||
default: '#3c9cff'
|
||||
},
|
||||
startText: {
|
||||
type: String,
|
||||
default: '开始'
|
||||
},
|
||||
endText: {
|
||||
type: String,
|
||||
default: '结束'
|
||||
},
|
||||
range: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
multiple: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 是否允许日期范围的起止时间为同一天,mode = range时有效
|
||||
allowSameDay: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
getDate() {
|
||||
return Array.isArray(this.date) ? this.date[0] : this.date;
|
||||
},
|
||||
/**
|
||||
* for i18n
|
||||
*/
|
||||
todayText() {
|
||||
return t("uv-calender.today")
|
||||
},
|
||||
monText() {
|
||||
return t("uv-calender.MON")
|
||||
},
|
||||
TUEText() {
|
||||
return t("uv-calender.TUE")
|
||||
},
|
||||
WEDText() {
|
||||
return t("uv-calender.WED")
|
||||
},
|
||||
THUText() {
|
||||
return t("uv-calender.THU")
|
||||
},
|
||||
FRIText() {
|
||||
return t("uv-calender.FRI")
|
||||
},
|
||||
SATText() {
|
||||
return t("uv-calender.SAT")
|
||||
},
|
||||
SUNText() {
|
||||
return t("uv-calender.SUN")
|
||||
},
|
||||
rangeInfoText(weeks) {
|
||||
return weeks=> {
|
||||
if(this.allowSameDay && weeks.beforeRange && weeks.afterRange && weeks.dateEqual) {
|
||||
return this.setInfo(weeks,`${this.startText}/${this.endText}`);
|
||||
}
|
||||
if(weeks.beforeRange) {
|
||||
return this.setInfo(weeks,this.startText);
|
||||
}
|
||||
if(weeks.afterRange) {
|
||||
return this.setInfo(weeks,this.endText);
|
||||
}
|
||||
if(weeks.extraInfo?.info_old == ' ') {
|
||||
weeks.extraInfo.info = null;
|
||||
}else if(weeks.extraInfo?.info_old) {
|
||||
weeks.extraInfo.info = weeks.extraInfo.info_old;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
setInfo(weeks,text) {
|
||||
this.setInfoOld(weeks);
|
||||
if(weeks.extraInfo) {
|
||||
weeks.extraInfo.info = text;
|
||||
}else {
|
||||
weeks.extraInfo = {
|
||||
info: text
|
||||
}
|
||||
}
|
||||
},
|
||||
setInfoOld(weeks) {
|
||||
if(weeks.extraInfo) {
|
||||
weeks.extraInfo.info_old = weeks.extraInfo.info ? weeks.extraInfo.info_old || weeks.extraInfo.info : ' ';
|
||||
}
|
||||
},
|
||||
bindDateChange(e) {
|
||||
this.$emit('bindDateChange', e);
|
||||
},
|
||||
backToday() {
|
||||
this.$emit('backToday');
|
||||
},
|
||||
pre() {
|
||||
this.$emit('pre');
|
||||
},
|
||||
next() {
|
||||
this.$emit('next');
|
||||
},
|
||||
choiceDate(e) {
|
||||
this.$emit('choiceDate', e);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@mixin flex($direction: row) {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: $direction;
|
||||
}
|
||||
$uv-bg-color-mask: rgba($color: #000000, $alpha: 0.4);
|
||||
$uv-border-color: #EDEDED !default;
|
||||
$uv-text-color: #333;
|
||||
$uv-bg-color-hover: #f1f1f1;
|
||||
$uv-font-size-base: 14px;
|
||||
$uv-text-color-placeholder: #808080;
|
||||
$uv-color-subtitle: #555555;
|
||||
$uv-text-color-grey: #999;
|
||||
.uv-calendar {
|
||||
@include flex(column);
|
||||
}
|
||||
.uv-calendar__mask {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-color: $uv-bg-color-mask;
|
||||
transition-property: opacity;
|
||||
transition-duration: 0.3s;
|
||||
opacity: 0;
|
||||
/* #ifndef APP-NVUE */
|
||||
z-index: 99;
|
||||
/* #endif */
|
||||
}
|
||||
.uv-calendar--mask-show {
|
||||
opacity: 1
|
||||
}
|
||||
.uv-calendar--fixed {
|
||||
position: fixed;
|
||||
/* #ifdef APP-NVUE */
|
||||
bottom: 0;
|
||||
/* #endif */
|
||||
left: 0;
|
||||
right: 0;
|
||||
transition-property: transform;
|
||||
transition-duration: 0.3s;
|
||||
transform: translateY(460px);
|
||||
/* #ifndef APP-NVUE */
|
||||
bottom: calc(var(--window-bottom));
|
||||
z-index: 99;
|
||||
/* #endif */
|
||||
}
|
||||
.uv-calendar--ani-show {
|
||||
transform: translateY(0);
|
||||
}
|
||||
.uv-calendar__content {
|
||||
background-color: #fff;
|
||||
}
|
||||
.uv-calendar__header {
|
||||
position: relative;
|
||||
@include flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 50px;
|
||||
border-bottom-color: $uv-border-color;
|
||||
border-bottom-style: solid;
|
||||
border-bottom-width: 1px;
|
||||
}
|
||||
.uv-calendar--fixed-top {
|
||||
@include flex;
|
||||
justify-content: space-between;
|
||||
border-top-color: $uv-border-color;
|
||||
border-top-style: solid;
|
||||
border-top-width: 1px;
|
||||
}
|
||||
.uv-calendar--fixed-width {
|
||||
width: 50px;
|
||||
}
|
||||
.uv-calendar__backtoday {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 25rpx;
|
||||
padding: 0 5px;
|
||||
padding-left: 10px;
|
||||
height: 25px;
|
||||
line-height: 25px;
|
||||
font-size: 12px;
|
||||
border-top-left-radius: 25px;
|
||||
border-bottom-left-radius: 25px;
|
||||
color: $uv-text-color;
|
||||
background-color: $uv-bg-color-hover;
|
||||
}
|
||||
.uv-calendar__header-text {
|
||||
text-align: center;
|
||||
width: 100px;
|
||||
font-size: $uv-font-size-base;
|
||||
color: $uv-text-color;
|
||||
}
|
||||
.uv-calendar__header-btn-box {
|
||||
@include flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
}
|
||||
.uv-calendar__header-btn {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-left-color: $uv-text-color-placeholder;
|
||||
border-left-style: solid;
|
||||
border-left-width: 2px;
|
||||
border-top-color: $uv-color-subtitle;
|
||||
border-top-style: solid;
|
||||
border-top-width: 2px;
|
||||
}
|
||||
.uv-calendar--left {
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
.uv-calendar--right {
|
||||
transform: rotate(135deg);
|
||||
}
|
||||
.uv-calendar__weeks {
|
||||
position: relative;
|
||||
@include flex;
|
||||
}
|
||||
.uv-calendar__weeks-week {
|
||||
padding: 0 0 2rpx;
|
||||
}
|
||||
.uv-calendar__weeks-item {
|
||||
flex: 1;
|
||||
}
|
||||
.uv-calendar__weeks-day {
|
||||
flex: 1;
|
||||
@include flex(column);
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 45px;
|
||||
border-bottom-color: #F5F5F5;
|
||||
border-bottom-style: solid;
|
||||
border-bottom-width: 1px;
|
||||
}
|
||||
.uv-calendar__weeks-day-text {
|
||||
font-size: 14px;
|
||||
}
|
||||
.uv-calendar__box {
|
||||
position: relative;
|
||||
}
|
||||
.uv-calendar__box-bg {
|
||||
@include flex(column);
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
.uv-calendar__box-bg-text {
|
||||
font-size: 200px;
|
||||
font-weight: bold;
|
||||
color: $uv-text-color-grey;
|
||||
opacity: 0.1;
|
||||
text-align: center;
|
||||
/* #ifndef APP-NVUE */
|
||||
line-height: 1;
|
||||
/* #endif */
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,347 +0,0 @@
|
|||
<template>
|
||||
<view
|
||||
class="uv-calendar-item__weeks-box"
|
||||
:class="{
|
||||
'uv-calendar-item--disable':
|
||||
weeks.disable || (weeks.extraInfo && weeks.extraInfo.disable),
|
||||
'uv-calendar-item--isDay':
|
||||
calendar.fullDate === weeks.fullDate && weeks.isDay && !multiple,
|
||||
'uv-calendar-item--checked':
|
||||
calendar.fullDate === weeks.fullDate && !weeks.isDay && !multiple,
|
||||
'uv-calendar-item--before-checked': weeks.beforeRange,
|
||||
'uv-calendar-item--range': weeks.range,
|
||||
'uv-calendar-item--after-checked': weeks.afterRange,
|
||||
'uv-calendar-item--multiple': weeks.multiple,
|
||||
}"
|
||||
:style="[itemBoxStyle]"
|
||||
@click="choiceDate(weeks)"
|
||||
>
|
||||
<view class="uv-calendar-item__weeks-box-item">
|
||||
<text
|
||||
v-if="selected && weeks.extraInfo && weeks.extraInfo.badge"
|
||||
:style="{ background: weeks.extraInfo.badgeBg }"
|
||||
class="uv-calendar-item__weeks-box-circle"
|
||||
></text>
|
||||
<text
|
||||
class="uv-calendar-item__weeks-top-text"
|
||||
v-if="weeks.extraInfo && weeks.extraInfo.topinfo"
|
||||
:style="[infoStyle('top')]"
|
||||
>{{ weeks.extraInfo && weeks.extraInfo.topinfo }}</text
|
||||
>
|
||||
<text
|
||||
class="uv-calendar-item__weeks-box-text"
|
||||
:class="{
|
||||
'uv-calendar-item--isDay-text': weeks.isDay,
|
||||
'uv-calendar-item--isDay':
|
||||
calendar.fullDate === weeks.fullDate && weeks.isDay && !multiple,
|
||||
'uv-calendar-item--checked':
|
||||
calendar.fullDate === weeks.fullDate && !weeks.isDay && !multiple,
|
||||
'uv-calendar-item--before-checked': weeks.beforeRange,
|
||||
'uv-calendar-item--range': weeks.range,
|
||||
'uv-calendar-item--after-checked': weeks.afterRange,
|
||||
'uv-calendar-item--multiple': weeks.multiple,
|
||||
'uv-calendar-item--disable':
|
||||
weeks.disable || (weeks.extraInfo && weeks.extraInfo.disable),
|
||||
}"
|
||||
:style="[itemBoxStyle]"
|
||||
>{{ weeks.date }}</text
|
||||
>
|
||||
<!-- <text
|
||||
v-if="!lunar && !weeks.extraInfo && weeks.isDay"
|
||||
class="uv-calendar-item__weeks-lunar-text"
|
||||
:class="{
|
||||
'uv-calendar-item--isDay-text': weeks.isDay,
|
||||
'uv-calendar-item--isDay':
|
||||
calendar.fullDate === weeks.fullDate && weeks.isDay && !multiple,
|
||||
'uv-calendar-item--checked':
|
||||
calendar.fullDate === weeks.fullDate && !weeks.isDay && !multiple,
|
||||
'uv-calendar-item--before-checked': weeks.beforeRange,
|
||||
'uv-calendar-item--range': weeks.range,
|
||||
'uv-calendar-item--after-checked': weeks.afterRange,
|
||||
'uv-calendar-item--multiple': weeks.multiple,
|
||||
}"
|
||||
:style="[itemBoxStyle]"
|
||||
>{{ todayText }}</text
|
||||
> -->
|
||||
<!-- <text
|
||||
v-if="lunar && !weeks.extraInfo"
|
||||
class="uv-calendar-item__weeks-lunar-text"
|
||||
:class="{
|
||||
'uv-calendar-item--isDay-text': weeks.isDay,
|
||||
'uv-calendar-item--isDay':
|
||||
calendar.fullDate === weeks.fullDate && weeks.isDay && !multiple,
|
||||
'uv-calendar-item--checked':
|
||||
calendar.fullDate === weeks.fullDate && !weeks.isDay && !multiple,
|
||||
'uv-calendar-item--before-checked': weeks.beforeRange,
|
||||
'uv-calendar-item--range': weeks.range,
|
||||
'uv-calendar-item--after-checked': weeks.afterRange,
|
||||
'uv-calendar-item--multiple': weeks.multiple,
|
||||
'uv-calendar-item--disable':
|
||||
weeks.disable || (weeks.extraInfo && weeks.extraInfo.disable),
|
||||
}"
|
||||
:style="[itemBoxStyle]"
|
||||
>{{
|
||||
weeks.isDay
|
||||
? todayText
|
||||
: weeks.lunar.IDayCn === '初一'
|
||||
? weeks.lunar.IMonthCn
|
||||
: weeks.lunar.IDayCn
|
||||
}}</text
|
||||
> -->
|
||||
<!-- <text
|
||||
v-if="weeks.extraInfo && weeks.extraInfo.info"
|
||||
class="uv-calendar-item__weeks-lunar-text"
|
||||
:class="{
|
||||
'uv-calendar-item__weeks-lunar-text--equal': weeks.dateEqual,
|
||||
}"
|
||||
:style="[infoStyle('bottom')]"
|
||||
>{{ weeks.extraInfo.info }}</text
|
||||
> -->
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
import { colorGradient } from '@climblee/uv-ui/libs/function/colorGradient.js'
|
||||
import { initVueI18n } from '@dcloudio/uni-i18n'
|
||||
import i18nMessages from './i18n/index.js'
|
||||
const { t } = initVueI18n(i18nMessages)
|
||||
export default {
|
||||
emits: ['change'],
|
||||
props: {
|
||||
weeks: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {}
|
||||
},
|
||||
},
|
||||
calendar: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
},
|
||||
},
|
||||
selected: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return []
|
||||
},
|
||||
},
|
||||
lunar: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
color: {
|
||||
type: String,
|
||||
default: '#3c9cff',
|
||||
},
|
||||
range: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
multiple: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
todayText() {
|
||||
return t('uv-calender.today')
|
||||
},
|
||||
itemBoxStyle() {
|
||||
const style = {}
|
||||
if (this.multiple) {
|
||||
// 多选状态
|
||||
if (this.weeks.multiple) {
|
||||
style.backgroundColor = this.color
|
||||
style.color = '#fff'
|
||||
} else if (this.weeks.isDay) {
|
||||
style.color = this.color
|
||||
}
|
||||
} else if (this.range) {
|
||||
// 范围选择
|
||||
if (this.weeks.beforeRange || this.weeks.afterRange) {
|
||||
style.backgroundColor = this.color
|
||||
} else if (this.weeks.range) {
|
||||
style.backgroundColor = colorGradient(this.color, '#ffffff', 100)[90]
|
||||
style.color = this.color
|
||||
style.opacity = 0.8
|
||||
style.borderRadius = 0
|
||||
}
|
||||
} else {
|
||||
if (this.weeks.isDay) {
|
||||
style.color = this.color
|
||||
}
|
||||
if (this.calendar.fullDate === this.weeks.fullDate) {
|
||||
style.backgroundColor = this.color
|
||||
style.color = '#fff'
|
||||
}
|
||||
}
|
||||
return style
|
||||
},
|
||||
infoStyle(val) {
|
||||
return (val) => {
|
||||
const style = {}
|
||||
if (!this.weeks.multiple) {
|
||||
if (val == 'top') {
|
||||
style.color = this.weeks.extraInfo.topinfoColor
|
||||
? this.weeks.extraInfo.topinfoColor
|
||||
: '#606266'
|
||||
} else if (val == 'bottom') {
|
||||
style.color = this.weeks.extraInfo.infoColor
|
||||
? this.weeks.extraInfo.infoColor
|
||||
: '#f56c6c'
|
||||
}
|
||||
if (this.weeks.range) {
|
||||
style.color = this.color
|
||||
}
|
||||
if (
|
||||
this.calendar.fullDate === this.weeks.fullDate ||
|
||||
this.weeks.beforeRange ||
|
||||
this.weeks.afterRange
|
||||
) {
|
||||
style.color = this.multiple ? style.color : '#fff'
|
||||
}
|
||||
} else {
|
||||
style.color = '#fff'
|
||||
}
|
||||
return style
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
choiceDate(weeks) {
|
||||
if (this.weeks.extraInfo && this.weeks.extraInfo.disable) return
|
||||
this.$emit('change', weeks)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.uv-calendar-item__weeks-box {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
.uv-calendar__weeks-item {
|
||||
// display: flex !important;
|
||||
// justify-content: center;
|
||||
// align-items: center;
|
||||
}
|
||||
.uv-calendar-item--checked {
|
||||
// width: 60rpx;
|
||||
// height: 60rpx;
|
||||
.uv-calendar-item__weeks-box-item {
|
||||
.uv-calendar-item__weeks-box-text {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
@apply flex-center rounded-full;
|
||||
}
|
||||
}
|
||||
}
|
||||
.uv-calendar-item--isDay {
|
||||
.uv-calendar-item__weeks-box-item {
|
||||
.uv-calendar-item__weeks-box-text {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
@apply flex-center rounded-full;
|
||||
}
|
||||
}
|
||||
}
|
||||
@mixin flex($direction: row) {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: $direction;
|
||||
}
|
||||
$uv-font-size-base: 14px;
|
||||
$uv-text-color: #333;
|
||||
$uv-font-size-sm: 24rpx;
|
||||
$uv-error: #f56c6c !default;
|
||||
$uv-opacity-disabled: 0.3;
|
||||
$uv-text-color-disable: #c0c0c0;
|
||||
$uv-primary: #3c9cff !default;
|
||||
$info-height: 32rpx;
|
||||
.uv-calendar-item__weeks-box {
|
||||
flex: 1;
|
||||
@include flex(column);
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.uv-calendar-item__weeks-top-text {
|
||||
height: $info-height;
|
||||
line-height: $info-height;
|
||||
font-size: $uv-font-size-sm;
|
||||
}
|
||||
.uv-calendar-item__weeks-box-text {
|
||||
font-size: $uv-font-size-base;
|
||||
color: $uv-text-color;
|
||||
}
|
||||
.uv-calendar-item__weeks-lunar-text {
|
||||
height: $info-height;
|
||||
line-height: $info-height;
|
||||
font-size: $uv-font-size-sm;
|
||||
color: $uv-text-color;
|
||||
}
|
||||
.uv-calendar-item__weeks-lunar-text--equal {
|
||||
/* #ifdef H5 */
|
||||
white-space: nowrap;
|
||||
transform: scale(0.8);
|
||||
/* #endif */
|
||||
/* #ifndef H5 */
|
||||
font-size: 20rpx;
|
||||
/* #endif */
|
||||
}
|
||||
.uv-calendar-item__weeks-box-item {
|
||||
position: relative;
|
||||
@include flex(column);
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 106rpx;
|
||||
height: 56px;
|
||||
}
|
||||
.uv-calendar-item__weeks-box-circle {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 5px;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 8px;
|
||||
background-color: $uv-error;
|
||||
}
|
||||
.uv-calendar-item--disable {
|
||||
background-color: rgba(249, 249, 249, $uv-opacity-disabled);
|
||||
color: $uv-text-color-disable;
|
||||
}
|
||||
.uv-calendar-item--isDay-text {
|
||||
color: $uv-primary;
|
||||
}
|
||||
.uv-calendar-item--isDay {
|
||||
background-color: $uv-primary;
|
||||
color: #fff;
|
||||
}
|
||||
.uv-calendar-item--checked {
|
||||
background-color: $uv-primary;
|
||||
color: #fff;
|
||||
border-radius: 4px;
|
||||
}
|
||||
// .uv-calendar-item--range {
|
||||
// background-color: $uv-primary;
|
||||
// color: #fff;
|
||||
// }
|
||||
.uv-calendar-item--before-checked {
|
||||
color: #fff;
|
||||
}
|
||||
.uv-calendar-item--after-checked {
|
||||
color: #fff;
|
||||
}
|
||||
.uv-calendar-item--multiple {
|
||||
background-color: $uv-primary;
|
||||
color: #fff;
|
||||
}
|
||||
.uv-calendar-item__weeks-box-circle {
|
||||
left: 50%;
|
||||
bottom: 0 !important;
|
||||
top:unset;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,546 +0,0 @@
|
|||
/**
|
||||
* @1900-2100区间内的公历、农历互转
|
||||
* @charset UTF-8
|
||||
* @github https://github.com/jjonline/calendar.js
|
||||
* @Author Jea杨(JJonline@JJonline.Cn)
|
||||
* @Time 2014-7-21
|
||||
* @Time 2016-8-13 Fixed 2033hex、Attribution Annals
|
||||
* @Time 2016-9-25 Fixed lunar LeapMonth Param Bug
|
||||
* @Time 2017-7-24 Fixed use getTerm Func Param Error.use solar year,NOT lunar year
|
||||
* @Version 1.0.3
|
||||
* @公历转农历:calendar.solar2lunar(1987,11,01); //[you can ignore params of prefix 0]
|
||||
* @农历转公历:calendar.lunar2solar(1987,09,10); //[you can ignore params of prefix 0]
|
||||
*/
|
||||
/* eslint-disable */
|
||||
var calendar = {
|
||||
|
||||
/**
|
||||
* 农历1900-2100的润大小信息表
|
||||
* @Array Of Property
|
||||
* @return Hex
|
||||
*/
|
||||
lunarInfo: [0x04bd8, 0x04ae0, 0x0a570, 0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0, 0x09ad0, 0x055d2, // 1900-1909
|
||||
0x04ae0, 0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540, 0x0d6a0, 0x0ada2, 0x095b0, 0x14977, // 1910-1919
|
||||
0x04970, 0x0a4b0, 0x0b4b5, 0x06a50, 0x06d40, 0x1ab54, 0x02b60, 0x09570, 0x052f2, 0x04970, // 1920-1929
|
||||
0x06566, 0x0d4a0, 0x0ea50, 0x06e95, 0x05ad0, 0x02b60, 0x186e3, 0x092e0, 0x1c8d7, 0x0c950, // 1930-1939
|
||||
0x0d4a0, 0x1d8a6, 0x0b550, 0x056a0, 0x1a5b4, 0x025d0, 0x092d0, 0x0d2b2, 0x0a950, 0x0b557, // 1940-1949
|
||||
0x06ca0, 0x0b550, 0x15355, 0x04da0, 0x0a5b0, 0x14573, 0x052b0, 0x0a9a8, 0x0e950, 0x06aa0, // 1950-1959
|
||||
0x0aea6, 0x0ab50, 0x04b60, 0x0aae4, 0x0a570, 0x05260, 0x0f263, 0x0d950, 0x05b57, 0x056a0, // 1960-1969
|
||||
0x096d0, 0x04dd5, 0x04ad0, 0x0a4d0, 0x0d4d4, 0x0d250, 0x0d558, 0x0b540, 0x0b6a0, 0x195a6, // 1970-1979
|
||||
0x095b0, 0x049b0, 0x0a974, 0x0a4b0, 0x0b27a, 0x06a50, 0x06d40, 0x0af46, 0x0ab60, 0x09570, // 1980-1989
|
||||
0x04af5, 0x04970, 0x064b0, 0x074a3, 0x0ea50, 0x06b58, 0x05ac0, 0x0ab60, 0x096d5, 0x092e0, // 1990-1999
|
||||
0x0c960, 0x0d954, 0x0d4a0, 0x0da50, 0x07552, 0x056a0, 0x0abb7, 0x025d0, 0x092d0, 0x0cab5, // 2000-2009
|
||||
0x0a950, 0x0b4a0, 0x0baa4, 0x0ad50, 0x055d9, 0x04ba0, 0x0a5b0, 0x15176, 0x052b0, 0x0a930, // 2010-2019
|
||||
0x07954, 0x06aa0, 0x0ad50, 0x05b52, 0x04b60, 0x0a6e6, 0x0a4e0, 0x0d260, 0x0ea65, 0x0d530, // 2020-2029
|
||||
0x05aa0, 0x076a3, 0x096d0, 0x04afb, 0x04ad0, 0x0a4d0, 0x1d0b6, 0x0d250, 0x0d520, 0x0dd45, // 2030-2039
|
||||
0x0b5a0, 0x056d0, 0x055b2, 0x049b0, 0x0a577, 0x0a4b0, 0x0aa50, 0x1b255, 0x06d20, 0x0ada0, // 2040-2049
|
||||
/** Add By JJonline@JJonline.Cn**/
|
||||
0x14b63, 0x09370, 0x049f8, 0x04970, 0x064b0, 0x168a6, 0x0ea50, 0x06b20, 0x1a6c4, 0x0aae0, // 2050-2059
|
||||
0x0a2e0, 0x0d2e3, 0x0c960, 0x0d557, 0x0d4a0, 0x0da50, 0x05d55, 0x056a0, 0x0a6d0, 0x055d4, // 2060-2069
|
||||
0x052d0, 0x0a9b8, 0x0a950, 0x0b4a0, 0x0b6a6, 0x0ad50, 0x055a0, 0x0aba4, 0x0a5b0, 0x052b0, // 2070-2079
|
||||
0x0b273, 0x06930, 0x07337, 0x06aa0, 0x0ad50, 0x14b55, 0x04b60, 0x0a570, 0x054e4, 0x0d160, // 2080-2089
|
||||
0x0e968, 0x0d520, 0x0daa0, 0x16aa6, 0x056d0, 0x04ae0, 0x0a9d4, 0x0a2d0, 0x0d150, 0x0f252, // 2090-2099
|
||||
0x0d520], // 2100
|
||||
|
||||
/**
|
||||
* 公历每个月份的天数普通表
|
||||
* @Array Of Property
|
||||
* @return Number
|
||||
*/
|
||||
solarMonth: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
|
||||
|
||||
/**
|
||||
* 天干地支之天干速查表
|
||||
* @Array Of Property trans["甲","乙","丙","丁","戊","己","庚","辛","壬","癸"]
|
||||
* @return Cn string
|
||||
*/
|
||||
Gan: ['\u7532', '\u4e59', '\u4e19', '\u4e01', '\u620a', '\u5df1', '\u5e9a', '\u8f9b', '\u58ec', '\u7678'],
|
||||
|
||||
/**
|
||||
* 天干地支之地支速查表
|
||||
* @Array Of Property
|
||||
* @trans["子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥"]
|
||||
* @return Cn string
|
||||
*/
|
||||
Zhi: ['\u5b50', '\u4e11', '\u5bc5', '\u536f', '\u8fb0', '\u5df3', '\u5348', '\u672a', '\u7533', '\u9149', '\u620c', '\u4ea5'],
|
||||
|
||||
/**
|
||||
* 天干地支之地支速查表<=>生肖
|
||||
* @Array Of Property
|
||||
* @trans["鼠","牛","虎","兔","龙","蛇","马","羊","猴","鸡","狗","猪"]
|
||||
* @return Cn string
|
||||
*/
|
||||
Animals: ['\u9f20', '\u725b', '\u864e', '\u5154', '\u9f99', '\u86c7', '\u9a6c', '\u7f8a', '\u7334', '\u9e21', '\u72d7', '\u732a'],
|
||||
|
||||
/**
|
||||
* 24节气速查表
|
||||
* @Array Of Property
|
||||
* @trans["小寒","大寒","立春","雨水","惊蛰","春分","清明","谷雨","立夏","小满","芒种","夏至","小暑","大暑","立秋","处暑","白露","秋分","寒露","霜降","立冬","小雪","大雪","冬至"]
|
||||
* @return Cn string
|
||||
*/
|
||||
solarTerm: ['\u5c0f\u5bd2', '\u5927\u5bd2', '\u7acb\u6625', '\u96e8\u6c34', '\u60ca\u86f0', '\u6625\u5206', '\u6e05\u660e', '\u8c37\u96e8', '\u7acb\u590f', '\u5c0f\u6ee1', '\u8292\u79cd', '\u590f\u81f3', '\u5c0f\u6691', '\u5927\u6691', '\u7acb\u79cb', '\u5904\u6691', '\u767d\u9732', '\u79cb\u5206', '\u5bd2\u9732', '\u971c\u964d', '\u7acb\u51ac', '\u5c0f\u96ea', '\u5927\u96ea', '\u51ac\u81f3'],
|
||||
|
||||
/**
|
||||
* 1900-2100各年的24节气日期速查表
|
||||
* @Array Of Property
|
||||
* @return 0x string For splice
|
||||
*/
|
||||
sTermInfo: ['9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf97c3598082c95f8c965cc920f',
|
||||
'97bd0b06bdb0722c965ce1cfcc920f', 'b027097bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
|
||||
'97bcf97c359801ec95f8c965cc920f', '97bd0b06bdb0722c965ce1cfcc920f', 'b027097bd097c36b0b6fc9274c91aa',
|
||||
'97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f', '97bd0b06bdb0722c965ce1cfcc920f',
|
||||
'b027097bd097c36b0b6fc9274c91aa', '9778397bd19801ec9210c965cc920e', '97b6b97bd19801ec95f8c965cc920f',
|
||||
'97bd09801d98082c95f8e1cfcc920f', '97bd097bd097c36b0b6fc9210c8dc2', '9778397bd197c36c9210c9274c91aa',
|
||||
'97b6b97bd19801ec95f8c965cc920e', '97bd09801d98082c95f8e1cfcc920f', '97bd097bd097c36b0b6fc9210c8dc2',
|
||||
'9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec95f8c965cc920e', '97bcf97c3598082c95f8e1cfcc920f',
|
||||
'97bd097bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec9210c965cc920e',
|
||||
'97bcf97c3598082c95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
|
||||
'97b6b97bd19801ec9210c965cc920e', '97bcf97c3598082c95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722',
|
||||
'9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f',
|
||||
'97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
|
||||
'97bcf97c359801ec95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
|
||||
'97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f', '97bd097bd07f595b0b6fc920fb0722',
|
||||
'9778397bd097c36b0b6fc9210c8dc2', '9778397bd19801ec9210c9274c920e', '97b6b97bd19801ec95f8c965cc920f',
|
||||
'97bd07f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c920e',
|
||||
'97b6b97bd19801ec95f8c965cc920f', '97bd07f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2',
|
||||
'9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bd07f1487f595b0b0bc920fb0722',
|
||||
'7f0e397bd097c36b0b6fc9210c8dc2', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
|
||||
'97bcf7f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
|
||||
'97b6b97bd19801ec9210c965cc920e', '97bcf7f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722',
|
||||
'9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf7f1487f531b0b0bb0b6fb0722',
|
||||
'7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
|
||||
'97bcf7f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
|
||||
'97b6b97bd19801ec9210c9274c920e', '97bcf7f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722',
|
||||
'9778397bd097c36b0b6fc9210c91aa', '97b6b97bd197c36c9210c9274c920e', '97bcf7f0e47f531b0b0bb0b6fb0722',
|
||||
'7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c920e',
|
||||
'97b6b7f0e47f531b0723b0b6fb0722', '7f0e37f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2',
|
||||
'9778397bd097c36b0b70c9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', '7f0e37f1487f595b0b0bb0b6fb0722',
|
||||
'7f0e397bd097c35b0b6fc9210c8dc2', '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721',
|
||||
'7f0e27f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
|
||||
'97b6b7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722',
|
||||
'9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722',
|
||||
'7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721',
|
||||
'7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
|
||||
'97b6b7f0e47f531b0723b0787b0721', '7f0e27f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722',
|
||||
'9778397bd097c36b0b6fc9210c91aa', '97b6b7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722',
|
||||
'7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9210c8dc2', '977837f0e37f149b0723b0787b0721',
|
||||
'7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f5307f595b0b0bc920fb0722', '7f0e397bd097c35b0b6fc9210c8dc2',
|
||||
'977837f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e37f1487f595b0b0bb0b6fb0722',
|
||||
'7f0e397bd097c35b0b6fc9210c8dc2', '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
|
||||
'7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '977837f0e37f14998082b0787b06bd',
|
||||
'7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722',
|
||||
'977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722',
|
||||
'7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
|
||||
'7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14998082b0787b06bd',
|
||||
'7f07e7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722',
|
||||
'977837f0e37f14998082b0723b06bd', '7f07e7f0e37f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722',
|
||||
'7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b0721',
|
||||
'7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f1487f595b0b0bb0b6fb0722', '7f0e37f0e37f14898082b0723b02d5',
|
||||
'7ec967f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f1487f531b0b0bb0b6fb0722',
|
||||
'7f0e37f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
|
||||
'7f0e37f1487f531b0b0bb0b6fb0722', '7f0e37f0e37f14898082b072297c35', '7ec967f0e37f14998082b0787b06bd',
|
||||
'7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e37f0e37f14898082b072297c35',
|
||||
'7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722',
|
||||
'7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f149b0723b0787b0721',
|
||||
'7f0e27f1487f531b0b0bb0b6fb0722', '7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14998082b0723b06bd',
|
||||
'7f07e7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722', '7f0e37f0e366aa89801eb072297c35',
|
||||
'7ec967f0e37f14998082b0723b06bd', '7f07e7f0e37f14998083b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722',
|
||||
'7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14898082b0723b02d5', '7f07e7f0e37f14998082b0787b0721',
|
||||
'7f07e7f0e47f531b0723b0b6fb0722', '7f0e36665b66aa89801e9808297c35', '665f67f0e37f14898082b0723b02d5',
|
||||
'7ec967f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0722', '7f0e36665b66a449801e9808297c35',
|
||||
'665f67f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
|
||||
'7f0e36665b66a449801e9808297c35', '665f67f0e37f14898082b072297c35', '7ec967f0e37f14998082b0787b06bd',
|
||||
'7f07e7f0e47f531b0723b0b6fb0721', '7f0e26665b66a449801e9808297c35', '665f67f0e37f1489801eb072297c35',
|
||||
'7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722'],
|
||||
|
||||
/**
|
||||
* 数字转中文速查表
|
||||
* @Array Of Property
|
||||
* @trans ['日','一','二','三','四','五','六','七','八','九','十']
|
||||
* @return Cn string
|
||||
*/
|
||||
nStr1: ['\u65e5', '\u4e00', '\u4e8c', '\u4e09', '\u56db', '\u4e94', '\u516d', '\u4e03', '\u516b', '\u4e5d', '\u5341'],
|
||||
|
||||
/**
|
||||
* 日期转农历称呼速查表
|
||||
* @Array Of Property
|
||||
* @trans ['初','十','廿','卅']
|
||||
* @return Cn string
|
||||
*/
|
||||
nStr2: ['\u521d', '\u5341', '\u5eff', '\u5345'],
|
||||
|
||||
/**
|
||||
* 月份转农历称呼速查表
|
||||
* @Array Of Property
|
||||
* @trans ['正','一','二','三','四','五','六','七','八','九','十','冬','腊']
|
||||
* @return Cn string
|
||||
*/
|
||||
nStr3: ['\u6b63', '\u4e8c', '\u4e09', '\u56db', '\u4e94', '\u516d', '\u4e03', '\u516b', '\u4e5d', '\u5341', '\u51ac', '\u814a'],
|
||||
|
||||
/**
|
||||
* 返回农历y年一整年的总天数
|
||||
* @param lunar Year
|
||||
* @return Number
|
||||
* @eg:var count = calendar.lYearDays(1987) ;//count=387
|
||||
*/
|
||||
lYearDays: function (y) {
|
||||
var i; var sum = 348
|
||||
for (i = 0x8000; i > 0x8; i >>= 1) { sum += (this.lunarInfo[y - 1900] & i) ? 1 : 0 }
|
||||
return (sum + this.leapDays(y))
|
||||
},
|
||||
|
||||
/**
|
||||
* 返回农历y年闰月是哪个月;若y年没有闰月 则返回0
|
||||
* @param lunar Year
|
||||
* @return Number (0-12)
|
||||
* @eg:var leapMonth = calendar.leapMonth(1987) ;//leapMonth=6
|
||||
*/
|
||||
leapMonth: function (y) { // 闰字编码 \u95f0
|
||||
return (this.lunarInfo[y - 1900] & 0xf)
|
||||
},
|
||||
|
||||
/**
|
||||
* 返回农历y年闰月的天数 若该年没有闰月则返回0
|
||||
* @param lunar Year
|
||||
* @return Number (0、29、30)
|
||||
* @eg:var leapMonthDay = calendar.leapDays(1987) ;//leapMonthDay=29
|
||||
*/
|
||||
leapDays: function (y) {
|
||||
if (this.leapMonth(y)) {
|
||||
return ((this.lunarInfo[y - 1900] & 0x10000) ? 30 : 29)
|
||||
}
|
||||
return (0)
|
||||
},
|
||||
|
||||
/**
|
||||
* 返回农历y年m月(非闰月)的总天数,计算m为闰月时的天数请使用leapDays方法
|
||||
* @param lunar Year
|
||||
* @return Number (-1、29、30)
|
||||
* @eg:var MonthDay = calendar.monthDays(1987,9) ;//MonthDay=29
|
||||
*/
|
||||
monthDays: function (y, m) {
|
||||
if (m > 12 || m < 1) { return -1 }// 月份参数从1至12,参数错误返回-1
|
||||
return ((this.lunarInfo[y - 1900] & (0x10000 >> m)) ? 30 : 29)
|
||||
},
|
||||
|
||||
/**
|
||||
* 返回公历(!)y年m月的天数
|
||||
* @param solar Year
|
||||
* @return Number (-1、28、29、30、31)
|
||||
* @eg:var solarMonthDay = calendar.leapDays(1987) ;//solarMonthDay=30
|
||||
*/
|
||||
solarDays: function (y, m) {
|
||||
if (m > 12 || m < 1) { return -1 } // 若参数错误 返回-1
|
||||
var ms = m - 1
|
||||
if (ms == 1) { // 2月份的闰平规律测算后确认返回28或29
|
||||
return (((y % 4 == 0) && (y % 100 != 0) || (y % 400 == 0)) ? 29 : 28)
|
||||
} else {
|
||||
return (this.solarMonth[ms])
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 农历年份转换为干支纪年
|
||||
* @param lYear 农历年的年份数
|
||||
* @return Cn string
|
||||
*/
|
||||
toGanZhiYear: function (lYear) {
|
||||
var ganKey = (lYear - 3) % 10
|
||||
var zhiKey = (lYear - 3) % 12
|
||||
if (ganKey == 0) ganKey = 10// 如果余数为0则为最后一个天干
|
||||
if (zhiKey == 0) zhiKey = 12// 如果余数为0则为最后一个地支
|
||||
return this.Gan[ganKey - 1] + this.Zhi[zhiKey - 1]
|
||||
},
|
||||
|
||||
/**
|
||||
* 公历月、日判断所属星座
|
||||
* @param cMonth [description]
|
||||
* @param cDay [description]
|
||||
* @return Cn string
|
||||
*/
|
||||
toAstro: function (cMonth, cDay) {
|
||||
var s = '\u9b54\u7faf\u6c34\u74f6\u53cc\u9c7c\u767d\u7f8a\u91d1\u725b\u53cc\u5b50\u5de8\u87f9\u72ee\u5b50\u5904\u5973\u5929\u79e4\u5929\u874e\u5c04\u624b\u9b54\u7faf'
|
||||
var arr = [20, 19, 21, 21, 21, 22, 23, 23, 23, 23, 22, 22]
|
||||
return s.substr(cMonth * 2 - (cDay < arr[cMonth - 1] ? 2 : 0), 2) + '\u5ea7'// 座
|
||||
},
|
||||
|
||||
/**
|
||||
* 传入offset偏移量返回干支
|
||||
* @param offset 相对甲子的偏移量
|
||||
* @return Cn string
|
||||
*/
|
||||
toGanZhi: function (offset) {
|
||||
return this.Gan[offset % 10] + this.Zhi[offset % 12]
|
||||
},
|
||||
|
||||
/**
|
||||
* 传入公历(!)y年获得该年第n个节气的公历日期
|
||||
* @param y公历年(1900-2100);n二十四节气中的第几个节气(1~24);从n=1(小寒)算起
|
||||
* @return day Number
|
||||
* @eg:var _24 = calendar.getTerm(1987,3) ;//_24=4;意即1987年2月4日立春
|
||||
*/
|
||||
getTerm: function (y, n) {
|
||||
if (y < 1900 || y > 2100) { return -1 }
|
||||
if (n < 1 || n > 24) { return -1 }
|
||||
var _table = this.sTermInfo[y - 1900]
|
||||
var _info = [
|
||||
parseInt('0x' + _table.substr(0, 5)).toString(),
|
||||
parseInt('0x' + _table.substr(5, 5)).toString(),
|
||||
parseInt('0x' + _table.substr(10, 5)).toString(),
|
||||
parseInt('0x' + _table.substr(15, 5)).toString(),
|
||||
parseInt('0x' + _table.substr(20, 5)).toString(),
|
||||
parseInt('0x' + _table.substr(25, 5)).toString()
|
||||
]
|
||||
var _calday = [
|
||||
_info[0].substr(0, 1),
|
||||
_info[0].substr(1, 2),
|
||||
_info[0].substr(3, 1),
|
||||
_info[0].substr(4, 2),
|
||||
|
||||
_info[1].substr(0, 1),
|
||||
_info[1].substr(1, 2),
|
||||
_info[1].substr(3, 1),
|
||||
_info[1].substr(4, 2),
|
||||
|
||||
_info[2].substr(0, 1),
|
||||
_info[2].substr(1, 2),
|
||||
_info[2].substr(3, 1),
|
||||
_info[2].substr(4, 2),
|
||||
|
||||
_info[3].substr(0, 1),
|
||||
_info[3].substr(1, 2),
|
||||
_info[3].substr(3, 1),
|
||||
_info[3].substr(4, 2),
|
||||
|
||||
_info[4].substr(0, 1),
|
||||
_info[4].substr(1, 2),
|
||||
_info[4].substr(3, 1),
|
||||
_info[4].substr(4, 2),
|
||||
|
||||
_info[5].substr(0, 1),
|
||||
_info[5].substr(1, 2),
|
||||
_info[5].substr(3, 1),
|
||||
_info[5].substr(4, 2)
|
||||
]
|
||||
return parseInt(_calday[n - 1])
|
||||
},
|
||||
|
||||
/**
|
||||
* 传入农历数字月份返回汉语通俗表示法
|
||||
* @param lunar month
|
||||
* @return Cn string
|
||||
* @eg:var cnMonth = calendar.toChinaMonth(12) ;//cnMonth='腊月'
|
||||
*/
|
||||
toChinaMonth: function (m) { // 月 => \u6708
|
||||
if (m > 12 || m < 1) { return -1 } // 若参数错误 返回-1
|
||||
var s = this.nStr3[m - 1]
|
||||
s += '\u6708'// 加上月字
|
||||
return s
|
||||
},
|
||||
|
||||
/**
|
||||
* 传入农历日期数字返回汉字表示法
|
||||
* @param lunar day
|
||||
* @return Cn string
|
||||
* @eg:var cnDay = calendar.toChinaDay(21) ;//cnMonth='廿一'
|
||||
*/
|
||||
toChinaDay: function (d) { // 日 => \u65e5
|
||||
var s
|
||||
switch (d) {
|
||||
case 10:
|
||||
s = '\u521d\u5341'; break
|
||||
case 20:
|
||||
s = '\u4e8c\u5341'; break
|
||||
break
|
||||
case 30:
|
||||
s = '\u4e09\u5341'; break
|
||||
break
|
||||
default :
|
||||
s = this.nStr2[Math.floor(d / 10)]
|
||||
s += this.nStr1[d % 10]
|
||||
}
|
||||
return (s)
|
||||
},
|
||||
|
||||
/**
|
||||
* 年份转生肖[!仅能大致转换] => 精确划分生肖分界线是“立春”
|
||||
* @param y year
|
||||
* @return Cn string
|
||||
* @eg:var animal = calendar.getAnimal(1987) ;//animal='兔'
|
||||
*/
|
||||
getAnimal: function (y) {
|
||||
return this.Animals[(y - 4) % 12]
|
||||
},
|
||||
|
||||
/**
|
||||
* 传入阳历年月日获得详细的公历、农历object信息 <=>JSON
|
||||
* @param y solar year
|
||||
* @param m solar month
|
||||
* @param d solar day
|
||||
* @return JSON object
|
||||
* @eg:console.log(calendar.solar2lunar(1987,11,01));
|
||||
*/
|
||||
solar2lunar: function (y, m, d) { // 参数区间1900.1.31~2100.12.31
|
||||
// 年份限定、上限
|
||||
if (y < 1900 || y > 2100) {
|
||||
return -1// undefined转换为数字变为NaN
|
||||
}
|
||||
// 公历传参最下限
|
||||
if (y == 1900 && m == 1 && d < 31) {
|
||||
return -1
|
||||
}
|
||||
// 未传参 获得当天
|
||||
if (!y) {
|
||||
var objDate = new Date()
|
||||
} else {
|
||||
var objDate = new Date(y, parseInt(m) - 1, d)
|
||||
}
|
||||
var i; var leap = 0; var temp = 0
|
||||
// 修正ymd参数
|
||||
var y = objDate.getFullYear()
|
||||
var m = objDate.getMonth() + 1
|
||||
var d = objDate.getDate()
|
||||
var offset = (Date.UTC(objDate.getFullYear(), objDate.getMonth(), objDate.getDate()) - Date.UTC(1900, 0, 31)) / 86400000
|
||||
for (i = 1900; i < 2101 && offset > 0; i++) {
|
||||
temp = this.lYearDays(i)
|
||||
offset -= temp
|
||||
}
|
||||
if (offset < 0) {
|
||||
offset += temp; i--
|
||||
}
|
||||
|
||||
// 是否今天
|
||||
var isTodayObj = new Date()
|
||||
var isToday = false
|
||||
if (isTodayObj.getFullYear() == y && isTodayObj.getMonth() + 1 == m && isTodayObj.getDate() == d) {
|
||||
isToday = true
|
||||
}
|
||||
// 星期几
|
||||
var nWeek = objDate.getDay()
|
||||
var cWeek = this.nStr1[nWeek]
|
||||
// 数字表示周几顺应天朝周一开始的惯例
|
||||
if (nWeek == 0) {
|
||||
nWeek = 7
|
||||
}
|
||||
// 农历年
|
||||
var year = i
|
||||
var leap = this.leapMonth(i) // 闰哪个月
|
||||
var isLeap = false
|
||||
|
||||
// 效验闰月
|
||||
for (i = 1; i < 13 && offset > 0; i++) {
|
||||
// 闰月
|
||||
if (leap > 0 && i == (leap + 1) && isLeap == false) {
|
||||
--i
|
||||
isLeap = true; temp = this.leapDays(year) // 计算农历闰月天数
|
||||
} else {
|
||||
temp = this.monthDays(year, i)// 计算农历普通月天数
|
||||
}
|
||||
// 解除闰月
|
||||
if (isLeap == true && i == (leap + 1)) { isLeap = false }
|
||||
offset -= temp
|
||||
}
|
||||
// 闰月导致数组下标重叠取反
|
||||
if (offset == 0 && leap > 0 && i == leap + 1) {
|
||||
if (isLeap) {
|
||||
isLeap = false
|
||||
} else {
|
||||
isLeap = true; --i
|
||||
}
|
||||
}
|
||||
if (offset < 0) {
|
||||
offset += temp; --i
|
||||
}
|
||||
// 农历月
|
||||
var month = i
|
||||
// 农历日
|
||||
var day = offset + 1
|
||||
// 天干地支处理
|
||||
var sm = m - 1
|
||||
var gzY = this.toGanZhiYear(year)
|
||||
|
||||
// 当月的两个节气
|
||||
// bugfix-2017-7-24 11:03:38 use lunar Year Param `y` Not `year`
|
||||
var firstNode = this.getTerm(y, (m * 2 - 1))// 返回当月「节」为几日开始
|
||||
var secondNode = this.getTerm(y, (m * 2))// 返回当月「节」为几日开始
|
||||
|
||||
// 依据12节气修正干支月
|
||||
var gzM = this.toGanZhi((y - 1900) * 12 + m + 11)
|
||||
if (d >= firstNode) {
|
||||
gzM = this.toGanZhi((y - 1900) * 12 + m + 12)
|
||||
}
|
||||
|
||||
// 传入的日期的节气与否
|
||||
var isTerm = false
|
||||
var Term = null
|
||||
if (firstNode == d) {
|
||||
isTerm = true
|
||||
Term = this.solarTerm[m * 2 - 2]
|
||||
}
|
||||
if (secondNode == d) {
|
||||
isTerm = true
|
||||
Term = this.solarTerm[m * 2 - 1]
|
||||
}
|
||||
// 日柱 当月一日与 1900/1/1 相差天数
|
||||
var dayCyclical = Date.UTC(y, sm, 1, 0, 0, 0, 0) / 86400000 + 25567 + 10
|
||||
var gzD = this.toGanZhi(dayCyclical + d - 1)
|
||||
// 该日期所属的星座
|
||||
var astro = this.toAstro(m, d)
|
||||
|
||||
return { 'lYear': year, 'lMonth': month, 'lDay': day, 'Animal': this.getAnimal(year), 'IMonthCn': (isLeap ? '\u95f0' : '') + this.toChinaMonth(month), 'IDayCn': this.toChinaDay(day), 'cYear': y, 'cMonth': m, 'cDay': d, 'gzYear': gzY, 'gzMonth': gzM, 'gzDay': gzD, 'isToday': isToday, 'isLeap': isLeap, 'nWeek': nWeek, 'ncWeek': '\u661f\u671f' + cWeek, 'isTerm': isTerm, 'Term': Term, 'astro': astro }
|
||||
},
|
||||
|
||||
/**
|
||||
* 传入农历年月日以及传入的月份是否闰月获得详细的公历、农历object信息 <=>JSON
|
||||
* @param y lunar year
|
||||
* @param m lunar month
|
||||
* @param d lunar day
|
||||
* @param isLeapMonth lunar month is leap or not.[如果是农历闰月第四个参数赋值true即可]
|
||||
* @return JSON object
|
||||
* @eg:console.log(calendar.lunar2solar(1987,9,10));
|
||||
*/
|
||||
lunar2solar: function (y, m, d, isLeapMonth) { // 参数区间1900.1.31~2100.12.1
|
||||
var isLeapMonth = !!isLeapMonth
|
||||
var leapOffset = 0
|
||||
var leapMonth = this.leapMonth(y)
|
||||
var leapDay = this.leapDays(y)
|
||||
if (isLeapMonth && (leapMonth != m)) { return -1 }// 传参要求计算该闰月公历 但该年得出的闰月与传参的月份并不同
|
||||
if (y == 2100 && m == 12 && d > 1 || y == 1900 && m == 1 && d < 31) { return -1 }// 超出了最大极限值
|
||||
var day = this.monthDays(y, m)
|
||||
var _day = day
|
||||
// bugFix 2016-9-25
|
||||
// if month is leap, _day use leapDays method
|
||||
if (isLeapMonth) {
|
||||
_day = this.leapDays(y, m)
|
||||
}
|
||||
if (y < 1900 || y > 2100 || d > _day) { return -1 }// 参数合法性效验
|
||||
|
||||
// 计算农历的时间差
|
||||
var offset = 0
|
||||
for (var i = 1900; i < y; i++) {
|
||||
offset += this.lYearDays(i)
|
||||
}
|
||||
var leap = 0; var isAdd = false
|
||||
for (var i = 1; i < m; i++) {
|
||||
leap = this.leapMonth(y)
|
||||
if (!isAdd) { // 处理闰月
|
||||
if (leap <= i && leap > 0) {
|
||||
offset += this.leapDays(y); isAdd = true
|
||||
}
|
||||
}
|
||||
offset += this.monthDays(y, i)
|
||||
}
|
||||
// 转换闰月农历 需补充该年闰月的前一个月的时差
|
||||
if (isLeapMonth) { offset += day }
|
||||
// 1900年农历正月一日的公历时间为1900年1月30日0时0分0秒(该时间也是本农历的最开始起始点)
|
||||
var stmap = Date.UTC(1900, 1, 30, 0, 0, 0)
|
||||
var calObj = new Date((offset + d - 31) * 86400000 + stmap)
|
||||
var cY = calObj.getUTCFullYear()
|
||||
var cM = calObj.getUTCMonth() + 1
|
||||
var cD = calObj.getUTCDate()
|
||||
|
||||
return this.solar2lunar(cY, cM, cD)
|
||||
}
|
||||
}
|
||||
|
||||
export default calendar
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
{
|
||||
"uv-calender.ok": "ok",
|
||||
"uv-calender.cancel": "cancel",
|
||||
"uv-calender.today": "today",
|
||||
"uv-calender.MON": "MON",
|
||||
"uv-calender.TUE": "TUE",
|
||||
"uv-calender.WED": "WED",
|
||||
"uv-calender.THU": "THU",
|
||||
"uv-calender.FRI": "FRI",
|
||||
"uv-calender.SAT": "SAT",
|
||||
"uv-calender.SUN": "SUN"
|
||||
}
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
import en from './en.json'
|
||||
import zhHans from './zh-Hans.json'
|
||||
import zhHant from './zh-Hant.json'
|
||||
export default {
|
||||
en,
|
||||
'zh-Hans': zhHans,
|
||||
'zh-Hant': zhHant
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
{
|
||||
"uv-calender.ok": "确定",
|
||||
"uv-calender.cancel": "取消",
|
||||
"uv-calender.today": "今日",
|
||||
"uv-calender.SUN": "日",
|
||||
"uv-calender.MON": "一",
|
||||
"uv-calender.TUE": "二",
|
||||
"uv-calender.WED": "三",
|
||||
"uv-calender.THU": "四",
|
||||
"uv-calender.FRI": "五",
|
||||
"uv-calender.SAT": "六"
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
{
|
||||
"uv-calender.ok": "確定",
|
||||
"uv-calender.cancel": "取消",
|
||||
"uv-calender.today": "今日",
|
||||
"uv-calender.SUN": "日",
|
||||
"uv-calender.MON": "一",
|
||||
"uv-calender.TUE": "二",
|
||||
"uv-calender.WED": "三",
|
||||
"uv-calender.THU": "四",
|
||||
"uv-calender.FRI": "五",
|
||||
"uv-calender.SAT": "六"
|
||||
}
|
||||
|
|
@ -1,435 +0,0 @@
|
|||
import CALENDAR from './calendar.js'
|
||||
class Calendar {
|
||||
constructor({
|
||||
date,
|
||||
selected,
|
||||
startDate,
|
||||
endDate,
|
||||
range,
|
||||
multiple,
|
||||
allowSameDay
|
||||
} = {}) {
|
||||
// 当前日期
|
||||
this.date = this.getDate(new Date()) // 当前初入日期
|
||||
// 打点信息
|
||||
this.selected = selected || [];
|
||||
// 范围开始
|
||||
this.startDate = startDate
|
||||
// 范围结束
|
||||
this.endDate = endDate
|
||||
this.range = range
|
||||
this.multiple = multiple
|
||||
this.allowSameDay = allowSameDay
|
||||
// 多选状态
|
||||
this.cleanRangeStatus()
|
||||
// 范围状态
|
||||
this.cleanMultipleStatus()
|
||||
// 每周日期
|
||||
this.weeks = {}
|
||||
// this._getWeek(this.date.fullDate)
|
||||
}
|
||||
/**
|
||||
* 设置日期
|
||||
* @param {Object} date
|
||||
*/
|
||||
setDate(date, status) {
|
||||
if (this.range && status == 'init') {
|
||||
this.cleanRangeStatus();
|
||||
if (Array.isArray(date)) {
|
||||
this.rangeStatus.before = date[0];
|
||||
this.rangeStatus.after = date.length > 1 ? date[date.length - 1] : '';
|
||||
if (this.rangeStatus.after && this.dateCompare(this.rangeStatus.before, this.rangeStatus.after)) {
|
||||
this.rangeStatus.data = this.geDateAll(this.rangeStatus.before, this.rangeStatus.after)
|
||||
}
|
||||
this.selectDate = this.getDate(date[0])
|
||||
this._getWeek(this.selectDate.fullDate)
|
||||
} else {
|
||||
this.selectDate = this.getDate(date)
|
||||
this.rangeStatus.before = this.selectDate.fullDate;
|
||||
this._getWeek(this.selectDate.fullDate)
|
||||
}
|
||||
} else if (this.multiple && status == 'init') {
|
||||
this.cleanMultipleStatus();
|
||||
if (Array.isArray(date)) {
|
||||
this.multipleStatus.data = date;
|
||||
this.selectDate = this.getDate(date[0])
|
||||
this._getWeek(this.selectDate.fullDate)
|
||||
} else {
|
||||
this.selectDate = this.getDate(date)
|
||||
this.multipleStatus.data = [this.selectDate.fullDate];
|
||||
this._getWeek(this.selectDate.fullDate)
|
||||
}
|
||||
} else {
|
||||
if (Array.isArray(date)) {
|
||||
this.selectDate = this.getDate(date[0])
|
||||
this._getWeek(this.selectDate.fullDate)
|
||||
} else {
|
||||
this.selectDate = this.getDate(date)
|
||||
this._getWeek(this.selectDate.fullDate)
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 清理多选状态
|
||||
*/
|
||||
cleanRangeStatus() {
|
||||
this.rangeStatus = {
|
||||
before: '',
|
||||
after: '',
|
||||
data: []
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 清理多选状态
|
||||
*/
|
||||
cleanMultipleStatus() {
|
||||
this.multipleStatus = {
|
||||
data: []
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 重置开始日期
|
||||
*/
|
||||
resetSatrtDate(startDate) {
|
||||
// 范围开始
|
||||
this.startDate = startDate
|
||||
}
|
||||
/**
|
||||
* 重置结束日期
|
||||
*/
|
||||
resetEndDate(endDate) {
|
||||
// 范围结束
|
||||
this.endDate = endDate
|
||||
}
|
||||
/**
|
||||
* 获取任意时间
|
||||
*/
|
||||
getDate(date, AddDayCount = 0, str = 'day') {
|
||||
if (!date) {
|
||||
date = new Date()
|
||||
}
|
||||
if (typeof date !== 'object') {
|
||||
date = date.replace(/-/g, '/')
|
||||
}
|
||||
const dd = new Date(date)
|
||||
switch (str) {
|
||||
case 'day':
|
||||
dd.setDate(dd.getDate() + AddDayCount) // 获取AddDayCount天后的日期
|
||||
break
|
||||
case 'month':
|
||||
if (dd.getDate() === 31 && AddDayCount > 0) {
|
||||
dd.setDate(dd.getDate() + AddDayCount)
|
||||
} else {
|
||||
const preMonth = dd.getMonth()
|
||||
dd.setMonth(preMonth + AddDayCount) // 获取AddDayCount天后的日期
|
||||
const nextMonth = dd.getMonth()
|
||||
// 处理 pre 切换月份目标月份为2月没有当前日(30 31) 切换错误问题
|
||||
if (AddDayCount < 0 && preMonth !== 0 && nextMonth - preMonth > AddDayCount) {
|
||||
dd.setMonth(nextMonth + (nextMonth - preMonth + AddDayCount))
|
||||
}
|
||||
// 处理 next 切换月份目标月份为2月没有当前日(30 31) 切换错误问题
|
||||
if (AddDayCount > 0 && nextMonth - preMonth > AddDayCount) {
|
||||
dd.setMonth(nextMonth - (nextMonth - preMonth - AddDayCount))
|
||||
}
|
||||
}
|
||||
break
|
||||
case 'year':
|
||||
dd.setFullYear(dd.getFullYear() + AddDayCount) // 获取AddDayCount天后的日期
|
||||
break
|
||||
}
|
||||
const y = dd.getFullYear()
|
||||
const m = dd.getMonth() + 1 < 10 ? '0' + (dd.getMonth() + 1) : dd.getMonth() + 1 // 获取当前月份的日期,不足10补0
|
||||
const d = dd.getDate() < 10 ? '0' + dd.getDate() : dd.getDate() // 获取当前几号,不足10补0
|
||||
return {
|
||||
fullDate: y + '-' + m + '-' + d,
|
||||
year: y,
|
||||
month: m,
|
||||
date: d,
|
||||
day: dd.getDay()
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 获取上月剩余天数
|
||||
*/
|
||||
_getLastMonthDays(firstDay, full) {
|
||||
let dateArr = []
|
||||
for (let i = firstDay; i > 0; i--) {
|
||||
const beforeDate = new Date(full.year, full.month - 1, -i + 1).getDate()
|
||||
dateArr.push({
|
||||
date: beforeDate,
|
||||
month: full.month - 1,
|
||||
lunar: this.getlunar(full.year, full.month - 1, beforeDate),
|
||||
disable: true
|
||||
})
|
||||
}
|
||||
return dateArr
|
||||
}
|
||||
/**
|
||||
* 获取本月天数
|
||||
*/
|
||||
_currentMonthDys(dateData, full) {
|
||||
let dateArr = []
|
||||
let fullDate = this.date.fullDate
|
||||
for (let i = 1; i <= dateData; i++) {
|
||||
let nowDate = full.year + '-' + (full.month < 10 ? full.month : full.month) + '-' + (i < 10 ? '0' + i : i)
|
||||
// 是否今天
|
||||
let isDay = fullDate === nowDate
|
||||
// 获取打点信息
|
||||
let info = this.selected && this.selected.find((item) => {
|
||||
if (this.dateEqual(nowDate, item.date)) {
|
||||
return item
|
||||
}
|
||||
})
|
||||
// 日期禁用
|
||||
let disableBefore = true
|
||||
let disableAfter = true
|
||||
if (this.startDate) {
|
||||
// let dateCompBefore = this.dateCompare(this.startDate, fullDate)
|
||||
// disableBefore = this.dateCompare(dateCompBefore ? this.startDate : fullDate, nowDate)
|
||||
disableBefore = this.dateCompare(this.startDate, nowDate)
|
||||
}
|
||||
if (this.endDate) {
|
||||
// let dateCompAfter = this.dateCompare(fullDate, this.endDate)
|
||||
// disableAfter = this.dateCompare(nowDate, dateCompAfter ? this.endDate : fullDate)
|
||||
disableAfter = this.dateCompare(nowDate, this.endDate)
|
||||
}
|
||||
let ranges = this.rangeStatus.data
|
||||
let checked = false
|
||||
let rangesStatus = -1
|
||||
if (this.range) {
|
||||
if (ranges) {
|
||||
rangesStatus = ranges.findIndex((item) => {
|
||||
return this.dateEqual(item, nowDate)
|
||||
})
|
||||
}
|
||||
if (rangesStatus !== -1) {
|
||||
checked = true
|
||||
}
|
||||
}
|
||||
let multiples = this.multipleStatus.data
|
||||
let checked_multiple = false
|
||||
let multiplesStatus = -1
|
||||
if (this.multiple) {
|
||||
if (multiples) {
|
||||
multiplesStatus = multiples.findIndex((item) => {
|
||||
return this.dateEqual(item, nowDate)
|
||||
})
|
||||
}
|
||||
if (multiplesStatus !== -1) {
|
||||
checked_multiple = true
|
||||
}
|
||||
}
|
||||
let data = {
|
||||
fullDate: nowDate,
|
||||
year: full.year,
|
||||
date: i,
|
||||
range: this.range ? checked : false,
|
||||
multiple: this.multiple ? checked_multiple : false,
|
||||
beforeRange: this.dateEqual(this.rangeStatus.before, nowDate),
|
||||
afterRange: this.dateEqual(this.rangeStatus.after, nowDate),
|
||||
dateEqual: this.range && checked && this.dateEqual(this.rangeStatus.before, this.rangeStatus.after),
|
||||
month: full.month,
|
||||
lunar: this.getlunar(full.year, full.month, i),
|
||||
disable: !(disableBefore && disableAfter),
|
||||
isDay
|
||||
}
|
||||
if (info) {
|
||||
data.extraInfo = info
|
||||
}
|
||||
dateArr.push(data)
|
||||
}
|
||||
return dateArr
|
||||
}
|
||||
/**
|
||||
* 获取下月天数
|
||||
*/
|
||||
_getNextMonthDays(surplus, full) {
|
||||
let dateArr = []
|
||||
for (let i = 1; i < surplus + 1; i++) {
|
||||
dateArr.push({
|
||||
date: i,
|
||||
month: Number(full.month) + 1,
|
||||
lunar: this.getlunar(full.year, Number(full.month) + 1, i),
|
||||
disable: true
|
||||
})
|
||||
}
|
||||
return dateArr
|
||||
}
|
||||
/**
|
||||
* 获取当前日期详情
|
||||
* @param {Object} date
|
||||
*/
|
||||
getInfo(date) {
|
||||
if (!date) {
|
||||
date = new Date()
|
||||
} else if (Array.isArray(date)) {
|
||||
date = date[0]
|
||||
}
|
||||
const dateInfo = this.canlender.find(item => item.fullDate === this.getDate(date).fullDate)
|
||||
return dateInfo
|
||||
}
|
||||
/**
|
||||
* 比较时间大小
|
||||
*/
|
||||
dateCompare(startDate, endDate) {
|
||||
// 计算截止时间
|
||||
startDate = new Date(startDate.replace('-', '/').replace('-', '/'))
|
||||
// 计算详细项的截止时间
|
||||
endDate = new Date(endDate.replace('-', '/').replace('-', '/'))
|
||||
if (startDate <= endDate) {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 比较时间是否相等
|
||||
*/
|
||||
dateEqual(before, after) {
|
||||
// 计算截止时间
|
||||
before = new Date(before.replace('-', '/').replace('-', '/'))
|
||||
// 计算详细项的截止时间
|
||||
after = new Date(after.replace('-', '/').replace('-', '/'))
|
||||
if (before.getTime() - after.getTime() === 0) {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 比较after时间是否大于before时间
|
||||
*/
|
||||
dateAfterLgBefore(before, after) {
|
||||
// 计算截止时间
|
||||
before = new Date(before.replace('-', '/').replace('-', '/'))
|
||||
// 计算详细项的截止时间
|
||||
after = new Date(after.replace('-', '/').replace('-', '/'))
|
||||
if (after.getTime() - before.getTime() > 0) {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 获取日期范围内所有日期
|
||||
* @param {Object} begin
|
||||
* @param {Object} end
|
||||
*/
|
||||
geDateAll(begin, end) {
|
||||
var arr = []
|
||||
var ab = begin.split('-')
|
||||
var ae = end.split('-')
|
||||
var db = new Date()
|
||||
db.setFullYear(ab[0], ab[1] - 1, ab[2])
|
||||
var de = new Date()
|
||||
de.setFullYear(ae[0], ae[1] - 1, ae[2])
|
||||
var unixDb = db.getTime() - 24 * 60 * 60 * 1000
|
||||
var unixDe = de.getTime() - 24 * 60 * 60 * 1000
|
||||
for (var k = unixDb; k <= unixDe;) {
|
||||
k = k + 24 * 60 * 60 * 1000
|
||||
arr.push(this.getDate(new Date(parseInt(k))).fullDate)
|
||||
}
|
||||
return arr
|
||||
}
|
||||
/**
|
||||
* 计算阴历日期显示
|
||||
*/
|
||||
getlunar(year, month, date) {
|
||||
return CALENDAR.solar2lunar(year, month, date)
|
||||
}
|
||||
/**
|
||||
* 设置打点
|
||||
*/
|
||||
setSelectInfo(data, value) {
|
||||
this.selected = value
|
||||
this._getWeek(data)
|
||||
}
|
||||
/**
|
||||
* 获取多选状态
|
||||
*/
|
||||
setMultiple(fullDate) {
|
||||
if (!this.multiple) return
|
||||
let multiples = this.multipleStatus.data;
|
||||
const findIndex = multiples.findIndex(item => this.dateEqual(fullDate, item));
|
||||
if (findIndex < 0) {
|
||||
this.multipleStatus.data = this.multipleStatus.data.concat([fullDate]);
|
||||
} else {
|
||||
this.multipleStatus.data.splice(findIndex, 1);
|
||||
}
|
||||
this._getWeek(fullDate)
|
||||
}
|
||||
/**
|
||||
* 获取范围状态
|
||||
*/
|
||||
setRange(fullDate) {
|
||||
let {
|
||||
before,
|
||||
after
|
||||
} = this.rangeStatus
|
||||
if (!this.range) return
|
||||
if (before && after) {
|
||||
this.cleanRangeStatus();
|
||||
this.rangeStatus.before = fullDate
|
||||
} else {
|
||||
if (!before) {
|
||||
this.rangeStatus.before = fullDate
|
||||
} else {
|
||||
if (this.allowSameDay && this.dateEqual(before, fullDate)) {
|
||||
this.rangeStatus.after = fullDate
|
||||
} else if (!this.dateAfterLgBefore(this.rangeStatus.before, fullDate)) {
|
||||
this.cleanRangeStatus();
|
||||
this.rangeStatus.before = fullDate
|
||||
this._getWeek(fullDate)
|
||||
return;
|
||||
}
|
||||
this.rangeStatus.after = fullDate
|
||||
if (this.dateCompare(this.rangeStatus.before, this.rangeStatus.after)) {
|
||||
this.rangeStatus.data = this.geDateAll(this.rangeStatus.before, this.rangeStatus.after);
|
||||
} else {
|
||||
this.rangeStatus.data = this.geDateAll(this.rangeStatus.after, this.rangeStatus.before);
|
||||
}
|
||||
}
|
||||
}
|
||||
this._getWeek(fullDate)
|
||||
}
|
||||
/**
|
||||
* 获取每周数据
|
||||
* @param {Object} dateData
|
||||
*/
|
||||
_getWeek(dateData) {
|
||||
const {
|
||||
year,
|
||||
month
|
||||
} = this.getDate(dateData)
|
||||
let firstDay = new Date(year, month - 1, 1).getDay()
|
||||
let currentDay = new Date(year, month, 0).getDate()
|
||||
let dates = {
|
||||
lastMonthDays: this._getLastMonthDays(firstDay, this.getDate(dateData)), // 上个月末尾几天
|
||||
currentMonthDys: this._currentMonthDys(currentDay, this.getDate(dateData)), // 本月天数
|
||||
nextMonthDays: [], // 下个月开始几天
|
||||
weeks: []
|
||||
}
|
||||
let canlender = []
|
||||
const surplus = 42 - (dates.lastMonthDays.length + dates.currentMonthDys.length)
|
||||
dates.nextMonthDays = this._getNextMonthDays(surplus, this.getDate(dateData))
|
||||
canlender = canlender.concat(dates.lastMonthDays, dates.currentMonthDys, dates.nextMonthDays)
|
||||
let weeks = {}
|
||||
// 拼接数组 上个月开始几天 + 本月天数+ 下个月开始几天
|
||||
for (let i = 0; i < canlender.length; i++) {
|
||||
if (i % 7 === 0) {
|
||||
weeks[parseInt(i / 7)] = new Array(7)
|
||||
}
|
||||
weeks[parseInt(i / 7)][i % 7] = canlender[i]
|
||||
}
|
||||
this.canlender = canlender
|
||||
this.weeks = weeks
|
||||
}
|
||||
//静态方法
|
||||
// static init(date) {
|
||||
// if (!this.instance) {
|
||||
// this.instance = new Calendar(date);
|
||||
// }
|
||||
// return this.instance;
|
||||
// }
|
||||
}
|
||||
export default Calendar
|
||||
|
|
@ -1,452 +0,0 @@
|
|||
<template>
|
||||
<view class="uv-calendar">
|
||||
<view class="uv-calendar__content" v-if="insert">
|
||||
<calendar-body
|
||||
:date="date"
|
||||
:nowDate="nowDate"
|
||||
:weeks="weeks"
|
||||
:calendar="calendar"
|
||||
:selected="selected"
|
||||
:lunar="lunar"
|
||||
:showMonth="showMonth"
|
||||
:color="color"
|
||||
:startText="startText"
|
||||
:endText="endText"
|
||||
:range="range"
|
||||
:multiple="multiple"
|
||||
:allowSameDay="allowSameDay"
|
||||
@bindDateChange="bindDateChange"
|
||||
@pre="pre"
|
||||
@next="next"
|
||||
@backToday="backToday"
|
||||
@choiceDate="choiceDate"
|
||||
></calendar-body>
|
||||
</view>
|
||||
<uv-popup ref="popup" mode="bottom" v-else :round="round" z-index="998" :close-on-click-overlay="closeOnClickOverlay" @maskClick="maskClick">
|
||||
<view style="min-height: 100px;">
|
||||
<uv-toolbar
|
||||
:show="true"
|
||||
:cancelColor="cancelColor"
|
||||
:confirmColor="getConfirmColor"
|
||||
:cancelText="cancelText"
|
||||
:confirmText="confirmText"
|
||||
:title="title"
|
||||
@cancel="close"
|
||||
@confirm="confirm"></uv-toolbar>
|
||||
<view class="line"></view>
|
||||
<calendar-body
|
||||
:nowDate="nowDate"
|
||||
:weeks="weeks"
|
||||
:calendar="calendar"
|
||||
:selected="selected"
|
||||
:lunar="lunar"
|
||||
:showMonth="showMonth"
|
||||
:color="color"
|
||||
:startText="startText"
|
||||
:endText="endText"
|
||||
:range="range"
|
||||
:multiple="multiple"
|
||||
:allowSameDay="allowSameDay"
|
||||
@bindDateChange="bindDateChange"
|
||||
@pre="pre"
|
||||
@next="next"
|
||||
@backToday="backToday"
|
||||
@choiceDate="choiceDate"
|
||||
></calendar-body>
|
||||
</view>
|
||||
</uv-popup>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
/**
|
||||
* Calendar 日历
|
||||
* @description 日历组件可以查看日期,选择任意范围内的日期,打点操作。常用场景如:酒店日期预订、火车机票选择购买日期、上下班打卡等
|
||||
* @tutorial https://ext.dcloud.net.cn/plugin?name=uv-calendar
|
||||
* @property {String} date 自定义当前时间,默认为今天
|
||||
* @property {Boolean} lunar 显示农历
|
||||
* @property {String} startDate 日期选择范围-开始日期
|
||||
* @property {String} endDate 日期选择范围-结束日期
|
||||
* @property {String} mode = [不传 | multiple | range ] 多个日期 | 选择日期范围 默认单日期
|
||||
* @property {Boolean} insert = [true|false] 插入模式,默认为false
|
||||
* @value true 弹窗模式
|
||||
* @value false 插入模式
|
||||
* @property {Boolean} clearDate = [true|false] 弹窗模式是否清空上次选择内容
|
||||
* @property {Array} selected 打点,期待格式[{date: '2019-06-27', info: '签到', data: { custom: '自定义信息', name: '自定义消息头',xxx:xxx... }}]
|
||||
* @property {String} cancelColor 取消按钮颜色
|
||||
* @property {String} confirmColor 确认按钮颜色,默认#3c9cff
|
||||
* @property {String} title 头部工具条中间的标题文字
|
||||
* @property {String} color 主题色,默认#3c9cff
|
||||
* @property {Number} round :insert="false"时的圆角
|
||||
* @property {Boolean} closeOnClickOverlay 点击遮罩是否关闭
|
||||
* @property {String} startText range为true时,第一个日期底部的提示文字
|
||||
* @property {String} endText range为true时,最后一个日期底部的提示文字
|
||||
* @property {String} readonly 是否为只读状态,只读状态下禁止选择日期,默认false
|
||||
*
|
||||
* @event {Function} change 日期改变,`insert :ture` 时生效
|
||||
* @event {Function} confirm 确认选择`insert :false` 时生效
|
||||
* @event {Function} monthSwitch 切换月份时触发
|
||||
*
|
||||
* @example <uv-calendar :insert="true":lunar="true" :start-date="'2019-3-2'":end-date="'2019-5-20'"@change="change" />
|
||||
*/
|
||||
import mpMixin from '@climblee/uv-ui/libs/mixin/mpMixin.js';
|
||||
import mixin from '@climblee/uv-ui/libs/mixin/mixin.js';
|
||||
import Calendar from './util.js';
|
||||
import calendarBody from './calendar-body.vue';
|
||||
import { initVueI18n } from '@dcloudio/uni-i18n';
|
||||
import i18nMessages from './i18n/index.js';
|
||||
const { t } = initVueI18n(i18nMessages);
|
||||
export default {
|
||||
components: {
|
||||
calendarBody
|
||||
},
|
||||
mixins: [mpMixin, mixin],
|
||||
emits: ['close', 'confirm', 'change', 'monthSwitch'],
|
||||
props: {
|
||||
// 取消按钮颜色
|
||||
cancelColor: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 确认按钮颜色,range模式下未选全显示灰色
|
||||
confirmColor: {
|
||||
type: String,
|
||||
default: '#3c9cff'
|
||||
},
|
||||
// 标题
|
||||
title: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 主题色
|
||||
color: {
|
||||
type: String,
|
||||
default: '#3c9cff'
|
||||
},
|
||||
// 默认显示日期
|
||||
date: {
|
||||
type: [String,Array],
|
||||
default: ''
|
||||
},
|
||||
// 打点等设置
|
||||
selected: {
|
||||
type: Array,
|
||||
default () {
|
||||
return []
|
||||
}
|
||||
},
|
||||
// 是否显示农历
|
||||
lunar: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 可选择的起始日期
|
||||
startDate: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 可选择的结束日期
|
||||
endDate: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// multiple - 选择多日期 range - 选择日期范围
|
||||
mode: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 是否插入模式
|
||||
insert: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 是否显示月份为背景
|
||||
showMonth: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 弹窗模式是否清空上次选择内容
|
||||
clearDate: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 弹窗圆角
|
||||
round: {
|
||||
type: [Number,String],
|
||||
default: 8
|
||||
},
|
||||
// 点击遮罩是否关闭弹窗
|
||||
closeOnClickOverlay: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// range为true时,第一个日期底部的提示文字
|
||||
startText: {
|
||||
type: String,
|
||||
default: '开始'
|
||||
},
|
||||
// range为true时,最后一个日期底部的提示文字
|
||||
endText: {
|
||||
type: String,
|
||||
default: '结束'
|
||||
},
|
||||
// 是否允许日期范围的起止时间为同一天,mode = range时有效
|
||||
allowSameDay: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 是否禁用
|
||||
readonly: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
...uni.$uv?.props?.calendars
|
||||
},
|
||||
data(){
|
||||
return {
|
||||
weeks: [],
|
||||
calendar: {},
|
||||
nowDate: '',
|
||||
allowConfirm: false,
|
||||
multiple: false,
|
||||
range: false
|
||||
}
|
||||
},
|
||||
computed:{
|
||||
/**
|
||||
* for i18n
|
||||
*/
|
||||
confirmText() {
|
||||
return t("uv-calender.ok")
|
||||
},
|
||||
cancelText() {
|
||||
return t("uv-calender.cancel")
|
||||
},
|
||||
getConfirmColor() {
|
||||
if(this.range || this.multiple || this.readonly) {
|
||||
return this.allowConfirm? this.confirmColor: '#999'
|
||||
}else {
|
||||
return this.confirmColor;
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
date(newVal) {
|
||||
this.init(newVal)
|
||||
},
|
||||
startDate(val) {
|
||||
this.cale.resetSatrtDate(val)
|
||||
this.cale.setDate(this.nowDate.fullDate)
|
||||
this.weeks = this.cale.weeks
|
||||
},
|
||||
endDate(val) {
|
||||
this.cale.resetEndDate(val)
|
||||
this.cale.setDate(this.nowDate.fullDate)
|
||||
this.weeks = this.cale.weeks
|
||||
},
|
||||
selected(newVal) {
|
||||
this.cale.setSelectInfo(this.nowDate.fullDate, newVal)
|
||||
this.weeks = this.cale.weeks
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.setMode();
|
||||
this.cale = new Calendar({
|
||||
selected: this.selected,
|
||||
startDate: this.startDate,
|
||||
endDate: this.endDate,
|
||||
range: this.range,
|
||||
multiple: this.multiple,
|
||||
allowSameDay: this.allowSameDay
|
||||
})
|
||||
this.init(this.date)
|
||||
},
|
||||
methods: {
|
||||
setMode() {
|
||||
switch (this.mode){
|
||||
case 'range':
|
||||
this.range = true;
|
||||
break;
|
||||
case 'multiple':
|
||||
this.multiple = true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
},
|
||||
async open() {
|
||||
if (this.clearDate && !this.insert) {
|
||||
this.cale.cleanRangeStatus()
|
||||
this.init(this.date)
|
||||
}
|
||||
if(!this.insert){
|
||||
this.$refs.popup.open();
|
||||
}
|
||||
},
|
||||
close() {
|
||||
this.$refs.popup.close();
|
||||
this.$emit('close');
|
||||
},
|
||||
confirm() {
|
||||
if(this.readonly) {
|
||||
return;
|
||||
} else if(this.range && !this.cale.rangeStatus.after) {
|
||||
return;
|
||||
} else if(this.multiple && this.cale.multipleStatus.data.length == 0){
|
||||
return;
|
||||
}
|
||||
this.setEmit('confirm');
|
||||
this.close()
|
||||
},
|
||||
maskClick() {
|
||||
if(this.closeOnClickOverlay) {
|
||||
this.$emit('close');
|
||||
}
|
||||
},
|
||||
bindDateChange(e) {
|
||||
const value = e.detail.value + '-1'
|
||||
this.setDate(value)
|
||||
|
||||
const { year, month } = this.cale.getDate(value)
|
||||
this.$emit('monthSwitch', {
|
||||
year,
|
||||
month
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 初始化日期显示
|
||||
* @param {Object} date
|
||||
*/
|
||||
init(date) {
|
||||
if(this.range) {
|
||||
// 重置范围选择状态
|
||||
this.cale.cleanRangeStatus();
|
||||
}else if(this.multiple){
|
||||
// 重置多选状态
|
||||
this.cale.cleanMultipleStatus();
|
||||
}
|
||||
this.cale.setDate(date,'init')
|
||||
this.weeks = this.cale.weeks
|
||||
this.nowDate = this.calendar = this.cale.getInfo(date)
|
||||
this.changeConfirmStatus();
|
||||
},
|
||||
/**
|
||||
* 变化触发
|
||||
*/
|
||||
change() {
|
||||
this.changeConfirmStatus();
|
||||
if (!this.insert) return
|
||||
this.setEmit('change')
|
||||
},
|
||||
changeConfirmStatus() {
|
||||
if(this.readonly) {
|
||||
this.allowConfirm = false;
|
||||
} else if (this.range) {
|
||||
this.allowConfirm = this.cale.rangeStatus.after ? true : false;
|
||||
} else if(this.multiple) {
|
||||
this.allowConfirm = this.cale.multipleStatus.data.length > 0 ? true : false;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 选择月份触发
|
||||
*/
|
||||
monthSwitch() {
|
||||
let {
|
||||
year,
|
||||
month
|
||||
} = this.nowDate
|
||||
this.$emit('monthSwitch', {
|
||||
year,
|
||||
month: Number(month)
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 派发事件
|
||||
* @param {Object} name
|
||||
*/
|
||||
setEmit(name) {
|
||||
let {
|
||||
year,
|
||||
month,
|
||||
date,
|
||||
fullDate,
|
||||
lunar,
|
||||
extraInfo
|
||||
} = this.calendar
|
||||
this.$emit(name, {
|
||||
range: this.cale.rangeStatus,
|
||||
multiple: this.cale.multipleStatus,
|
||||
year,
|
||||
month,
|
||||
date,
|
||||
fulldate: fullDate,
|
||||
lunar,
|
||||
extraInfo: extraInfo || {}
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 选择天触发
|
||||
* @param {Object} weeks
|
||||
*/
|
||||
choiceDate(weeks) {
|
||||
if (weeks.disable || this.readonly) return
|
||||
this.calendar = weeks
|
||||
// 设置范围选择
|
||||
this.cale.setRange(this.calendar.fullDate)
|
||||
// 设置多选
|
||||
this.cale.setMultiple(this.calendar.fullDate);
|
||||
this.weeks = this.cale.weeks
|
||||
this.change()
|
||||
},
|
||||
/**
|
||||
* 回到今天
|
||||
*/
|
||||
backToday() {
|
||||
const nowYearMonth = `${this.nowDate.year}-${this.nowDate.month}`
|
||||
const date = this.cale.getDate(new Date())
|
||||
const todayYearMonth = `${date.year}-${date.month}`
|
||||
this.init(date.fullDate)
|
||||
if (nowYearMonth !== todayYearMonth) {
|
||||
this.monthSwitch()
|
||||
}
|
||||
this.change()
|
||||
},
|
||||
/**
|
||||
* 上个月
|
||||
*/
|
||||
pre() {
|
||||
const preDate = this.cale.getDate(this.nowDate.fullDate, -1, 'month').fullDate
|
||||
this.setDate(preDate)
|
||||
this.monthSwitch()
|
||||
},
|
||||
/**
|
||||
* 下个月
|
||||
*/
|
||||
next() {
|
||||
const nextDate = this.cale.getDate(this.nowDate.fullDate, +1, 'month').fullDate
|
||||
this.setDate(nextDate)
|
||||
this.monthSwitch()
|
||||
},
|
||||
/**
|
||||
* 设置日期
|
||||
* @param {Object} date
|
||||
*/
|
||||
setDate(date) {
|
||||
this.cale.setDate(date)
|
||||
this.weeks = this.cale.weeks
|
||||
this.nowDate = this.cale.getInfo(date)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
$uv-border-color: #EDEDED !default;
|
||||
.uv-calendar__content {
|
||||
background-color: #fff;
|
||||
}
|
||||
.line {
|
||||
width: 750rpx;
|
||||
height: 1px;
|
||||
border-bottom-color: $uv-border-color;
|
||||
border-bottom-style: solid;
|
||||
border-bottom-width: 1px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -11,12 +11,11 @@
|
|||
>
|
||||
<template #left>
|
||||
<slot name="left">
|
||||
<!-- <image
|
||||
<image
|
||||
v-if="isBack && !leftIcon"
|
||||
class="w-54rpx h-54rpx"
|
||||
src="/static/images/icon_back_def.svg"
|
||||
></image> -->
|
||||
<uv-icon size="36rpx" color="white" v-if="isBack && !leftIcon" name="arrow-left"></uv-icon>
|
||||
></image>
|
||||
</slot>
|
||||
</template>
|
||||
<template #center>
|
||||
|
|
@ -100,7 +99,6 @@ const paddingRight = computed(() => {
|
|||
return `${rightButtonWidth}px`
|
||||
})
|
||||
const onLeftClick = () => {
|
||||
if (!props.isBack) return
|
||||
emit('leftClick')
|
||||
if (props.autoBack) {
|
||||
// #ifdef H5
|
||||
|
|
|
|||
|
|
@ -1,46 +0,0 @@
|
|||
<template>
|
||||
<view class="card-shadow bg-white rounded-19rpx p-base space-y-10rpx">
|
||||
<view class="flex items-center justify-between pb-10rpx">
|
||||
<view class="text-30rpx">{{ title }}</view>
|
||||
<view class="text-24rpx" :style="{color: statusColor}">{{ statusText }}</view>
|
||||
</view>
|
||||
<template v-if="body && body.length > 0">
|
||||
<uv-line />
|
||||
<view class="body text-hex-999999 text-28rpx">
|
||||
<view v-for="(item, i) in body" :key="i" class="body-item flex mt-10rpx">
|
||||
<view class="label mr-10rpx">{{ item.label }}</view>
|
||||
<view class="value">{{ item.value }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<template v-if="images && images.length > 0">
|
||||
<uv-scroll-list :indicator="false">
|
||||
<view class="space-x-15rpx flex">
|
||||
<view v-for="(url, index) in images.slice(0, 3)" :key="index">
|
||||
<image :src="url" mode="heightFix" style="height: 160rpx"></image>
|
||||
</view>
|
||||
</view>
|
||||
</uv-scroll-list>
|
||||
</template>
|
||||
<slot name="footer"></slot>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
title: [String, Number],
|
||||
statusText: [String, Number],
|
||||
statusColor: {
|
||||
type: String,
|
||||
default: '#3c9cff'
|
||||
},
|
||||
body: Array,
|
||||
images: Array,
|
||||
})
|
||||
</script>
|
||||
<style scoped>
|
||||
.uv-scroll-list {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -62,6 +62,4 @@ const upCallback = async (mescroll) => {
|
|||
mescroll.endErr() // 隐藏加载进度
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,57 +0,0 @@
|
|||
/**
|
||||
* nuxt项目目录/composables/http.ts
|
||||
*/
|
||||
// 基于useFetch()的网络请求封装
|
||||
|
||||
//全局基础URL
|
||||
const BASEURL: string = "http://127.xxx.xxx:3000"; //全局后台服务器请求地址
|
||||
|
||||
//定义ts变量类型接口
|
||||
interface HttpParms {
|
||||
baseURL?: string, //请求的基本URL,即后台服务器地址,(若服务器请求地址只有一个,可不填)
|
||||
url: string, //请求api接口地址
|
||||
method?: any, //请求方法
|
||||
query?: any, //添加查询搜索参数到URL
|
||||
body?: any //请求体
|
||||
}
|
||||
|
||||
/**
|
||||
* 网络请求方法
|
||||
* @param obj 请求参数
|
||||
* @returns 响应结果
|
||||
*/
|
||||
export const http = (obj: HttpParms) => {
|
||||
const res = new Promise<void>((resolve, reject) => {
|
||||
useFetch(
|
||||
(obj.baseURL ?? BASEURL) + obj.url,
|
||||
{
|
||||
method: obj.method ?? "GET",
|
||||
query: obj?.query ?? null,
|
||||
body: obj?.body ?? null,
|
||||
onRequest({ request, options }) {
|
||||
// 设置请求报头
|
||||
options.headers = options.headers || {}
|
||||
/**如果接口需求携带token请求,则可先自行使用官方的useCookie()方法设置Cookie存储后,再使用useCookie()方法,取出token使用。如下例子:*/
|
||||
//const token = useCookie('token')
|
||||
//@ts-ignore
|
||||
//options.headers.Authorization = token.value||null
|
||||
},
|
||||
onRequestError({ request, options, error }) {
|
||||
// 处理请求错误
|
||||
console.log("服务器链接失败!")
|
||||
reject(error)
|
||||
},
|
||||
onResponse({ request, response, options }) {
|
||||
// 处理响应数据
|
||||
resolve(response._data)
|
||||
},
|
||||
onResponseError({ request, response, options }) {
|
||||
// 处理响应错误
|
||||
}
|
||||
},
|
||||
|
||||
)
|
||||
})
|
||||
return res;
|
||||
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name" : "托管门店助手",
|
||||
"appid" : "__UNI__1EFE850",
|
||||
"name" : "",
|
||||
"appid" : "",
|
||||
"description" : "",
|
||||
"versionName" : "1.0.0",
|
||||
"versionCode" : "100",
|
||||
|
|
@ -10,21 +10,14 @@
|
|||
"usingComponents" : true,
|
||||
"nvueStyleCompiler" : "uni-app",
|
||||
"compilerVersion" : 3,
|
||||
"compatible" : {
|
||||
"ignoreVersion" : true //true表示忽略版本检查提示框,HBuilderX1.9.0及以上版本支持
|
||||
},
|
||||
"splashscreen" : {
|
||||
"alwaysShowBeforeRender" : false,
|
||||
"alwaysShowBeforeRender" : true,
|
||||
"waiting" : true,
|
||||
"autoclose" : false,
|
||||
"autoclose" : true,
|
||||
"delay" : 0
|
||||
},
|
||||
/* 模块配置 */
|
||||
"modules" : {
|
||||
"VideoPlayer" : {},
|
||||
"Camera" : {},
|
||||
"Geolocation" : {}
|
||||
},
|
||||
"modules" : {},
|
||||
/* 应用发布信息 */
|
||||
"distribute" : {
|
||||
/* android打包配置 */
|
||||
|
|
@ -48,62 +41,9 @@
|
|||
]
|
||||
},
|
||||
/* ios打包配置 */
|
||||
"ios" : {
|
||||
"dSYMs" : false,
|
||||
"privacyDescription" : {
|
||||
"NSPhotoLibraryUsageDescription" : "请允许访问相册,以便于上传凭证、个人头像时上传照片",
|
||||
"NSPhotoLibraryAddUsageDescription" : "请允许访问相册,以便于上传凭证、个人头像时上传照片",
|
||||
"NSCameraUsageDescription" : "请允许访问相机,以便于上传凭证、个人头像时上传照片",
|
||||
"NSLocationWhenInUseUsageDescription" : "请允许获取位置信息,以便于位置定位",
|
||||
"NSLocationAlwaysAndWhenInUseUsageDescription" : "请允许获取位置信息,以便于位置定位"
|
||||
},
|
||||
"idfa" : false
|
||||
},
|
||||
"ios" : {},
|
||||
/* SDK配置 */
|
||||
"sdkConfigs" : {
|
||||
"ad" : {},
|
||||
"geolocation" : {
|
||||
"system" : {
|
||||
"__platform__" : [ "ios", "android" ]
|
||||
}
|
||||
}
|
||||
},
|
||||
"icons" : {
|
||||
"android" : {
|
||||
"hdpi" : "unpackage/res/icons/72x72.png",
|
||||
"xhdpi" : "unpackage/res/icons/96x96.png",
|
||||
"xxhdpi" : "unpackage/res/icons/144x144.png",
|
||||
"xxxhdpi" : "unpackage/res/icons/192x192.png"
|
||||
},
|
||||
"ios" : {
|
||||
"appstore" : "unpackage/res/icons/1024x1024.png",
|
||||
"ipad" : {
|
||||
"app" : "unpackage/res/icons/76x76.png",
|
||||
"app@2x" : "unpackage/res/icons/152x152.png",
|
||||
"notification" : "unpackage/res/icons/20x20.png",
|
||||
"notification@2x" : "unpackage/res/icons/40x40.png",
|
||||
"proapp@2x" : "unpackage/res/icons/167x167.png",
|
||||
"settings" : "unpackage/res/icons/29x29.png",
|
||||
"settings@2x" : "unpackage/res/icons/58x58.png",
|
||||
"spotlight" : "unpackage/res/icons/40x40.png",
|
||||
"spotlight@2x" : "unpackage/res/icons/80x80.png"
|
||||
},
|
||||
"iphone" : {
|
||||
"app@2x" : "unpackage/res/icons/120x120.png",
|
||||
"app@3x" : "unpackage/res/icons/180x180.png",
|
||||
"notification@2x" : "unpackage/res/icons/40x40.png",
|
||||
"notification@3x" : "unpackage/res/icons/60x60.png",
|
||||
"settings@2x" : "unpackage/res/icons/58x58.png",
|
||||
"settings@3x" : "unpackage/res/icons/87x87.png",
|
||||
"spotlight@2x" : "unpackage/res/icons/80x80.png",
|
||||
"spotlight@3x" : "unpackage/res/icons/120x120.png"
|
||||
}
|
||||
}
|
||||
},
|
||||
"splashscreen" : {
|
||||
"androidStyle" : "common",
|
||||
"useOriginalMsgbox" : false
|
||||
}
|
||||
"sdkConfigs" : {}
|
||||
}
|
||||
},
|
||||
/* 快应用特有相关 */
|
||||
|
|
@ -125,8 +65,8 @@
|
|||
"mp-toutiao" : {
|
||||
"usingComponents" : true
|
||||
},
|
||||
"uniStatistics" : {
|
||||
"enable" : false
|
||||
"uniStatistics": {
|
||||
"enable": false
|
||||
},
|
||||
"vueVersion" : "3"
|
||||
}
|
||||
|
|
|
|||
245
src/pages.json
245
src/pages.json
|
|
@ -1,25 +1,9 @@
|
|||
{
|
||||
"pages": [
|
||||
{
|
||||
"path": "pages/guide/judge",
|
||||
"path": "pages/login/index",
|
||||
"style": {
|
||||
"enablePullDownRefresh": false,
|
||||
"onReachBottomDistance": 100,
|
||||
"navigationStyle": "custom",
|
||||
"app-plus": {
|
||||
"contentAdjust": false,
|
||||
"bounce": "none"
|
||||
}
|
||||
},
|
||||
"meta": {
|
||||
"login": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/webview/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "隐私协议",
|
||||
"navigationStyle": "default"
|
||||
"navigationBarTitleText": "登录"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -28,12 +12,6 @@
|
|||
"navigationBarTitleText": "首页"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/login/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "登录"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/revert/index",
|
||||
"style": {
|
||||
|
|
@ -51,65 +29,6 @@
|
|||
"style": {
|
||||
"navigationBarTitleText": "我的"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/message/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "消息"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/message/detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "消息详情"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/clockout/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "考勤打卡"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/clockout/logs",
|
||||
"style": {
|
||||
"navigationBarTitleText": "考勤记录"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/userInfo/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "个人信息"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/notfound/index",
|
||||
"style": {
|
||||
"enablePullDownRefresh": false,
|
||||
"onReachBottomDistance": 100,
|
||||
"navigationBarTitleText": "错误页",
|
||||
"app-plus": {
|
||||
"contentAdjust": false,
|
||||
"bounce": "none"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/upgrade/index",
|
||||
"style": {
|
||||
"disableScroll": true,
|
||||
"disableSwipeBack": true,
|
||||
"app-plus": {
|
||||
"backgroundColorTop": "transparent",
|
||||
"background": "transparent",
|
||||
"titleNView": false,
|
||||
"scrollIndicator": false,
|
||||
|
||||
"popGesture": "none",
|
||||
"animationType": "fade-in",
|
||||
"animationDuration": 200
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"subPackages": [
|
||||
|
|
@ -232,12 +151,6 @@
|
|||
"navigationBarTitleText": "报销管理"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "报销详情"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "submit",
|
||||
"style": {
|
||||
|
|
@ -255,12 +168,6 @@
|
|||
"navigationBarTitleText": "升职申请"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "升职申请"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "create",
|
||||
"style": {
|
||||
|
|
@ -269,121 +176,6 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/make-card",
|
||||
"pages": [
|
||||
{
|
||||
"path": "list",
|
||||
"style": {
|
||||
"navigationBarTitleText": "补卡申请"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "create",
|
||||
"style": {
|
||||
"navigationBarTitleText": "补卡申请"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "补卡审核"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/ask-leave",
|
||||
"pages": [
|
||||
{
|
||||
"path": "list",
|
||||
"style": {
|
||||
"navigationBarTitleText": "请假申请"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "create",
|
||||
"style": {
|
||||
"navigationBarTitleText": "请假申请"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "请假详情"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/business",
|
||||
"pages": [
|
||||
{
|
||||
"path": "list",
|
||||
"style": {
|
||||
"navigationBarTitleText": "出差报备"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "create",
|
||||
"style": {
|
||||
"navigationBarTitleText": "出差报备"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "出差详情"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/overtime",
|
||||
"pages": [
|
||||
{
|
||||
"path": "list",
|
||||
"style": {
|
||||
"navigationBarTitleText": "加班报备"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "create",
|
||||
"style": {
|
||||
"navigationBarTitleText": "加班报备"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "加班详情"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/contract",
|
||||
"pages": [
|
||||
{
|
||||
"path": "list",
|
||||
"style": {
|
||||
"navigationBarTitleText": "合同管理"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "create",
|
||||
"style": {
|
||||
"navigationBarTitleText": "我的合同"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "合同详细"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/train-books",
|
||||
"pages": [
|
||||
|
|
@ -417,23 +209,6 @@
|
|||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/audits",
|
||||
"pages": [
|
||||
{
|
||||
"path": "detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "审核详情"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "log",
|
||||
"style": {
|
||||
"navigationBarTitleText": "审核流程"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"globalStyle": {
|
||||
|
|
@ -451,31 +226,31 @@
|
|||
"tabBar": {
|
||||
"color": "#333",
|
||||
"selectedColor": "#ff3c2a",
|
||||
"borderStyle": "#fff",
|
||||
"borderStyle": "black",
|
||||
"backgroundColor": "#ffffff",
|
||||
"list": [
|
||||
{
|
||||
"pagePath": "pages/home/index",
|
||||
"selectedIconPath": "static/images/home-a.png",
|
||||
"selectedIconPath": "static/images/home.png",
|
||||
"iconPath": "static/images/home.png",
|
||||
"text": "首页"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/revert/index",
|
||||
"selectedIconPath": "static/images/update-a.png",
|
||||
"iconPath": "static/images/update.png",
|
||||
"selectedIconPath": "static/images/home.png",
|
||||
"iconPath": "static/images/home.png",
|
||||
"text": "上报"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/statement/index",
|
||||
"selectedIconPath": "static/images/table-a.png",
|
||||
"iconPath": "static/images/table.png",
|
||||
"selectedIconPath": "static/images/home.png",
|
||||
"iconPath": "static/images/home.png",
|
||||
"text": "报表"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/mine/index",
|
||||
"selectedIconPath": "static/images/mine-a.png",
|
||||
"iconPath": "static/images/mine.png",
|
||||
"selectedIconPath": "static/images/home.png",
|
||||
"iconPath": "static/images/home.png",
|
||||
"text": "我的"
|
||||
}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1,173 +0,0 @@
|
|||
<template>
|
||||
<view>
|
||||
<CuNavbar title="请假申请"></CuNavbar>
|
||||
<view class="card-shadow px-base">
|
||||
<uv-form labelPosition="left" :model="form" :rules="rules" ref="formRef" errorType="toast" labelWidth="250rpx">
|
||||
<uv-form-item required label="请假类别" prop="type_id">
|
||||
<uv-input
|
||||
placeholder="请选择"
|
||||
@click="openPicker"
|
||||
readonly
|
||||
inputAlign="right"
|
||||
:border="`none`"
|
||||
v-model="form.type_id"
|
||||
>
|
||||
</uv-input>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item required label="请假开始时间" prop="start_at">
|
||||
<uv-input
|
||||
placeholder="请选择日期"
|
||||
readonly
|
||||
@click="openStartDatePicker"
|
||||
inputAlign="right"
|
||||
:border="`none`"
|
||||
v-model="form.start_at"
|
||||
>
|
||||
</uv-input>
|
||||
</uv-form-item>
|
||||
<uv-form-item required label="请假结束时间" prop="end_at">
|
||||
<uv-input
|
||||
placeholder="请选择日期"
|
||||
readonly
|
||||
@click="openEndDatePicker"
|
||||
inputAlign="right"
|
||||
:border="`none`"
|
||||
v-model="form.end_at"
|
||||
>
|
||||
</uv-input>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item required label="请假事由" prop="reason" labelPosition="top">
|
||||
<uv-textarea :customStyle="{ padding: '0' }" v-model="form.reason" count placeholder="请输入请假事由" :border="`none`" :maxlength="200"></uv-textarea>
|
||||
</uv-form-item>
|
||||
</uv-form>
|
||||
</view>
|
||||
<view class="mt-20rpx px-base">
|
||||
<uv-button type="primary" @click="submit">提交</uv-button>
|
||||
</view>
|
||||
<uv-picker ref="pickerRef" :columns="columns" @confirm="confirmPicker"></uv-picker>
|
||||
<uv-datetime-picker
|
||||
placeholder="请选择日期"
|
||||
v-model="startValue"
|
||||
ref="dateStartPicker"
|
||||
mode="datetime"
|
||||
@confirm="confirmStartDatePicker"
|
||||
>
|
||||
</uv-datetime-picker>
|
||||
<uv-datetime-picker
|
||||
v-model="endValue"
|
||||
placeholder="请选择日期"
|
||||
ref="dateEndPicker"
|
||||
mode="datetime"
|
||||
@confirm="confirmEndDatePicker"
|
||||
>
|
||||
</uv-datetime-picker>
|
||||
<uv-modal ref="modalRef" title="提示" content="确定提交吗?" @confirm="onSubmit" :showCancelButton="true"></uv-modal>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from "@/components/cu-navbar/index"
|
||||
import { ref, reactive, computed } from "vue"
|
||||
import { onLoad } from "@dcloudio/uni-app"
|
||||
import { http } from "@/utils/request"
|
||||
import { timeFormat } from "@climblee/uv-ui/libs/function/index"
|
||||
const columns = ref([])
|
||||
const pickerData = ref([])
|
||||
const formRef = ref(null)
|
||||
const dateStartPicker = ref(null)
|
||||
const dateEndPicker = ref(null)
|
||||
const pickerRef = ref(null)
|
||||
const modalRef = ref(null)
|
||||
const startValue = ref(Number(new Date()))
|
||||
const endValue = ref(Number(new Date()))
|
||||
const id = ref(0)
|
||||
const loading = ref(false)
|
||||
const form = reactive({
|
||||
start_at: "",
|
||||
end_at: "",
|
||||
reason: "",
|
||||
type_id: ""
|
||||
})
|
||||
const openPicker = () => {
|
||||
pickerRef.value.open()
|
||||
}
|
||||
const openStartDatePicker = () => {
|
||||
dateStartPicker.value.open()
|
||||
}
|
||||
const openEndDatePicker = () => {
|
||||
dateEndPicker.value.open()
|
||||
}
|
||||
const confirmStartDatePicker = e => {
|
||||
form.start_at = timeFormat(e.value, "yyyy-mm-dd hh:MM")
|
||||
}
|
||||
const confirmEndDatePicker = e => {
|
||||
form.end_at = timeFormat(e.value, "yyyy-mm-dd hh:MM")
|
||||
}
|
||||
const confirmPicker = e => {
|
||||
form.type_id = e.value[0]
|
||||
}
|
||||
const rules = reactive({
|
||||
start_at: [{ required: true, message: "请选择时间" }],
|
||||
end_at: [{ required: true, message: "请选择时间" }],
|
||||
reason: [{ required: true, message: "请输入请假事由" }],
|
||||
type_id: [{ required: true, message: "请选择请假类别" }]
|
||||
})
|
||||
onLoad(options => {
|
||||
http.get(`/keywords?parent_key=holiday_type`).then(res => {
|
||||
let names = res.map(item => item.name)
|
||||
columns.value = [names]
|
||||
pickerData.value = res
|
||||
})
|
||||
id.value = options.id
|
||||
if (id.value) {
|
||||
http.get(`/hr/holidays/${options.id}`).then(res => {
|
||||
startValue.value = res.start_at * 1000
|
||||
endValue.value = res.end_at * 1000
|
||||
form.start_at = timeFormat(res.start_at, "yyyy-mm-dd hh:MM:ss")
|
||||
form.end_at = timeFormat(res.end_at, "yyyy-mm-dd hh:MM:ss")
|
||||
form.reason = res.reason
|
||||
form.type_id = res.type.name
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const submit = () => {
|
||||
formRef.value.validate().then(res => {
|
||||
modalRef.value.open()
|
||||
})
|
||||
}
|
||||
|
||||
const onSubmit = async () => {
|
||||
if (loading.value) return
|
||||
loading.value = true
|
||||
try {
|
||||
let url = id.value ? `/hr/holidays/${id.value}` : "/hr/holidays"
|
||||
let method = id.value ? "PUT" : "POST"
|
||||
await http.request({
|
||||
url: url,
|
||||
method: method,
|
||||
header: {
|
||||
Accept: "application/json"
|
||||
},
|
||||
data: {
|
||||
start_at: form.start_at,
|
||||
type_id: pickerData.value.find(item => item.name === form.type_id).id,
|
||||
reason: form.reason,
|
||||
end_at: form.end_at
|
||||
}
|
||||
})
|
||||
uni.showToast({
|
||||
title: "提交成功",
|
||||
icon: "none"
|
||||
})
|
||||
formRef.value.resetFields()
|
||||
uni.$emit('refresh')
|
||||
uni.navigateBack()
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -1,91 +0,0 @@
|
|||
<template>
|
||||
<view class="px-base" v-if="detail">
|
||||
<CuNavbar title="请假详情">
|
||||
<template v-if="actions.length > 0" #right>
|
||||
<uv-icon color="white" @click="open" name="more-dot-fill"></uv-icon>
|
||||
</template>
|
||||
</CuNavbar>
|
||||
<view class="mt-30rpx card-shadow bg-white rounded-19rpx px-base text-[#333333] text-27rpx">
|
||||
<BaseData :data="detail" :colums="columns" />
|
||||
</view>
|
||||
<uv-action-sheet ref="pickerRef" :actions="actions" @select="confirmPicker" />
|
||||
<uv-modal ref="modalRef" title="提示" content="确定删除吗?" @confirm="onSubmit" :showCancelButton="true"></uv-modal>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from "@/components/cu-navbar/index"
|
||||
import { http } from "@/utils/request"
|
||||
import { onLoad } from "@dcloudio/uni-app"
|
||||
import { ref } from "vue"
|
||||
import BaseData from '../audits/base-data'
|
||||
import statusFun from '@/utils/status'
|
||||
|
||||
const modalRef = ref(null)
|
||||
const actions = ref([
|
||||
{ name: '修改', value: 'edit', disabled: false },
|
||||
{ name: '删除', value: 'delete', disabled: false },
|
||||
{ name: '审核流程', value: 'check-logs', disabled: false }
|
||||
])
|
||||
const detail = ref()
|
||||
const pickerRef = ref(null)
|
||||
const id = ref(0)
|
||||
|
||||
const columns = [
|
||||
{ title: '审核状态', dataIndex: 'workflow_check.check_status', format: (value) => statusFun(value, 'statusExpense', 'name') },
|
||||
{ title: '申请人', dataIndex: 'employee.name' },
|
||||
{ title: '所属门店', dataIndex: 'store.title' },
|
||||
{ title: '电话号码', dataIndex: 'employee.phone' },
|
||||
{ title: '申请时间', dataIndex: 'created_format' },
|
||||
{ title: '请假类型', dataIndex: 'type.name' },
|
||||
{ title: '请假开始时间', dataIndex: 'start_format' },
|
||||
{ title: '请假结束时间', dataIndex: 'end_format' },
|
||||
{ title: '请假事由', dataIndex: 'reason', labelPosition: 'top' },
|
||||
{ title: '未通过原因', dataIndex: 'workflow_check.check_remarks', labelPosition: 'top', isShow: (data) => data?.workflow_check?.check_status == 4 },
|
||||
]
|
||||
|
||||
const open = () => {
|
||||
pickerRef.value.open()
|
||||
}
|
||||
const confirmPicker = e => {
|
||||
if (e.value == 'edit') {
|
||||
return uni.navigateTo({
|
||||
url: `/pages/ask-leave/create?id=${id.value}`
|
||||
})
|
||||
}
|
||||
if (e.value == 'delete') {
|
||||
return modalRef.value.open()
|
||||
} else if (e.value == 'check-logs') {
|
||||
return uni.navigateTo({
|
||||
url: `/pages/audits/log?id=${detail.value.workflow_check.id}`
|
||||
})
|
||||
}
|
||||
}
|
||||
const onSubmit = async () => {
|
||||
try {
|
||||
await http.delete(`/hr/holidays/${id.value}`)
|
||||
uni.showToast({
|
||||
title: "删除成功",
|
||||
icon: "none"
|
||||
})
|
||||
uni.$emit('refresh')
|
||||
uni.navigateBack()
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
onLoad(options => {
|
||||
id.value = options.id
|
||||
http.get(`/hr/holidays/${options.id}`).then(res => {
|
||||
detail.value = res
|
||||
|
||||
let status = res.workflow_check.check_status
|
||||
if ([2, 3].indexOf(status) != -1) {
|
||||
actions.value[0].disabled = true
|
||||
actions.value[1].disabled = true
|
||||
// actions.value.splice(0, 2)
|
||||
}
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
|
@ -1,131 +0,0 @@
|
|||
<template>
|
||||
<view>
|
||||
<CuNavbar title="请假申请">
|
||||
<template #right>
|
||||
<view @click="goPath('/pages/ask-leave/create')" class="text-24rpx text-white">申请</view>
|
||||
</template>
|
||||
</CuNavbar>
|
||||
<uv-sticky bgColor="#fff">
|
||||
<uv-tabs
|
||||
:activeStyle="{ color: '#ee2c37' }"
|
||||
:scrollable="false"
|
||||
lineColor="#ee2c37"
|
||||
:list="tabList"
|
||||
@change="tabChange"
|
||||
></uv-tabs>
|
||||
</uv-sticky>
|
||||
<MescrollItem
|
||||
ref="mescrollItem0"
|
||||
:top="88"
|
||||
:i="0"
|
||||
:index="tabIndex"
|
||||
:apiUrl="tabList[0].apiUrl"
|
||||
>
|
||||
<template v-slot="{ list }">
|
||||
<view class="space-y-15rpx p-base">
|
||||
<ListItem
|
||||
v-for="item in list" :key="item.id"
|
||||
title="请假申请"
|
||||
:status-text="statusFun(item.workflow_check.check_status, 'statusExpense', 'name')"
|
||||
:status-color="statusFun(item.workflow_check.check_status, 'statusExpense', 'color')"
|
||||
:body="[
|
||||
{ label:'请假类型: ', value: item.type.name },
|
||||
{ label:'请假事由: ', value: item.reason },
|
||||
{ label:'申请时间: ', value: item.created_format },
|
||||
]"
|
||||
@click.stop="applyDetail(item)"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
</MescrollItem>
|
||||
<MescrollItem
|
||||
ref="mescrollItem1"
|
||||
:top="88"
|
||||
:i="1"
|
||||
:index="tabIndex"
|
||||
:apiUrl="tabList[1].apiUrl"
|
||||
:params="tabList[1].params"
|
||||
>
|
||||
<template v-slot="{ list }">
|
||||
<view class="space-y-15rpx p-base">
|
||||
<ListItem
|
||||
v-for="item in list" :key="item.id"
|
||||
title="请假申请"
|
||||
:status-text="statusFun( item.check_status,'statusExpense2','name')"
|
||||
:status-color="statusFun( item.check_status,'statusExpense2','color')"
|
||||
:body="[
|
||||
{ label:'申请人: ', value: item.check.subject.employee.name },
|
||||
{ label:'请假类型: ', value: item.check.subject.type.name },
|
||||
{ label:'请假事由: ', value: item.check.subject.reason },
|
||||
{ label:'申请时间: ', value: item.check.subject.created_format },
|
||||
]"
|
||||
@click.stop="checkDetail(item)"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
</MescrollItem>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import { ref } from 'vue'
|
||||
import { onPageScroll, onReachBottom, onLoad } from '@dcloudio/uni-app'
|
||||
import useMescrollMore from '@/uni_modules/mescroll-uni/hooks/useMescrollMore.js'
|
||||
import MescrollItem from '@/components/mescroll-api/more.vue'
|
||||
import statusFun from '@/utils/status'
|
||||
import ListItem from '@/components/list-item/index'
|
||||
|
||||
const tabList = ref([
|
||||
{
|
||||
name: '我的请假',
|
||||
apiUrl: '/hr/holidays',
|
||||
},
|
||||
{
|
||||
name: '请假审核',
|
||||
apiUrl: '/workflow',
|
||||
params: {
|
||||
subject_type: 'holiday_applies',
|
||||
include: 'check.subject.employee,check.subject.type',
|
||||
},
|
||||
},
|
||||
])
|
||||
const mescrollItem0 = ref(null)
|
||||
const mescrollItem1 = ref(null)
|
||||
|
||||
const mescrollItems = [mescrollItem0, mescrollItem1]
|
||||
const { tabIndex, getMescroll, scrollToLastY } = useMescrollMore(
|
||||
mescrollItems,
|
||||
onPageScroll,
|
||||
onReachBottom
|
||||
)
|
||||
|
||||
onLoad(() => {
|
||||
uni.$on('refresh', () => {
|
||||
mescrollItem0?.value?.getMescroll()?.resetUpScroll()
|
||||
mescrollItem1?.value?.getMescroll()?.resetUpScroll()
|
||||
})
|
||||
})
|
||||
|
||||
const goPath = (url) => {
|
||||
uni.navigateTo({
|
||||
url,
|
||||
})
|
||||
}
|
||||
const tabChange = ({ index }) => {
|
||||
tabIndex.value = index
|
||||
scrollToLastY()
|
||||
}
|
||||
|
||||
const applyDetail = (item) => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/ask-leave/detail?id=${item.id}`,
|
||||
})
|
||||
}
|
||||
|
||||
const checkDetail = (item) => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/audits/detail?id=${item.id}&type=${item.check.subject_type}`
|
||||
})
|
||||
}
|
||||
|
||||
</script>
|
||||
|
|
@ -1,94 +0,0 @@
|
|||
<template>
|
||||
<uv-form labelWidth="200rpx">
|
||||
<template v-for="(item, i) in columsList" :key="i">
|
||||
<template v-if="item.show">
|
||||
<uv-form-item
|
||||
v-if="item.type == 'album'"
|
||||
:label="item.title"
|
||||
:labelWidth="item.labelWidth"
|
||||
labelPosition="top"
|
||||
>
|
||||
<!-- {{ item.value }} -->
|
||||
<view class="mt-20rpx w-full">
|
||||
<uv-album
|
||||
multipleSize="190rpx"
|
||||
singleSize="190rpx"
|
||||
:urls="item.value"
|
||||
:rowCount="3"
|
||||
:maxCount="50"
|
||||
space="18rpx"
|
||||
:showMore="false"
|
||||
></uv-album>
|
||||
</view>
|
||||
</uv-form-item>
|
||||
<uv-form-item
|
||||
v-else
|
||||
:label="item.title"
|
||||
:labelPosition="item.labelPosition"
|
||||
:labelWidth="item.labelWidth"
|
||||
>
|
||||
<view
|
||||
class="w-full text-hex-999"
|
||||
:style="[addStyle(item.customStyle)]"
|
||||
:class="[
|
||||
[
|
||||
item.labelPosition == 'top'
|
||||
? 'text-left mt-10rpx'
|
||||
: 'text-right',
|
||||
],
|
||||
]"
|
||||
>{{ item.value }}</view
|
||||
>
|
||||
</uv-form-item>
|
||||
<uv-line
|
||||
v-if="i < columsList.length - 1 && (item?.bottomBorder || true)"
|
||||
color="#f5f5f5"
|
||||
></uv-line>
|
||||
</template>
|
||||
</template>
|
||||
</uv-form>
|
||||
</template>
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
import { addStyle } from '@climblee/uv-ui/libs/function/index'
|
||||
|
||||
const props = defineProps({
|
||||
colums: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
data: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
})
|
||||
|
||||
const columsList = computed(() => {
|
||||
const arr = []
|
||||
props.colums.forEach((e) => {
|
||||
const { dataIndex, format, isShow } = e
|
||||
let str = getValue(props.data, dataIndex)
|
||||
let show = true
|
||||
if (isFunction(format)) {
|
||||
str = format(str)
|
||||
}
|
||||
if (isFunction(isShow)) {
|
||||
show = isShow(props.data)
|
||||
}
|
||||
arr.push({
|
||||
...e,
|
||||
value: str,
|
||||
show: show,
|
||||
})
|
||||
})
|
||||
return arr
|
||||
})
|
||||
|
||||
const getValue = (obj, path) => {
|
||||
return path.split('.').reduce((acc, key) => (acc ? acc[key] : undefined), obj)
|
||||
}
|
||||
|
||||
const isFunction = (fn) => {
|
||||
return typeof fn === 'function'
|
||||
}
|
||||
</script>
|
||||
|
|
@ -1,149 +0,0 @@
|
|||
import { timeFormat } from '@climblee/uv-ui/libs/function'
|
||||
import statusFun from '@/utils/status'
|
||||
|
||||
export default {
|
||||
//清洁任务
|
||||
task_hygienes: {
|
||||
data: [
|
||||
{ title: '审核状态', dataIndex: 'check_status', format: (value) => statusFun(value, 'statusExpense2', 'name') },
|
||||
{ title: '申请人', dataIndex: 'check.employee.name' },
|
||||
{ title: '所属门店', dataIndex: 'check.subject.store.title' },
|
||||
{ title: '电话号码', dataIndex: 'check.subject.store_master.phone' },
|
||||
{ title: '申请时间', dataIndex: 'check.subject.created_format' },
|
||||
{ title: '清洁范围', dataIndex: 'check.subject.description', labelPosition: 'top' },
|
||||
{ title: '清洁结果', dataIndex: 'check.subject.photos', type: 'album' },
|
||||
{ title: '未通过原因', dataIndex: 'remarks', labelPosition: 'top', isShow: (item) => item?.check_status == 4 },
|
||||
],
|
||||
params: { include: 'check.subject.task,check.subject.storeMaster,check.subject.store,check.employee' }
|
||||
},
|
||||
//报销
|
||||
reimbursements: {
|
||||
params: {
|
||||
include: 'check.subject.type,check.subject.employee,check.subject.store',
|
||||
},
|
||||
data: [
|
||||
{ title: '审核状态', dataIndex: 'check_status', format: (value) => statusFun(value, 'statusExpense2', 'name') },
|
||||
{ title: "申请人", dataIndex: "check.subject.employee.name" },
|
||||
{ title: "所属门店", dataIndex: "check.subject.store.title" },
|
||||
{ title: "电话号码", dataIndex: "check.subject.employee.phone" },
|
||||
{ title: "申请时间", dataIndex: "check.subject.created_format" },
|
||||
{ title: '报销分类', dataIndex: 'check.subject.type.name' },
|
||||
{ title: '报销金额', dataIndex: 'check.subject.expense' },
|
||||
{ title: '报销原因', dataIndex: 'check.subject.reason', labelPosition: 'top' },
|
||||
{ title: '报销凭证', dataIndex: 'check.subject.photos', type: 'album' },
|
||||
{ title: '未通过原因', dataIndex: 'remarks', labelPosition: 'top', isShow: (item) => item?.check_status == 4 },
|
||||
]
|
||||
},
|
||||
//升职
|
||||
employee_promotions: {
|
||||
params: {
|
||||
include: 'check.subject.store,check.subject.invitor,check.subject.employee,check.subject.job',
|
||||
},
|
||||
data: [
|
||||
{ title: '审核状态', dataIndex: 'check_status', format: (value) => statusFun(value, 'statusExpense2', 'name')},
|
||||
|
||||
{ title: '晋升职位', dataIndex: 'check.subject.job.name'},
|
||||
{ title: '推荐人', dataIndex: 'check.subject.invitor.name'},
|
||||
{ title: '申请人', dataIndex: 'check.subject.employee.name'},
|
||||
{ title: '年龄', dataIndex: 'check.subject.employee_data.age'},
|
||||
{ title: '性别', dataIndex: 'check.subject.employee_data.sex'},
|
||||
{ title: '学历', dataIndex: 'check.subject.employee_data.education'},
|
||||
{ title: '首次参加工作时间', dataIndex: 'check.subject.employee_data.first_work_time', labelWidth: "250rpx"},
|
||||
{ title: '工作年限', dataIndex: 'check.subject.employee_data.work_years'},
|
||||
{ title: '本公司工作年限', dataIndex: 'check.subject.employee_data.work_years_in_company'},
|
||||
{ title: '员工自评', dataIndex: 'check.subject.employee_data.comment_self', labelPosition: 'top'},
|
||||
{ title: '未来计划', dataIndex: 'check.subject.employee_data.plans', labelPosition: 'top'},
|
||||
{ title: '推荐理由', dataIndex: 'check.subject.employee_data.reason', labelPosition: 'top'},
|
||||
{ title: '未通过原因', dataIndex: 'remarks', labelPosition: 'top', isShow: (item) => item?.check_status == 4},
|
||||
]
|
||||
},
|
||||
//补卡申请
|
||||
employee_sign_repairs: {
|
||||
params: {
|
||||
include: 'check.subject.employee,check.subject.store',
|
||||
},
|
||||
data: [
|
||||
{ title: '审核状态', dataIndex: 'check_status', format: (value) => statusFun(value, 'statusExpense2', 'name')},
|
||||
|
||||
{ title: '申请人', dataIndex: 'check.subject.employee.name'},
|
||||
{ title: '所属门店', dataIndex: 'check.subject.store.title'},
|
||||
{ title: '电话号码', dataIndex: 'check.subject.employee.phone'},
|
||||
{ title: '申请时间', dataIndex: 'check.subject.created_format'},
|
||||
{ title: '补卡时间', dataIndex: 'check.subject.date_format'},
|
||||
{ title: '补卡类别', dataIndex: 'check.subject.sign_time_text'},
|
||||
{ title: '补卡原因', dataIndex: 'check.subject.reason', labelPosition: 'top'},
|
||||
{ title: '是否外勤', dataIndex: 'check.subject.sign_type', format: (e) => e == 1 ? '否' : '是'},
|
||||
{ title: '外勤事由', dataIndex: 'check.subject.outside_remarks', labelPosition: 'top', isShow: (item) => item?.check?.subject?.sign_type == 2},
|
||||
{ title: '未通过原因', dataIndex: 'remarks', labelPosition: 'top', isShow: (item) => item?.check_status == 4},
|
||||
]
|
||||
},
|
||||
//请假申请
|
||||
holiday_applies: {
|
||||
params: {
|
||||
include: 'check.subject.employee,check.subject.type,check.subject.store'
|
||||
},
|
||||
data: [
|
||||
{ title: '审核状态', dataIndex: 'check_status', format: (value) => statusFun(value, 'statusExpense2', 'name')},
|
||||
{ title: '申请人', dataIndex: 'check.subject.employee.name'},
|
||||
{ title: '所属门店', dataIndex: 'check.subject.store.title'},
|
||||
{ title: '电话号码', dataIndex: 'check.subject.employee.phone'},
|
||||
{ title: '申请时间', dataIndex: 'check.subject.created_format'},
|
||||
{ title: '请假类型', dataIndex: 'check.subject.type.name'},
|
||||
{ title: '请假开始时间', dataIndex: 'check.subject.start_format'},
|
||||
{ title: '请假结束时间', dataIndex: 'check.subject.end_format'},
|
||||
{ title: '请假事由', dataIndex: 'check.subject.reason', labelPosition: 'top'},
|
||||
{ title: '未通过原因', dataIndex: 'remarks', labelPosition: 'top', isShow: (item) => item?.check_status == 4},
|
||||
]
|
||||
},
|
||||
offical_business: {
|
||||
params: {
|
||||
include: 'check.subject.employee,check.subject.store'
|
||||
},
|
||||
data: [
|
||||
{ title: '审核状态', dataIndex: 'check_status', format: (value) => statusFun(value, 'statusExpense2', 'name')},
|
||||
{ title: '申请人', dataIndex: 'check.subject.employee.name' },
|
||||
{ title: '所属门店', dataIndex: 'check.subject.store.title' },
|
||||
{ title: '电话号码', dataIndex: 'check.subject.employee.phone' },
|
||||
{ title: '申请时间', dataIndex: 'check.subject.created_format' },
|
||||
{ title: '目的地', dataIndex: 'check.subject.address' },
|
||||
{ title: '开始时间', dataIndex: 'check.subject.start_format' },
|
||||
{ title: '结束时间', dataIndex: 'check.subject.end_format' },
|
||||
{ title: '出差事由', dataIndex: 'check.subject.reason', labelPosition: 'top' },
|
||||
{ title: '未通过原因', dataIndex: 'remarks', labelPosition: 'top', isShow: (item) => item?.check_status == 4 },
|
||||
]
|
||||
},
|
||||
overtime_applies: {
|
||||
params: {
|
||||
include: 'check.subject.employee,check.subject.store'
|
||||
},
|
||||
data: [
|
||||
{ title: '审核状态', dataIndex: 'check_status', format: (value) => statusFun(value, 'statusExpense2', 'name')},
|
||||
|
||||
{ title: '申请人', dataIndex: 'check.subject.employee.name' },
|
||||
{ title: '所属门店', dataIndex: 'check.subject.store.title' },
|
||||
{ title: '电话号码', dataIndex: 'check.subject.employee.phone' },
|
||||
{ title: '申请时间', dataIndex: 'check.subject.created_format' },
|
||||
{ title: '加班日期', dataIndex: 'check.subject.date_format' },
|
||||
{ title: '开始时间', dataIndex: 'check.subject.start_format' },
|
||||
{ title: '结束时间', dataIndex: 'check.subject.end_format' },
|
||||
{ title: '加班时长', dataIndex: 'check.subject.hours' ,format: (value) => value + ' 小时'},
|
||||
{ title: '加班事由', dataIndex: 'check.subject.reason', labelPosition: 'top' },
|
||||
{ title: '未通过原因', dataIndex: 'remarks', labelPosition: 'top', isShow: (item) => item?.check_status == 4 },
|
||||
]
|
||||
},
|
||||
agreements: {
|
||||
params: {
|
||||
include: 'check.subject.employee,check.subject.store'
|
||||
},
|
||||
data: [
|
||||
{ title: '审核状态', dataIndex: 'check_status', format: (value) => statusFun(value, 'statusExpense2', 'name')},
|
||||
{ title: '上传人', dataIndex: 'check.subject.employee.name' },
|
||||
{ title: '所属门店', dataIndex: 'check.subject.store.title' },
|
||||
{ title: '电话号码', dataIndex: 'check.subject.employee.phone' },
|
||||
{ title: '上传时间', dataIndex: 'check.subject.created_format' },
|
||||
{ title: '合同名称', dataIndex: 'check.subject.name' },
|
||||
{ title: '合同内容', dataIndex: 'check.subject.images', type: 'album' },
|
||||
{ title: '未通过原因', dataIndex: 'remarks', labelPosition: 'top', isShow: (item) => item?.check_status == 4 },
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -1,124 +0,0 @@
|
|||
<template>
|
||||
<view>
|
||||
<CuNavbar title="审核详情">
|
||||
<template #right>
|
||||
<view class="text-sm text-white" @click="goPath(`/pages/audits/log?id=${data.check_id}`)">审核流程</view>
|
||||
</template>
|
||||
</CuNavbar>
|
||||
<view class="px-base mt-30rpx">
|
||||
<view class="card-shadow bg-white rounded-19rpx px-base">
|
||||
<BaseData :colums="colums" :data="data"></BaseData>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="checkable" class="h-100rpx">
|
||||
<view
|
||||
class="fixed bottom-0 left-0 right-0 h-120rpx bg-white flex items-center px-base space-x-30rpx"
|
||||
>
|
||||
<view class="flex-1">
|
||||
<uv-button @click="onJj" color="#999999" shape="circle" plain block>
|
||||
拒绝
|
||||
</uv-button>
|
||||
</view>
|
||||
<view class="flex-1">
|
||||
<uv-button type="primary" shape="circle" block @click="onTg">
|
||||
通过
|
||||
</uv-button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<uv-modal
|
||||
ref="modalRef"
|
||||
title="提示"
|
||||
:content="modelOptions.content"
|
||||
@confirm="modelOptions.onConfirm"
|
||||
:showCancelButton="true"
|
||||
>
|
||||
<view class="flex-1" v-if="modelOptions.isValue">
|
||||
<view class="w-full">
|
||||
<uv-textarea v-model="value" placeholder="请填写未通过原因"></uv-textarea>
|
||||
</view>
|
||||
</view>
|
||||
</uv-modal>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { ref, computed, reactive } from 'vue'
|
||||
import { http } from '@/utils/request'
|
||||
import BaseData from './base-data.vue'
|
||||
import datajson from './data.data'
|
||||
|
||||
const value = ref('')
|
||||
const colums = computed(() => datajson[type.value].data ?? [])
|
||||
const params = computed(() => datajson[type.value].params ?? {})
|
||||
const id = ref(null)
|
||||
const type = ref(null)
|
||||
const data = ref(null)
|
||||
const checkable = ref(false)
|
||||
|
||||
const modalRef = ref(null)
|
||||
|
||||
const modelOptions = reactive({
|
||||
title: '提示',
|
||||
content: '确定通过吗?',
|
||||
isValue: false,
|
||||
onConfirm: () => {},
|
||||
})
|
||||
|
||||
const onConfirm = async () => {
|
||||
if (modelOptions.isValue && !value.value) {
|
||||
return uni.showToast({title: "请填写未通过原因", icon: "none"})
|
||||
}
|
||||
try {
|
||||
await http.post(`/workflow/${id.value}/check`, {
|
||||
status: !modelOptions.isValue,
|
||||
remarks: modelOptions.isValue ? value.value : '',
|
||||
})
|
||||
uni.$emit('refresh', { index: 'check' })
|
||||
uni.navigateBack()
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
|
||||
const onTg = () => {
|
||||
value.value = ''
|
||||
modelOptions.title = '提示'
|
||||
modelOptions.content = '确定通过吗?'
|
||||
modelOptions.isValue = false
|
||||
modelOptions.onConfirm = onConfirm
|
||||
modalRef.value.open()
|
||||
}
|
||||
const onJj = () => {
|
||||
value.value = ''
|
||||
modelOptions.title = '拒绝原因'
|
||||
modelOptions.content = '确定拒绝吗?'
|
||||
modelOptions.isValue = true
|
||||
modelOptions.onConfirm = onConfirm
|
||||
modalRef.value.open()
|
||||
}
|
||||
|
||||
onLoad((opt) => {
|
||||
id.value = opt.id
|
||||
type.value = opt.type
|
||||
getData()
|
||||
})
|
||||
|
||||
const getData = async () => {
|
||||
const resData = await http.get(`/workflow/${id.value}`, {
|
||||
params: {
|
||||
subject_type: type.value,
|
||||
...params.value,
|
||||
},
|
||||
})
|
||||
data.value = resData.data
|
||||
checkable.value = resData.checkable
|
||||
}
|
||||
|
||||
const goPath = (url) => {
|
||||
uni.navigateTo({ url })
|
||||
}
|
||||
</script>
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
<template>
|
||||
<view class="p-base">
|
||||
<CuNavbar title="审核流程"></CuNavbar>
|
||||
<view class="card-shadow bg-white p-base">
|
||||
<uv-steps direction="column">
|
||||
<uv-steps-item v-for="item in list" :key="item.id">
|
||||
<template #icon>
|
||||
<view class="w-31rpx h-31rpx rounded-full mt-4rpx" :class="[item.check_status == 2 || item.check_status == 3? 'bg-blue': 'bg-gray-300']"></view>
|
||||
</template>
|
||||
<template #title>
|
||||
<view class="space-y-6rpx">
|
||||
<view class="flex items-center space-x-14rpx">
|
||||
<view> {{ item.check_user ? item.check_user.name : item.check_name }}</view>
|
||||
</view>
|
||||
<view v-if="item.check_status > 1" class="text-26rpx" :style="{ color: statusFun(item.check_status, 'statusExpense', 'color')}">
|
||||
{{ statusFun(item.check_status, 'statusExpense', 'name') }}
|
||||
</view>
|
||||
<view class="text-26rpx text-red" v-if="item.check_status == 4">{{item.remarks}}</view>
|
||||
</view>
|
||||
</template>
|
||||
<template #desc>
|
||||
<view v-if="item.checked_at" class="text-26rpx text-hex-999">{{ item.checked_format }}</view>
|
||||
</template>
|
||||
</uv-steps-item>
|
||||
</uv-steps>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import { http } from '@/utils/request'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { computed, ref } from 'vue'
|
||||
import { timeFormat } from '@climblee/uv-ui/libs/function'
|
||||
import statusFun from '@/utils/status'
|
||||
const list = ref([])
|
||||
onLoad((options) => {
|
||||
http.get(`/workflow/${options.id}/logs`).then((res) => {
|
||||
list.value = res
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
|
@ -1,176 +0,0 @@
|
|||
<template>
|
||||
<view>
|
||||
<CuNavbar title="出差申请">
|
||||
<template #right>
|
||||
<view class="text-24rpx text-white" @click="submit">提交</view>
|
||||
</template>
|
||||
</CuNavbar>
|
||||
<view class="card-shadow px-base">
|
||||
<uv-form labelPosition="left" :model="form" :rules="rules" ref="formRef" errorType="toast" labelWidth="250rpx">
|
||||
<uv-form-item required label="目的地" prop="address">
|
||||
<uv-input placeholder="请输入目的地" inputAlign="right" :border="`none`" v-model="form.address">
|
||||
</uv-input>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item required label="出差开始时间" prop="start_at">
|
||||
<uv-input
|
||||
placeholder="请选择出差开始时间"
|
||||
readonly
|
||||
@click="openStartDatePicker"
|
||||
inputAlign="right"
|
||||
:border="`none`"
|
||||
v-model="form.start_at"
|
||||
>
|
||||
</uv-input>
|
||||
</uv-form-item>
|
||||
<uv-form-item required label="出差结束时间" prop="end_at">
|
||||
<uv-input
|
||||
placeholder="请选择出差结束时间"
|
||||
readonly
|
||||
@click="openEndDatePicker"
|
||||
inputAlign="right"
|
||||
:border="`none`"
|
||||
v-model="form.end_at"
|
||||
>
|
||||
</uv-input>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item required label="出差事由" prop="reason" labelPosition="top">
|
||||
<uv-textarea :customStyle="{ padding: '0' }" v-model="form.reason" count placeholder="请输入出差事由" :border="`none`" :maxlength="200"></uv-textarea>
|
||||
</uv-form-item>
|
||||
</uv-form>
|
||||
</view>
|
||||
<uv-datetime-picker
|
||||
placeholder="请选择日期"
|
||||
v-model="startValue"
|
||||
ref="dateStartPicker"
|
||||
mode="datetime"
|
||||
@confirm="confirmStartDatePicker"
|
||||
>
|
||||
</uv-datetime-picker>
|
||||
<uv-datetime-picker
|
||||
v-model="endValue"
|
||||
placeholder="请选择日期"
|
||||
ref="dateEndPicker"
|
||||
mode="datetime"
|
||||
@confirm="confirmEndDatePicker"
|
||||
>
|
||||
</uv-datetime-picker>
|
||||
<uv-modal ref="modalRef" title="提示" content="确定提交吗?" @confirm="onSubmit" :showCancelButton="true"></uv-modal>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from "@/components/cu-navbar/index"
|
||||
import { ref, reactive, computed } from "vue"
|
||||
import { onLoad } from "@dcloudio/uni-app"
|
||||
import { http } from "@/utils/request"
|
||||
import { timeFormat } from "@climblee/uv-ui/libs/function/index"
|
||||
const columns = ref([])
|
||||
const pickerData = ref([])
|
||||
const formRef = ref(null)
|
||||
const dateStartPicker = ref(null)
|
||||
const dateEndPicker = ref(null)
|
||||
const modalRef = ref(null)
|
||||
const startValue = ref(Number(new Date()))
|
||||
const endValue = ref(Number(new Date()))
|
||||
const id = ref(0)
|
||||
const loading = ref(false)
|
||||
const form = reactive({
|
||||
start_at: "",
|
||||
end_at: "",
|
||||
reason: "",
|
||||
address: ""
|
||||
})
|
||||
const openStartDatePicker = () => {
|
||||
dateStartPicker.value.open()
|
||||
}
|
||||
const openEndDatePicker = () => {
|
||||
dateEndPicker.value.open()
|
||||
}
|
||||
const confirmStartDatePicker = e => {
|
||||
form.start_at = timeFormat(e.value, "yyyy-mm-dd hh:MM:ss")
|
||||
}
|
||||
const confirmEndDatePicker = e => {
|
||||
form.end_at = timeFormat(e.value, "yyyy-mm-dd hh:MM:ss")
|
||||
}
|
||||
const rules = reactive({
|
||||
address: [{ required: true, message: "请输入目的地" }],
|
||||
start_at: [{ required: true, message: "请选择出差开始时间" }],
|
||||
end_at: [{ required: true, message: "请选择出差结束时间" }],
|
||||
reason: [{ required: true, message: "请输入出差事由" }],
|
||||
|
||||
})
|
||||
onLoad(options => {
|
||||
http
|
||||
.request({
|
||||
url: `/keywords?parent_key=holiday_type`,
|
||||
method: "GET",
|
||||
header: {
|
||||
Accept: "application/json"
|
||||
}
|
||||
})
|
||||
.then(res => {
|
||||
let names = res.map(item => item.name)
|
||||
columns.value = [names]
|
||||
pickerData.value = res
|
||||
})
|
||||
id.value = options.id
|
||||
if (id.value) {
|
||||
http
|
||||
.request({
|
||||
url: `/hr/offical-bussiness/${options.id}`,
|
||||
method: "GET",
|
||||
header: {
|
||||
Accept: "application/json"
|
||||
}
|
||||
})
|
||||
.then(res => {
|
||||
startValue.value = res.start_at * 1000
|
||||
endValue.value = res.end_at * 1000
|
||||
form.start_at = timeFormat(res.start_at, "yyyy-mm-dd hh:MM:ss")
|
||||
form.end_at = timeFormat(res.end_at, "yyyy-mm-dd hh:MM:ss")
|
||||
form.reason = res.reason
|
||||
form.address = res.address
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const submit = () => {
|
||||
formRef.value.validate().then(res => {
|
||||
modalRef.value.open()
|
||||
})
|
||||
}
|
||||
|
||||
const onSubmit = async () => {
|
||||
if (loading.value) return
|
||||
loading.value = true
|
||||
try {
|
||||
let url = id.value ? `/hr/offical-bussiness/${id.value}` : "/hr/offical-bussiness"
|
||||
let method = id.value ? "PUT" : "POST"
|
||||
await http.request({
|
||||
url: url,
|
||||
method: method,
|
||||
header: {
|
||||
Accept: "application/json"
|
||||
},
|
||||
data: {
|
||||
start_at: form.start_at,
|
||||
address: form.address,
|
||||
reason: form.reason,
|
||||
end_at: form.end_at
|
||||
}
|
||||
})
|
||||
uni.showToast({
|
||||
title: "提交成功",
|
||||
icon: "none"
|
||||
})
|
||||
formRef.value.resetFields()
|
||||
uni.$emit('refresh')
|
||||
uni.navigateBack()
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -1,98 +0,0 @@
|
|||
<template>
|
||||
<view class="px-base" v-if="detail">
|
||||
<CuNavbar title="出差详情">
|
||||
<template v-if="actions.length > 0" #right>
|
||||
<uv-icon color="white" @click="open" name="more-dot-fill"></uv-icon>
|
||||
</template>
|
||||
</CuNavbar>
|
||||
<view class="mt-30rpx card-shadow bg-white rounded-19rpx px-base text-[#333333] text-27rpx">
|
||||
<BaseData :data="detail" :colums="columns" />
|
||||
</view>
|
||||
<uv-action-sheet ref="pickerRef" :actions="actions" @select="confirmPicker" />
|
||||
<uv-modal ref="modalRef" title="提示" content="确定删除吗?" @confirm="onSubmit" :showCancelButton="true"></uv-modal>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from "@/components/cu-navbar/index"
|
||||
import { http } from "@/utils/request"
|
||||
import { onLoad } from "@dcloudio/uni-app"
|
||||
import { ref } from "vue"
|
||||
import { timeFormat } from "@climblee/uv-ui/libs/function/index"
|
||||
import BaseData from '../audits/base-data'
|
||||
import statusFun from '@/utils/status'
|
||||
|
||||
const modalRef = ref(null)
|
||||
const actions = ref([
|
||||
{ name: '修改', value: 'edit', disabled: false },
|
||||
{ name: '删除', value: 'delete', disabled: false },
|
||||
{ name: '审核流程', value: 'check-logs', disabled: false }
|
||||
])
|
||||
const detail = ref({})
|
||||
|
||||
const columns = [
|
||||
{ title: '审核状态', dataIndex: 'workflow_check.check_status', format: (value) => statusFun(value, 'statusExpense', 'name') },
|
||||
{ title: '申请人', dataIndex: 'employee.name' },
|
||||
{ title: '所属门店', dataIndex: 'store.title' },
|
||||
{ title: '电话号码', dataIndex: 'employee.phone' },
|
||||
{ title: '申请时间', dataIndex: 'created_format' },
|
||||
{ title: '目的地', dataIndex: 'address' },
|
||||
{ title: '开始时间', dataIndex: 'start_format' },
|
||||
{ title: '结束时间', dataIndex: 'end_format' },
|
||||
{ title: '出差事由', dataIndex: 'reason', labelPosition: 'top' },
|
||||
{ title: '未通过原因', dataIndex: 'workflow_check.check_remarks', labelPosition: 'top', isShow: (data) => data?.workflow_check?.check_status == 4 },
|
||||
]
|
||||
|
||||
const pickerRef = ref(null)
|
||||
const id = ref(0)
|
||||
const open = () => {
|
||||
pickerRef.value.open()
|
||||
}
|
||||
const confirmPicker = e => {
|
||||
if (e.value == 'edit') {
|
||||
return uni.navigateTo({
|
||||
url: `/pages/business/create?id=${id.value}`
|
||||
})
|
||||
}
|
||||
if (e.value == 'delete') {
|
||||
return modalRef.value.open()
|
||||
}
|
||||
if (e.value == 'check-logs') {
|
||||
return uni.navigateTo({
|
||||
url: `/pages/audits/log?id=${detail.value.workflow_check.id}`
|
||||
})
|
||||
}
|
||||
}
|
||||
const onSubmit = async () => {
|
||||
try {
|
||||
await http.request({
|
||||
url: `/hr/offical-bussiness/${id.value}`,
|
||||
method: "DELETE",
|
||||
header: {
|
||||
Accept: "application/json"
|
||||
}
|
||||
})
|
||||
uni.showToast({
|
||||
title: "删除成功",
|
||||
icon: "none"
|
||||
})
|
||||
uni.$emit('refresh')
|
||||
uni.navigateBack()
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
onLoad(options => {
|
||||
id.value = options.id
|
||||
http.get(`/hr/offical-bussiness/${options.id}`).then(res => {
|
||||
detail.value = res
|
||||
let status = res.workflow_check.check_status
|
||||
if ([2, 3].indexOf(status) != -1) {
|
||||
actions.value[0].disabled = true
|
||||
actions.value[1].disabled = true
|
||||
// actions.value.splice(0, 2)
|
||||
}
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
|
@ -1,130 +0,0 @@
|
|||
<template>
|
||||
<view>
|
||||
<CuNavbar title="出差报备">
|
||||
<template #right>
|
||||
<view @click="goPath('/pages/business/create')" class="text-24rpx text-white">申请</view>
|
||||
</template>
|
||||
</CuNavbar>
|
||||
<uv-sticky bgColor="#fff">
|
||||
<uv-tabs
|
||||
:activeStyle="{ color: '#ee2c37' }"
|
||||
:scrollable="false"
|
||||
lineColor="#ee2c37"
|
||||
:list="tabList"
|
||||
@change="tabChange"
|
||||
></uv-tabs>
|
||||
</uv-sticky>
|
||||
<MescrollItem
|
||||
ref="mescrollItem0"
|
||||
:top="88"
|
||||
:i="0"
|
||||
:index="tabIndex"
|
||||
:apiUrl="tabList[0].apiUrl"
|
||||
>
|
||||
<template v-slot="{ list }">
|
||||
<view class="space-y-15rpx p-base">
|
||||
<ListItem
|
||||
v-for="item in list" :key="item.id"
|
||||
title="出差报备"
|
||||
:status-text="statusFun(item.workflow_check.check_status, 'statusExpense', 'name')"
|
||||
:status-color="statusFun(item.workflow_check.check_status, 'statusExpense', 'color')"
|
||||
:body="[
|
||||
{label: '目的地: ', value: item.address},
|
||||
{label: '出差事由: ', value: item.reason},
|
||||
{label: '申请时间: ', value: item.created_format},
|
||||
]"
|
||||
@click="applyDetail(item)"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
</MescrollItem>
|
||||
|
||||
<MescrollItem
|
||||
ref="mescrollItem1"
|
||||
:top="88"
|
||||
:i="1"
|
||||
:index="tabIndex"
|
||||
:apiUrl="tabList[1].apiUrl"
|
||||
:params="tabList[1].params"
|
||||
>
|
||||
<template v-slot="{ list }">
|
||||
<view class="space-y-15rpx p-base">
|
||||
<ListItem
|
||||
v-for="item in list" :key="item.id"
|
||||
title="出差报备"
|
||||
:status-text="statusFun( item.check_status,'statusExpense2','name')"
|
||||
:status-color="statusFun( item.check_status,'statusExpense2','color')"
|
||||
:body="[
|
||||
{label: '申请人: ', value: item.check.subject.employee.name},
|
||||
{label: '目的地: ', value: item.check.subject.address},
|
||||
{label: '出差事由: ', value: item.check.subject.reason},
|
||||
{label: '申请时间: ', value: item.check.subject.created_format},
|
||||
]"
|
||||
@click="checkDetail(item)"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
</MescrollItem>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import { ref } from 'vue'
|
||||
import { onPageScroll, onReachBottom, onLoad } from '@dcloudio/uni-app'
|
||||
import useMescrollMore from '@/uni_modules/mescroll-uni/hooks/useMescrollMore.js'
|
||||
import MescrollItem from '@/components/mescroll-api/more.vue'
|
||||
import statusFun from "@/utils/status"
|
||||
import ListItem from '@/components/list-item'
|
||||
|
||||
const tabList = ref([
|
||||
{
|
||||
name: '我的出差',
|
||||
apiUrl: '/hr/offical-bussiness',
|
||||
},
|
||||
{
|
||||
name: '出差审核',
|
||||
apiUrl: '/workflow',
|
||||
params: {
|
||||
subject_type: 'offical_business',
|
||||
include: 'check.subject.employee',
|
||||
},
|
||||
},
|
||||
])
|
||||
const mescrollItem0 = ref(null)
|
||||
const mescrollItem1 = ref(null)
|
||||
|
||||
const mescrollItems = [mescrollItem0, mescrollItem1]
|
||||
const { tabIndex, getMescroll, scrollToLastY } = useMescrollMore(
|
||||
mescrollItems,
|
||||
onPageScroll,
|
||||
onReachBottom
|
||||
)
|
||||
|
||||
onLoad(() => {
|
||||
uni.$on('refresh', () => {
|
||||
mescrollItem0?.value?.getMescroll()?.resetUpScroll()
|
||||
mescrollItem1?.value?.getMescroll()?.resetUpScroll()
|
||||
})
|
||||
})
|
||||
const goPath = (url) => {
|
||||
uni.navigateTo({
|
||||
url,
|
||||
})
|
||||
}
|
||||
const tabChange = ({ index }) => {
|
||||
tabIndex.value = index
|
||||
scrollToLastY()
|
||||
}
|
||||
|
||||
const applyDetail = (item) => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/business/detail?id=${item.id}`
|
||||
})
|
||||
}
|
||||
|
||||
const checkDetail = (item) => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/audits/detail?id=${item.id}&type=${item.check.subject_type}`
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
|
@ -1,242 +0,0 @@
|
|||
<template>
|
||||
<view class="px-base">
|
||||
<CuNavbar title="考勤打卡">
|
||||
<template #right>
|
||||
<view
|
||||
@click="goPage('/pages/clockout/logs')"
|
||||
class="text-24rpx text-white"
|
||||
>打卡记录</view
|
||||
>
|
||||
</template>
|
||||
</CuNavbar>
|
||||
<view class="card-shadow px-base mt-base">
|
||||
<uv-form
|
||||
labelPosition="left"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
ref="formRef"
|
||||
labelWidth="160rpx"
|
||||
errorType="toast"
|
||||
>
|
||||
<uv-form-item :label="form.sign_time" @click="openPicker" prop="sign">
|
||||
<view class="w-full">
|
||||
<view class="text-hex-999" v-if="!form.sign_time">
|
||||
请选择打卡时间
|
||||
</view>
|
||||
<!-- <uv-input
|
||||
:border="`none`"
|
||||
readonly
|
||||
v-model="form.sign_time"
|
||||
placeholder="请选择打卡时间"
|
||||
></uv-input> -->
|
||||
</view>
|
||||
<template v-slot:right>
|
||||
<uv-icon name="arrow-right"></uv-icon>
|
||||
</template>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item label="外勤" prop="type">
|
||||
<view class="flex flex-1 justify-end">
|
||||
<uv-switch
|
||||
size="20"
|
||||
:activeValue="2"
|
||||
:inactiveValue="1"
|
||||
v-model="form.type"
|
||||
></uv-switch>
|
||||
</view>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item v-if="form.type == 2" label="事由" prop="remarks">
|
||||
<uv-input
|
||||
v-model="form.remarks"
|
||||
count
|
||||
inputAlign="right"
|
||||
placeholder="请输入外勤事由"
|
||||
:border="`none`"
|
||||
:maxlength="200"
|
||||
></uv-input>
|
||||
</uv-form-item>
|
||||
</uv-form>
|
||||
|
||||
<view class="h-40vh flex-center flex-col">
|
||||
<view
|
||||
:disabled="!(Check && isType)"
|
||||
@click="clockIn"
|
||||
class="w-220rpx h-220rpx rounded-full overflow-hidden card-shadow1 flex-center btn"
|
||||
>
|
||||
<view class="text-white text-center">
|
||||
<view class="text-40rpx">打卡</view>
|
||||
<view class="mt-1">{{ timeFormat(newTime, 'hh:MM:ss') }}</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="mt-40rpx text-center flex-center flex-col">
|
||||
<!-- <view v-if="isGPS === false" class="text-primary text-26rpx"
|
||||
>定位失败,请检查手机定位权限是否开启</view
|
||||
> -->
|
||||
|
||||
<view class="text-hex-999 text-26rpx">{{ detail.description }}</view>
|
||||
<view
|
||||
@click="getLoca"
|
||||
class="flex items-center mt-10rpx text-hex-9397df text-28rpx"
|
||||
>
|
||||
<uv-icon size="28rpx" color="#9397df" name="map-fill"></uv-icon>
|
||||
<view>重新获取定位</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<uv-picker
|
||||
ref="timePicker"
|
||||
:columns="timeList"
|
||||
keyName="name"
|
||||
@confirm="timeConfirm"
|
||||
></uv-picker>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import { ref, onMounted, reactive, computed } from 'vue'
|
||||
import { http } from '@/utils/request'
|
||||
import { timeFormat } from '@climblee/uv-ui/libs/function'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
const loading = ref(false)
|
||||
const isGPS = ref(true)
|
||||
const timePicker = ref(null)
|
||||
const timeList = ref([
|
||||
[
|
||||
{
|
||||
name: '上班打卡',
|
||||
value: 1,
|
||||
},
|
||||
{
|
||||
name: '下班打卡',
|
||||
value: 2,
|
||||
},
|
||||
],
|
||||
])
|
||||
const position = ref({})
|
||||
const newTime = ref('')
|
||||
const detail = ref({})
|
||||
const form = reactive({
|
||||
time: null,
|
||||
type: 1,
|
||||
remarks: '',
|
||||
sign_time: '',
|
||||
})
|
||||
const rules = ref({})
|
||||
|
||||
const Check = computed(() => {
|
||||
return detail.value.enable
|
||||
})
|
||||
const isType = computed(() => {
|
||||
if (detail.value.type == 2) {
|
||||
if (form.type == 2) {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
const maxDistance = computed(() => {
|
||||
return detail.value.maxDistance
|
||||
})
|
||||
|
||||
const timeConfirm = ({ value }) => {
|
||||
form.time = value[0].value
|
||||
form.sign_time = value[0].name
|
||||
}
|
||||
|
||||
onLoad(() => {
|
||||
getLoca()
|
||||
setInterval(() => {
|
||||
newTime.value = new Date()
|
||||
}, 1000)
|
||||
})
|
||||
|
||||
const getLoca = async () => {
|
||||
// uni.openLocation
|
||||
uni.getLocation({
|
||||
type: 'wgs84',
|
||||
fail: (err) => {
|
||||
isGPS.value = false
|
||||
// uni.showToast({
|
||||
// icon: 'none',
|
||||
// title: '定位失败,请检查手机定位权限是否开启',
|
||||
// })
|
||||
},
|
||||
success: (res) => {
|
||||
isGPS.value = true
|
||||
},
|
||||
complete: async (e) => {
|
||||
position.value = {
|
||||
lat: e.latitude,
|
||||
lon: e.longitude,
|
||||
...e,
|
||||
}
|
||||
initLo()
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
const initLo = async () => {
|
||||
const resdata = await http.get('/hr/sign/info', {
|
||||
params: {
|
||||
...position.value,
|
||||
},
|
||||
})
|
||||
detail.value = resdata
|
||||
form.time = resdata.time || 1
|
||||
form.sign_time = timeList.value[0].find((e) => e.value == form.time)?.name
|
||||
}
|
||||
|
||||
const openPicker = () => {
|
||||
timePicker.value.open()
|
||||
}
|
||||
|
||||
const clockIn = async () => {
|
||||
if (!form.time) {
|
||||
return uni.showToast({ title: '请选择打卡时间', icon: 'none' })
|
||||
}
|
||||
if (form.type == 2 && !form.remarks) {
|
||||
return uni.showToast({ title: '请填写外勤事由', icon: 'none' })
|
||||
}
|
||||
|
||||
if (loading.value) return
|
||||
loading.value = true
|
||||
|
||||
try {
|
||||
await http.post('/hr/sign', {
|
||||
time: form.time,
|
||||
type: form.type,
|
||||
remarks: form.remarks,
|
||||
position: position.value,
|
||||
})
|
||||
form.remarks = ''
|
||||
uni.showToast({ title: '打卡成功', icon: 'none' })
|
||||
// uni.navigateTo({ url: '/pages/clockout/logs' })
|
||||
} catch (error) {
|
||||
} finally {
|
||||
initLo()
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
const goPage = (url) => {
|
||||
uni.navigateTo({ url: url })
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.card-shadow1 {
|
||||
background: #3678f7;
|
||||
box-shadow: 0px 0px 16px 0px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.btn {
|
||||
&[disabled='true'] {
|
||||
@apply bg-hex-999 pointer-events-none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,122 +0,0 @@
|
|||
<template>
|
||||
<view>
|
||||
<CuNavbar title="打卡记录"></CuNavbar>
|
||||
<view class="card-shadow">
|
||||
<cu-calendars
|
||||
insert
|
||||
@monthSwitch="onChange"
|
||||
:selected="selected"
|
||||
@change="onChangeDay"
|
||||
:endDate="timeFormat(new Date())"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view
|
||||
v-if="current?.sign_status"
|
||||
class="px-90rpx mt-20rpx card-shadow bg-white rounded-19rpx p-base mx-base"
|
||||
>
|
||||
<uv-steps current="0" dot direction="column">
|
||||
<uv-steps-item title="上班打卡">
|
||||
<template #icon>
|
||||
<view
|
||||
class="w-16rpx h-16rpx rounded-full"
|
||||
:style="{ background: current.first_time ? '#3c9cff' : '#999' }"
|
||||
></view>
|
||||
</template>
|
||||
<template #desc>
|
||||
<view class="text-24rpx text-hex-999">{{
|
||||
current.first_time
|
||||
}}</view>
|
||||
<view class="flex" v-if="!current.first_time">
|
||||
<uv-tags plain size="mini" text="缺卡" type="error"></uv-tags>
|
||||
</view>
|
||||
</template>
|
||||
</uv-steps-item>
|
||||
<uv-steps-item title="下班打卡">
|
||||
<template #icon>
|
||||
<view
|
||||
class="w-16rpx h-16rpx rounded-full"
|
||||
:style="{ background: current.last_time ? '#3c9cff' : '#999' }"
|
||||
></view>
|
||||
</template>
|
||||
<template #desc>
|
||||
<view class="text-24rpx text-hex-999">{{ current.last_time }}</view>
|
||||
<view class="flex" v-if="!current.last_time">
|
||||
<uv-tags plain size="mini" text="缺卡" type="error"></uv-tags>
|
||||
</view>
|
||||
</template>
|
||||
</uv-steps-item>
|
||||
</uv-steps>
|
||||
<view
|
||||
@click="goC"
|
||||
class="flex text-24rpx mt-10rpx"
|
||||
v-if="current?.sign_status != 1"
|
||||
>
|
||||
<view class="text-hex-3c9cff">补卡申请></view>
|
||||
<view>更新打卡</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue'
|
||||
import { http } from '@/utils/request'
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import { onLoad, onShow } from '@dcloudio/uni-app'
|
||||
import { timeFormat } from '@climblee/uv-ui/libs/function/index'
|
||||
import CuCalendars from '@/components/cu-calendars/uv-calendars'
|
||||
const selected = ref([])
|
||||
const time = ref('')
|
||||
const date = ref('')
|
||||
onShow(() => {
|
||||
getData()
|
||||
})
|
||||
|
||||
const current = computed(
|
||||
() => selected.value.find((e) => e.date == date.value)?.data ?? {}
|
||||
)
|
||||
|
||||
const getData = async () => {
|
||||
const res = await http.get('/hr/sign', {
|
||||
params: {
|
||||
time: time.value,
|
||||
},
|
||||
})
|
||||
if (!current.value)
|
||||
current.value = res.find((e) => e.date == timeFormat(new Date()))
|
||||
const arr = res.reduce((a, b) => {
|
||||
a.push({
|
||||
date: b.date,
|
||||
badge: b.sign_status == 1 || b.sign_status == 2 || b.sign_status == 3,
|
||||
badgeBg:
|
||||
b.sign_status == 1
|
||||
? '#3c9cff'
|
||||
: b.sign_status == 2 || b.sign_status == 3
|
||||
? '#949494'
|
||||
: '',
|
||||
data: b,
|
||||
})
|
||||
return a
|
||||
}, [])
|
||||
selected.value = arr
|
||||
}
|
||||
|
||||
const onChange = ({ year, month }) => {
|
||||
time.value = `${year}-${month}`
|
||||
getData()
|
||||
}
|
||||
|
||||
const onChangeDay = (e) => {
|
||||
date.value = e.fulldate
|
||||
}
|
||||
|
||||
const goC = () => {
|
||||
// /pages/make-card/create
|
||||
let type
|
||||
if (!current.value.last_time) type = 2
|
||||
if (!current.value.first_time) type = 1
|
||||
uni.navigateTo({
|
||||
url: `/pages/make-card/create?date=${current.value.date}&type=${type}`,
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
|
@ -1,160 +0,0 @@
|
|||
<template>
|
||||
<view class="">
|
||||
<CuNavbar title="合同上传">
|
||||
<template #right>
|
||||
<view class="text-24rpx text-white" @click="submit">提交</view>
|
||||
</template>
|
||||
</CuNavbar>
|
||||
<view class="card-shadow px-base">
|
||||
<uv-form labelPosition="left" :model="form" :rules="rules" ref="formRef" errorType="toast" labelWidth="150rpx">
|
||||
<uv-form-item required label="合同名称" prop="name">
|
||||
<uv-input placeholder="请输入合同名称" inputAlign="right" :border="`none`" v-model="form.name"> </uv-input>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item label="合同照片" prop="images" required>
|
||||
<view class="text-right w-full text-hex-999">{{ form.images.length }}/{{ maxCount }}</view>
|
||||
</uv-form-item>
|
||||
<view class="w-full">
|
||||
<uv-upload
|
||||
:maxCount="maxCount"
|
||||
multiple
|
||||
:fileList="form.images"
|
||||
@afterRead="afterRead"
|
||||
@delete="deletePic"
|
||||
name="images"
|
||||
></uv-upload>
|
||||
</view>
|
||||
</uv-form>
|
||||
</view>
|
||||
<uv-modal ref="modalRef" title="提示" content="确定提交吗?" @confirm="onSubmit" :showCancelButton="true"></uv-modal>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from "@/components/cu-navbar/index"
|
||||
import { ref, reactive, computed } from "vue"
|
||||
import { onLoad } from "@dcloudio/uni-app"
|
||||
import { http } from "@/utils/request"
|
||||
const formRef = ref(null)
|
||||
const modalRef = ref(null)
|
||||
const id = ref(0)
|
||||
const loading = ref(false)
|
||||
const maxCount = ref(50)
|
||||
const form = reactive({
|
||||
name: "",
|
||||
images: []
|
||||
})
|
||||
const rules = reactive({
|
||||
name: [{ required: true, message: "请输入合同名称" }],
|
||||
images: {
|
||||
type: "array",
|
||||
required: true,
|
||||
message: "请上传合同照片",
|
||||
}
|
||||
})
|
||||
onLoad(options => {
|
||||
id.value = options.id
|
||||
if (id.value) {
|
||||
http
|
||||
.request({
|
||||
url: `/agreements/${options.id}`,
|
||||
method: "GET",
|
||||
header: {
|
||||
Accept: "application/json"
|
||||
}
|
||||
})
|
||||
.then(res => {
|
||||
form.name = res.name
|
||||
if (res.images && res.images.length > 0) {
|
||||
res.images.forEach(item => {
|
||||
form.images.push({url: item})
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const submit = () => {
|
||||
formRef.value.validate().then(res => {
|
||||
modalRef.value.open()
|
||||
})
|
||||
}
|
||||
|
||||
const onSubmit = async () => {
|
||||
if (loading.value) return
|
||||
loading.value = true
|
||||
try {
|
||||
let url = id.value ? `/agreements/${id.value}` : "/agreements"
|
||||
let method = id.value ? "PUT" : "POST"
|
||||
await http.request({
|
||||
url: url,
|
||||
method: method,
|
||||
header: {
|
||||
Accept: "application/json"
|
||||
},
|
||||
data: {
|
||||
name: form.name,
|
||||
images: form.images.map(item => item.url)
|
||||
}
|
||||
})
|
||||
uni.showToast({
|
||||
title: "提交成功",
|
||||
icon: "none"
|
||||
})
|
||||
form.images = []
|
||||
formRef.value.resetFields()
|
||||
uni.$emit('refresh')
|
||||
uni.navigateBack()
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const afterRead = async event => {
|
||||
let lists = [].concat(event.file)
|
||||
let fileListLen = form[event.name].length
|
||||
|
||||
lists.map(item => {
|
||||
form[event.name].push({
|
||||
...item,
|
||||
status: "uploading",
|
||||
message: "上传中"
|
||||
})
|
||||
})
|
||||
for (let i = 0; i < lists.length; i++) {
|
||||
const result = await uploadFilePromise(lists[i].url)
|
||||
let item = form[event.name][fileListLen]
|
||||
form[event.name].splice(
|
||||
fileListLen,
|
||||
1,
|
||||
Object.assign(item, {
|
||||
status: "success",
|
||||
message: "",
|
||||
url: result
|
||||
})
|
||||
)
|
||||
fileListLen++
|
||||
}
|
||||
}
|
||||
|
||||
const uploadFilePromise = url => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http
|
||||
.upload("/fileupload", {
|
||||
filePath: url,
|
||||
name: "file"
|
||||
})
|
||||
.then(res => {
|
||||
resolve(res.url)
|
||||
})
|
||||
.catch(err => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const deletePic = event => {
|
||||
form[event.name].splice(event.index, 1)
|
||||
}
|
||||
</script>
|
||||
|
|
@ -1,91 +0,0 @@
|
|||
<template>
|
||||
<view class="px-base" v-if="detail">
|
||||
<CuNavbar title="合同详情">
|
||||
<template #right>
|
||||
<uv-icon color="white" @click="open" name="more-dot-fill"></uv-icon>
|
||||
</template>
|
||||
</CuNavbar>
|
||||
<view class="mt-30rpx card-shadow bg-white rounded-19rpx px-base text-[#333333] text-27rpx">
|
||||
<BaseData :data="detail" :colums="columns" />
|
||||
</view>
|
||||
|
||||
<uv-action-sheet ref="pickerRef" :actions="actions" @select="confirmPicker" />
|
||||
<uv-modal ref="modalRef" title="提示" content="确定删除吗?" @confirm="onSubmit" :showCancelButton="true"></uv-modal>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import { http } from '@/utils/request'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { ref } from 'vue'
|
||||
import { timeFormat } from '@climblee/uv-ui/libs/function/index'
|
||||
import BaseData from '../audits/base-data'
|
||||
import statusFun from "@/utils/status"
|
||||
|
||||
const modalRef = ref(null)
|
||||
const actions = ref([
|
||||
{ name: '修改', value: 'edit', disabled: false },
|
||||
{ name: '删除', value: 'delete', disabled: false },
|
||||
{ name: '审核流程', value: 'check-logs', disabled: false }
|
||||
])
|
||||
const detail = ref()
|
||||
const pickerRef = ref(null)
|
||||
const id = ref(0)
|
||||
|
||||
const columns = [
|
||||
{ title: '审核状态', dataIndex: 'workflow_check.check_status', format: (value) => statusFun(value, 'statusExpense', 'name') },
|
||||
{ title: '上传人', dataIndex: 'employee.name' },
|
||||
{ title: '所属门店', dataIndex: 'store.title' },
|
||||
{ title: '电话号码', dataIndex: 'employee.phone' },
|
||||
{ title: '上传时间', dataIndex: 'created_format' },
|
||||
{ title: '合同名称', dataIndex: 'name' },
|
||||
{ title: '合同内容', dataIndex: 'images', type: 'album' },
|
||||
{ title: '未通过原因', dataIndex: 'workflow_check.check_remarks', labelPosition: 'top', isShow: (data) => data?.workflow_check?.check_status == 4 },
|
||||
]
|
||||
|
||||
const open = () => {
|
||||
pickerRef.value.open()
|
||||
}
|
||||
const confirmPicker = (e) => {
|
||||
if (e.value == 'edit') {
|
||||
return uni.navigateTo({
|
||||
url: `/pages/contract/create?id=${id.value}`,
|
||||
})
|
||||
}
|
||||
if (e.value == 'delete') {
|
||||
return modalRef.value.open()
|
||||
}
|
||||
if (e.value == 'check-logs') {
|
||||
return uni.navigateTo({
|
||||
url: `/pages/audits/log?id=${detail.value.workflow_check.id}`
|
||||
})
|
||||
}
|
||||
}
|
||||
const onSubmit = async () => {
|
||||
try {
|
||||
await http.delete(`/agreements/${id.value}`)
|
||||
uni.showToast({
|
||||
title: '删除成功',
|
||||
icon: 'none',
|
||||
})
|
||||
uni.$emit('refresh')
|
||||
uni.navigateBack()
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
onLoad((options) => {
|
||||
id.value = options.id
|
||||
http.get(`/agreements/${options.id}`).then((res) => {
|
||||
detail.value = res
|
||||
let status = res.workflow_check.check_status
|
||||
if ([2, 3].indexOf(status) != -1) {
|
||||
actions.value[0].disabled = true
|
||||
actions.value[1].disabled = true
|
||||
// actions.value.splice(0, 2)
|
||||
}
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
|
@ -1,132 +0,0 @@
|
|||
<template>
|
||||
<view>
|
||||
<CuNavbar title="合同管理">
|
||||
<template #right>
|
||||
<view @click="goPath('/pages/contract/create')" class="text-24rpx text-white">上传</view>
|
||||
</template>
|
||||
</CuNavbar>
|
||||
<uv-sticky bgColor="#fff">
|
||||
<uv-tabs
|
||||
height="44"
|
||||
:activeStyle="{ color: '#ee2c37' }"
|
||||
:scrollable="false"
|
||||
:current="tabIndex"
|
||||
lineColor="#ee2c37"
|
||||
:list="tabList"
|
||||
@change="tabChange"
|
||||
></uv-tabs>
|
||||
</uv-sticky>
|
||||
|
||||
<MescrollItem
|
||||
ref="mescrollItem0"
|
||||
:top="88"
|
||||
:i="0"
|
||||
:index="tabIndex"
|
||||
:apiUrl="tabList[0].apiUrl"
|
||||
>
|
||||
<template v-slot="{ list }">
|
||||
<view class="space-y-15rpx p-base">
|
||||
<ListItem
|
||||
v-for="item in list" :key="item.id"
|
||||
:title="item.name"
|
||||
:status-text="statusFun(item.workflow_check.check_status,'statusExpense','name')"
|
||||
:status-color="statusFun(item.workflow_check.check_status,'statusExpense','color')"
|
||||
:images="item.images"
|
||||
:body="[
|
||||
// { label: '创建时间', value: item.created_format }
|
||||
]"
|
||||
@click.stop="applyDetail(item)"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
</MescrollItem>
|
||||
|
||||
<MescrollItem
|
||||
ref="mescrollItem1"
|
||||
:top="88"
|
||||
:i="1"
|
||||
:index="tabIndex"
|
||||
:apiUrl="tabList[1].apiUrl"
|
||||
:params="tabList[1].params"
|
||||
>
|
||||
<template v-slot="{ list }">
|
||||
<view class="space-y-15rpx p-base">
|
||||
<ListItem
|
||||
v-for="item in list" :key="item.id"
|
||||
:title="item.check.subject.name"
|
||||
:status-text="statusFun( item.check_status,'statusExpense2','name')"
|
||||
:status-color="statusFun( item.check_status,'statusExpense2','color')"
|
||||
:images="item.check.subject.images"
|
||||
:body="[
|
||||
// { label: '创建人', value: item.check.subject.employee.name },
|
||||
// { label: '创建时间', value: item.check.subject.created_format }
|
||||
]"
|
||||
@click.stop="checkDetail(item)"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
</MescrollItem>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import { computed, reactive, ref } from 'vue'
|
||||
import { onPageScroll, onReachBottom, onLoad } from '@dcloudio/uni-app'
|
||||
import useMescrollMore from '@/uni_modules/mescroll-uni/hooks/useMescrollMore.js'
|
||||
import MescrollItem from '@/components/mescroll-api/more.vue'
|
||||
import statusFun from '@/utils/status'
|
||||
import ListItem from '@/components/list-item/index'
|
||||
|
||||
const mescrollItem0 = ref(null)
|
||||
const mescrollItem1 = ref(null)
|
||||
|
||||
const mescrollItems = [mescrollItem0, mescrollItem1]
|
||||
const { tabIndex, getMescroll, scrollToLastY } = useMescrollMore(
|
||||
mescrollItems,
|
||||
onPageScroll,
|
||||
onReachBottom
|
||||
)
|
||||
const tabList = ref([
|
||||
{
|
||||
name: '我的合同',
|
||||
apiUrl: '/agreements',
|
||||
},
|
||||
{
|
||||
name: '合同审核',
|
||||
apiUrl: '/workflow',
|
||||
params: {
|
||||
subject_type: 'agreements',
|
||||
include: 'check.subject.employee'
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
onLoad(() => {
|
||||
uni.$on('refresh', () => {
|
||||
mescrollItem0?.value?.getMescroll()?.resetUpScroll()
|
||||
mescrollItem1?.value?.getMescroll()?.resetUpScroll()
|
||||
})
|
||||
})
|
||||
|
||||
const goPath = (url) => {
|
||||
uni.navigateTo({
|
||||
url,
|
||||
})
|
||||
}
|
||||
const tabChange = ({ index }) => {
|
||||
tabIndex.value = index
|
||||
scrollToLastY()
|
||||
}
|
||||
|
||||
const applyDetail = (item) => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/contract/detail?id=${item.id}`,
|
||||
})
|
||||
}
|
||||
|
||||
const checkDetail = (item) => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/audits/detail?id=${item.id}&type=${item.check.subject_type}`
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
|
@ -1,15 +1,14 @@
|
|||
<template>
|
||||
<view>
|
||||
<CuNavbar title="提成数据" isBack></CuNavbar>
|
||||
<MescrollItem :top="44" :i="0" apiUrl="/account/store-master-commissions">
|
||||
<template v-slot="{ list }">
|
||||
<view class="space-y-20rpx px-base mt-20rpx">
|
||||
<view v-for="(item, i) in list" :key="i">
|
||||
<Item :data="item"></Item>
|
||||
</view>
|
||||
|
||||
<mescroll-body @init="mescrollInit" @down="downCallback" @up="upCallback">
|
||||
<view class="space-y-20rpx px-base mt-20rpx">
|
||||
<view v-for="(item, i) in list" :key="i">
|
||||
<Item :data="item"></Item>
|
||||
</view>
|
||||
</template>
|
||||
</MescrollItem>
|
||||
</view>
|
||||
</mescroll-body>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
|
@ -19,8 +18,33 @@ import Item from './components/item.vue'
|
|||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { http } from '@/utils/request'
|
||||
import { ref } from 'vue'
|
||||
import MescrollItem from '@/components/mescroll-api/one'
|
||||
import { onPageScroll, onReachBottom } from '@dcloudio/uni-app'
|
||||
import useMescrollComp from '@/uni_modules/mescroll-uni/hooks/useMescrollComp.js'
|
||||
const { mescrollItem } = useMescrollComp(onPageScroll, onReachBottom)
|
||||
import useMescroll from '@/uni_modules/mescroll-uni/hooks/useMescroll.js'
|
||||
|
||||
const { mescrollInit, downCallback, getMescroll } = useMescroll(
|
||||
onPageScroll,
|
||||
onReachBottom
|
||||
)
|
||||
|
||||
const list = ref([])
|
||||
|
||||
|
||||
|
||||
const upCallback = async (mescroll) => {
|
||||
const { size, num } = mescroll
|
||||
try {
|
||||
const resData = await http.get('/account/store-master-commissions', {
|
||||
params: {
|
||||
per_page: size,
|
||||
page: num,
|
||||
},
|
||||
})
|
||||
const curPageData = resData.data || []
|
||||
if (num === 1) list.value = []
|
||||
list.value = list.value.concat(curPageData)
|
||||
mescroll.endSuccess(curPageData.length)
|
||||
} catch (error) {
|
||||
mescroll.endErr() // 请求失败, 结束加载
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -28,31 +28,20 @@
|
|||
</view>
|
||||
</uv-sticky>
|
||||
<view class="">
|
||||
<view v-for="(ob, i) in showList" :key="i">
|
||||
<uv-sticky bgColor="#f5f5f5" zIndex="10" offsetTop="44">
|
||||
<view v-for="ob in 10" :key="ob">
|
||||
<uv-sticky bgColor="#f5f5f5" zIndex="10" offsetTop="44" >
|
||||
<view class="h-80rpx flex items-center px-base">
|
||||
<TitleComp :title="i"></TitleComp>
|
||||
<TitleComp title="2024"></TitleComp>
|
||||
</view>
|
||||
</uv-sticky>
|
||||
<view class="card">
|
||||
<view v-for="(item, i) in ob" :key="i">
|
||||
<view v-for="(item, i) in 3" :key="i">
|
||||
<view class="flex items-center h-84rpx">
|
||||
<view class="w-110rpx text-primary"
|
||||
>{{ timeFormat(`${item.month}-01`, 'mm') }}月</view
|
||||
>
|
||||
<view class="flex-1"
|
||||
>{{ item.actual_performance }}/{{
|
||||
item.expected_performance
|
||||
}}</view
|
||||
>
|
||||
<view
|
||||
:style="{
|
||||
color: statusFun(item.status, 'shore_task_status', 'color'),
|
||||
}"
|
||||
>{{ statusFun(item.status, 'shore_task_status', 'name') }}</view
|
||||
>
|
||||
<view class="w-110rpx text-primary">4月</view>
|
||||
<view class="flex-1">0/150000</view>
|
||||
<view>未开始</view>
|
||||
</view>
|
||||
<uv-line v-if="i !== ob.length - 1" color="#f5f5f5"></uv-line>
|
||||
<uv-line></uv-line>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
|
@ -67,7 +56,7 @@ import { http } from '@/utils/request'
|
|||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { timeFormat } from '@climblee/uv-ui/libs/function/index'
|
||||
import { ref, reactive, computed } from 'vue'
|
||||
import statusFun from '@/utils/status'
|
||||
|
||||
const list = ref([])
|
||||
const tabList = [
|
||||
{ name: '业绩目标', value: 'future' },
|
||||
|
|
@ -81,7 +70,6 @@ const countData = reactive({
|
|||
expected_performance: 0,
|
||||
})
|
||||
const currentTabObj = computed(() => tabList[currentTab.value])
|
||||
const showList = computed(() => encapsulateDataByMonth(list.value))
|
||||
|
||||
onLoad(() => {
|
||||
getCount()
|
||||
|
|
@ -116,15 +104,4 @@ const getList = async () => {
|
|||
})
|
||||
list.value = resData
|
||||
}
|
||||
|
||||
function encapsulateDataByMonth(data) {
|
||||
return data.reduce((groupedData, item) => {
|
||||
|
||||
const year = timeFormat(new Date(item.month), 'yyyy')
|
||||
|
||||
groupedData[year] = groupedData[year] || []
|
||||
groupedData[year].push(item)
|
||||
return groupedData
|
||||
}, {})
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,269 +1,68 @@
|
|||
<template>
|
||||
<view>
|
||||
<CuNavbar title="培训考试">
|
||||
<template v-if="!readonly && !notfound" #right>
|
||||
<view class="text-white" @click="submit">提交</view>
|
||||
<view class="items-center justify-between">
|
||||
<view>{{ index }}/{{ total }}</view>
|
||||
<view>
|
||||
<view v-if="index > 0" @click="prev">上一题</view>
|
||||
<view v-if="index < total" @click="next">下一题</view>
|
||||
<view v-if="index >= total" @click="submit">提交</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="content">
|
||||
<template v-for="(item, key) in list" :key="key">
|
||||
<view v-show="key == index" class="item">
|
||||
<view class="title">({{ item.cate_name }}){{ item.title }}</view>
|
||||
<view class="options">
|
||||
<u-checkbox-group v-if="item.cate == 1">
|
||||
<u-checkbox v-for="(option, optionKey) in item.options" :key="optionKey" :label="option.text" :name="optionKey" />
|
||||
</u-checkbox-group>
|
||||
<u-radio-group v-if="item.cate == 2">
|
||||
<u-radio v-for="(option, optionKey) in item.options" :key="optionKey" :label="option.text" :name="optionKey" />
|
||||
</u-radio-group>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</CuNavbar>
|
||||
|
||||
<template v-if="notfound">
|
||||
<view class="h-60vh flex-center">
|
||||
<uv-empty text="试卷不存在" :icon="NotFoundImg"> </uv-empty>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<uv-sticky bgColor="#fff">
|
||||
<view class="flex items-center justify-between h-90rpx px-base">
|
||||
<view class="w-140rpx">
|
||||
<view class="btn" :disabled="index == 0" @click="prev">上一题</view>
|
||||
</view>
|
||||
<view>{{ index + 1 }}/{{ total }}</view>
|
||||
<view class="w-140rpx text-right">
|
||||
<view class="btn" :disabled="index == total - 1" @click="next">
|
||||
下一题</view
|
||||
>
|
||||
</view>
|
||||
</view>
|
||||
</uv-sticky>
|
||||
<view class="p-base">
|
||||
<view class="card-shadow bg-white rounded-19rpx p-base min-h-30vh">
|
||||
<template v-for="(item, key) in list" :key="key">
|
||||
<view v-show="key == index" class="item">
|
||||
<view class="title text-30rpx"
|
||||
>({{ item.cate_name }}){{ item.title }}
|
||||
|
||||
<text v-if="readonly" class="text-primary"
|
||||
>(得分:{{ item.user_score }})</text
|
||||
>
|
||||
</view>
|
||||
<view
|
||||
class="pt-base"
|
||||
:class="[readonly ? 'pointer-events-none' : '']"
|
||||
>
|
||||
<template v-if="item.cate == 2">
|
||||
<uv-checkbox-group
|
||||
activeColor="#ee2c37"
|
||||
v-model="item.answer"
|
||||
placement="column"
|
||||
>
|
||||
<uv-checkbox
|
||||
:customStyle="{ margin: '8px' }"
|
||||
v-for="(op, i) in item.options"
|
||||
:activeColor="
|
||||
op.selected != op.is_true && op.selected
|
||||
? '#e3e3e3'
|
||||
: '#3678f7'
|
||||
"
|
||||
:key="i"
|
||||
:label="op.text"
|
||||
:name="i"
|
||||
>
|
||||
<view class="flex items-center">
|
||||
<view>{{ op.text }}</view>
|
||||
<uv-icon
|
||||
v-if="(op.selected || op.is_true) && readonly"
|
||||
:color="
|
||||
op.is_true && op.selected ? '#4caf50' : '#ee2c37'
|
||||
"
|
||||
:name="
|
||||
op.is_true && op.selected
|
||||
? 'checkbox-mark'
|
||||
: 'close'
|
||||
"
|
||||
></uv-icon>
|
||||
</view>
|
||||
</uv-checkbox>
|
||||
</uv-checkbox-group>
|
||||
</template>
|
||||
<template v-if="item.cate == 1">
|
||||
<uv-radio-group
|
||||
v-if="!readonly"
|
||||
activeColor="#ee2c37"
|
||||
v-model="item.answer"
|
||||
placement="column"
|
||||
>
|
||||
<uv-radio
|
||||
:customStyle="{ margin: '8px' }"
|
||||
v-for="(op, i) in item.options"
|
||||
:key="i"
|
||||
:label="op.text"
|
||||
:name="i"
|
||||
>
|
||||
<view class="flex items-center">
|
||||
<view>{{ op.text }}</view>
|
||||
<uv-icon
|
||||
v-if="op.selected && readonly"
|
||||
:color="op.is_true ? '#ee2c37' : '#5ac725'"
|
||||
:name="op.is_true ? 'checkbox-mark' : 'close'"
|
||||
></uv-icon>
|
||||
</view>
|
||||
</uv-radio>
|
||||
</uv-radio-group>
|
||||
<template v-else>
|
||||
<uv-checkbox-group
|
||||
activeColor="#ee2c37"
|
||||
v-model="item.answer"
|
||||
placement="column"
|
||||
>
|
||||
<uv-checkbox
|
||||
:customStyle="{ margin: '8px' }"
|
||||
v-for="(op, i) in item.options"
|
||||
:activeColor="
|
||||
op.selected != op.is_true && op.selected
|
||||
? '#e3e3e3'
|
||||
: '#3678f7'
|
||||
"
|
||||
:key="i"
|
||||
:label="op.text"
|
||||
:name="i"
|
||||
>
|
||||
<view class="flex items-center">
|
||||
<view>{{ op.text }}</view>
|
||||
<uv-icon
|
||||
v-if="(op.selected || op.is_true) && readonly"
|
||||
:color="
|
||||
op.is_true && op.selected ? '#4caf50' : '#ee2c37'
|
||||
"
|
||||
:name="
|
||||
op.is_true && op.selected
|
||||
? 'checkbox-mark'
|
||||
: 'close'
|
||||
"
|
||||
></uv-icon>
|
||||
</view>
|
||||
</uv-checkbox>
|
||||
</uv-checkbox-group>
|
||||
</template>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<uv-modal
|
||||
ref="modalRef"
|
||||
title="提示"
|
||||
:content="`确认提交?`"
|
||||
:showCancelButton="true"
|
||||
@confirm="onSubmit"
|
||||
></uv-modal>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import NotFoundImg from '@/static/images/404.svg'
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import { http } from '@/utils/request'
|
||||
import { onLoad, onShow } from '@dcloudio/uni-app'
|
||||
import { computed, ref } from 'vue'
|
||||
const notfound = ref(false)
|
||||
const modalRef = ref(null)
|
||||
const info = ref({})
|
||||
const id = ref(0)
|
||||
// 考题记录
|
||||
// const list = ref([])
|
||||
// 总题数
|
||||
// const total = ref(0)
|
||||
// 序号
|
||||
const index = ref(0)
|
||||
// 只读模式
|
||||
// const readonly = ref(true)
|
||||
const loading = ref(false)
|
||||
const list = computed(() => {
|
||||
const content = info.value?.content ?? []
|
||||
content.forEach((item) => {
|
||||
if (readonly.value) {
|
||||
const trueIndices = item.options.reduce((indices, item, index) => {
|
||||
if (item.is_true || item.selected) {
|
||||
indices.push(index)
|
||||
}
|
||||
return indices
|
||||
}, [])
|
||||
item.answer = trueIndices
|
||||
} else {
|
||||
if (item.cate == 1) {
|
||||
item.answer = item.user_answer?.[0] ?? ''
|
||||
} else {
|
||||
item.answer = item.user_answer ?? []
|
||||
import { http } from '@/utils/request'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { ref } from 'vue'
|
||||
|
||||
const info = ref({})
|
||||
// 考题记录
|
||||
const list = ref([])
|
||||
// 总题数
|
||||
const total = ref(0)
|
||||
// 序号
|
||||
const index = ref(0)
|
||||
// 只读模式
|
||||
const readonly = ref(true)
|
||||
onLoad((options) => {
|
||||
http.get(`/train/examinations/${options.id}`).then(res => {
|
||||
if (res.finished_at) {
|
||||
readonly = false
|
||||
}
|
||||
}
|
||||
})
|
||||
return info.value.content || []
|
||||
})
|
||||
const total = computed(() => list.value.length)
|
||||
const readonly = computed(() => (info.value.finished_at ? true : false))
|
||||
|
||||
function findAllIndices(arr, predicate) {
|
||||
return arr.filter(predicate).keys()
|
||||
}
|
||||
|
||||
const answer = computed(() => {
|
||||
const arr = list.value.reduce((a, b) => {
|
||||
const c = [].concat(b.answer ?? [])
|
||||
a.push(c)
|
||||
return a
|
||||
}, [])
|
||||
return arr || []
|
||||
})
|
||||
|
||||
onLoad((options) => {
|
||||
id.value = options.id
|
||||
})
|
||||
onShow(() => {
|
||||
getDetail()
|
||||
})
|
||||
|
||||
const getDetail = async () => {
|
||||
try {
|
||||
await http.get(`/train/examinations/${id.value}`).then((resData) => {
|
||||
const res = resData
|
||||
info.value = res
|
||||
list.value = res.content
|
||||
total.value = res.content.length
|
||||
})
|
||||
notfound.value = false
|
||||
} catch (error) {
|
||||
const { statusCode } = error
|
||||
if (statusCode == 404) {
|
||||
notfound.value = true
|
||||
})
|
||||
|
||||
const next = () => {
|
||||
if (index < total) {
|
||||
index.value++
|
||||
}
|
||||
}
|
||||
const prev = () => {
|
||||
if (index > 0) {
|
||||
index.value--
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const next = () => {
|
||||
if (index.value < total.value - 1) {
|
||||
index.value++
|
||||
}
|
||||
}
|
||||
const prev = () => {
|
||||
if (index.value > 0) {
|
||||
index.value--
|
||||
}
|
||||
}
|
||||
const submit = () => {
|
||||
modalRef.value.open()
|
||||
}
|
||||
const onSubmit = async () => {
|
||||
if (loading.value) return
|
||||
loading.value = true
|
||||
try {
|
||||
await http.post(`/train/examinations/${id.value}/answer`, {
|
||||
answers: answer.value,
|
||||
const submit = () => {
|
||||
http.post(`/train/examinations/${info.id}/answer`).then(res => {
|
||||
})
|
||||
uni.$emit('examination:onRefresh')
|
||||
uni.navigateBack()
|
||||
} catch (error) {
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.btn {
|
||||
@apply text-28rpx;
|
||||
}
|
||||
.btn[disabled='true'] {
|
||||
color: #999;
|
||||
@apply pointer-events-none;
|
||||
}
|
||||
</style>
|
||||
</script>
|
||||
|
|
@ -1,23 +1,15 @@
|
|||
<template>
|
||||
<view>
|
||||
<CuNavbar title="培训考试"></CuNavbar>
|
||||
<MescrollItem ref="mescrollItem" :top="88" :i="0" apiUrl="/train/examinations">
|
||||
<MescrollItem :top="88" :i="0" apiUrl="/train/examinations">
|
||||
<template v-slot="{ list }">
|
||||
<view class="space-y-15rpx p-base">
|
||||
<template v-for="item in list" :key="item.id">
|
||||
<view
|
||||
class="card-shadow space-y-10rpx bg-white rounded-19rpx p-base space-y-10rpx"
|
||||
@click="detail(item)"
|
||||
>
|
||||
<view class="text-30rpx">{{ item.examination.name }}</view>
|
||||
<view
|
||||
class="flex items-center justify-between text-24rpx text-hex-999999"
|
||||
>
|
||||
<view class=""
|
||||
>发布日期:
|
||||
{{ timeFormat(item.examination.published_at) }}</view
|
||||
>
|
||||
<view :class="{'text-dark': item.mark != null}">{{ item.mark != null ? item.mark + '分' : '未完成' }}</view>
|
||||
<view class="card-shadow bg-white rounded-19rpx p-base space-y-10rpx" @click="detail(item)">
|
||||
<view class="text-30rpx">{{ item.name }}</view>
|
||||
<view class="flex items-center justify-between">
|
||||
<view class="text-30rpx">发布日期: {{ item.examination.published_at }}</view>
|
||||
<view class="text-30rpx">{{ item.mark == null ? item.mark : '未完成' }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
|
@ -28,23 +20,22 @@
|
|||
</template>
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { http } from '@/utils/request'
|
||||
import { http } from '@/utils/index'
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import MescrollItem from '@/components/mescroll-api/one'
|
||||
import { onPageScroll, onReachBottom, onLoad } from '@dcloudio/uni-app'
|
||||
import useMescrollComp from '@/uni_modules/mescroll-uni/hooks/useMescrollComp.js'
|
||||
import { timeFormat } from '@climblee/uv-ui/libs/function/index'
|
||||
const { mescrollItem } = useMescrollComp(onPageScroll, onReachBottom)
|
||||
import useMescrollMore from '@/uni_modules/mescroll-uni/hooks/useMescrollMore.js'
|
||||
import MescrollItem from '@/components/mescroll-api/more.vue'
|
||||
|
||||
onLoad(() => {
|
||||
uni.$on('examination:onRefresh', () => {
|
||||
mescrollItem?.value?.getMescroll()?.resetUpScroll()
|
||||
})
|
||||
})
|
||||
const mescrollItem = ref('')
|
||||
|
||||
const { getMescroll, scrollToLastY } = useMescrollMore(
|
||||
mescrollItem,
|
||||
onPageScroll,
|
||||
onReachBottom
|
||||
)
|
||||
|
||||
const detail = (item) => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/examination/detail?id=${item.id}`,
|
||||
})
|
||||
}
|
||||
</script>
|
||||
</script>
|
||||
|
|
@ -1,97 +0,0 @@
|
|||
<template>
|
||||
<view>
|
||||
<CuNavbar title="报销详情">
|
||||
<template #right>
|
||||
<uv-icon color="white" @click="open" name="more-dot-fill"></uv-icon>
|
||||
</template>
|
||||
</CuNavbar>
|
||||
<view class="px-base mt-30rpx">
|
||||
<view class="card-shadow bg-white rounded-19rpx px-base">
|
||||
<BaseData :colums="colums" :data="data"></BaseData>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<uv-action-sheet ref="actionSheet" :actions="actions" @select="select" />
|
||||
|
||||
<uv-modal ref="modalRef" title="提示" content="确定删除吗?" @confirm="onDelete" :showCancelButton="true"></uv-modal>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from '@/components/cu-navbar/index.vue'
|
||||
import BaseData from '@/pages/audits/base-data.vue'
|
||||
import { ref } from 'vue'
|
||||
import { onLoad ,onShow} from '@dcloudio/uni-app'
|
||||
import { http } from '@/utils/request'
|
||||
import statusFun from '@/utils/status'
|
||||
|
||||
const modalRef = ref(null)
|
||||
const actions = ref([
|
||||
{ name: '修改', value: 'edit', disabled: false },
|
||||
{ name: '删除', value: 'delete', disabled: false },
|
||||
{ name: '审核流程', value: 'check-logs', disabled: false }
|
||||
])
|
||||
|
||||
const colums = [
|
||||
{ title: '审核状态', dataIndex: 'workflow_check.check_status', format: (value) => statusFun(value, 'statusExpense', 'name') },
|
||||
{ title: '申请人', dataIndex: 'employee.name' },
|
||||
{ title: '所属门店', dataIndex: 'store.title' },
|
||||
{ title: '电话号码', dataIndex: 'employee.phone' },
|
||||
{ title: '申请时间', dataIndex: 'created_format' },
|
||||
{ title: '报销分类', dataIndex: 'type.name' },
|
||||
{ title: '报销金额', dataIndex: 'expense' },
|
||||
{ title: '报销原因', dataIndex: 'reason', labelPosition: 'top' },
|
||||
{ title: '报销凭证', dataIndex: 'photos', type: 'album' },
|
||||
{ title: '未通过原因', dataIndex: 'workflow_check.check_remarks', labelPosition: 'top', isShow: (item) => item?.workflow_check.check_status == 4 },
|
||||
]
|
||||
const actionSheet = ref(null)
|
||||
const data = ref(null)
|
||||
const id = ref(null)
|
||||
|
||||
const open = () => {
|
||||
actionSheet.value.open()
|
||||
}
|
||||
|
||||
const select = (e) => {
|
||||
if (e.value == 'edit') {
|
||||
uni.navigateTo({
|
||||
url: `/pages/expense-account/submit?id=${id.value}`,
|
||||
})
|
||||
} else if (e.value == 'delete') {
|
||||
modalRef.value.open()
|
||||
} else if (e.value == 'check-logs') {
|
||||
return uni.navigateTo({
|
||||
url: `/pages/audits/log?id=${data.value.workflow_check.id}`
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const onDelete = () => {
|
||||
http.delete(`/reimbursements/${id.value}`).then(() => {
|
||||
uni.$emit('refresh')
|
||||
uni.showToast({
|
||||
title: '删除成功',
|
||||
icon: 'none',
|
||||
})
|
||||
uni.navigateBack()
|
||||
})
|
||||
}
|
||||
|
||||
onLoad((option) => {
|
||||
id.value = option.id
|
||||
})
|
||||
onShow(()=>{
|
||||
getDetail()
|
||||
})
|
||||
|
||||
const getDetail = () => {
|
||||
http.get(`/reimbursements/${id.value}`).then((res) => {
|
||||
data.value = res
|
||||
let status = res.workflow_check.check_status
|
||||
if ([2, 3].indexOf(status) != -1) {
|
||||
actions.value[0].disabled = true
|
||||
actions.value[1].disabled = true
|
||||
// actions.value.splice(0, 2)
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
|
@ -2,7 +2,11 @@
|
|||
<view>
|
||||
<CuNavbar title="报销管理">
|
||||
<template #right>
|
||||
<view @click="goPath('/pages/expense-account/submit')" class="text-24rpx text-white">申请</view>
|
||||
<view
|
||||
@click="goPath('/pages/expense-account/submit')"
|
||||
class="text-24rpx text-white"
|
||||
>申请</view
|
||||
>
|
||||
</template>
|
||||
</CuNavbar>
|
||||
<uv-sticky bgColor="#fff">
|
||||
|
|
@ -11,107 +15,94 @@
|
|||
:scrollable="false"
|
||||
lineColor="#ee2c37"
|
||||
:list="tabList"
|
||||
:current="tabIndex"
|
||||
@change="tabChange"
|
||||
></uv-tabs>
|
||||
</uv-sticky>
|
||||
<view class="">
|
||||
<MescrollItem
|
||||
ref="mescrollItem0"
|
||||
:top="88"
|
||||
:i="0"
|
||||
:index="tabIndex"
|
||||
:apiUrl="tabList[0].apiUrl"
|
||||
>
|
||||
<template v-slot="{ list }">
|
||||
<view class="space-y-15rpx p-base">
|
||||
<ListItem
|
||||
v-for="item in list"
|
||||
:key="item.id"
|
||||
:title="item.type?.name"
|
||||
:status-text="statusFun(item.workflow_check?.check_status, 'statusExpense', 'name')"
|
||||
:status-color="statusFun(item.workflow_check?.check_status, 'statusExpense', 'color')"
|
||||
:body="[
|
||||
{ label: '报销金额: ', value: item.expense },
|
||||
{ label: '报销原因: ', value: item.reason },
|
||||
{ label: '报销时间: ', value: item.created_format },
|
||||
<mescroll-body @init="mescrollInit" @down="downCallback" @up="upCallback">
|
||||
<view class="px-base space-y-20rpx mt-30rpx">
|
||||
<view
|
||||
v-for="item in list"
|
||||
:key="item.id"
|
||||
class="card-shadow bg-white rounded-19rpx p-base space-y-10rpx"
|
||||
>
|
||||
<view class="flex items-center justify-between">
|
||||
<view class="text-30rpx"> {{ item.type.name }} </view>
|
||||
<view
|
||||
:style="[
|
||||
{
|
||||
color: statusFun(
|
||||
item.workflow_check.check_status,
|
||||
'statusExpense',
|
||||
'color'
|
||||
),
|
||||
},
|
||||
]"
|
||||
@click="applyDetail(item)"
|
||||
/>
|
||||
class="text-24rpx"
|
||||
>{{ item.workflow_check.check_status_text }}</view
|
||||
>
|
||||
</view>
|
||||
</template>
|
||||
</MescrollItem>
|
||||
<MescrollItem
|
||||
ref="mescrollItem1"
|
||||
:i="1"
|
||||
:top="88"
|
||||
:index="tabIndex"
|
||||
:apiUrl="tabList[1].apiUrl"
|
||||
:params="tabList[1].params"
|
||||
>
|
||||
<template v-slot="{ list }">
|
||||
<view class="space-y-15rpx p-base">
|
||||
<ListItem
|
||||
v-for="item in list"
|
||||
:key="item.id"
|
||||
:title="item.check.subject.type?.name"
|
||||
:status-text="statusFun(item.check_status, 'statusExpense2', 'name')"
|
||||
:status-color="statusFun(item.check_status, 'statusExpense2', 'color')"
|
||||
:body="[
|
||||
{ label: '申请人: ', value: item.check.subject.employee.name },
|
||||
{ label: '报销金额: ', value: item.check.subject.expense },
|
||||
{ label: '报销原因: ', value: item.check.subject.reason },
|
||||
{ label: '报销时间: ', value: item.check.subject.created_format },
|
||||
]"
|
||||
@click="checkDetail(item)"
|
||||
/>
|
||||
<view class="text-24rpx text-hex-999999 flex">
|
||||
<view class="w-140rpx">报销金额</view>
|
||||
<view class="text-primary">{{ item.expense }}</view>
|
||||
</view>
|
||||
</template>
|
||||
</MescrollItem>
|
||||
</view>
|
||||
<view class="text-24rpx text-hex-999999 flex">
|
||||
<view class="w-140rpx">报销时间</view>
|
||||
<view class="text-hex-333">{{ timeFormat(item.created_at) }}</view>
|
||||
</view>
|
||||
<view class="text-24rpx text-hex-999999">
|
||||
<view class="">
|
||||
<text class="w-140rpx inline-block">报销原因:</text>
|
||||
<text class="text-hex-333 leading-27rpx">{{ item.reason }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</mescroll-body>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import { http } from '@/utils/request'
|
||||
import { ref } from 'vue'
|
||||
import { onPageScroll, onReachBottom, onLoad } from '@dcloudio/uni-app'
|
||||
import useMescrollMore from '@/uni_modules/mescroll-uni/hooks/useMescrollMore.js'
|
||||
import MescrollItem from '@/components/mescroll-api/more.vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { onPageScroll, onReachBottom } from '@dcloudio/uni-app'
|
||||
import useMescroll from '@/uni_modules/mescroll-uni/hooks/useMescroll.js'
|
||||
import { timeFormat } from '@climblee/uv-ui/libs/function'
|
||||
import statusFun from '@/utils/status'
|
||||
import ListItem from '@/components/list-item/index'
|
||||
|
||||
const mescrollItem0 = ref(null)
|
||||
const mescrollItem1 = ref(null)
|
||||
|
||||
const mescrollItems = [mescrollItem0, mescrollItem1]
|
||||
const { tabIndex, getMescroll, scrollToLastY } = useMescrollMore(
|
||||
mescrollItems,
|
||||
const { mescrollInit, downCallback, getMescroll } = useMescroll(
|
||||
onPageScroll,
|
||||
onReachBottom
|
||||
)
|
||||
const list = ref([])
|
||||
|
||||
const tabList = ref([
|
||||
{
|
||||
name: '我的报销',
|
||||
apiUrl: '/reimbursements',
|
||||
},
|
||||
{
|
||||
name: '报销审核',
|
||||
apiUrl: '/workflow',
|
||||
params: { subject_type: 'reimbursements', include: 'check.subject.type,check.subject.employee' },
|
||||
},
|
||||
])
|
||||
|
||||
onLoad(() => {
|
||||
uni.$on('refresh', () => {
|
||||
mescrollItem0?.value?.getMescroll()?.resetUpScroll()
|
||||
mescrollItem1?.value?.getMescroll()?.resetUpScroll()
|
||||
})
|
||||
})
|
||||
const upCallback = async (mescroll) => {
|
||||
const { size, num } = mescroll
|
||||
|
||||
const tabChange = ({ index }) => {
|
||||
tabIndex.value = index
|
||||
scrollToLastY()
|
||||
try {
|
||||
const resData = await http.get('/reimbursements', {
|
||||
params: {
|
||||
per_page: size,
|
||||
page: num,
|
||||
},
|
||||
})
|
||||
const curPageData = resData || []
|
||||
if (num === 1) list.value = []
|
||||
list.value = list.value.concat(curPageData)
|
||||
mescroll.endSuccess(curPageData.length)
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
mescroll.endErr() // 请求失败, 结束加载
|
||||
} finally {
|
||||
// firstloading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const goPath = (url) => {
|
||||
|
|
@ -119,16 +110,4 @@ const goPath = (url) => {
|
|||
url,
|
||||
})
|
||||
}
|
||||
|
||||
const applyDetail = (item) => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/expense-account/detail?id=${item.id}`
|
||||
})
|
||||
}
|
||||
|
||||
const checkDetail = (item) => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/audits/detail?id=${item.id}&type=${item.check.subject_type}`
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -17,9 +17,7 @@
|
|||
keyName="name"
|
||||
class="h-full w-full flex justify-end"
|
||||
>
|
||||
<view :class="{ 'text-gray': !type.name }">{{
|
||||
type.name ?? '请选择'
|
||||
}}</view>
|
||||
{{ type.name }}
|
||||
<uv-icon name="arrow-right"></uv-icon>
|
||||
</view>
|
||||
</uv-form-item>
|
||||
|
|
@ -31,7 +29,6 @@
|
|||
type="digit"
|
||||
input-align="right"
|
||||
v-model="form.expense"
|
||||
@blur="handleBlurExpense"
|
||||
></uv-input>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
|
|
@ -39,32 +36,32 @@
|
|||
label="报销原因"
|
||||
required
|
||||
prop="reason"
|
||||
:borderBottom="true"
|
||||
labelPosition="top"
|
||||
>
|
||||
<uv-textarea
|
||||
:border="`none`"
|
||||
v-model="form.reason"
|
||||
placeholder="请输入报销原因"
|
||||
:customStyle="{ padding: '0' }"
|
||||
></uv-textarea>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item label="报销凭证" prop="photos" required>
|
||||
<view class="text-right w-full text-hex-999"
|
||||
>{{ form.photos.length }}/9</view
|
||||
>
|
||||
<uv-form-item
|
||||
label="报销凭证"
|
||||
labelPosition="top"
|
||||
prop="photos"
|
||||
required
|
||||
>
|
||||
<view class="w-full mt-15rpx">
|
||||
<uv-upload
|
||||
:maxCount="9"
|
||||
multiple
|
||||
:fileList="form.photos"
|
||||
@afterRead="afterRead"
|
||||
@delete="deletePic"
|
||||
name="photos"
|
||||
></uv-upload>
|
||||
</view>
|
||||
</uv-form-item>
|
||||
<view class="w-full">
|
||||
<uv-upload
|
||||
:maxCount="9"
|
||||
multiple
|
||||
:fileList="form.photos"
|
||||
@afterRead="afterRead"
|
||||
@delete="deletePic"
|
||||
@error="uploadError"
|
||||
name="photos"
|
||||
></uv-upload>
|
||||
</view>
|
||||
</uv-form>
|
||||
</view>
|
||||
</view>
|
||||
|
|
@ -100,7 +97,6 @@ const type = ref({})
|
|||
const modalRef = ref(null)
|
||||
const formRef = ref(null)
|
||||
const loading = ref(false)
|
||||
const id = ref(null)
|
||||
const form = reactive({
|
||||
reimbursement_type_id: '',
|
||||
expense: '',
|
||||
|
|
@ -114,15 +110,7 @@ const rules = reactive({
|
|||
message: '请选择报销分类',
|
||||
},
|
||||
],
|
||||
expense: [
|
||||
{ required: true, message: '请输入报销金额' },
|
||||
{
|
||||
required: true,
|
||||
type: 'number',
|
||||
min: 0,
|
||||
message: '报销金额不能小于0',
|
||||
},
|
||||
],
|
||||
expense: [{ required: true, message: '请输入报销金额' }],
|
||||
reason: [{ required: true, message: '请输入报销原因' }],
|
||||
photos: {
|
||||
type: 'array',
|
||||
|
|
@ -131,57 +119,31 @@ const rules = reactive({
|
|||
},
|
||||
})
|
||||
|
||||
onLoad((e) => {
|
||||
if (e.id) {
|
||||
id.value = e.id
|
||||
http.get(`reimbursements/${e.id}`).then((res) => {
|
||||
type.value = res.type
|
||||
form.reimbursement_type_id = res.reimbursement_type_id
|
||||
form.expense = res.expense
|
||||
form.reason = res.reason
|
||||
if (res.photos && res.photos.length > 0) {
|
||||
form.photos = res.photos.map((item) => {
|
||||
return { url: item }
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
onLoad(() => {
|
||||
getTypes()
|
||||
})
|
||||
|
||||
const handleBlurExpense = (e) => {
|
||||
form.expense = Math.floor(e * 100) / 100
|
||||
}
|
||||
|
||||
const submit = () => {
|
||||
formRef.value
|
||||
.validate()
|
||||
.then((res) => {
|
||||
modalRef.value.open()
|
||||
})
|
||||
.catch((error) => {})
|
||||
formRef.value.validate().then((res) => {
|
||||
modalRef.value.open()
|
||||
})
|
||||
}
|
||||
const onSubmit = async () => {
|
||||
if (loading.value) return
|
||||
loading.value = true
|
||||
try {
|
||||
const params = {
|
||||
const resData = await http.post('/reimbursements', {
|
||||
reimbursement_type_id: form.reimbursement_type_id,
|
||||
expense: form.expense,
|
||||
reason: form.reason,
|
||||
photos: form.photos.map((item) => item.url),
|
||||
}
|
||||
if (id.value) {
|
||||
await http.put(`/reimbursements/${id.value}`, params)
|
||||
} else {
|
||||
await http.post('/reimbursements', params)
|
||||
}
|
||||
})
|
||||
uni.showToast({
|
||||
title: '提交成功',
|
||||
icon: 'none',
|
||||
})
|
||||
formRef.value.resetFields()
|
||||
uni.$emit('refresh', { index: 0 })
|
||||
uni.$emit('ex:submit', resData)
|
||||
uni.navigateBack()
|
||||
} catch (error) {
|
||||
} finally {
|
||||
|
|
@ -249,11 +211,4 @@ const typeConfirm = ({ value }) => {
|
|||
const openType = () => {
|
||||
typeRef.value.open()
|
||||
}
|
||||
|
||||
const uploadError = (err) => {
|
||||
// uni.showToast({
|
||||
// icon: 'none',
|
||||
// title: '权限未开启,请前往设置给予APP相应权限',
|
||||
// })
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,217 +0,0 @@
|
|||
<template>
|
||||
<view class="content">
|
||||
<template v-if="list.length">
|
||||
<uv-swiper
|
||||
height="100vh"
|
||||
:list="list"
|
||||
:autoplay="false"
|
||||
:border-radius="0"
|
||||
:circular="false"
|
||||
circular
|
||||
></uv-swiper>
|
||||
|
||||
<div class="z-99999" id="timer" @click.stop="launchApp">
|
||||
<div id="info">跳过</div>
|
||||
<div class="circleProgress_wrapper">
|
||||
<div class="wrapper right">
|
||||
<div class="circleProgress rightcircle"></div>
|
||||
</div>
|
||||
<div class="wrapper left">
|
||||
<div class="circleProgress leftcircle"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onLoad, onReady, onUnload } from '@dcloudio/uni-app'
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
import { http } from '@/utils/request'
|
||||
import { ref,nextTick } from 'vue'
|
||||
|
||||
const userStore = useUserStore()
|
||||
const list = ref([])
|
||||
const timer = ref(null)
|
||||
|
||||
onLoad(() => {
|
||||
getInit()
|
||||
})
|
||||
|
||||
onReady(() => {
|
||||
setTimer()
|
||||
})
|
||||
|
||||
onUnload(() => {
|
||||
if (timer.value) clearInterval(timer.value)
|
||||
timer.value = null
|
||||
})
|
||||
|
||||
function setTimer() {
|
||||
let count = 6
|
||||
timer.value = setInterval(() => {
|
||||
count--
|
||||
if (count == 0) {
|
||||
clearInterval(timer.value)
|
||||
launchApp()
|
||||
}
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
function launchApp() {
|
||||
checkLogin()
|
||||
}
|
||||
|
||||
async function getInit() {
|
||||
try {
|
||||
const resData = await http.get('/configurations')
|
||||
list.value = resData.launch_images
|
||||
|
||||
if (list.value.length === 0) {
|
||||
checkLogin()
|
||||
}
|
||||
} catch (error) {
|
||||
|
||||
} finally {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
const checkLogin = () => {
|
||||
if (!userStore.isLogin) {
|
||||
uni.redirectTo({
|
||||
url: '/pages/login/index',
|
||||
})
|
||||
} else {
|
||||
uni.switchTab({
|
||||
url: '/pages/home/index',
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
#timer {
|
||||
display: inline-block;
|
||||
position: fixed;
|
||||
top: 40px;
|
||||
right: 10px;
|
||||
box-sizing: inherit;
|
||||
}
|
||||
|
||||
#info {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
line-height: 36px;
|
||||
border-radius: 50%;
|
||||
background-color: rgba(0, 0, 0, 0.3);
|
||||
text-align: center;
|
||||
color: #ffffff;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.circleProgress_wrapper {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
width: 18px;
|
||||
height: 36px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.right {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.left {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.circleProgress {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border: 2px solid #ffffff;
|
||||
border-radius: 50%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
box-sizing: border-box;
|
||||
-webkit-transform: rotate(45deg);
|
||||
}
|
||||
|
||||
.rightcircle {
|
||||
border-top: 2px solid #03a9f4;
|
||||
border-right: 2px solid #03a9f4;
|
||||
right: 0;
|
||||
-webkit-animation: circleProgressLoad_right 6s linear;
|
||||
/*动画停留在最后一帧*/
|
||||
animation-fill-mode: forwards;
|
||||
-moz-animation-fill-mode: forwards;
|
||||
-webkit-animation-fill-mode: forwards;
|
||||
-o-animation-fill-mode: forwards;
|
||||
}
|
||||
|
||||
.leftcircle {
|
||||
border-bottom: 2px solid #03a9f4;
|
||||
border-left: 2px solid #03a9f4;
|
||||
left: 0;
|
||||
-webkit-animation: circleProgressLoad_left 6s linear;
|
||||
/*动画停留在最后一帧*/
|
||||
animation-fill-mode: forwards;
|
||||
-moz-animation-fill-mode: forwards;
|
||||
-webkit-animation-fill-mode: forwards;
|
||||
-o-animation-fill-mode: forwards;
|
||||
}
|
||||
|
||||
@keyframes circleProgressLoad_right {
|
||||
0% {
|
||||
border-top: 2px solid #03a9f4;
|
||||
border-right: 2px solid #03a9f4;
|
||||
-webkit-transform: rotate(45deg);
|
||||
}
|
||||
|
||||
50% {
|
||||
border-top: 2px solid #03a9f4;
|
||||
border-right: 2px solid #03a9f4;
|
||||
border-left: 2px solid #ffffff;
|
||||
border-bottom: 2px solid #ffffff;
|
||||
-webkit-transform: rotate(225deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
border-left: 2px solid #ffffff;
|
||||
border-bottom: 2px solid #ffffff;
|
||||
-webkit-transform: rotate(225deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes circleProgressLoad_left {
|
||||
0% {
|
||||
border-bottom: 2px solid #03a9f4;
|
||||
border-left: 2px solid #03a9f4;
|
||||
-webkit-transform: rotate(45deg);
|
||||
}
|
||||
|
||||
50% {
|
||||
border-bottom: 2px solid #03a9f4;
|
||||
border-left: 2px solid #03a9f4;
|
||||
border-top: 2px solid #ffffff;
|
||||
border-right: 2px solid #ffffff;
|
||||
-webkit-transform: rotate(45deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
border-top: 2px solid #ffffff;
|
||||
border-right: 2px solid #ffffff;
|
||||
-webkit-transform: rotate(225deg);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -4,24 +4,19 @@
|
|||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import { ref, watch, reactive } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
data: Array,
|
||||
})
|
||||
|
||||
const opts = {
|
||||
color: ['#ee2c37'],
|
||||
dataLabel: false,
|
||||
dataPointShape: true,
|
||||
import { ref } from 'vue'
|
||||
const opts = ref({
|
||||
color: [
|
||||
'#ee2c37',
|
||||
|
||||
],
|
||||
padding: [15, 15, 0, 15],
|
||||
enableScroll: false,
|
||||
legend: {
|
||||
show: false,
|
||||
show:false
|
||||
},
|
||||
|
||||
xAxis: {
|
||||
boundaryGap: 'justify',
|
||||
format: 'ssss',
|
||||
disableGrid: true,
|
||||
},
|
||||
yAxis: {
|
||||
gridType: 'dash',
|
||||
|
|
@ -36,47 +31,15 @@ const opts = {
|
|||
gradient: true,
|
||||
activeType: 'hollow',
|
||||
},
|
||||
tooltip: {
|
||||
legendShow: false,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
const chartData = reactive({})
|
||||
watch(
|
||||
() => props.data,
|
||||
(e) => {
|
||||
const obj = {
|
||||
categories: e.map((el) => el.key),
|
||||
series: [
|
||||
{
|
||||
name: '金额',
|
||||
data: e.map((el) => el.value),
|
||||
},
|
||||
],
|
||||
})
|
||||
const chartData = ref({
|
||||
categories: ['2016', '2017', '2018', '2019', '2020', '2021'],
|
||||
series: [
|
||||
{
|
||||
name: '目标值',
|
||||
data: [35, 36, 31, 33, 13, 34],
|
||||
}
|
||||
Object.assign(chartData, JSON.parse(JSON.stringify(obj)))
|
||||
|
||||
|
||||
// chartData = {
|
||||
// categories: e.map((el) => el.key),
|
||||
// series: [
|
||||
// {
|
||||
// name: '金额',
|
||||
// data: e.map((el) => el.value),
|
||||
// },
|
||||
// ],
|
||||
// }
|
||||
console.log(e)
|
||||
// chartData.categories= ['03月29日', '03月30日', '03月31日', '04月01日', '04月02日', '04月03日', '04月04日', '04月05日', '04月06日', '04月07日', '04月08日', '04月09日', '04月10日', '04月11日', '04月12日', '04月13日', '04月14日', '04月15日', '04月16日', '04月17日', '04月18日', '04月19日', '04月20日', '04月21日', '04月22日', '04月23日', '04月24日', '04月25日', '04月26日', '04月27日']
|
||||
// chartData.categories = e.map((el) => el.key)
|
||||
// console.log(e.map((el) => el.value));
|
||||
// chartData.series[0].data = e.map((el) => el.value)
|
||||
// chartData.series[0].data = ['0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '2', '0', '0', '0', '0', '0', '0', '0', '1', '11', '112', '1', '0', '100', '20040']
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
deep: true,
|
||||
}
|
||||
)
|
||||
],
|
||||
})
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,240 +0,0 @@
|
|||
<template>
|
||||
<view>
|
||||
<view class="flex-center h-44px text-white" :style="{ color: color }">
|
||||
<view class="flex-center flex-1" @click="openRegions">
|
||||
<view class="line-clamp-1">{{ regionseText }}</view>
|
||||
<uv-icon
|
||||
:color="color"
|
||||
class="ml-10rpx"
|
||||
size="20rpx"
|
||||
name="arrow-down-fill"
|
||||
></uv-icon>
|
||||
</view>
|
||||
<view class="flex-center flex-1" @click="openStore">
|
||||
<view class="line-clamp-1">{{ storeText }}</view>
|
||||
<uv-icon
|
||||
:color="color"
|
||||
class="ml-10rpx"
|
||||
size="20rpx"
|
||||
name="arrow-down-fill"
|
||||
></uv-icon>
|
||||
</view>
|
||||
</view>
|
||||
<uv-picker
|
||||
ref="regionsRef"
|
||||
:columns="addressList"
|
||||
@change="regionsChange"
|
||||
keyName="name"
|
||||
@confirm="regionsConfirm"
|
||||
>
|
||||
</uv-picker>
|
||||
|
||||
<uv-picker
|
||||
ref="storeRef"
|
||||
:columns="storeList"
|
||||
keyName="title"
|
||||
@confirm="storeConfirm"
|
||||
>
|
||||
</uv-picker>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import { http } from '@/utils/request'
|
||||
import { onMounted, ref, reactive, computed, toRaw } from 'vue'
|
||||
import debounce from '@climblee/uv-ui/libs/function/debounce'
|
||||
import { empty } from '@climblee/uv-ui/libs/function/test'
|
||||
const props = defineProps({
|
||||
color: {
|
||||
type: String,
|
||||
default: '#fff',
|
||||
},
|
||||
isAll: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
isLotteryStore:{
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
})
|
||||
onMounted(() => {
|
||||
getData()
|
||||
getStoreData()
|
||||
})
|
||||
|
||||
const regionsRef = ref(null)
|
||||
const storeRef = ref(null)
|
||||
// 筛选结果
|
||||
const result = ref([])
|
||||
// 地区数据
|
||||
const regions = ref([])
|
||||
const provinces = ref([])
|
||||
const citys = ref([])
|
||||
const areas = ref([])
|
||||
const store = ref([])
|
||||
const addressList = computed(() => {
|
||||
return [provinces.value, citys.value]
|
||||
})
|
||||
const storeList = computed(() => {
|
||||
return [store.value]
|
||||
})
|
||||
const emit = defineEmits(['change'])
|
||||
|
||||
const regionseText = computed(() => {
|
||||
if (result.value.length == 0) {
|
||||
return '全部区域'
|
||||
} else {
|
||||
const province = result.value.find((item) => item.name == 'province_code')
|
||||
const city = result.value.find((item) => item.name == 'city_code')
|
||||
let text = province?.label
|
||||
if (city?.value)
|
||||
text = truncateString(text, 3) + `/${truncateString(city?.label, 3)}`
|
||||
return text
|
||||
}
|
||||
})
|
||||
|
||||
const storeText = computed(() => {
|
||||
if (result.value.length == 0) {
|
||||
return '全部门店'
|
||||
} else {
|
||||
const store = result.value.find((item) => item.name == 'store_id')
|
||||
return store?.label
|
||||
}
|
||||
})
|
||||
|
||||
function truncateString(str, maxLength) {
|
||||
if (str.length <= maxLength) {
|
||||
return str
|
||||
}
|
||||
if (maxLength <= 3) {
|
||||
return str.substring(0, maxLength) + '...'
|
||||
}
|
||||
return str.substring(0, maxLength - 3) + '...'
|
||||
}
|
||||
|
||||
const selectMenu = (e) => {
|
||||
e.forEach((item) => {
|
||||
const findIndex = result.value.findIndex((el) => el.name == item.name)
|
||||
if (findIndex >= 0) {
|
||||
result.value[findIndex] = item
|
||||
} else {
|
||||
result.value.push(item)
|
||||
}
|
||||
})
|
||||
|
||||
debounce(
|
||||
() => {
|
||||
const obj = toRaw(arrayToObject(result.value))
|
||||
if (!props.isAll && empty(obj.store_id)) return
|
||||
|
||||
emit('change', toRaw(arrayToObject(result.value)))
|
||||
},
|
||||
500,
|
||||
false
|
||||
)
|
||||
}
|
||||
|
||||
function arrayToObject(arr) {
|
||||
const obj = {}
|
||||
arr.forEach((item) => {
|
||||
obj[item.name] = item.value
|
||||
if(item.name == 'store_id' && props.isLotteryStore) obj['is_lottery_store'] = item.is_lottery_store
|
||||
})
|
||||
return obj
|
||||
}
|
||||
|
||||
const getData = async () => {
|
||||
http.get('/region').then((res) => {
|
||||
regions.value = res
|
||||
let _all = []
|
||||
|
||||
_all = [{ name: '全部区域', code: null }]
|
||||
|
||||
provinces.value = _all.concat(res.province)
|
||||
citys.value = getCityByCode()
|
||||
regionsConfirm({
|
||||
value: [provinces.value[0], citys.value[0]],
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const regionsConfirm = (e) => {
|
||||
const { value } = e
|
||||
const parmas = [
|
||||
{
|
||||
name: 'province_code',
|
||||
value: value[0].code,
|
||||
label: value[0].name,
|
||||
},
|
||||
{
|
||||
name: 'city_code',
|
||||
value: value[1].code,
|
||||
label: value[1].name,
|
||||
},
|
||||
]
|
||||
selectMenu(parmas)
|
||||
getStoreData()
|
||||
}
|
||||
|
||||
const getStoreData = () => {
|
||||
storeRef.value?.setIndexs([0], true)
|
||||
const params = {
|
||||
province_code: result.value.find((item) => item.name == 'province_code')
|
||||
?.value,
|
||||
city_code: result.value.find((item) => item.name == 'city_code')?.value,
|
||||
}
|
||||
http
|
||||
.get('/auth/stores', {
|
||||
params: params,
|
||||
})
|
||||
.then((res) => {
|
||||
let _all = []
|
||||
if (props.isAll) {
|
||||
_all = [{ title: '全部门店', id: null }]
|
||||
}
|
||||
store.value = _all.concat(res)
|
||||
storeConfirm({ value: [store.value[0]] })
|
||||
})
|
||||
}
|
||||
|
||||
const openRegions = () => {
|
||||
regionsRef.value?.open()
|
||||
}
|
||||
|
||||
const openStore = () => {
|
||||
storeRef.value?.open()
|
||||
}
|
||||
|
||||
const regionsChange = (e) => {
|
||||
const { columnIndex, index, indexs } = e
|
||||
if (columnIndex === 0) {
|
||||
const { code } = provinces.value[index]
|
||||
citys.value = getCityByCode(code)
|
||||
regionsRef.value?.setIndexs([index, 0], true)
|
||||
}
|
||||
}
|
||||
|
||||
const getCityByCode = (code) => {
|
||||
const _citys = regions.value.city
|
||||
const _city = _citys[code]
|
||||
let arr = [{ name: '全部市', code: null }]
|
||||
if (_city == null) {
|
||||
arr = arr.concat(Object.values(_citys).flat())
|
||||
} else {
|
||||
arr = arr.concat(_city)
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
||||
const storeConfirm = (e) => {
|
||||
const parmas = [
|
||||
{
|
||||
name: 'store_id',
|
||||
value: e.value[0].id,
|
||||
label: e.value[0].title,
|
||||
is_lottery_store: e.value[0].is_lottery_store,
|
||||
},
|
||||
]
|
||||
selectMenu(parmas)
|
||||
}
|
||||
</script>
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,166 +1,192 @@
|
|||
<template>
|
||||
<view>
|
||||
<view class="flex-center h-44px text-white">
|
||||
<view class="flex-center flex-1" @click="openCity">
|
||||
<view>{{ selected.area_text }}</view>
|
||||
<uv-icon
|
||||
color="white"
|
||||
class="ml-10rpx"
|
||||
size="20rpx"
|
||||
name="arrow-down-fill"
|
||||
></uv-icon>
|
||||
<uv-sticky bgColor="#fff">
|
||||
<view class="flex-center h-44px">
|
||||
<view class="flex-center flex-1" @click="selectMenu({ name: 'shore' })">
|
||||
<view>全部区域</view>
|
||||
<uv-icon
|
||||
class="ml-10rpx"
|
||||
size="20rpx"
|
||||
name="arrow-down-fill"
|
||||
></uv-icon>
|
||||
</view>
|
||||
<view class="flex-center flex-1" @click="selectMenu({ name: 'store' })">
|
||||
<view>全部区域</view>
|
||||
<uv-icon
|
||||
class="ml-10rpx"
|
||||
size="20rpx"
|
||||
name="arrow-down-fill"
|
||||
></uv-icon>
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex-center flex-1" @click="openStore">
|
||||
<view>{{ selected.store_text }}</view>
|
||||
<uv-icon
|
||||
color="white"
|
||||
class="ml-10rpx"
|
||||
size="20rpx"
|
||||
name="arrow-down-fill"
|
||||
></uv-icon>
|
||||
</view>
|
||||
</view>
|
||||
</uv-sticky>
|
||||
<uv-picker
|
||||
ref="cityRef"
|
||||
ref="shoreRef"
|
||||
keyName="name"
|
||||
:columns="cityList"
|
||||
:loading="cityLoading"
|
||||
cancelText="重置"
|
||||
@confirm="cityConfirm"
|
||||
@change="cityChange"
|
||||
@cancel="cityReset"
|
||||
/>
|
||||
@change="shoreChange"
|
||||
:columns="shoreList"
|
||||
@confirm="shoreConfirm"
|
||||
></uv-picker>
|
||||
|
||||
<uv-picker
|
||||
ref="storeRef"
|
||||
keyName="title"
|
||||
keyName="address"
|
||||
@change="shoreChange"
|
||||
:columns="storeList"
|
||||
:loading="storeLoading"
|
||||
@confirm="storeConfirm"
|
||||
@confirm="shoreConfirm"
|
||||
></uv-picker>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
import { http } from '@/utils/request'
|
||||
import data from './da.json'
|
||||
|
||||
export default {
|
||||
name: 'StoreDropDown',
|
||||
onPageScroll() {
|
||||
// 滚动后及时更新位置
|
||||
// this.$refs.dropDown.init()
|
||||
},
|
||||
computed: {
|
||||
dropItem(name) {
|
||||
return (name) => {
|
||||
return {
|
||||
label: name,
|
||||
value: name,
|
||||
}
|
||||
}
|
||||
},
|
||||
// 获取当前下拉筛选项
|
||||
currentDropItem() {
|
||||
return this[this.activeName]
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
cityData: {},
|
||||
// 已选择的地区 {province: {code, name}, city: {code, name}, area_text: '全部区域', store: {id, name}, store_text: '全部门店'}
|
||||
selected: {
|
||||
area_text: '全部区域',
|
||||
store_text: '全部门店',
|
||||
},
|
||||
cityLoading: false,
|
||||
cityList: [],
|
||||
storeLoading: false,
|
||||
shoreList: [],
|
||||
storeList: [],
|
||||
// 表示value等于这些值,就属于默认值
|
||||
defaultValue: [0, 'all'],
|
||||
// 筛选结果
|
||||
result: [],
|
||||
activeName: 'shore',
|
||||
shore: {
|
||||
label: '全部区域',
|
||||
activeIndex: [0, 0],
|
||||
color: '#333',
|
||||
activeColor: '#2878ff',
|
||||
},
|
||||
store: {
|
||||
label: '全部门店',
|
||||
activeIndex: 0,
|
||||
color: '#333',
|
||||
activeColor: '#2878ff',
|
||||
},
|
||||
cityData: data,
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.init()
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
this.cityLoading = true
|
||||
http
|
||||
.get('/region')
|
||||
.then((res) => {
|
||||
this.cityLoading = false
|
||||
this.cityData = res
|
||||
const firstProvince = this.cityData.province[0]
|
||||
this.cityList = [
|
||||
this.cityData.province,
|
||||
this.findCityByProvince(firstProvince.code),
|
||||
]
|
||||
this.findStoreList()
|
||||
})
|
||||
.catch((error) => {
|
||||
this.cityLoading = false
|
||||
})
|
||||
async init() {
|
||||
const province = this.cityData.province
|
||||
this.shoreList = [
|
||||
province,
|
||||
this.getCityByProvince(province[this.shore.activeIndex[1]].code),
|
||||
]
|
||||
},
|
||||
findStoreList() {
|
||||
const params = {}
|
||||
if (this.selected.province) {
|
||||
params.province_code = this.selected.province.code
|
||||
change(e) {
|
||||
console.log('弹窗打开状态:', e)
|
||||
},
|
||||
/**
|
||||
* 点击每个筛选项回调
|
||||
* @param {Object} e { name, active, type } = e
|
||||
*/
|
||||
selectMenu(e) {
|
||||
const { name } = e
|
||||
this.activeName = name
|
||||
if (name === 'shore') {
|
||||
const active = this.shore.activeIndex
|
||||
const list = this.getCityByProvince(this.shoreList[0][active[0]].code)
|
||||
this.shoreList[1] = list
|
||||
this.$refs.shoreRef.setColumnValues(1, list)
|
||||
this.$refs.shoreRef.setIndexs(active, true)
|
||||
this.$refs.shoreRef.open()
|
||||
}
|
||||
if (this.selected.city) {
|
||||
params.city_code = this.selected.city.code
|
||||
}
|
||||
this.storeLoading = true
|
||||
http
|
||||
.get('/auth/stores', { params })
|
||||
.then((res) => {
|
||||
this.storeLoading = false
|
||||
res.unshift({ title: '全部门店', id: 'all' })
|
||||
this.storeList = [res]
|
||||
})
|
||||
.catch((error) => {
|
||||
this.storeLoading = false
|
||||
})
|
||||
},
|
||||
loadData() {
|
||||
console.log('加载数据....', this.selected)
|
||||
this.$emit('refresh', this.selected)
|
||||
},
|
||||
openCity() {
|
||||
this.$refs.cityRef.open()
|
||||
},
|
||||
cityReset() {
|
||||
this.selected = { area_text: '全部区域', store_text: '全部门店' }
|
||||
this.loadData()
|
||||
},
|
||||
cityConfirm(e) {
|
||||
const province = e.value[0]
|
||||
const city = e.value[1]
|
||||
if (province && city) {
|
||||
if (province.code != 'all') {
|
||||
this.selected.province = province
|
||||
}
|
||||
if (city.code != 'all') {
|
||||
this.selected.city = city
|
||||
}
|
||||
this.selected.area_text = city.code == 'all' ? province.name : city.name
|
||||
this.storeReset()
|
||||
this.findStoreList()
|
||||
this.loadData()
|
||||
if (name === 'store') {
|
||||
this.$refs.storeRef.open()
|
||||
}
|
||||
},
|
||||
cityChange(e) {
|
||||
/**
|
||||
* 点击菜单回调处理
|
||||
* @param {Object} item 选中项 { label,value } = e
|
||||
*/
|
||||
clickItem(e) {},
|
||||
shoreChange(e) {
|
||||
const { columnIndex, index } = e
|
||||
if (columnIndex == 0) {
|
||||
const province = this.cityData.province[index]
|
||||
this.$refs.cityRef.setColumnValues(
|
||||
const item = this.shoreList[columnIndex][index]
|
||||
this.shoreList[1] = this.getCityByProvince(item.code)
|
||||
this.$refs.shoreRef.setColumnValues(
|
||||
1,
|
||||
this.findCityByProvince(province.code)
|
||||
this.getCityByProvince(item.code)
|
||||
)
|
||||
}
|
||||
},
|
||||
openStore() {
|
||||
this.$refs.storeRef.open()
|
||||
},
|
||||
storeConfirm(e) {
|
||||
const store = e.value[0]
|
||||
if (store) {
|
||||
if (store.id != 'all') {
|
||||
this.selected.store = store
|
||||
}
|
||||
this.selected.store_text = store.title
|
||||
this.loadData()
|
||||
shoreConfirm(e) {
|
||||
this.shore.activeIndex = e.indexs
|
||||
const item = {
|
||||
name: 'shore',
|
||||
}
|
||||
const cityIndex = this.shore.activeIndex[1]
|
||||
const index = cityIndex == 0 ? 0 : 1
|
||||
const index2 = e.indexs[index]
|
||||
},
|
||||
storeReset() {
|
||||
this.selected.store_text = '全部门店'
|
||||
this.selected.store = null
|
||||
getCityByProvince(province) {
|
||||
return [
|
||||
{
|
||||
name: '全部',
|
||||
code: 'all',
|
||||
},
|
||||
].concat(this.cityData.city[province])
|
||||
},
|
||||
findCityByProvince(provinceCode) {
|
||||
const cityList = this.cityData.city[provinceCode]
|
||||
if (cityList.length > 1 && cityList[0].code != 'all') {
|
||||
cityList.unshift({ name: '全部', code: 'all' })
|
||||
}
|
||||
return cityList
|
||||
|
||||
getStoreByCity(city) {
|
||||
const res = http.get('/auth/stores', {
|
||||
params: {
|
||||
city: city,
|
||||
},
|
||||
})
|
||||
this.storeList = [
|
||||
{
|
||||
id: 1,
|
||||
title: '1',
|
||||
master_id: 1,
|
||||
category_id: 'store_category_1_1',
|
||||
business_id: 'store_business_1',
|
||||
level_id: 'store_level_2',
|
||||
region: {
|
||||
city: '天津市市辖区',
|
||||
code: 120100,
|
||||
street: null,
|
||||
cityCode: 120100,
|
||||
district: null,
|
||||
province: '天津市',
|
||||
districtCode: 0,
|
||||
provinceCode: 120000,
|
||||
},
|
||||
address: '回龙观(地铁站)',
|
||||
lon: '116.34266369754',
|
||||
lat: '40.076418413591',
|
||||
profit_ratio: 0,
|
||||
profit_money: '0.00',
|
||||
business_status: 1,
|
||||
created_at: '2024-04-03 17:17:02',
|
||||
updated_at: '2024-04-03 17:17:02',
|
||||
business_status_text: '开业',
|
||||
business_status_color: 'success',
|
||||
},
|
||||
]
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,81 +1,28 @@
|
|||
<template>
|
||||
<view>
|
||||
<!-- <view class="z-9999 relative">
|
||||
<uv-no-network @connected="onConnected"></uv-no-network>
|
||||
</view> -->
|
||||
<CuNavbar :isBack="false" title="首页">
|
||||
<template #center>
|
||||
<view class="w-full" v-if="checkPermission(['admin'])">
|
||||
<StoreDown @change="storeChange"></StoreDown>
|
||||
</view>
|
||||
</template>
|
||||
</CuNavbar>
|
||||
<view class="bg-primary p-base text-center text-white relative">
|
||||
<view
|
||||
class="absolute top-20rpx right-20rpx z-888"
|
||||
@click="goPath('/pages/message/index')"
|
||||
>
|
||||
<cu-badge
|
||||
:value="unread_notifications"
|
||||
color="#fff"
|
||||
bgColor="transparent"
|
||||
>
|
||||
<uv-icon color="#fff" size="48rpx" name="chat"></uv-icon>
|
||||
</cu-badge>
|
||||
</view>
|
||||
<view>
|
||||
<StoreDropDown></StoreDropDown>
|
||||
</view>
|
||||
|
||||
<swiper class="h-300rpx">
|
||||
<swiper-item>
|
||||
<view class="mt-60rpx">昨日累计金额</view>
|
||||
<view class="mt-20rpx">截止{{ yesday_ledger.date }}</view>
|
||||
<view class="flex items-center mt-40rpx">
|
||||
<view class="flex-1 text-center">
|
||||
<view>销售</view>
|
||||
<view>{{ yesday_ledger.sales }}</view>
|
||||
</view>
|
||||
<view class="h-80rpx flex-none flex-center">
|
||||
<uv-line direction="vertical"></uv-line>
|
||||
</view>
|
||||
<view class="flex-1 text-center">
|
||||
<view v-if="isLotteryStore">兑奖</view>
|
||||
<view v-else>支出</view>
|
||||
<view>{{ yesday_ledger.expenditure }}</view>
|
||||
</view>
|
||||
<view class="h-80rpx flex-none flex-center">
|
||||
<uv-line direction="vertical"></uv-line>
|
||||
</view>
|
||||
<view class="flex-1 text-center">
|
||||
<view>客户</view>
|
||||
<view>{{ yesday_ledger.new_customers }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</swiper-item>
|
||||
<swiper-item>
|
||||
<view class="mt-60rpx">本月累计金额</view>
|
||||
<view class="mt-20rpx">截止{{ current_month_ledger.deadline }}</view>
|
||||
<view class="flex items-center mt-40rpx">
|
||||
<view class="flex-1 text-center">
|
||||
<view>销售</view>
|
||||
<view>{{ current_month_ledger.sales }}</view>
|
||||
</view>
|
||||
<view class="h-80rpx flex-none flex-center">
|
||||
<uv-line direction="vertical"></uv-line>
|
||||
</view>
|
||||
<view class="flex-1 text-center">
|
||||
<view v-if="isLotteryStore">兑奖</view>
|
||||
<view v-else>支出</view>
|
||||
<view>{{ current_month_ledger.expenditure }}</view>
|
||||
</view>
|
||||
<view class="h-80rpx flex-none flex-center">
|
||||
<uv-line direction="vertical"></uv-line>
|
||||
</view>
|
||||
<view class="flex-1 text-center">
|
||||
<view>客户</view>
|
||||
<view>{{ current_month_ledger.new_customers }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
<view class="bg-primary p-base text-center text-white relative">
|
||||
<view class="absolute top-20rpx right-20rpx">
|
||||
<uv-icon color="#fff" size="48rpx" name="chat"></uv-icon>
|
||||
</view>
|
||||
<view class="mt-60rpx">昨日累计金额</view>
|
||||
<view class="mt-20rpx">截止2024-03-21</view>
|
||||
<view class="flex items-center mt-40rpx">
|
||||
<view class="flex-1 text-center">
|
||||
<view>销售</view>
|
||||
<view>20000</view>
|
||||
</view>
|
||||
<view class="h-80rpx flex-none flex-center">
|
||||
<uv-line direction="vertical"></uv-line>
|
||||
</view>
|
||||
<view class="flex-1 text-center">
|
||||
<view>支出</view>
|
||||
<view>20000</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view>
|
||||
<view class="h-80rpx leading-80rpx px-base">近30天趋势数据</view>
|
||||
|
|
@ -85,172 +32,28 @@
|
|||
:activeStyle="{ color: '#ee2c37' }"
|
||||
lineColor="#ee2c37"
|
||||
:list="list"
|
||||
:current="tabIndex"
|
||||
@click="onTabClick"
|
||||
:scrollable="false"
|
||||
></uv-tabs>
|
||||
|
||||
<!-- <ChartComp :data="countData"></ChartComp> -->
|
||||
<qiun-data-charts type="area" :opts="opts" :chartData="chartData" />
|
||||
<ChartComp></ChartComp>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import { ref, reactive, computed } from 'vue'
|
||||
import ChartComp from './components/chart.vue'
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import StoreDropDown from '@/pages/home/components/store-drop-down/index.vue'
|
||||
import { http } from '@/utils/request'
|
||||
import { onShow } from '@dcloudio/uni-app'
|
||||
import { timeFormat } from '@climblee/uv-ui/libs/function'
|
||||
import StoreDown from './components/store-down.vue'
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
import cuBadge from '@/components/cu-badge/index.vue'
|
||||
import checkPermission from '@/utils/permission'
|
||||
import checkUpdate from '@/pages/upgrade/check-update'
|
||||
// #ifdef APP-PLUS
|
||||
checkUpdate()
|
||||
// #endif
|
||||
|
||||
const onConnected = () => {
|
||||
getData()
|
||||
userStore.fetchUserInfo()
|
||||
}
|
||||
|
||||
const userStore = useUserStore()
|
||||
const userInfo = computed(() => userStore.userInfo)
|
||||
const isLotteryStore = computed(
|
||||
() => (userStore.userInfo?.store?.is_lottery_store || checkPermission(['admin']))
|
||||
)
|
||||
const unread_notifications = computed(
|
||||
() => userInfo.value.unread_notifications || 0
|
||||
)
|
||||
const opts = {
|
||||
color: ['#ee2c37'],
|
||||
dataLabel: false,
|
||||
dataPointShape: true,
|
||||
enableScroll: false,
|
||||
legend: {
|
||||
show: false,
|
||||
const list = ref([
|
||||
{
|
||||
name: '销售金额',
|
||||
},
|
||||
|
||||
xAxis: {
|
||||
boundaryGap: 'justify',
|
||||
format: 'ssss',
|
||||
{
|
||||
name: '支出金额',
|
||||
},
|
||||
yAxis: {
|
||||
gridType: 'dash',
|
||||
dashLength: 2,
|
||||
},
|
||||
extra: {
|
||||
area: {
|
||||
type: 'curve',
|
||||
opacity: 0.2,
|
||||
addLine: true,
|
||||
width: 2,
|
||||
gradient: true,
|
||||
activeType: 'hollow',
|
||||
},
|
||||
tooltip: {
|
||||
legendShow: false,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// const list = ref([
|
||||
// {
|
||||
// name: '销售金额',
|
||||
// key: 'sales',
|
||||
// },
|
||||
// {
|
||||
// name: '支出金额',
|
||||
// key: 'expenditure',
|
||||
// },
|
||||
// ])
|
||||
|
||||
const list = computed(() => {
|
||||
return [
|
||||
{
|
||||
name: '销售金额',
|
||||
key: 'sales',
|
||||
},
|
||||
{
|
||||
name: isLotteryStore.value ? '兑奖金额' : '支出金额',
|
||||
key: 'expenditure',
|
||||
},
|
||||
]
|
||||
})
|
||||
|
||||
const tabIndex = ref(0)
|
||||
const detail = ref({
|
||||
yesday_ledger: {},
|
||||
current_month_ledger: {},
|
||||
})
|
||||
const chartData = ref({})
|
||||
const yesday_ledger = computed(() => detail.value.yesday_ledger || {})
|
||||
const current_month_ledger = computed(
|
||||
() => detail.value.current_month_ledger || {}
|
||||
)
|
||||
const trends_of_30days = computed(() => detail.value.trends_of_30days || [])
|
||||
|
||||
const yesterday = computed(() => {
|
||||
return timeFormat(Number(new Date()) - 1000 * 60 * 60 * 24)
|
||||
})
|
||||
const tabObj = computed(() => list.value[tabIndex.value])
|
||||
|
||||
const storeChange = (e) => {
|
||||
getData(e)
|
||||
}
|
||||
])
|
||||
|
||||
const onTabClick = (e) => {
|
||||
tabIndex.value = e.index
|
||||
updateData()
|
||||
}
|
||||
|
||||
const updateData = () => {
|
||||
const arr =
|
||||
trends_of_30days?.value?.reduce((p, c) => {
|
||||
p.push({
|
||||
key: timeFormat(c.date, 'mm月dd日'),
|
||||
value: c[tabObj.value.key],
|
||||
})
|
||||
return p
|
||||
}, []) ?? []
|
||||
chartData.value = {
|
||||
categories: arr.map((el) => el.key),
|
||||
series: [
|
||||
{
|
||||
name: '金额',
|
||||
data: arr.map((el) => el.value),
|
||||
},
|
||||
],
|
||||
}
|
||||
// countData.value = arr
|
||||
}
|
||||
|
||||
onShow(() => {
|
||||
getData()
|
||||
userStore.fetchUserInfo()
|
||||
})
|
||||
|
||||
const getData = (e = {}) => {
|
||||
if (!checkPermission(['admin'])) {
|
||||
e.store_id = userStore?.userInfo?.store?.id
|
||||
}
|
||||
http
|
||||
.get('/statistics/dashboard', {
|
||||
params: {
|
||||
date: yesterday.value,
|
||||
...e,
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
detail.value = res
|
||||
updateData()
|
||||
})
|
||||
}
|
||||
|
||||
const goPath = (url) => {
|
||||
uni.navigateTo({ url })
|
||||
console.log(e)
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,20 +1,20 @@
|
|||
|
||||
|
||||
<template>
|
||||
<view class="w-full flex flex-col">
|
||||
<view class="mt-20vh flex-center">
|
||||
<image class="w-200rpx h-200rpx" src="@/static/logo.png"></image>
|
||||
<view class="mt-20vh">
|
||||
<view class="b-1px b-solid h-120rpx"></view>
|
||||
</view>
|
||||
<view class="text-35rpx text-hex-333333 font-600 mt-80rpx"
|
||||
>托管门店助手</view
|
||||
>
|
||||
<view class="text-35rpx text-hex-333333 font-600 mt-80rpx">体彩管理系统</view>
|
||||
<view class="text-27rpx text-hex-333333">欢迎登录</view>
|
||||
<view class="flex-1 flex flex-col justify-end mt-0rpx">
|
||||
<LoginForm></LoginForm>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import LoginForm from './LoginForm.vue'
|
||||
|
||||
</script>
|
||||
<style scoped lang="scss"></style>
|
||||
<style scoped lang="scss">
|
||||
|
||||
</style>
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<view class="">
|
||||
<uv-form :model="form" ref="formRef" errorType="toast" :rules="rules">
|
||||
<uv-form-item prop="username">
|
||||
<uv-form>
|
||||
<uv-form-item>
|
||||
<view class="h-92rpx bg-white rounded-full w-full flex-center">
|
||||
<uv-input
|
||||
v-model="form.username"
|
||||
|
|
@ -16,7 +16,7 @@
|
|||
</view>
|
||||
</uv-form-item>
|
||||
|
||||
<uv-form-item prop="password">
|
||||
<uv-form-item>
|
||||
<view class="h-92rpx bg-white rounded-full w-full flex-center">
|
||||
<uv-input
|
||||
v-model="form.password"
|
||||
|
|
@ -29,22 +29,9 @@
|
|||
</uv-input>
|
||||
</view>
|
||||
</uv-form-item>
|
||||
<view class="mt-40rpx">
|
||||
<uv-checkbox-group
|
||||
shape="circle"
|
||||
activeColor="#ff0000"
|
||||
v-model="checkboxValue"
|
||||
>
|
||||
<uv-checkbox :customStyle="{ marginBottom: '8px' }" :name="true">
|
||||
<view @click.stop="handleW" class="text-24rpx"
|
||||
>登录并同意《隐私政策》</view
|
||||
>
|
||||
</uv-checkbox>
|
||||
</uv-checkbox-group>
|
||||
</view>
|
||||
</uv-form>
|
||||
<view class="mt-115rpx">
|
||||
<uv-button block type="primary" shape="circle" @click="onValidate"
|
||||
<uv-button block type="primary" shape="circle" @click="handleClick"
|
||||
>登录</uv-button
|
||||
>
|
||||
</view>
|
||||
|
|
@ -53,7 +40,7 @@
|
|||
<script setup>
|
||||
import { ref, reactive, computed } from 'vue'
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
const checkboxValue = ref([false])
|
||||
|
||||
const userStore = useUserStore()
|
||||
|
||||
const form = ref({
|
||||
|
|
@ -61,43 +48,13 @@ const form = ref({
|
|||
password: '',
|
||||
})
|
||||
|
||||
const rules = computed(() => {
|
||||
return {
|
||||
username: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入帐号',
|
||||
},
|
||||
],
|
||||
password: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入密码',
|
||||
},
|
||||
],
|
||||
}
|
||||
})
|
||||
|
||||
const formRef = ref(null)
|
||||
|
||||
const handleW = () => {
|
||||
uni.navigateTo({ url: '/pages/webview/index' })
|
||||
}
|
||||
|
||||
const onValidate = () => {
|
||||
formRef.value.validate().then(() => {
|
||||
handleClick()
|
||||
})
|
||||
}
|
||||
|
||||
const handleClick = async () => {
|
||||
checkboxValue.value = [true]
|
||||
try {
|
||||
const { username, password } = form.value
|
||||
await userStore.login({
|
||||
username,
|
||||
password,
|
||||
})
|
||||
// const { username, password } = form.value
|
||||
// await userStore.login({
|
||||
// username,
|
||||
// password,
|
||||
// })
|
||||
uni.switchTab({
|
||||
url: '/pages/home/index',
|
||||
})
|
||||
|
|
|
|||
|
|
@ -6,14 +6,6 @@
|
|||
|
||||
<script setup>
|
||||
import Layout from './Layout.vue'
|
||||
import { onLoad, onBackPress } from '@dcloudio/uni-app'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { ref } from 'vue'
|
||||
|
||||
onBackPress((options) => {
|
||||
if (options.from == 'backbutton') {
|
||||
return true
|
||||
} else if (options.from == 'navigateBack') {
|
||||
return false
|
||||
}
|
||||
})
|
||||
</script>
|
||||
</script>
|
||||
|
|
@ -1,200 +0,0 @@
|
|||
<template>
|
||||
<view>
|
||||
<CuNavbar title="补卡申请"> </CuNavbar>
|
||||
<view class="card-shadow px-base">
|
||||
<uv-form
|
||||
labelPosition="left"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
ref="formRef"
|
||||
errorType="toast"
|
||||
labelWidth="250rpx"
|
||||
>
|
||||
<uv-form-item required label="补卡时间" prop="date">
|
||||
<uv-input
|
||||
placeholder="请选择补卡时间"
|
||||
readonly
|
||||
@click="openDatePicker"
|
||||
inputAlign="right"
|
||||
:border="`none`"
|
||||
v-model="form.date"
|
||||
>
|
||||
</uv-input>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item required label="补卡类别" prop="sign_time">
|
||||
<uv-input
|
||||
placeholder="请选择补卡类别"
|
||||
@click="openPicker"
|
||||
readonly
|
||||
inputAlign="right"
|
||||
:border="`none`"
|
||||
v-model="form.sign_time"
|
||||
>
|
||||
</uv-input>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item
|
||||
required
|
||||
label="补卡理由"
|
||||
prop="reason"
|
||||
labelPosition="top"
|
||||
>
|
||||
<uv-textarea
|
||||
v-model="form.reason"
|
||||
count
|
||||
placeholder="请输入补卡理由"
|
||||
:border="`none`"
|
||||
:maxlength="200"
|
||||
:customStyle="{ padding: '0' }"
|
||||
></uv-textarea>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item label="外勤" prop="isOutSide">
|
||||
<view class="flex flex-1 justify-end">
|
||||
<uv-switch size="20" v-model="form.isOutSide"></uv-switch>
|
||||
</view>
|
||||
</uv-form-item>
|
||||
<uv-form-item
|
||||
v-if="form.isOutSide"
|
||||
required
|
||||
label="外勤事由"
|
||||
prop="outside_remarks"
|
||||
labelPosition="top"
|
||||
>
|
||||
<uv-textarea
|
||||
v-model="form.outside_remarks"
|
||||
count
|
||||
placeholder="请输入外勤事由"
|
||||
:border="`none`"
|
||||
:customStyle="{ padding: '0' }"
|
||||
:maxlength="200"
|
||||
></uv-textarea>
|
||||
</uv-form-item>
|
||||
</uv-form>
|
||||
</view>
|
||||
<view class="mt-20rpx px-base">
|
||||
<uv-button type="primary" @click="submit">提交</uv-button>
|
||||
</view>
|
||||
<uv-picker
|
||||
ref="pickerRef"
|
||||
:columns="columns"
|
||||
@confirm="confirmPicker"
|
||||
></uv-picker>
|
||||
<uv-datetime-picker
|
||||
v-model="value"
|
||||
placeholder="请选择日期"
|
||||
ref="datetimePicker"
|
||||
mode="datetime"
|
||||
:maxDate="new Date().getTime()"
|
||||
@confirm="confirmDatePicker"
|
||||
>
|
||||
</uv-datetime-picker>
|
||||
<uv-modal
|
||||
ref="modalRef"
|
||||
title="提示"
|
||||
content="确定提交吗?"
|
||||
@confirm="onSubmit"
|
||||
:showCancelButton="true"
|
||||
></uv-modal>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import { ref, reactive, computed } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { http } from '@/utils/request'
|
||||
import { timeFormat } from '@climblee/uv-ui/libs/function/index'
|
||||
const columns = [['上班补卡', '下班补卡']]
|
||||
const formRef = ref(null)
|
||||
const datetimePicker = ref(null)
|
||||
const pickerRef = ref(null)
|
||||
const modalRef = ref(null)
|
||||
const value = ref(Number(new Date()))
|
||||
const id = ref(0)
|
||||
const loading = ref(false)
|
||||
const form = reactive({
|
||||
date: '',
|
||||
sign_time: '',
|
||||
reason: '',
|
||||
outside_remarks: '',
|
||||
isOutSide: false,
|
||||
})
|
||||
const openPicker = () => {
|
||||
pickerRef.value.open()
|
||||
}
|
||||
const openDatePicker = () => {
|
||||
datetimePicker.value.open()
|
||||
}
|
||||
const confirmDatePicker = (e) => {
|
||||
form.date = timeFormat(e.value, 'yyyy-mm-dd hh:MM')
|
||||
}
|
||||
const confirmPicker = (e) => {
|
||||
form.sign_time = e.value[0]
|
||||
}
|
||||
const rules = reactive({
|
||||
date: [{ required: true, message: '请选择补卡时间' }],
|
||||
sign_time: [{ required: true, message: '请选择补卡类别' }],
|
||||
reason: [{ required: true, message: '请输入补卡理由' }],
|
||||
outside_remarks: [{ required: true, message: '请输入外勤事由' }],
|
||||
})
|
||||
onLoad((options) => {
|
||||
id.value = options.id
|
||||
if (options.type) {
|
||||
form.sign_time = options.type == 1 ? '上班补卡' : '下班补卡'
|
||||
}
|
||||
if (id.value) {
|
||||
http.get(`/hr/sign-repairs/${options.id}`).then((res) => {
|
||||
value.value = res.date * 1000
|
||||
form.date = timeFormat(res.date, 'yyyy-mm-dd hh:MM')
|
||||
form.reason = res.reason
|
||||
form.isOutSide = res.sign_type == 1 ? false : true
|
||||
form.outside_remarks = res.outside_remarks
|
||||
form.sign_time = res.sign_time == 1 ? '上班补卡' : '下班补卡'
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const submit = () => {
|
||||
formRef.value
|
||||
.validate()
|
||||
.then((res) => {
|
||||
modalRef.value.open()
|
||||
})
|
||||
.catch((error) => {})
|
||||
}
|
||||
|
||||
const onSubmit = async () => {
|
||||
if (loading.value) return
|
||||
loading.value = true
|
||||
try {
|
||||
let url = id.value ? `/hr/sign-repairs/${id.value}` : '/hr/sign-repairs'
|
||||
let method = id.value ? 'PUT' : 'POST'
|
||||
await http.request({
|
||||
url: url,
|
||||
method: method,
|
||||
header: {
|
||||
Accept: 'application/json',
|
||||
},
|
||||
data: {
|
||||
date: form.date,
|
||||
sign_time: form.sign_time == '上班补卡' ? 1 : 2,
|
||||
reason: form.reason,
|
||||
outside_remarks: form.outside_remarks,
|
||||
sign_type: form.isOutSide ? 2 : 1,
|
||||
},
|
||||
})
|
||||
uni.showToast({
|
||||
title: '提交成功',
|
||||
icon: 'none',
|
||||
})
|
||||
formRef.value.resetFields()
|
||||
uni.$emit('refresh')
|
||||
uni.navigateBack()
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -1,129 +0,0 @@
|
|||
<template>
|
||||
<view class="px-base" v-if="detail">
|
||||
<CuNavbar title="补卡详情">
|
||||
<template v-if="actions.length > 0" #right>
|
||||
<uv-icon color="white" @click="open" name="more-dot-fill"></uv-icon>
|
||||
</template>
|
||||
</CuNavbar>
|
||||
<view class="mt-30rpx card-shadow bg-white rounded-19rpx px-base text-[#333333] text-27rpx">
|
||||
<BaseData :colums="detailColumns" :data="detail"></BaseData>
|
||||
</view>
|
||||
<uv-action-sheet ref="pickerRef" :actions="actions" @select="confirmPicker" />
|
||||
<uv-modal ref="modalRef" title="提示" content="确定删除吗?" @confirm="onSubmit" :showCancelButton="true"></uv-modal>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from "@/components/cu-navbar/index"
|
||||
import { http } from "@/utils/request"
|
||||
import { onLoad } from "@dcloudio/uni-app"
|
||||
import { ref } from "vue"
|
||||
import { timeFormat } from "@climblee/uv-ui/libs/function/index"
|
||||
import BaseData from '@/pages/audits/base-data.vue'
|
||||
import statusFun from '@/utils/status'
|
||||
|
||||
const modalRef = ref(null)
|
||||
const actions = ref([
|
||||
{ name: '修改', value: 'edit', disabled: false },
|
||||
{ name: '删除', value: 'delete', disabled: false },
|
||||
{ name: '审核流程', value: 'check-logs', disabled: false }
|
||||
])
|
||||
const detail = ref()
|
||||
const pickerRef = ref(null)
|
||||
const id = ref(0)
|
||||
const detailColumns = [
|
||||
{
|
||||
title: "审核状态",
|
||||
dataIndex: "workflow_check.check_status",
|
||||
format: (value) => statusFun(value, 'statusExpense', 'name')
|
||||
},
|
||||
{
|
||||
title: "申请人",
|
||||
dataIndex: "employee.name"
|
||||
},
|
||||
{
|
||||
title: "所属门店",
|
||||
dataIndex: "store.title"
|
||||
},
|
||||
{
|
||||
title: "电话号码",
|
||||
dataIndex: "employee.phone"
|
||||
},
|
||||
{
|
||||
title: "申请时间",
|
||||
dataIndex: "created_format"
|
||||
},
|
||||
{
|
||||
title: "补卡时间",
|
||||
dataIndex: "date_format"
|
||||
},
|
||||
{
|
||||
title: "补卡类别",
|
||||
dataIndex: "sign_time_text"
|
||||
},
|
||||
{
|
||||
title: "补卡原因",
|
||||
dataIndex: "reason"
|
||||
},
|
||||
{
|
||||
title: "是否外勤",
|
||||
dataIndex: "sign_type",
|
||||
format: (value) => value == 1 ? "否" : "是"
|
||||
},
|
||||
{
|
||||
title: "外勤事由",
|
||||
dataIndex: "outside_remarks",
|
||||
labelPosition: 'top',
|
||||
isShow: (data) => data?.sign_type == 2
|
||||
},
|
||||
{
|
||||
title: '未通过原因',
|
||||
dataIndex: 'workflow_check.check_remarks',
|
||||
labelPosition: 'top',
|
||||
isShow: (row) => row?.workflow_check.check_status == 4
|
||||
},
|
||||
];
|
||||
const open = () => {
|
||||
pickerRef.value.open()
|
||||
}
|
||||
const confirmPicker = e => {
|
||||
if (e.value == 'edit') {
|
||||
uni.navigateTo({
|
||||
url: `/pages/make-card/create?id=${id.value}`
|
||||
})
|
||||
} else if (e.value == 'delete') {
|
||||
modalRef.value.open()
|
||||
} else if (e.value == 'check-logs') {
|
||||
return uni.navigateTo({
|
||||
url: `/pages/audits/log?id=${detail.value.workflow_check.id}`
|
||||
})
|
||||
}
|
||||
}
|
||||
const onSubmit = async () => {
|
||||
try {
|
||||
await http.delete(`/hr/sign-repairs/${id.value}`)
|
||||
uni.showToast({
|
||||
title: "删除成功",
|
||||
icon: "none"
|
||||
})
|
||||
uni.$emit('refresh')
|
||||
uni.navigateBack()
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
onLoad(options => {
|
||||
id.value = options.id
|
||||
http.get(`/hr/sign-repairs/${options.id}`).then(res => {
|
||||
detail.value = res
|
||||
let status = res.workflow_check.check_status
|
||||
if ([2, 3].indexOf(status) != -1) {
|
||||
actions.value[0].disabled = true
|
||||
actions.value[1].disabled = true
|
||||
// actions.value.splice(0, 2)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
</script>
|
||||
|
|
@ -1,132 +0,0 @@
|
|||
<template>
|
||||
<view>
|
||||
<CuNavbar title="补卡申请">
|
||||
<template #right>
|
||||
<view @click="goPath('/pages/make-card/create')" class="text-24rpx text-white">申请</view>
|
||||
</template>
|
||||
</CuNavbar>
|
||||
<uv-sticky bgColor="#fff">
|
||||
<uv-tabs
|
||||
:activeStyle="{ color: '#ee2c37' }"
|
||||
:scrollable="false"
|
||||
lineColor="#ee2c37"
|
||||
:list="tabList"
|
||||
@change="tabChange"
|
||||
></uv-tabs>
|
||||
</uv-sticky>
|
||||
<MescrollItem
|
||||
ref="mescrollItem0"
|
||||
:top="88"
|
||||
:i="0"
|
||||
:index="tabIndex"
|
||||
:apiUrl="tabList[0].apiUrl"
|
||||
>
|
||||
<template v-slot="{ list }">
|
||||
<view class="space-y-15rpx p-base">
|
||||
<ListItem
|
||||
v-for="item in list" :key="item.id"
|
||||
title="补卡申请"
|
||||
:status-text="statusFun(item.workflow_check.check_status,'statusExpense','name')"
|
||||
:status-color="statusFun(item.workflow_check.check_status,'statusExpense','color')"
|
||||
:body="[
|
||||
{ label: '补卡时间: ', value: item.date_format },
|
||||
{ label: '补卡类别: ', value: item.sign_time_text },
|
||||
{ label: '补卡原因: ', value: item.reason },
|
||||
{ label: '申请时间: ', value: item.created_format },
|
||||
]"
|
||||
@click.stop="applyDetail(item)"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
</MescrollItem>
|
||||
<MescrollItem
|
||||
ref="mescrollItem1"
|
||||
:top="88"
|
||||
:i="1"
|
||||
:index="tabIndex"
|
||||
:apiUrl="tabList[1].apiUrl"
|
||||
:params="tabList[1].params"
|
||||
>
|
||||
<template v-slot="{ list }">
|
||||
<view class="space-y-15rpx p-base">
|
||||
<ListItem
|
||||
v-for="item in list" :key="item.id"
|
||||
title="补卡申请"
|
||||
:status-text="statusFun(item.check_status, 'statusExpense2', 'name')"
|
||||
:status-color="statusFun(item.check_status, 'statusExpense2', 'color')"
|
||||
:body="[
|
||||
{ label: '申请人: ', value: item.check.subject.employee.name },
|
||||
{ label: '补卡时间: ', value: item.check.subject.date_format },
|
||||
{ label: '补卡类别: ', value: item.check.subject.sign_time_text },
|
||||
{ label: '补卡原因: ', value: item.check.subject.reason },
|
||||
{ label: '申请时间: ', value: item.check.subject.created_format },
|
||||
]"
|
||||
@click.stop="checkDetail(item)"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
</MescrollItem>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import { ref } from 'vue'
|
||||
import { onPageScroll, onReachBottom, onLoad } from '@dcloudio/uni-app'
|
||||
import useMescrollMore from '@/uni_modules/mescroll-uni/hooks/useMescrollMore.js'
|
||||
import MescrollItem from '@/components/mescroll-api/more.vue'
|
||||
import statusFun from '@/utils/status'
|
||||
import ListItem from '@/components/list-item/index'
|
||||
const tabList = ref([
|
||||
{
|
||||
name: '我的补卡',
|
||||
apiUrl: '/hr/sign-repairs',
|
||||
},
|
||||
{
|
||||
name: '补卡审核',
|
||||
apiUrl: '/workflow',
|
||||
params: {
|
||||
subject_type: 'employee_sign_repairs',
|
||||
include: 'check.subject.employee'
|
||||
},
|
||||
},
|
||||
])
|
||||
const mescrollItem0 = ref(null)
|
||||
const mescrollItem1 = ref(null)
|
||||
|
||||
const mescrollItems = [mescrollItem0, mescrollItem1]
|
||||
const { tabIndex, getMescroll, scrollToLastY } = useMescrollMore(
|
||||
mescrollItems,
|
||||
onPageScroll,
|
||||
onReachBottom
|
||||
)
|
||||
|
||||
onLoad(() => {
|
||||
uni.$on('refresh', () => {
|
||||
console.log('refresh')
|
||||
mescrollItem0?.value?.getMescroll()?.resetUpScroll()
|
||||
mescrollItem1?.value?.getMescroll()?.resetUpScroll()
|
||||
})
|
||||
})
|
||||
|
||||
const goPath = (url) => {
|
||||
uni.navigateTo({
|
||||
url,
|
||||
})
|
||||
}
|
||||
const tabChange = ({ index }) => {
|
||||
tabIndex.value = index
|
||||
scrollToLastY()
|
||||
}
|
||||
|
||||
const applyDetail = (item) => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/make-card/detail?id=${item.id}`,
|
||||
})
|
||||
}
|
||||
|
||||
const checkDetail = (item) => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/audits/detail?id=${item.id}&type=${item.check.subject_type}`,
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
|
@ -1,101 +0,0 @@
|
|||
<template>
|
||||
<view class="card-shadow p-base relative" @click="onClick">
|
||||
<view class="flex items-center justify-between">
|
||||
<view>{{ statusFun(item.type, 'messages', 'name') }}</view>
|
||||
<view class="text-hex-999 text-24rpx">{{
|
||||
timeFormat(item?.created_at, 'mm月dd日 hh:MM')
|
||||
}}</view>
|
||||
</view>
|
||||
<view class="mt-14rpx text-hex-999 text-26rpx"> {{ item?.content }} </view>
|
||||
<view
|
||||
class="text-right text-hex-999 text-24rpx flex items-center justify-end"
|
||||
>
|
||||
<view class="flex items-center">
|
||||
<view>点击查看详情</view>
|
||||
<uv-icon size="22rpx" class="ml-10rpx" name="arrow-right"></uv-icon>
|
||||
</view>
|
||||
</view>
|
||||
<view class="absolute right-10rpx top-10rpx" v-if="item.is_read == 0">
|
||||
<uv-badge :isDot="true" type="error"></uv-badge>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import { timeFormat } from '@climblee/uv-ui/libs/function/index'
|
||||
import statusFun from '@/utils/status'
|
||||
import { http } from '@/utils/request'
|
||||
|
||||
const pageData = {
|
||||
task_hygienes: {
|
||||
path: '/pages/task/detail',
|
||||
},
|
||||
reimbursements: {
|
||||
path: '/pages/expense-account/detail',
|
||||
},
|
||||
employee_promotions: {
|
||||
path: '/pages/work/detail',
|
||||
},
|
||||
employee_sign_repairs: {
|
||||
path: '/pages/make-card/detail',
|
||||
},
|
||||
holiday_applies: {
|
||||
path: '/pages/ask-leave/detail',
|
||||
},
|
||||
offical_business: {
|
||||
path: '/pages/business/detail',
|
||||
},
|
||||
overtime_applies: {
|
||||
path: '/pages/overtime/detail',
|
||||
},
|
||||
agreements: {
|
||||
path: '/pages/contract/detail',
|
||||
},
|
||||
}
|
||||
const props = defineProps({
|
||||
item: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
})
|
||||
|
||||
const onClick = () => {
|
||||
// props.item.is_read = 1
|
||||
|
||||
const { type, is_read, id } = props.item
|
||||
const { additional } = props.item
|
||||
|
||||
if (is_read == 0) {
|
||||
http.get(`/message/messages/${id}`)
|
||||
props.item.is_read = 1
|
||||
}
|
||||
|
||||
if (type == 'approval') {
|
||||
//详情
|
||||
if (additional.subject) {
|
||||
const subject_type = additional.subject_type
|
||||
const { id } = additional.subject
|
||||
const path = pageData[subject_type].path
|
||||
if (path) {
|
||||
uni.navigateTo({
|
||||
url: `${path}?id=${id}&type=${subject_type}`,
|
||||
})
|
||||
}
|
||||
}
|
||||
//审批
|
||||
if (additional.workflow_log) {
|
||||
const { check,id } = additional.workflow_log
|
||||
const { subject_type, subject_id } = check
|
||||
uni.navigateTo({
|
||||
url: `/pages/audits/detail?id=${id}&type=${subject_type}`,
|
||||
})
|
||||
}
|
||||
} else if (type == 'exam') {
|
||||
//考试
|
||||
const { paper } = additional
|
||||
const { id } = paper
|
||||
uni.navigateTo({
|
||||
url: `/pages/examination/detail?id=${id}`,
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
<template>
|
||||
<view>
|
||||
<CuNavbar title="消息详情"></CuNavbar>
|
||||
<view></view>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import { http } from '@/utils/request'
|
||||
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { ref } from 'vue'
|
||||
const detail = ref({})
|
||||
const id = ref(0)
|
||||
onLoad((op) => {
|
||||
id.value = op.id
|
||||
getDetail()
|
||||
})
|
||||
|
||||
const getDetail = () => {
|
||||
http.get(`/message/messages/${id.value}`).then((res) => {
|
||||
detail.value = res
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
|
@ -1,97 +0,0 @@
|
|||
<template>
|
||||
<view>
|
||||
<CuNavbar title="消息">
|
||||
<template #right>
|
||||
<view class="text-24rpx text-white" @click="onRead"> 一键已读 </view>
|
||||
</template>
|
||||
</CuNavbar>
|
||||
<uv-sticky bgColor="#fff">
|
||||
<uv-tabs
|
||||
height="44"
|
||||
:activeStyle="{ color: '#ee2c37' }"
|
||||
:scrollable="false"
|
||||
:current="tabIndex"
|
||||
lineColor="#ee2c37"
|
||||
:list="tabList"
|
||||
@change="tabChange"
|
||||
></uv-tabs>
|
||||
</uv-sticky>
|
||||
<MescrollItem
|
||||
ref="mescrollItem0"
|
||||
:top="88"
|
||||
:i="0"
|
||||
:index="tabIndex"
|
||||
:apiUrl="tabList[0].apiUrl"
|
||||
:params="tabList[0].params"
|
||||
>
|
||||
<template v-slot="{ list }">
|
||||
<view class="space-y-15rpx p-base">
|
||||
<view v-for="(item, i) in list" :key="i">
|
||||
<Item :item="item"></Item>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</MescrollItem>
|
||||
<MescrollItem
|
||||
ref="mescrollItem1"
|
||||
:i="1"
|
||||
:top="88"
|
||||
:index="tabIndex"
|
||||
:apiUrl="tabList[1].apiUrl"
|
||||
:params="tabList[1].params"
|
||||
>
|
||||
<template v-slot="{ list }">
|
||||
<view class="space-y-15rpx p-base">
|
||||
<view v-for="(item, i) in list" :key="i">
|
||||
<Item :item="item"></Item>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</MescrollItem>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import { computed, reactive, ref } from 'vue'
|
||||
import { onPageScroll, onReachBottom, onShow } from '@dcloudio/uni-app'
|
||||
import useMescrollMore from '@/uni_modules/mescroll-uni/hooks/useMescrollMore.js'
|
||||
import MescrollItem from '@/components/mescroll-api/more.vue'
|
||||
import Item from './components/item.vue'
|
||||
import { http } from '@/utils/request'
|
||||
const mescrollItem0 = ref(null)
|
||||
const mescrollItem1 = ref(null)
|
||||
|
||||
const mescrollItems = [mescrollItem0, mescrollItem1]
|
||||
const { tabIndex, getMescroll, scrollToLastY } = useMescrollMore(
|
||||
mescrollItems,
|
||||
onPageScroll,
|
||||
onReachBottom
|
||||
)
|
||||
const tabList = ref([
|
||||
{
|
||||
name: '系统通知',
|
||||
apiUrl: '/message/messages',
|
||||
params: {
|
||||
filter: 'system',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: '办公通知',
|
||||
apiUrl: '/message/messages',
|
||||
params: {
|
||||
filter: 'work',
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
const tabChange = ({ index }) => {
|
||||
tabIndex.value = index
|
||||
scrollToLastY()
|
||||
}
|
||||
|
||||
const onRead = () => {
|
||||
http.post('/message/read-all').then(() => {
|
||||
getMescroll(tabIndex.value).resetUpScroll()
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<view class="flex-center flex-col" @click="onClick">
|
||||
<uv-icon :name="data.icon" size="60rpx" color="#909399"></uv-icon>
|
||||
<uv-icon :name="data.icon" size="38" color="#909399"></uv-icon>
|
||||
<view class="text-28rpx mt-10rpx">{{ data.title }}</view>
|
||||
</view>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -3,124 +3,41 @@
|
|||
<CuNavbar :isBack="false" title="我的">
|
||||
<template #right>
|
||||
<view class="h-full flex-center">
|
||||
<image
|
||||
@click="goPath('/pages/setting/index')"
|
||||
class="w-32rpx h-32rpx"
|
||||
src="/static/images/setting.svg"
|
||||
></image>
|
||||
<image @click="goPath('/pages/setting/index')" class="w-32rpx h-32rpx" src="/static/images/setting.svg"></image>
|
||||
</view>
|
||||
</template>
|
||||
</CuNavbar>
|
||||
<view class="px-base mt-30rpx">
|
||||
<view class="card-shadow bg-white rounded-19rpx p-base relative">
|
||||
<view class="flex">
|
||||
<view class="w-120rpx h-120rpx rounded-full overflow-hidden">
|
||||
<image class="w-full h-full" :src="userInfo?.avatar"></image>
|
||||
</view>
|
||||
<view class="ml-20rpx">
|
||||
<view class="text-28rpx font-medium flex items-center">
|
||||
<view>{{ userInfo.name }}</view>
|
||||
<view class="ml-20rpx" @click="goPath('/pages/userInfo/index')">
|
||||
<uv-icon size="36rpx" name="edit-pen"></uv-icon>
|
||||
</view>
|
||||
</view>
|
||||
<view class="text-26rpx">{{ userInfo.phone }}</view>
|
||||
<view class="flex">
|
||||
<uv-tags
|
||||
v-for="(item, i) in userInfo.jobs"
|
||||
:key="i"
|
||||
plain
|
||||
size="mini"
|
||||
:text="item.name"
|
||||
></uv-tags>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="absolute right-base top-base">
|
||||
<view class="flex items-center">
|
||||
<view
|
||||
class="flex items-center mr-10rpx"
|
||||
@click="goPath('/pages/clockout/index')"
|
||||
>
|
||||
<image
|
||||
class="w-40px h-40rpx"
|
||||
src="@/static/images/rl.svg"
|
||||
></image>
|
||||
</view>
|
||||
<cu-badge color="white" :value="unread_notifications">
|
||||
<uv-icon
|
||||
@click="goPath('/pages/message/index')"
|
||||
color="#8a8a8a"
|
||||
size="54rpx"
|
||||
name="chat"
|
||||
></uv-icon>
|
||||
</cu-badge>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="px-base space-y-15rpx mt-30rpx">
|
||||
<view class="card" v-for="(item, i) in opList" :key="i">
|
||||
<TitleComp :title="item.title"></TitleComp>
|
||||
<view class="grid grid-cols-3 mt-20rpx gap-34rpx">
|
||||
<template v-for="(child, ii) in item.children" :key="ii">
|
||||
<OpItem
|
||||
:data="child"
|
||||
v-if="child?.rouls ? checkPermission(child.rouls) : true"
|
||||
></OpItem>
|
||||
</template>
|
||||
<view class="grid grid-cols-3 mt-20rpx gap-20rpx">
|
||||
<OpItem
|
||||
v-for="(child, ii) in item.children"
|
||||
:key="ii"
|
||||
:data="child"
|
||||
></OpItem>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
import TitleComp from '@/components/title-comp/index'
|
||||
import OpItem from './components/op-item.vue'
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import checkPermission from '@/utils/permission'
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
import performanceIcon from '@/static/images/performance.svg'
|
||||
import brokerageIcon from '@/static/images/brokerage.svg'
|
||||
import userIcon from '@/static/images/user.svg'
|
||||
import taskIcon from '@/static/images/task.svg'
|
||||
import expenseIcon from '@/static/images/expense.svg'
|
||||
import workIcon from '@/static/images/work.svg'
|
||||
import makeIcon from '@/static/images/make.svg'
|
||||
import leaveIcon from '@/static/images/leave.svg'
|
||||
import businessIcon from '@/static/images/business.svg'
|
||||
import overtimeIcon from '@/static/images/overtime.svg'
|
||||
import contractIcon from '@/static/images/contract.svg'
|
||||
import booksIcon from '@/static/images/books.svg'
|
||||
import examinationIcon from '@/static/images/examination.svg'
|
||||
import cuBadge from '@/components/cu-badge/index.vue'
|
||||
import { onShow } from '@dcloudio/uni-app'
|
||||
const userStore = useUserStore()
|
||||
|
||||
const userInfo = computed(() => userStore.userInfo)
|
||||
const unread_notifications = computed(
|
||||
() => userInfo.value.unread_notifications || 0
|
||||
)
|
||||
|
||||
onShow(() => {
|
||||
userStore.fetchUserInfo()
|
||||
})
|
||||
|
||||
const opList = [
|
||||
{
|
||||
title: '门店数据',
|
||||
children: [
|
||||
{
|
||||
icon: performanceIcon,
|
||||
icon: 'order',
|
||||
title: '业绩数据',
|
||||
url: '/pages/data/performance/index',
|
||||
},
|
||||
{
|
||||
icon: brokerageIcon,
|
||||
icon: 'folder',
|
||||
title: '提成数据',
|
||||
url: '/pages/data/brokerage/index',
|
||||
rouls: ['store'],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
|
@ -128,50 +45,49 @@ const opList = [
|
|||
title: '办公管理',
|
||||
children: [
|
||||
{
|
||||
icon: userIcon,
|
||||
icon: 'photo-fill',
|
||||
title: '员工管理',
|
||||
url: '/pages/user/index',
|
||||
rouls: ['store', 'admin'],
|
||||
},
|
||||
{
|
||||
icon: taskIcon,
|
||||
icon: 'lock',
|
||||
title: '我的任务',
|
||||
url: '/pages/task/index',
|
||||
},
|
||||
{
|
||||
icon: expenseIcon,
|
||||
icon: 'home-fill',
|
||||
title: '报销管理',
|
||||
url: '/pages/expense-account/index',
|
||||
},
|
||||
{
|
||||
icon: workIcon,
|
||||
icon: 'map-fill',
|
||||
title: '升职申请',
|
||||
url: '/pages/work/list',
|
||||
},
|
||||
{
|
||||
icon: makeIcon,
|
||||
icon: 'grid-fill',
|
||||
title: '补卡申请',
|
||||
url: '/pages/make-card/list',
|
||||
url: '',
|
||||
},
|
||||
{
|
||||
icon: leaveIcon,
|
||||
icon: 'car',
|
||||
title: '请假申请',
|
||||
url: '/pages/ask-leave/list',
|
||||
url: '',
|
||||
},
|
||||
{
|
||||
icon: businessIcon,
|
||||
icon: 'setting-fill',
|
||||
title: '出差报备',
|
||||
url: '/pages/business/list',
|
||||
url: '',
|
||||
},
|
||||
{
|
||||
icon: overtimeIcon,
|
||||
icon: 'server-man',
|
||||
title: '加班报备',
|
||||
url: '/pages/overtime/list',
|
||||
url: '',
|
||||
},
|
||||
{
|
||||
icon: contractIcon,
|
||||
icon: 'camera',
|
||||
title: '合同管理',
|
||||
url: '/pages/contract/list',
|
||||
url: '',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
|
@ -179,14 +95,14 @@ const opList = [
|
|||
title: '天天向上',
|
||||
children: [
|
||||
{
|
||||
icon: booksIcon,
|
||||
icon: 'account',
|
||||
title: '培训课件',
|
||||
url: '/pages/train-books/index',
|
||||
url: '',
|
||||
},
|
||||
{
|
||||
icon: examinationIcon,
|
||||
icon: 'twitte',
|
||||
title: '培训考试',
|
||||
url: '/pages/examination/index',
|
||||
url: '',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
|
@ -194,7 +110,8 @@ const opList = [
|
|||
|
||||
const goPath = (url) => {
|
||||
uni.navigateTo({
|
||||
url,
|
||||
url
|
||||
})
|
||||
}
|
||||
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,20 +0,0 @@
|
|||
<template>
|
||||
<view>
|
||||
<CuNavbar></CuNavbar>
|
||||
<view class="h-60vh flex-center">
|
||||
<uv-empty :text="message" :icon="NotFoundImg"> </uv-empty>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import NotFoundImg from '@/static/images/404.svg'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { ref } from 'vue'
|
||||
const message = ref('')
|
||||
|
||||
onLoad((opt) => {
|
||||
message.value = opt.msg?.replace(/\s+/g, '');
|
||||
})
|
||||
</script>
|
||||
|
|
@ -1,269 +0,0 @@
|
|||
<template>
|
||||
<view>
|
||||
<CuNavbar title="加班申请">
|
||||
<template #right>
|
||||
<view class="text-24rpx text-white" @click="submit">提交</view>
|
||||
</template>
|
||||
</CuNavbar>
|
||||
<view class="card-shadow px-base">
|
||||
<uv-form
|
||||
labelPosition="left"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
ref="formRef"
|
||||
errorType="toast"
|
||||
labelWidth="250rpx"
|
||||
>
|
||||
<!-- <uv-form-item required label="日期" prop="date">
|
||||
<uv-input
|
||||
placeholder="请选择日期"
|
||||
readonly
|
||||
@click="openDate"
|
||||
inputAlign="right"
|
||||
:border="`none`"
|
||||
v-model="form.date"
|
||||
>
|
||||
</uv-input>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line> -->
|
||||
<uv-form-item required label="加班开始时间" prop="start_at">
|
||||
<uv-input
|
||||
placeholder="请选择加班开始时间"
|
||||
readonly
|
||||
@click="openStartDatePicker"
|
||||
inputAlign="right"
|
||||
:border="`none`"
|
||||
v-model="form.start_at"
|
||||
>
|
||||
</uv-input>
|
||||
</uv-form-item>
|
||||
<uv-form-item required label="加班时长" prop="duration">
|
||||
<uv-input
|
||||
placeholder="请输入加班时长(时)"
|
||||
type="number"
|
||||
inputAlign="right"
|
||||
border="`none`"
|
||||
v-model="form.duration"
|
||||
></uv-input>
|
||||
</uv-form-item>
|
||||
<!-- <uv-form-item required label="加班结束时间" prop="end_at">
|
||||
<uv-input
|
||||
placeholder="请选择加班结束时间"
|
||||
readonly
|
||||
@click="openEndDatePicker"
|
||||
inputAlign="right"
|
||||
:border="`none`"
|
||||
v-model="form.end_at"
|
||||
>
|
||||
</uv-input>
|
||||
</uv-form-item> -->
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item
|
||||
required
|
||||
label="加班事由"
|
||||
prop="reason"
|
||||
labelPosition="top"
|
||||
>
|
||||
<uv-textarea
|
||||
:customStyle="{ padding: '0' }"
|
||||
v-model="form.reason"
|
||||
count
|
||||
placeholder="请输入加班事由"
|
||||
:border="`none`"
|
||||
:maxlength="200"
|
||||
></uv-textarea>
|
||||
</uv-form-item>
|
||||
</uv-form>
|
||||
</view>
|
||||
<uv-datetime-picker
|
||||
placeholder="请选择日期"
|
||||
v-model="dateValue"
|
||||
ref="datePicker"
|
||||
mode="date"
|
||||
@confirm="confirmDatePicker"
|
||||
>
|
||||
</uv-datetime-picker>
|
||||
<uv-datetime-picker
|
||||
placeholder="请选择时间"
|
||||
v-model="startValue"
|
||||
ref="dateStartPicker"
|
||||
mode="datetime"
|
||||
@confirm="confirmStartDatePicker"
|
||||
>
|
||||
</uv-datetime-picker>
|
||||
<uv-datetime-picker
|
||||
v-model="endValue"
|
||||
placeholder="请选择时间"
|
||||
ref="dateEndPicker"
|
||||
mode="datetime"
|
||||
:minDate="endTime.min"
|
||||
@confirm="confirmEndDatePicker"
|
||||
>
|
||||
</uv-datetime-picker>
|
||||
<uv-modal
|
||||
ref="modalRef"
|
||||
title="提示"
|
||||
content="确定提交吗?"
|
||||
@confirm="onSubmit"
|
||||
:showCancelButton="true"
|
||||
></uv-modal>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import { ref, reactive, computed } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { http } from '@/utils/request'
|
||||
import { timeFormat } from '@climblee/uv-ui/libs/function/index'
|
||||
const columns = ref([])
|
||||
const pickerData = ref([])
|
||||
const formRef = ref(null)
|
||||
const dateStartPicker = ref(null)
|
||||
const datePicker = ref(null)
|
||||
const dateEndPicker = ref(null)
|
||||
const modalRef = ref(null)
|
||||
const startValue = ref(Number(new Date()))
|
||||
const dateValue = ref(Number(new Date()))
|
||||
const endValue = ref(Number(new Date()))
|
||||
const id = ref(0)
|
||||
const loading = ref(false)
|
||||
const form = reactive({
|
||||
start_at: '',
|
||||
end_at: '',
|
||||
reason: '',
|
||||
date: '',
|
||||
})
|
||||
const endTime = computed(() => {
|
||||
return {
|
||||
min: form.start_at ? new Date(form.start_at).getTime() : null,
|
||||
max: new Date().getTime(),
|
||||
}
|
||||
})
|
||||
const openDate = () => {
|
||||
datePicker.value.open()
|
||||
}
|
||||
const openStartDatePicker = () => {
|
||||
dateStartPicker.value.open()
|
||||
}
|
||||
const openEndDatePicker = () => {
|
||||
dateEndPicker.value.open()
|
||||
}
|
||||
const confirmDatePicker = (e) => {
|
||||
form.date = timeFormat(e.value, 'yyyy-mm-dd')
|
||||
}
|
||||
const confirmStartDatePicker = (e) => {
|
||||
form.end_at = null
|
||||
form.start_at = timeFormat(e.value, 'yyyy-mm-dd hh:MM')
|
||||
}
|
||||
const confirmEndDatePicker = (e) => {
|
||||
form.end_at = timeFormat(e.value, 'yyyy-mm-dd hh:MM')
|
||||
}
|
||||
const rules = reactive({
|
||||
start_at: [{ required: true, message: '请选择加班开始时间' }],
|
||||
duration: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入加班时长',
|
||||
},
|
||||
{
|
||||
type: 'integer',
|
||||
message: '加班时长必须为整数',
|
||||
},
|
||||
{
|
||||
type: 'integer',
|
||||
min: 1,
|
||||
message: '加班时长不能小于1小时',
|
||||
},
|
||||
],
|
||||
end_at: [
|
||||
{ required: true, message: '请选择加班结束时间' },
|
||||
{
|
||||
validator: (rule, value, callback) => {
|
||||
const startTime = new Date(form.start_at).getTime()
|
||||
const endTime = new Date(value).getTime()
|
||||
if (endTime < startTime) {
|
||||
callback(new Error('结束时间不能小于开始时间'))
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
validator: (rule, value, callback) => {
|
||||
const endTime = new Date(value).getTime()
|
||||
const startTime = new Date(form.start_at).getTime()
|
||||
const diff = endTime - startTime
|
||||
if (diff < 1000 * 60 * 60) {
|
||||
callback(new Error('加班时间不能小于1小时'))
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
reason: [{ required: true, message: '请输入加班事由' }],
|
||||
date: [{ required: true, message: '请选择日期' }],
|
||||
})
|
||||
onLoad((options) => {
|
||||
id.value = options.id
|
||||
if (id.value) {
|
||||
http
|
||||
.request({
|
||||
url: `/hr/overtimes/${options.id}`,
|
||||
method: 'GET',
|
||||
header: {
|
||||
Accept: 'application/json',
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
startValue.value = res.start_at * 1000
|
||||
endValue.value = res.end_at * 1000
|
||||
dateValue.value = res.date * 1000
|
||||
form.start_at = timeFormat(res.start_at, 'yyyy-mm-dd hh:MM')
|
||||
form.end_at = timeFormat(res.end_at, 'yyyy-mm-dd hh:MM')
|
||||
form.date = timeFormat(res.date, 'yyyy-mm-dd')
|
||||
// form.duration = res.duration
|
||||
form.duration = res.hours
|
||||
form.reason = res.reason
|
||||
form.address = res.address
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const submit = () => {
|
||||
formRef.value.validate().then((res) => {
|
||||
//判断开始时间和结束时间是否小于1小时
|
||||
modalRef.value.open()
|
||||
})
|
||||
}
|
||||
|
||||
const onSubmit = async () => {
|
||||
if (loading.value) return
|
||||
loading.value = true
|
||||
try {
|
||||
let url = id.value ? `/hr/overtimes/${id.value}` : '/hr/overtimes'
|
||||
let method = id.value ? 'PUT' : 'POST'
|
||||
await http.request({
|
||||
url: url,
|
||||
method: method,
|
||||
header: {
|
||||
Accept: 'application/json',
|
||||
},
|
||||
data: {
|
||||
start_at: form.start_at,
|
||||
// date: form.date,
|
||||
duration: form.duration,
|
||||
reason: form.reason,
|
||||
// end_at: form.end_at,
|
||||
},
|
||||
})
|
||||
uni.showToast({
|
||||
title: '提交成功',
|
||||
icon: 'none',
|
||||
})
|
||||
formRef.value.resetFields()
|
||||
uni.$emit('refresh')
|
||||
uni.navigateBack()
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -1,117 +0,0 @@
|
|||
<template>
|
||||
<view class="px-base" v-if="detail">
|
||||
<CuNavbar title="加班详情">
|
||||
<template #right>
|
||||
<uv-icon color="white" @click="open" name="more-dot-fill"></uv-icon>
|
||||
</template>
|
||||
</CuNavbar>
|
||||
<view
|
||||
class="mt-30rpx card-shadow bg-white rounded-19rpx px-base text-[#333333] text-27rpx"
|
||||
>
|
||||
<BaseData :data="detail" :colums="columns" />
|
||||
</view>
|
||||
<uv-action-sheet
|
||||
ref="pickerRef"
|
||||
:actions="actions"
|
||||
@select="confirmPicker"
|
||||
/>
|
||||
<uv-modal
|
||||
ref="modalRef"
|
||||
title="提示"
|
||||
content="确定删除吗?"
|
||||
@confirm="onSubmit"
|
||||
:showCancelButton="true"
|
||||
></uv-modal>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import { http } from '@/utils/request'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { ref } from 'vue'
|
||||
import BaseData from '../audits/base-data'
|
||||
import statusFun from "@/utils/status"
|
||||
|
||||
const modalRef = ref(null)
|
||||
const actions = ref([
|
||||
{ name: '修改', value: 'edit', disabled: false },
|
||||
{ name: '删除', value: 'delete', disabled: false },
|
||||
{ name: '审核流程', value: 'check-logs', disabled: false }
|
||||
])
|
||||
const detail = ref({})
|
||||
const pickerRef = ref(null)
|
||||
const id = ref(null)
|
||||
|
||||
const columns = [
|
||||
{ title: '审核状态', dataIndex: 'workflow_check.check_status', format: (value) => statusFun(value, 'statusExpense', 'name') },
|
||||
{ title: '申请人', dataIndex: 'employee.name' },
|
||||
|
||||
{ title: '所属门店', dataIndex: 'store.title' },
|
||||
{ title: '电话号码', dataIndex: 'employee.phone' },
|
||||
{ title: '申请时间', dataIndex: 'created_format' },
|
||||
{ title: '加班日期', dataIndex: 'date_format' },
|
||||
{ title: '开始时间', dataIndex: 'start_format' },
|
||||
{ title: '结束时间', dataIndex: 'end_format' },
|
||||
{ title: '加班时长', dataIndex: 'hours',format: (value) => value + ' 小时' },
|
||||
{ title: '加班事由', dataIndex: 'reason', labelPosition: 'top' },
|
||||
{
|
||||
title: '未通过原因',
|
||||
dataIndex: 'workflow_check.check_remarks',
|
||||
labelPosition: 'top',
|
||||
isShow: (data) => data?.workflow_check?.check_status == 4,
|
||||
},
|
||||
]
|
||||
|
||||
const open = () => {
|
||||
pickerRef.value.open()
|
||||
}
|
||||
const confirmPicker = (e) => {
|
||||
if (e.value == 'edit') {
|
||||
return uni.navigateTo({
|
||||
url: `/pages/overtime/create?id=${id.value}`,
|
||||
})
|
||||
}
|
||||
if (e.value == 'delete') {
|
||||
return modalRef.value.open()
|
||||
}
|
||||
if (e.value == 'check-logs') {
|
||||
return uni.navigateTo({
|
||||
url: `/pages/audits/log?id=${detail.value.workflow_check.id}`
|
||||
})
|
||||
}
|
||||
}
|
||||
const onSubmit = async () => {
|
||||
try {
|
||||
await http.delete(`/hr/overtimes/${id.value}`)
|
||||
uni.showToast({
|
||||
title: '删除成功',
|
||||
icon: 'none',
|
||||
})
|
||||
uni.$emit('refresh')
|
||||
uni.navigateBack()
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const init = () => {
|
||||
if (id.value) {
|
||||
http.get(`/hr/overtimes/${id.value}`).then((res) => {
|
||||
detail.value = res
|
||||
let status = res.workflow_check.check_status
|
||||
if ([2, 3].indexOf(status) != -1) {
|
||||
actions.value[0].disabled = true
|
||||
actions.value[1].disabled = true
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
onLoad((options) => {
|
||||
if (options.id) {
|
||||
id.value = options.id
|
||||
init()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
@ -1,132 +0,0 @@
|
|||
<template>
|
||||
<view>
|
||||
<CuNavbar title="加班报备">
|
||||
<template #right>
|
||||
<view @click="goPath('/pages/overtime/create')" class="text-24rpx text-white">申请</view>
|
||||
</template>
|
||||
</CuNavbar>
|
||||
<uv-sticky bgColor="#fff">
|
||||
<uv-tabs
|
||||
:activeStyle="{ color: '#ee2c37' }"
|
||||
:scrollable="false"
|
||||
lineColor="#ee2c37"
|
||||
:list="tabList"
|
||||
@change="tabChange"
|
||||
></uv-tabs>
|
||||
</uv-sticky>
|
||||
<MescrollItem
|
||||
ref="mescrollItem0"
|
||||
:top="88"
|
||||
:i="0"
|
||||
:index="tabIndex"
|
||||
:apiUrl="tabList[0].apiUrl"
|
||||
>
|
||||
<template v-slot="{ list }">
|
||||
<view class="space-y-15rpx p-base">
|
||||
<ListItem
|
||||
v-for="item in list" :key="item.id"
|
||||
title="加班报备"
|
||||
:status-text="statusFun( item.workflow_check.check_status,'statusExpense','name')"
|
||||
:status-color="statusFun( item.workflow_check.check_status,'statusExpense','color')"
|
||||
:body="[
|
||||
{ label:'加班日期: ', value: item.date_format },
|
||||
{ label:'加班时间: ', value: item.start_format + '-' + item.end_format },
|
||||
{ label:'加班事由: ', value: item.reason },
|
||||
{ label:'申请时间: ', value: item.created_format },
|
||||
]"
|
||||
@click.stop="applyDetail(item)"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
</MescrollItem>
|
||||
|
||||
<MescrollItem
|
||||
ref="mescrollItem1"
|
||||
:top="88"
|
||||
:i="1"
|
||||
:index="tabIndex"
|
||||
:apiUrl="tabList[1].apiUrl"
|
||||
:params="tabList[1].params"
|
||||
>
|
||||
<template v-slot="{ list }">
|
||||
<view class="space-y-15rpx p-base">
|
||||
<ListItem
|
||||
v-for="item in list" :key="item.id"
|
||||
title="加班报备"
|
||||
:status-text="statusFun( item.check_status,'statusExpense2','name')"
|
||||
:status-color="statusFun( item.check_status,'statusExpense2','color')"
|
||||
:body="[
|
||||
{ label:'申请人: ', value: item.check.subject.employee.name },
|
||||
{ label:'加班日期: ', value: item.check.subject.date_format },
|
||||
{ label:'加班时间: ', value: item.check.subject.start_format + '-' + item.check.subject.end_format },
|
||||
{ label:'加班事由: ', value: item.check.subject.reason },
|
||||
{ label:'申请时间: ', value: item.check.subject.created_format },
|
||||
]"
|
||||
@click.stop="checkDetail(item)"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
</MescrollItem>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import { ref } from 'vue'
|
||||
import { onPageScroll, onReachBottom, onLoad } from '@dcloudio/uni-app'
|
||||
import useMescrollMore from '@/uni_modules/mescroll-uni/hooks/useMescrollMore.js'
|
||||
import MescrollItem from '@/components/mescroll-api/more.vue'
|
||||
import statusFun from "@/utils/status"
|
||||
import ListItem from '@/components/list-item/index'
|
||||
|
||||
const tabList = ref([
|
||||
{
|
||||
name: '我的加班',
|
||||
apiUrl: '/hr/overtimes',
|
||||
},
|
||||
{
|
||||
name: '加班审核',
|
||||
apiUrl: '/workflow',
|
||||
params: {
|
||||
subject_type: 'overtime_applies',
|
||||
include: 'check.subject.employee'
|
||||
},
|
||||
},
|
||||
])
|
||||
const mescrollItem0 = ref(null)
|
||||
const mescrollItem1 = ref(null)
|
||||
|
||||
const mescrollItems = [mescrollItem0, mescrollItem1]
|
||||
const { tabIndex, getMescroll, scrollToLastY } = useMescrollMore(
|
||||
mescrollItems,
|
||||
onPageScroll,
|
||||
onReachBottom
|
||||
)
|
||||
onLoad(() => {
|
||||
uni.$on('refresh', () => {
|
||||
mescrollItem0?.value?.getMescroll()?.resetUpScroll()
|
||||
mescrollItem1?.value?.getMescroll()?.resetUpScroll()
|
||||
})
|
||||
})
|
||||
|
||||
const goPath = (url) => {
|
||||
uni.navigateTo({
|
||||
url,
|
||||
})
|
||||
}
|
||||
const tabChange = ({ index }) => {
|
||||
tabIndex.value = index
|
||||
scrollToLastY()
|
||||
}
|
||||
|
||||
const applyDetail = (item) => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/overtime/detail?id=${item.id}`
|
||||
})
|
||||
}
|
||||
|
||||
const checkDetail = (item) => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/audits/detail?id=${item.id}&type=${item.check.subject_type}`
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
|
@ -1,226 +0,0 @@
|
|||
<template>
|
||||
<view>
|
||||
<CuNavbar :isBack="isBack || false" title="数据上报"></CuNavbar>
|
||||
<uv-sticky
|
||||
customNavHeight="44px"
|
||||
:offset-top="offsetTop"
|
||||
bgColor="#fff"
|
||||
v-if="checkPermission(['admin'])"
|
||||
>
|
||||
<StoreDown isLotteryStore color="#333333" @change="storeChange" :isAll="false"></StoreDown>
|
||||
</uv-sticky>
|
||||
|
||||
<uv-form
|
||||
class="mt-30rpx"
|
||||
labelPosition="left"
|
||||
ref="formRef"
|
||||
:model="form"
|
||||
errorType="toast"
|
||||
labelWidth="130rpx"
|
||||
>
|
||||
<view class="px-base space-y-20rpx">
|
||||
<view class="card">
|
||||
<view class="pl-20rpx">
|
||||
<uv-form-item label="日期" prop="form.date" @click="showDateSelect">
|
||||
<uv-input
|
||||
disabled
|
||||
v-model="form.date"
|
||||
disabledColor="#ffffff"
|
||||
placeholder="请选择日期"
|
||||
:border="`none`"
|
||||
>
|
||||
</uv-input>
|
||||
<template v-slot:right>
|
||||
<uv-icon name="arrow-right"></uv-icon>
|
||||
</template>
|
||||
</uv-form-item>
|
||||
</view>
|
||||
</view>
|
||||
<view class="pointer-events-none">
|
||||
<view class="card" v-for="(item, i) in form.items" :key="i">
|
||||
<TitleComp :title="item.name"></TitleComp>
|
||||
<view class="mt-20rpx">
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
</view>
|
||||
<view class="pl-20rpx">
|
||||
<uv-form-item label="销售" :prop="`items.${i}.sales`">
|
||||
<uv-input
|
||||
|
||||
v-model="item.sales"
|
||||
:border="`none`"
|
||||
type="digit"
|
||||
:placeholder="``"
|
||||
></uv-input>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item label="兑奖" :prop="`items.${i}.expenditure`">
|
||||
<uv-input
|
||||
|
||||
v-model="item.expenditure"
|
||||
:border="`none`"
|
||||
type="digit"
|
||||
:placeholder="``"
|
||||
></uv-input>
|
||||
</uv-form-item>
|
||||
</view>
|
||||
</view>
|
||||
<view class="card">
|
||||
<TitleComp title="汇总情况"></TitleComp>
|
||||
<view class="mt-20rpx">
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
</view>
|
||||
<view class="pl-20rpx">
|
||||
<uv-form-item label="销售合计" prop="sales">
|
||||
<uv-input
|
||||
:border="`none`"
|
||||
type="digit"
|
||||
v-model="form.sales"
|
||||
placeholder=""
|
||||
></uv-input>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item
|
||||
:label="`${isLotteryStore ? '兑奖' : '支出'}合计`"
|
||||
prop="expenditure"
|
||||
>
|
||||
<uv-input
|
||||
type="digit"
|
||||
:border="`none`"
|
||||
v-model="form.expenditure"
|
||||
:placeholder="``"
|
||||
></uv-input>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item label="新增客户" prop="new_customers">
|
||||
<uv-input
|
||||
:border="`none`"
|
||||
v-model="form.new_customers"
|
||||
type="number"
|
||||
placeholder=""
|
||||
></uv-input>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item label="交账金额" prop="handover_amount">
|
||||
<uv-input
|
||||
:border="`none`"
|
||||
type="digit"
|
||||
v-model="form.handover_amount"
|
||||
placeholder=""
|
||||
></uv-input>
|
||||
</uv-form-item>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="card">
|
||||
<TitleComp title="时段报表照片">
|
||||
<template #right>
|
||||
<view class="text-24rpx text-gray-400"></view>
|
||||
</template>
|
||||
</TitleComp>
|
||||
<uv-form-item label="" prop="photos">
|
||||
<view>
|
||||
<uv-album
|
||||
multipleSize="200rpx"
|
||||
:urls="form.photos"
|
||||
keyName="url"
|
||||
></uv-album>
|
||||
</view>
|
||||
<!-- <view class="flex-center w-full" v-if="form.photos.length === 0">
|
||||
<uv-empty></uv-empty>
|
||||
</view> -->
|
||||
</uv-form-item>
|
||||
</view>
|
||||
</view>
|
||||
</uv-form>
|
||||
|
||||
<uv-calendars
|
||||
color="#ee2c37"
|
||||
confirmColor="#ee2c37"
|
||||
ref="calendars"
|
||||
@confirm="calendarsConfirm"
|
||||
:endDate="endDate"
|
||||
:date="form.date"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { http } from '@/utils/request'
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import TitleComp from '@/components/title-comp/index'
|
||||
import { sys } from '@climblee/uv-ui/libs/function/index'
|
||||
import StoreDown from '@/pages/home/components/store-down.vue'
|
||||
import { ref, computed, reactive } from 'vue'
|
||||
import checkPermission from '@/utils/permission'
|
||||
import { timeFormat } from '@climblee/uv-ui/libs/function/index'
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
|
||||
const props = defineProps({
|
||||
isBack: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
dete: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
})
|
||||
const endDate = timeFormat(
|
||||
props.dete ? new Date(props.dete) : new Date(),
|
||||
'yyyy-mm-dd'
|
||||
)
|
||||
const calendars = ref(null)
|
||||
const shoreInfo = ref({})
|
||||
const userStore = useUserStore()
|
||||
|
||||
const userInfo = computed(() => userStore.userInfo || {})
|
||||
const store = computed(() => userInfo.value.store)
|
||||
const isLotteryStore = computed(() => shoreInfo.value.is_lottery_store)
|
||||
|
||||
const form = reactive({
|
||||
date: endDate,
|
||||
items: [],
|
||||
new_customers: '',
|
||||
sales: '',
|
||||
expenditure: '',
|
||||
handover_amount: '',
|
||||
photos: [],
|
||||
})
|
||||
|
||||
const offsetTop = computed(() => {
|
||||
return sys().statusBarHeight
|
||||
})
|
||||
|
||||
const showDateSelect = () => {
|
||||
calendars.value.open()
|
||||
hideKeyboard()
|
||||
}
|
||||
|
||||
const calendarsConfirm = (e) => {
|
||||
form.date = e.fulldate
|
||||
getData()
|
||||
}
|
||||
const storeChange = (e) => {
|
||||
shoreInfo.value = e
|
||||
getData()
|
||||
}
|
||||
|
||||
const hideKeyboard = () => {
|
||||
uni.hideKeyboard()
|
||||
}
|
||||
|
||||
const getData = async () => {
|
||||
const resData = await http.get(`/ledgers/${form.date}`, {
|
||||
params: {
|
||||
...shoreInfo.value,
|
||||
},
|
||||
})
|
||||
|
||||
Object.assign(form, resData, {
|
||||
photos:
|
||||
resData?.photos?.map((item) => {
|
||||
return { url: item }
|
||||
}) || [],
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
|
@ -1,506 +0,0 @@
|
|||
<template>
|
||||
<view>
|
||||
<CuNavbar :isBack="isBack || false" title="数据上报"></CuNavbar>
|
||||
|
||||
<view
|
||||
:class="[
|
||||
checkPermission(['store']) && form.allow_rereport
|
||||
? ''
|
||||
: 'pointer-events-none',
|
||||
]"
|
||||
>
|
||||
<uv-form
|
||||
class="mt-30rpx"
|
||||
labelPosition="left"
|
||||
ref="formRef"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
errorType="toast"
|
||||
labelWidth="130rpx"
|
||||
>
|
||||
<view class="px-base space-y-20rpx">
|
||||
<view class="card">
|
||||
<view class="pl-20rpx">
|
||||
<uv-form-item
|
||||
label="日期"
|
||||
prop="form.date"
|
||||
@click="showDateSelect"
|
||||
>
|
||||
<uv-input
|
||||
disabled
|
||||
v-model="form.date"
|
||||
disabledColor="#ffffff"
|
||||
placeholder="请选择日期"
|
||||
:border="`none`"
|
||||
>
|
||||
</uv-input>
|
||||
<template v-slot:right>
|
||||
<uv-icon name="arrow-right"></uv-icon>
|
||||
</template>
|
||||
</uv-form-item>
|
||||
</view>
|
||||
</view>
|
||||
<view class="card" v-for="(item, i) in form.items" :key="i">
|
||||
<TitleComp :title="item.name"></TitleComp>
|
||||
<view class="mt-20rpx">
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
</view>
|
||||
<view class="pl-20rpx">
|
||||
<uv-form-item label="销售" :prop="`items.${i}.sales`">
|
||||
<uv-input
|
||||
@input="salesChange"
|
||||
v-model="item.sales"
|
||||
:border="`none`"
|
||||
type="digit"
|
||||
:placeholder="`请输入${item.name}销售金额`"
|
||||
></uv-input>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item label="兑奖" :prop="`items.${i}.expenditure`">
|
||||
<uv-input
|
||||
@input="expenditureChange"
|
||||
v-model="item.expenditure"
|
||||
:border="`none`"
|
||||
type="digit"
|
||||
:placeholder="`请输入${item.name}兑奖金额`"
|
||||
></uv-input>
|
||||
</uv-form-item>
|
||||
</view>
|
||||
</view>
|
||||
<view class="card">
|
||||
<TitleComp title="汇总情况"></TitleComp>
|
||||
<view class="mt-20rpx">
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
</view>
|
||||
<view class="pl-20rpx">
|
||||
<uv-form-item label="销售合计" prop="sales">
|
||||
<uv-input
|
||||
:border="`none`"
|
||||
type="digit"
|
||||
v-model="form.sales"
|
||||
placeholder="请输入总账销售金额"
|
||||
></uv-input>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item
|
||||
:label="`${store?.is_lottery_store ? '兑奖' : '支出'}合计`"
|
||||
prop="expenditure"
|
||||
>
|
||||
<uv-input
|
||||
type="digit"
|
||||
:border="`none`"
|
||||
v-model="form.expenditure"
|
||||
:placeholder="`请输入总账${
|
||||
store?.is_lottery_store ? '兑奖' : '支出'
|
||||
}金额`"
|
||||
></uv-input>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item label="新增客户" prop="new_customers">
|
||||
<uv-input
|
||||
:border="`none`"
|
||||
v-model="form.new_customers"
|
||||
type="number"
|
||||
placeholder="请输入微信新增人数"
|
||||
></uv-input>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item label="交账金额" prop="handover_amount">
|
||||
<uv-input
|
||||
:border="`none`"
|
||||
type="digit"
|
||||
v-model="form.handover_amount"
|
||||
placeholder="请输入交账金额"
|
||||
></uv-input>
|
||||
</uv-form-item>
|
||||
<view class="text-primary text-24rpx py-10rpx"
|
||||
>* 请确保填写的交账金额正确无误!</view
|
||||
>
|
||||
</view>
|
||||
</view>
|
||||
<view class="card">
|
||||
<TitleComp title="时段报表照片">
|
||||
<template #right>
|
||||
<view class="text-24rpx text-gray-400"
|
||||
>{{ form.photos.length }}/9</view
|
||||
>
|
||||
</template>
|
||||
</TitleComp>
|
||||
<uv-form-item label="" prop="photos">
|
||||
<view>
|
||||
<uv-upload
|
||||
width="200rpx"
|
||||
height="200rpx"
|
||||
:maxCount="9"
|
||||
multiple
|
||||
:fileList="form.photos"
|
||||
@afterRead="afterRead"
|
||||
@delete="deletePic"
|
||||
name="photos"
|
||||
></uv-upload>
|
||||
</view>
|
||||
</uv-form-item>
|
||||
<view class="text-primary text-24rpx py-10rpx">
|
||||
*竞彩时段报表照片,玩法时段报表照片,每日账本上传(需亲笔签字),销量本上传
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</uv-form>
|
||||
</view>
|
||||
<view class="h-130rpx">
|
||||
<view
|
||||
class="fixed z-10 bottom-0 left-0 right-0 h-120rpx bg-white flex-center box-border px-base"
|
||||
:style="style"
|
||||
>
|
||||
<view class="w-full">
|
||||
<uv-button
|
||||
:disabled="isRule"
|
||||
type="primary"
|
||||
shape="circle"
|
||||
block
|
||||
@click="submit"
|
||||
>
|
||||
上报
|
||||
</uv-button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<uv-calendars
|
||||
color="#ee2c37"
|
||||
confirmColor="#ee2c37"
|
||||
ref="calendars"
|
||||
@confirm="calendarsConfirm"
|
||||
:endDate="endDate"
|
||||
:date="form.date"
|
||||
/>
|
||||
|
||||
<uv-modal
|
||||
ref="modalRef"
|
||||
title="提示"
|
||||
content="确定提交?"
|
||||
@confirm="onSubmit"
|
||||
:showCancelButton="true"
|
||||
></uv-modal>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { http } from '@/utils/request'
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import TitleComp from '@/components/title-comp/index'
|
||||
import { addUnit, sys } from '@climblee/uv-ui/libs/function/index'
|
||||
import {
|
||||
computed,
|
||||
ref,
|
||||
onBeforeMount,
|
||||
reactive,
|
||||
onMounted,
|
||||
watch,
|
||||
nextTick,
|
||||
} from 'vue'
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
import { timeFormat } from '@climblee/uv-ui/libs/function/index'
|
||||
import { empty } from '@climblee/uv-ui/libs/function/test'
|
||||
import { add, sub } from '@/utils/index'
|
||||
import checkPermission from '@/utils/permission'
|
||||
import { onShow } from '@dcloudio/uni-app'
|
||||
|
||||
const props = defineProps({
|
||||
isBack: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
dete: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
})
|
||||
|
||||
const calendars = ref(null)
|
||||
const modalRef = ref(null)
|
||||
const formRef = ref(null)
|
||||
const userStore = useUserStore()
|
||||
|
||||
const userInfo = computed(() => userStore.userInfo || {})
|
||||
const store = computed(() => userInfo.value.store)
|
||||
|
||||
const endDate = timeFormat(
|
||||
props.dete ? new Date(props.dete) : new Date(),
|
||||
'yyyy-mm-dd'
|
||||
)
|
||||
const isRule = computed(() => {
|
||||
return !form.allow_rereport || !checkPermission(['store'])
|
||||
})
|
||||
|
||||
const form = reactive({
|
||||
date: endDate,
|
||||
items: [],
|
||||
new_customers: '',
|
||||
sales: '',
|
||||
expenditure: '',
|
||||
handover_amount: '',
|
||||
photos: [],
|
||||
})
|
||||
const rules = reactive({
|
||||
date: {
|
||||
required: true,
|
||||
message: '请选择日期',
|
||||
trigger: ['change'],
|
||||
},
|
||||
handover_amount: {
|
||||
required: true,
|
||||
message: '请输入交账金额',
|
||||
trigger: ['change'],
|
||||
},
|
||||
sales: {
|
||||
required: true,
|
||||
message: '请输入总账销售金额',
|
||||
},
|
||||
expenditure: {
|
||||
required: true,
|
||||
message: `请输入总账${store.value?.is_lottery_store ? '兑奖' : '支出'}金额`,
|
||||
},
|
||||
new_customers: {
|
||||
required: true,
|
||||
message: '请输入微信新增人数',
|
||||
},
|
||||
photos: {
|
||||
type: 'array',
|
||||
required: true,
|
||||
message: '请上传时段报表照片',
|
||||
},
|
||||
})
|
||||
|
||||
const style = computed(() => {
|
||||
const style = {}
|
||||
style.bottom = addUnit(sys().windowBottom, 'px')
|
||||
return style
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
// console.log(endDate);
|
||||
getData()
|
||||
})
|
||||
|
||||
const submit = () => {
|
||||
formRef.value.validate().then((res) => {
|
||||
modalRef.value.open()
|
||||
})
|
||||
}
|
||||
|
||||
function filterLotteryData(datas) {
|
||||
return datas.filter((item) => {
|
||||
if (empty(item.sales) && empty(item.expenditure)) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
function removeEmptyValues(datas) {
|
||||
return datas
|
||||
.map((item) => {
|
||||
// 过滤出空值的属性
|
||||
const filteredItem = Object.entries(item)
|
||||
.filter(([key, value]) => !empty(value))
|
||||
.reduce((acc, [key, value]) => {
|
||||
acc[key] = value
|
||||
return acc
|
||||
}, {})
|
||||
|
||||
return filteredItem
|
||||
})
|
||||
.filter((item) => Object.keys(item).length !== 0) // 移除所有属性都为空的对象
|
||||
}
|
||||
const onSubmit = async () => {
|
||||
let valid = false
|
||||
filterLotteryData(form.items).forEach((item) => {
|
||||
if (!item.sales) {
|
||||
valid = true
|
||||
return uni.showToast({
|
||||
title: `请填写${item.name}销售金额`,
|
||||
icon: 'none',
|
||||
})
|
||||
}
|
||||
|
||||
if (!item.expenditure) {
|
||||
valid = true
|
||||
return uni.showToast({
|
||||
title: `请填写${item.name}兑奖金额`,
|
||||
icon: 'none',
|
||||
})
|
||||
}
|
||||
})
|
||||
if (valid) return
|
||||
|
||||
const params = {
|
||||
date: form.date,
|
||||
sales: form.sales,
|
||||
expenditure: form.expenditure,
|
||||
handover_amount: form.handover_amount,
|
||||
new_customers: form.new_customers,
|
||||
photos: form.photos.map((item) => item.url),
|
||||
items: filterLotteryData(form.items),
|
||||
}
|
||||
http
|
||||
.request({
|
||||
url: '/ledgers',
|
||||
method: 'POST',
|
||||
header: {
|
||||
Accept: 'application/json',
|
||||
},
|
||||
data: params,
|
||||
})
|
||||
.then((res) => {
|
||||
uni.$emit('refresh')
|
||||
uni.showToast({
|
||||
title: '提交成功',
|
||||
icon: 'none',
|
||||
})
|
||||
if (props.isBack) {
|
||||
uni.navigateBack()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const getData = async () => {
|
||||
const resData = await http.get(`/ledgers/${form.date}`, {
|
||||
params: {
|
||||
store_id: store.value?.id,
|
||||
},
|
||||
})
|
||||
|
||||
Object.assign(form, resData, {
|
||||
photos:
|
||||
resData?.photos?.map((item) => {
|
||||
return { url: item }
|
||||
}) || [],
|
||||
})
|
||||
}
|
||||
|
||||
const getTypeList = () => {
|
||||
http
|
||||
.get('/keywords', {
|
||||
params: {
|
||||
parent_key: 'lottery_type',
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
form.items = res
|
||||
res.forEach((item, i) => {
|
||||
rules[`items.${i}.${'sales'}`] = {
|
||||
required: true,
|
||||
message: `请输入${item.name}销售金额`,
|
||||
}
|
||||
rules[`items.${i}.${'expenditure'}`] = {
|
||||
required: true,
|
||||
message: `请输入${item.name}兑奖金额`,
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const calendarsConfirm = (e) => {
|
||||
form.date = e.fulldate
|
||||
getData()
|
||||
}
|
||||
|
||||
const showDateSelect = () => {
|
||||
calendars.value.open()
|
||||
hideKeyboard()
|
||||
}
|
||||
|
||||
const hideKeyboard = () => {
|
||||
uni.hideKeyboard()
|
||||
}
|
||||
|
||||
const afterRead = async (event) => {
|
||||
let lists = [].concat(event.file)
|
||||
let fileListLen = form[event.name].length
|
||||
|
||||
lists.map((item) => {
|
||||
form[event.name].push({
|
||||
...item,
|
||||
status: 'uploading',
|
||||
message: '上传中',
|
||||
})
|
||||
})
|
||||
for (let i = 0; i < lists.length; i++) {
|
||||
const result = await uploadFilePromise(lists[i].url)
|
||||
let item = form[event.name][fileListLen]
|
||||
form[event.name].splice(
|
||||
fileListLen,
|
||||
1,
|
||||
Object.assign(item, {
|
||||
status: 'success',
|
||||
message: '',
|
||||
url: result,
|
||||
})
|
||||
)
|
||||
fileListLen++
|
||||
}
|
||||
}
|
||||
|
||||
const uploadFilePromise = (url) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http
|
||||
.upload('/fileupload', {
|
||||
filePath: url,
|
||||
name: 'file',
|
||||
})
|
||||
.then((res) => {
|
||||
resolve(res.url)
|
||||
})
|
||||
.catch((err) => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const deletePic = (event) => {
|
||||
form[event.name].splice(event.index, 1)
|
||||
}
|
||||
|
||||
const salesChange = async () => {
|
||||
await nextTick()
|
||||
const val = form?.items || []
|
||||
const sales = val.reduce((a, b) => {
|
||||
if (b.operator == '-') return sub(a, b?.sales ?? 0)
|
||||
else if (b.operator == '+') return add(a, b?.sales ?? 0)
|
||||
return a
|
||||
}, 0)
|
||||
|
||||
form.sales = sales || 0
|
||||
}
|
||||
|
||||
const expenditureChange = async () => {
|
||||
await nextTick()
|
||||
const val = form?.items || []
|
||||
const expenditure = val.reduce((a, b) => {
|
||||
if (b.operator == '-') return sub(a, b?.expenditure ?? 0)
|
||||
else if (b.operator == '+') return add(a, b?.expenditure ?? 0)
|
||||
return a
|
||||
}, 0)
|
||||
form.expenditure = expenditure || 0
|
||||
}
|
||||
|
||||
watch(
|
||||
() => form.items,
|
||||
(val) => {
|
||||
// const sales = val.reduce((a, b) => {
|
||||
// return add(a, b?.sales ?? 0)
|
||||
// }, 0)
|
||||
// const expenditure = val.reduce((a, b) => {
|
||||
// return add(a, b?.expenditure ?? 0)
|
||||
// }, 0)
|
||||
// form.sales = sales || null
|
||||
// form.expenditure = expenditure || null
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
deep: true,
|
||||
}
|
||||
)
|
||||
</script>
|
||||
|
|
@ -1,19 +1,396 @@
|
|||
<template>
|
||||
<view>
|
||||
<Admin v-if="checkPermission(['admin'])"></Admin>
|
||||
<Base v-else />
|
||||
<CuNavbar :isBack="isBack" title="上报"></CuNavbar>
|
||||
<view :class="[checkPermission(['store']) ? '' : 'pointer-events-none']">
|
||||
<uv-form
|
||||
class="mt-30rpx"
|
||||
labelPosition="left"
|
||||
ref="formRef"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
errorType="toast"
|
||||
labelWidth="130rpx"
|
||||
>
|
||||
<view class="px-base space-y-20rpx">
|
||||
<view class="card">
|
||||
<view class="pl-20rpx">
|
||||
<uv-form-item
|
||||
label="日期"
|
||||
prop="form.date"
|
||||
@click="showDateSelect"
|
||||
>
|
||||
<uv-input
|
||||
disabled
|
||||
v-model="form.date"
|
||||
disabledColor="#ffffff"
|
||||
placeholder="请选择日期"
|
||||
:border="`none`"
|
||||
>
|
||||
</uv-input>
|
||||
<template v-slot:right>
|
||||
<uv-icon name="arrow-right"></uv-icon>
|
||||
</template>
|
||||
</uv-form-item>
|
||||
</view>
|
||||
</view>
|
||||
<view class="card" v-for="(item, i) in form.items" :key="i">
|
||||
<TitleComp :title="item.name"></TitleComp>
|
||||
<view class="mt-20rpx">
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
</view>
|
||||
<view class="pl-20rpx">
|
||||
<uv-form-item label="销售" :prop="`items.${i}.sales`">
|
||||
<uv-input
|
||||
@input="salesChange"
|
||||
v-model="item.sales"
|
||||
:border="`none`"
|
||||
type="digit"
|
||||
:placeholder="`请输入${item.name}销售金额`"
|
||||
></uv-input>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item label="兑奖" :prop="`items.${i}.expenditure`">
|
||||
<uv-input
|
||||
@input="expenditureChange"
|
||||
v-model="item.expenditure"
|
||||
:border="`none`"
|
||||
type="digit"
|
||||
:placeholder="`请输入${item.name}兑奖金额`"
|
||||
></uv-input>
|
||||
</uv-form-item>
|
||||
</view>
|
||||
</view>
|
||||
<view class="card">
|
||||
<TitleComp title="汇总情况"></TitleComp>
|
||||
<view class="mt-20rpx">
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
</view>
|
||||
<view class="pl-20rpx">
|
||||
<uv-form-item label="销售合计" prop="sales">
|
||||
<uv-input
|
||||
:border="`none`"
|
||||
type="digit"
|
||||
v-model="form.sales"
|
||||
placeholder="请输入总账销售金额"
|
||||
></uv-input>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item label="兑奖合计" prop="expenditure">
|
||||
<uv-input
|
||||
type="digit"
|
||||
:border="`none`"
|
||||
v-model="form.expenditure"
|
||||
placeholder="请输入电总账兑奖金额"
|
||||
></uv-input>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item label="新增客户" prop="new_customers">
|
||||
<uv-input
|
||||
:border="`none`"
|
||||
v-model="form.new_customers"
|
||||
type="number"
|
||||
placeholder="请输入微信新增人数"
|
||||
></uv-input>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item label="交账金额" prop="handover_amount">
|
||||
<uv-input
|
||||
:border="`none`"
|
||||
type="digit"
|
||||
v-model="form.handover_amount"
|
||||
placeholder="请输入交账金额"
|
||||
></uv-input>
|
||||
</uv-form-item>
|
||||
<view class="text-primary text-24rpx py-10rpx"
|
||||
>* 请确保填写的交账金额正确无误!</view
|
||||
>
|
||||
</view>
|
||||
</view>
|
||||
<view class="card">
|
||||
<TitleComp title="时段报表照片">
|
||||
<template #right>
|
||||
<view class="text-24rpx text-gray-400"
|
||||
>{{ form.photos.length }}/9</view
|
||||
>
|
||||
</template>
|
||||
</TitleComp>
|
||||
<uv-form-item label="" prop="photos">
|
||||
<view>
|
||||
<uv-upload
|
||||
width="200rpx"
|
||||
height="200rpx"
|
||||
:maxCount="9"
|
||||
multiple
|
||||
:fileList="form.photos"
|
||||
@afterRead="afterRead"
|
||||
@delete="deletePic"
|
||||
name="photos"
|
||||
></uv-upload>
|
||||
</view>
|
||||
</uv-form-item>
|
||||
<view class="text-primary text-24rpx py-10rpx">
|
||||
*竞彩时段报表照片,玩法时段报表照片,每日账本上传(需亲笔签字),销量本上传
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</uv-form>
|
||||
</view>
|
||||
<view class="h-130rpx">
|
||||
<view
|
||||
class="fixed bottom-0 left-0 right-0 h-120rpx bg-white flex-center box-border px-base"
|
||||
:style="style"
|
||||
>
|
||||
<view class="w-full">
|
||||
<uv-button type="primary" shape="circle" block @click="submit">
|
||||
上报
|
||||
</uv-button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<uv-calendars
|
||||
color="#ee2c37"
|
||||
confirmColor="#ee2c37"
|
||||
ref="calendars"
|
||||
@confirm="calendarsConfirm"
|
||||
:endDate="endDate"
|
||||
:date="form.date"
|
||||
/>
|
||||
|
||||
<uv-modal
|
||||
ref="modalRef"
|
||||
title="提示"
|
||||
content="确定提交?"
|
||||
@confirm="onSubmit"
|
||||
:showCancelButton="true"
|
||||
></uv-modal>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import checkPermission from '@/utils/permission'
|
||||
import Base from './base.vue'
|
||||
import Admin from './admin.vue'
|
||||
import { http } from '@/utils/request'
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import TitleComp from '@/components/title-comp/index'
|
||||
import { addUnit, sys } from '@climblee/uv-ui/libs/function/index'
|
||||
import { computed, ref, onBeforeMount, reactive, onMounted, watch } from 'vue'
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
import { ref, computed } from 'vue'
|
||||
import { timeFormat } from '@climblee/uv-ui/libs/function/index'
|
||||
import { add } from '@/utils/index'
|
||||
import checkPermission from '@/utils/permission'
|
||||
import { onShow } from '@dcloudio/uni-app'
|
||||
const calendars = ref(null)
|
||||
const modalRef = ref(null)
|
||||
const formRef = ref(null)
|
||||
const userStore = useUserStore()
|
||||
|
||||
const rules = computed(() => {
|
||||
return userStore.roles
|
||||
const userInfo = computed(() => userStore.userInfo || {})
|
||||
const store = computed(() => userInfo.value.store)
|
||||
const endDate = timeFormat(new Date(), 'yyyy-mm-dd')
|
||||
|
||||
const form = reactive({
|
||||
date: endDate,
|
||||
items: [],
|
||||
new_customers: '',
|
||||
sales: '',
|
||||
expenditure: '',
|
||||
handover_amount: '',
|
||||
photos: [],
|
||||
})
|
||||
const rules = reactive({
|
||||
date: {
|
||||
required: true,
|
||||
message: '请选择日期',
|
||||
trigger: ['change'],
|
||||
},
|
||||
handover_amount: {
|
||||
required: true,
|
||||
message: '请输入交账金额',
|
||||
trigger: ['change'],
|
||||
},
|
||||
photos: {
|
||||
type: 'array',
|
||||
required: true,
|
||||
message: '请上传时段报表照片',
|
||||
},
|
||||
})
|
||||
|
||||
const props = defineProps({
|
||||
isBack: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
})
|
||||
const style = computed(() => {
|
||||
const style = {}
|
||||
style.bottom = addUnit(sys().windowBottom, 'px')
|
||||
return style
|
||||
})
|
||||
|
||||
onShow(() => {
|
||||
getData(endDate)
|
||||
})
|
||||
|
||||
const submit = () => {
|
||||
formRef.value.validate().then((res) => {
|
||||
modalRef.value.open()
|
||||
})
|
||||
}
|
||||
|
||||
const onSubmit = async () => {
|
||||
const params = {
|
||||
date: form.date,
|
||||
sales: form.sales,
|
||||
expenditure: form.expenditure,
|
||||
handover_amount: form.handover_amount,
|
||||
new_customers: form.new_customers,
|
||||
photos: form.photos.map((item) => item.url),
|
||||
items: form.items,
|
||||
}
|
||||
http
|
||||
.request({
|
||||
url: '/ledgers',
|
||||
method: 'POST',
|
||||
header: {
|
||||
'Accept': 'application/json',
|
||||
},
|
||||
data: params,
|
||||
})
|
||||
.then((res) => {
|
||||
uni.$emit('revert:submit', res)
|
||||
uni.showToast({
|
||||
title: '提交成功',
|
||||
duration: 2000,
|
||||
icon: 'none',
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const getData = async () => {
|
||||
const resData = await http.get(`/ledgers/${form.date}`)
|
||||
|
||||
Object.assign(form, resData, {
|
||||
photos:
|
||||
resData?.photos?.map((item) => {
|
||||
return { url: item }
|
||||
}) || [],
|
||||
})
|
||||
}
|
||||
|
||||
const getTypeList = () => {
|
||||
http
|
||||
.get('/keywords', {
|
||||
params: {
|
||||
parent_key: 'lottery_type',
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
form.items = res
|
||||
res.forEach((item, i) => {
|
||||
rules[`items.${i}.${'sales'}`] = {
|
||||
required: true,
|
||||
message: `请输入${item.name}销售金额`,
|
||||
}
|
||||
rules[`items.${i}.${'expenditure'}`] = {
|
||||
required: true,
|
||||
message: `请输入${item.name}兑奖金额`,
|
||||
}
|
||||
})
|
||||
console.log(rules)
|
||||
})
|
||||
}
|
||||
|
||||
const calendarsConfirm = (e) => {
|
||||
form.date = e.fulldate
|
||||
getData()
|
||||
}
|
||||
|
||||
const showDateSelect = () => {
|
||||
calendars.value.open()
|
||||
hideKeyboard()
|
||||
}
|
||||
|
||||
const hideKeyboard = () => {
|
||||
uni.hideKeyboard()
|
||||
}
|
||||
|
||||
const afterRead = async (event) => {
|
||||
let lists = [].concat(event.file)
|
||||
let fileListLen = form[event.name].length
|
||||
|
||||
lists.map((item) => {
|
||||
form[event.name].push({
|
||||
...item,
|
||||
status: 'uploading',
|
||||
message: '上传中',
|
||||
})
|
||||
})
|
||||
for (let i = 0; i < lists.length; i++) {
|
||||
const result = await uploadFilePromise(lists[i].url)
|
||||
let item = form[event.name][fileListLen]
|
||||
form[event.name].splice(
|
||||
fileListLen,
|
||||
1,
|
||||
Object.assign(item, {
|
||||
status: 'success',
|
||||
message: '',
|
||||
url: result,
|
||||
})
|
||||
)
|
||||
fileListLen++
|
||||
}
|
||||
}
|
||||
|
||||
const uploadFilePromise = (url) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http
|
||||
.upload('/fileupload', {
|
||||
filePath: url,
|
||||
name: 'file',
|
||||
})
|
||||
.then((res) => {
|
||||
resolve(res.url)
|
||||
})
|
||||
.catch((err) => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const deletePic = (event) => {
|
||||
form[event.name].splice(event.index, 1)
|
||||
}
|
||||
|
||||
const salesChange = () => {
|
||||
const val = form?.items || []
|
||||
const sales = val.reduce((a, b) => {
|
||||
return add(a, b?.sales ?? 0)
|
||||
}, 0)
|
||||
form.sales = sales || null
|
||||
}
|
||||
|
||||
const expenditureChange = () => {
|
||||
const val = form?.items || []
|
||||
const expenditure = val.reduce((a, b) => {
|
||||
return add(a, b?.expenditure ?? 0)
|
||||
}, 0)
|
||||
form.expenditure = expenditure || null
|
||||
}
|
||||
|
||||
watch(
|
||||
() => form.items,
|
||||
(val) => {
|
||||
const sales = val.reduce((a, b) => {
|
||||
return add(a, b?.sales ?? 0)
|
||||
}, 0)
|
||||
const expenditure = val.reduce((a, b) => {
|
||||
return add(a, b?.expenditure ?? 0)
|
||||
}, 0)
|
||||
// form.sales = sales || null
|
||||
// form.expenditure = expenditure || null
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
deep: true,
|
||||
}
|
||||
)
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
<uv-form-item label="投诉内容" prop="content">
|
||||
<uv-textarea
|
||||
maxlength="200"
|
||||
:customStyle="{ padding: 0, minHeight: '200rpx' }"
|
||||
:customStyle="{ padding: 0 ,minHeight: '200rpx'}"
|
||||
count
|
||||
placeholder="可描述具体投诉内容,至少20字"
|
||||
:border="`none`"
|
||||
|
|
@ -23,15 +23,12 @@
|
|||
>
|
||||
</uv-textarea>
|
||||
</uv-form-item>
|
||||
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item label="" prop="photos">
|
||||
<view class="w-full">
|
||||
<view class="flex justify-between text-15px">
|
||||
<view>证明材料(选填)</view>
|
||||
<view class="text-hex-999999 text-12px pr-9px"
|
||||
>{{ form.photos.length }}/9</view
|
||||
>
|
||||
<view class="text-hex-999999 text-12px pr-9px">{{form.photos.length}}/9</view>
|
||||
</view>
|
||||
<view class="mt-10rpx">
|
||||
<uv-upload
|
||||
|
|
@ -45,12 +42,6 @@
|
|||
</view>
|
||||
</view>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item labelPosition="left" label="匿名" prop="anonymous">
|
||||
<view class="flex justify-end w-full">
|
||||
<uv-switch v-model="form.anonymous"></uv-switch>
|
||||
</view>
|
||||
</uv-form-item>
|
||||
</uv-form>
|
||||
</view>
|
||||
</view>
|
||||
|
|
@ -74,10 +65,10 @@ import { ref, reactive } from 'vue'
|
|||
import { http } from '@/utils/request'
|
||||
const modalRef = ref(null)
|
||||
const formRef = ref(null)
|
||||
const fileList = ref([])
|
||||
const form = reactive({
|
||||
content: '',
|
||||
photos: [],
|
||||
anonymous: false,
|
||||
})
|
||||
const rules = reactive({
|
||||
content: [
|
||||
|
|
@ -105,29 +96,19 @@ const afterRead = async (event) => {
|
|||
})
|
||||
})
|
||||
for (let i = 0; i < lists.length; i++) {
|
||||
// console.log(lists[i]);
|
||||
const result = await uploadFilePromise(lists[i].url)
|
||||
let item = form[event.name][fileListLen]
|
||||
try {
|
||||
const result = await uploadFilePromise(lists[i].url)
|
||||
|
||||
form[event.name].splice(
|
||||
fileListLen,
|
||||
1,
|
||||
Object.assign(item, {
|
||||
status: 'success',
|
||||
message: '',
|
||||
url: result,
|
||||
})
|
||||
)
|
||||
fileListLen++
|
||||
} catch (error) {
|
||||
form[event.name].splice(
|
||||
fileListLen,
|
||||
1,
|
||||
Object.assign(item, {
|
||||
status: 'failed',
|
||||
})
|
||||
)
|
||||
}
|
||||
form[event.name].splice(
|
||||
fileListLen,
|
||||
1,
|
||||
Object.assign(item, {
|
||||
status: 'success',
|
||||
message: '',
|
||||
url: result,
|
||||
})
|
||||
)
|
||||
fileListLen++
|
||||
}
|
||||
}
|
||||
const deletePic = (event) => {
|
||||
|
|
@ -155,7 +136,7 @@ const onSubmit = () => {
|
|||
.post('/complaints', {
|
||||
content: form.content,
|
||||
photos: form.photos.map((item) => item.url),
|
||||
anonymous: form.anonymous,
|
||||
anonymous: true
|
||||
})
|
||||
.then((ress) => {
|
||||
uni.showToast({
|
||||
|
|
@ -163,7 +144,6 @@ const onSubmit = () => {
|
|||
duration: 2000,
|
||||
icon: 'none',
|
||||
})
|
||||
form.photos = []
|
||||
formRef.value.resetFields()
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,79 +3,33 @@
|
|||
<CuNavbar title="设置"></CuNavbar>
|
||||
<view class="space-y-base mt-base">
|
||||
<view class="card-shadow bg-white rounded-19rpx">
|
||||
<Cell
|
||||
title="修改密码"
|
||||
:shadow="false"
|
||||
@onClick="goPath('/pages/setting/password')"
|
||||
></Cell>
|
||||
<Cell title="修改密码" :shadow="false" @onClick="goPath('/pages/setting/password')"></Cell>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<Cell
|
||||
title="举报投诉"
|
||||
:shadow="false"
|
||||
@click="goPath('/pages/setting/complain')"
|
||||
></Cell>
|
||||
<Cell title="举报投诉" :shadow="false" @click="goPath('/pages/setting/complain')"></Cell>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<Cell
|
||||
title="意见箱"
|
||||
:shadow="false"
|
||||
@click="goPath('/pages/setting/suggestion')"
|
||||
></Cell>
|
||||
<Cell title="意见箱" :shadow="false" @click="goPath('/pages/setting/suggestion')"></Cell>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
</view>
|
||||
<view>
|
||||
<Cell @click="onCheckUpdate" title="当前版本" :isLink="false">
|
||||
<Cell title="当前版本" :isLink="false">
|
||||
<view class="flex justify-end text-hex-999999 text-24rpx px-base">
|
||||
v{{ varsion }}
|
||||
v1.0.0
|
||||
</view>
|
||||
</Cell>
|
||||
</view>
|
||||
</view>
|
||||
<view class="mt-100rpx">
|
||||
<uv-button @click="confirmLogout" block type="primary"
|
||||
>退出登录</uv-button
|
||||
>
|
||||
<uv-button block type="primary">退出登录</uv-button>
|
||||
</view>
|
||||
|
||||
<uv-modal
|
||||
ref="modalRef"
|
||||
title="提示"
|
||||
content="确定退出?"
|
||||
:showCancelButton="true"
|
||||
@confirm="logout"
|
||||
></uv-modal>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import Cell from '@/components/cell/index'
|
||||
import { sys } from '@climblee/uv-ui/libs/function'
|
||||
import { computed } from 'vue'
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
import checkUpdate from '@/pages/upgrade/check-update'
|
||||
const modalRef = ref(null)
|
||||
const userStore = useUserStore()
|
||||
|
||||
// const sysInfo = sys()
|
||||
const varsion = computed(() => import.meta.env.VITE_APP_VERSION)
|
||||
const goPath = (url) => {
|
||||
uni.navigateTo({
|
||||
url,
|
||||
url
|
||||
})
|
||||
}
|
||||
|
||||
const confirmLogout = () => {
|
||||
modalRef.value.open()
|
||||
}
|
||||
|
||||
const logout = () => {
|
||||
userStore.logout()
|
||||
uni.reLaunch({
|
||||
url: '/pages/login/index',
|
||||
})
|
||||
}
|
||||
|
||||
const onCheckUpdate = () => {
|
||||
checkUpdate()
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -21,20 +21,18 @@
|
|||
border="none"
|
||||
input-align="right"
|
||||
type="password"
|
||||
maxlength="15"
|
||||
v-model="form.password"
|
||||
placeholder="请输入密码"
|
||||
placeholder="请输入新登录密码"
|
||||
></uv-input>
|
||||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item label="确认密码" prop="password2">
|
||||
<uv-form-item label="新登录密码" prop="password2">
|
||||
<uv-input
|
||||
border="none"
|
||||
v-model="form.password2"
|
||||
maxlength="15"
|
||||
input-align="right"
|
||||
type="password"
|
||||
placeholder="请输入密码"
|
||||
placeholder="请输入新登录密码"
|
||||
></uv-input>
|
||||
</uv-form-item>
|
||||
</uv-form>
|
||||
|
|
@ -64,21 +62,9 @@ const form = reactive({
|
|||
password2: '',
|
||||
})
|
||||
const rules = reactive({
|
||||
password: [
|
||||
{ required: true, message: '请输入新登录密码' },
|
||||
{
|
||||
min: 6,
|
||||
message: '密码不能少于6位字符',
|
||||
},
|
||||
{
|
||||
validator: (rule, value) => {
|
||||
return /^[^\u4e00-\u9fa5]{0,}$/.test(value)
|
||||
},
|
||||
message: '密码不能包含中文',
|
||||
},
|
||||
],
|
||||
password: [{ required: true, message: '请输入新登录密码' }],
|
||||
password2: [
|
||||
{ required: true, message: '请再次输入新登录密码' },
|
||||
{ required: true, message: '请输入新登录密码' },
|
||||
{
|
||||
validator: (rule, value) => {
|
||||
return value === form.password
|
||||
|
|
|
|||
|
|
@ -1,159 +0,0 @@
|
|||
<template>
|
||||
<view class="relative">
|
||||
<uv-scroll-list
|
||||
:indicator="true"
|
||||
indicatorColor="#fff0f0"
|
||||
indicatorActiveColor="#f56c6c"
|
||||
>
|
||||
<view>
|
||||
<template v-for="(item, i) in list" :key="i">
|
||||
<view v-if="i == 0" class="flex items-center w-full text-24rpx">
|
||||
<view
|
||||
class="w-140rpx text-center flex-none h-120rpx flex-center td"
|
||||
>
|
||||
<!-- 日期 -->
|
||||
</view>
|
||||
|
||||
<view class="w-400rpx text-center leading-60rpx flex-none">
|
||||
<view class="h-60rpx td">总账</view>
|
||||
<template v-if="checkPermission(['admin'])">
|
||||
<view class="h-60rpx grid grid-cols-3">
|
||||
<view class="td">销售</view>
|
||||
<view class="td">支出</view>
|
||||
<view class="td">新增客户</view>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else-if="isLotteryStore">
|
||||
<view class="h-60rpx grid grid-cols-3">
|
||||
<view class="td">销售</view>
|
||||
<view class="td">兑奖</view>
|
||||
<view class="td">新增客户</view>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view class="h-60rpx grid grid-cols-3">
|
||||
<view class="td">销售</view>
|
||||
<view class="td">支出</view>
|
||||
<view class="td">新增客户</view>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
<view
|
||||
class="text-center leading-60rpx w-200rpx flex-none"
|
||||
v-for="(ty, j) in item.lottery_types"
|
||||
:key="j"
|
||||
>
|
||||
<view class="td">{{ ty.name }}</view>
|
||||
<view class="grid grid-cols-2">
|
||||
<view class="td">销售</view>
|
||||
<view class="td">兑奖</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view
|
||||
class="flex justify-between text-center text-24rpx items-center card-shadow bg-white rounded-19rpx"
|
||||
>
|
||||
<view class="flex-1 w-140rpx flex-none td flex-center h-60rpx">
|
||||
<!-- {{ timeFormat(item.date, 'mm-dd') }} -->
|
||||
</view>
|
||||
|
||||
<!-- 总账 -->
|
||||
<view class="w-400rpx flex flex-none">
|
||||
<template v-if="checkPermission(['admin'])">
|
||||
<view class="flex-1 td h-60rpx flex-center">{{
|
||||
item.ledger.sales
|
||||
}}</view>
|
||||
<view class="flex-1 td h-60rpx flex-center">{{
|
||||
item.ledger.expenditure
|
||||
}}</view>
|
||||
<view class="flex-1 td h-60rpx flex-center">{{
|
||||
item.ledger.new_customers
|
||||
}}</view>
|
||||
</template>
|
||||
<template v-else-if="isLotteryStore">
|
||||
<view class="flex-1 td h-60rpx flex-center">{{
|
||||
item.ledger.sales
|
||||
}}</view>
|
||||
<view class="flex-1 td h-60rpx flex-center">{{
|
||||
item.ledger.expenditure
|
||||
}}</view>
|
||||
<view class="flex-1 td h-60rpx flex-center">{{
|
||||
item.ledger.new_customers
|
||||
}}</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view class="flex-1 td h-60rpx flex-center">{{
|
||||
item.ledger.sales
|
||||
}}</view>
|
||||
<view class="flex-1 td h-60rpx flex-center">{{
|
||||
item.ledger.expenditure
|
||||
}}</view>
|
||||
<view class="flex-1 td h-60rpx flex-center">{{
|
||||
item.ledger.new_customers
|
||||
}}</view>
|
||||
</template>
|
||||
</view>
|
||||
|
||||
<!-- 种类 -->
|
||||
<template v-for="(ty, j) in item.lottery_types" :key="j">
|
||||
<view class="flex-1 td h-60rpx flex-center">{{ ty.sales }}</view>
|
||||
<view class="flex-1 td h-60rpx flex-center">{{
|
||||
ty.expenditure
|
||||
}}</view>
|
||||
</template>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</uv-scroll-list>
|
||||
<view>
|
||||
<view class="absolute left-0 right-0 top-0 bottom-0 pointer-events-none">
|
||||
<template v-for="(item, i) in list" :key="i">
|
||||
<view v-if="i == 0" class="flex items-center w-full text-24rpx">
|
||||
<view
|
||||
class="w-140rpx text-center flex-none h-120rpx flex-center td bg-white"
|
||||
>
|
||||
日期
|
||||
</view>
|
||||
</view>
|
||||
<view
|
||||
class="flex justify-between text-center text-24rpx items-center rounded-19rpx"
|
||||
>
|
||||
<view
|
||||
class="flex-1 w-140rpx flex-none td flex-center h-60rpx bg-white"
|
||||
>{{ timeFormat(item.date, 'mm-dd') }}</view
|
||||
>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
<view class="h-90vh"></view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import checkPermission from '@/utils/permission'
|
||||
import { timeFormat } from '@climblee/uv-ui/libs/function'
|
||||
import { computed } from 'vue'
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
const userStore = useUserStore()
|
||||
|
||||
const isLotteryStore = computed(
|
||||
() => userStore.userInfo?.store?.is_lottery_store
|
||||
)
|
||||
|
||||
const props = defineProps({
|
||||
list: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.tr {
|
||||
border: 0.5px solid #f5f5f5;
|
||||
}
|
||||
.td {
|
||||
border: 0.5px solid #f5f5f5;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,158 +0,0 @@
|
|||
<template>
|
||||
<view>
|
||||
<scroll-view :style="{ height: `${height}px` }" class="cu-scroll-view" scroll-x scroll-y>
|
||||
<view class="">
|
||||
<view class="sticky top-0 bg-white z-11">
|
||||
<template v-for="(item, i) in list" :key="i">
|
||||
<view v-if="i == 0" class="flex items-center w-full text-24rpx">
|
||||
<view
|
||||
class="w-140rpx sticky z-11 bg-white left-0 text-center flex-none h-120rpx flex-center td"
|
||||
>
|
||||
日期
|
||||
</view>
|
||||
|
||||
<view class="w-400rpx text-center leading-60rpx flex-none" :class="[isMore?'w-400rpx':'w-568rpx']">
|
||||
<view class="h-60rpx td">总账</view>
|
||||
<template v-if="checkPermission(['admin'])">
|
||||
<view class="h-60rpx grid grid-cols-3">
|
||||
<view class="td">销售</view>
|
||||
<view class="td">兑奖</view>
|
||||
<view class="td">新增客户</view>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else-if="isLotteryStore">
|
||||
<view class="h-60rpx grid grid-cols-3">
|
||||
<view class="td">销售</view>
|
||||
<view class="td">兑奖</view>
|
||||
<view class="td">新增客户</view>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view class="h-60rpx grid grid-cols-3">
|
||||
<view class="td">销售</view>
|
||||
<view class="td">支出</view>
|
||||
<view class="td">新增客户</view>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
<template v-if="checkPermission(['admin']) || isLotteryStore">
|
||||
<view
|
||||
class="text-center leading-60rpx w-200rpx flex-none"
|
||||
v-for="(ty, j) in item.lottery_types"
|
||||
:key="j"
|
||||
>
|
||||
<view class="td">{{ ty.name }}</view>
|
||||
<view class="grid grid-cols-2">
|
||||
<view class="td">销售</view>
|
||||
<view class="td">兑奖</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
|
||||
<view class="">
|
||||
<template v-for="(item, i) in list" :key="i">
|
||||
<view
|
||||
class="flex justify-between text-center text-24rpx items-center card-shadow bg-white rounded-19rpx"
|
||||
>
|
||||
<view
|
||||
class="flex-1 w-140rpx flex-none td flex-center h-60rpx sticky left-0 bg-white"
|
||||
>
|
||||
{{ timeFormat(item.date, 'mm-dd') }}
|
||||
</view>
|
||||
|
||||
<!-- 总账 -->
|
||||
<view class="w-400rpx flex flex-none" :class="[isMore?'w-400rpx':'w-568rpx']">
|
||||
<template v-if="checkPermission(['admin'])">
|
||||
<view class="flex-1 td h-60rpx flex-center">{{
|
||||
item.ledger.sales
|
||||
}}</view>
|
||||
<view class="flex-1 td h-60rpx flex-center">{{
|
||||
item.ledger.expenditure
|
||||
}}</view>
|
||||
<view class="flex-1 td h-60rpx flex-center">{{
|
||||
item.ledger.new_customers
|
||||
}}</view>
|
||||
</template>
|
||||
<template v-else-if="isLotteryStore">
|
||||
<view class="flex-1 td h-60rpx flex-center">{{
|
||||
item.ledger.sales
|
||||
}}</view>
|
||||
<view class="flex-1 td h-60rpx flex-center">{{
|
||||
item.ledger.expenditure
|
||||
}}</view>
|
||||
<view class="flex-1 td h-60rpx flex-center">{{
|
||||
item.ledger.new_customers
|
||||
}}</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view class="flex-1 td h-60rpx flex-center">{{
|
||||
item.ledger.sales
|
||||
}}</view>
|
||||
<view class="flex-1 td h-60rpx flex-center">{{
|
||||
item.ledger.expenditure
|
||||
}}</view>
|
||||
<view class="flex-1 td h-60rpx flex-center">{{
|
||||
item.ledger.new_customers
|
||||
}}</view>
|
||||
</template>
|
||||
</view>
|
||||
|
||||
<!-- 种类 -->
|
||||
<template v-if="checkPermission(['admin']) || isLotteryStore">
|
||||
<template v-for="(ty, j) in item.lottery_types" :key="j">
|
||||
<view class="w-200rpx flex flex-none">
|
||||
<view class="flex-1 td h-60rpx flex-center">{{
|
||||
ty.sales
|
||||
}}</view>
|
||||
<view class="flex-1 td h-60rpx flex-center">{{
|
||||
ty.expenditure
|
||||
}}</view>
|
||||
</view>
|
||||
</template>
|
||||
</template>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import checkPermission from '@/utils/permission'
|
||||
import { timeFormat } from '@climblee/uv-ui/libs/function'
|
||||
import { computed } from 'vue'
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
const userStore = useUserStore()
|
||||
|
||||
const isLotteryStore = computed(
|
||||
() => userStore.userInfo?.store?.is_lottery_store
|
||||
)
|
||||
|
||||
const isMore = computed(()=>{
|
||||
return checkPermission(['admin']) || isLotteryStore.value
|
||||
})
|
||||
|
||||
const props = defineProps({
|
||||
list: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
height:{
|
||||
type:Number,
|
||||
default:0
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.tr {
|
||||
border: 0.5px solid #f5f5f5;
|
||||
}
|
||||
.td {
|
||||
border: 0.5px solid #f5f5f5;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
<template>
|
||||
<view>
|
||||
<view
|
||||
class="flex justify-between text-center text-28rpx items-center h-80rpx"
|
||||
>
|
||||
<view class="flex-1">排名</view>
|
||||
<view class="flex-1">门店</view>
|
||||
<view class="flex-1" v-if="checkPermission(['admin'])">累计客户</view>
|
||||
<view class="flex-1" v-if="checkPermission(['admin'])">销售额</view>
|
||||
</view>
|
||||
<view
|
||||
class="flex justify-between text-center text-24rpx items-center bg-white rounded-19rpx h-80rpx"
|
||||
v-for="(item, i) in list"
|
||||
:key="i"
|
||||
>
|
||||
<view class="flex-1">
|
||||
<view v-if="i < 3">
|
||||
<image
|
||||
class="w-40rpx h-40rpx"
|
||||
:src="`/static/images/${i + 1}.jpg`"
|
||||
></image>
|
||||
</view>
|
||||
<view v-else> {{ item.ranking }}</view>
|
||||
</view>
|
||||
<view class="flex-1">{{ item.store.title }}</view>
|
||||
<view class="flex-1" v-if="checkPermission(['admin'])">{{
|
||||
item.new_customers
|
||||
}}</view>
|
||||
<view class="flex-1" v-if="checkPermission(['admin'])">{{
|
||||
item.sales
|
||||
}}</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import checkPermission from '@/utils/permission'
|
||||
import { timeFormat } from '@climblee/uv-ui/libs/function'
|
||||
const props = defineProps({
|
||||
list: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
|
@ -1,334 +0,0 @@
|
|||
<template>
|
||||
<view>
|
||||
<CuNavbar :isBack="false" title="数据报表"></CuNavbar>
|
||||
<uv-sticky
|
||||
customNavHeight="44px"
|
||||
:offset-top="offsetTop"
|
||||
bgColor="#fff"
|
||||
v-if="checkPermission(['admin'])"
|
||||
>
|
||||
<StoreDown color="#333333" @change="storeChange"></StoreDown>
|
||||
</uv-sticky>
|
||||
|
||||
<view class="card">
|
||||
<view class="headBox">
|
||||
<uv-tabs
|
||||
:lineColor="'#ee2c37'"
|
||||
:list="tabsList"
|
||||
:scrollable="false"
|
||||
:current="tabIndex"
|
||||
keyName="label"
|
||||
@change="tabChange"
|
||||
></uv-tabs>
|
||||
|
||||
<view class="text-center text-28rpx py-4rpx" v-if="tabIndex != 0"
|
||||
>{{ currentC.start }} 至 {{ currentC.end }}
|
||||
</view>
|
||||
<view class="text-center text-28rpx" v-else>{{ currentC.start }}</view>
|
||||
|
||||
<view class="flex my-20rpx items-center table">
|
||||
<view class="text-center flex-1 tr">
|
||||
<view class="flex-center h-80rpx">销售金额</view>
|
||||
<view class="font-600 flex-center h-80rpx">{{ ledger.sales }}</view>
|
||||
</view>
|
||||
|
||||
<view class="text-center flex-1 tr">
|
||||
<view
|
||||
class="flex-center h-80rpx"
|
||||
v-if="isLotteryStore || checkPermission(['admin'])"
|
||||
>
|
||||
<view>兑奖金额</view>
|
||||
</view>
|
||||
<view class="flex-center h-80rpx" v-else>支出金额</view>
|
||||
<view class="font-600 flex-center h-80rpx">{{
|
||||
ledger.expenditure
|
||||
}}</view>
|
||||
</view>
|
||||
|
||||
<view class="text-center flex-1 tr">
|
||||
<view class="flex-center h-80rpx">销售涨幅</view>
|
||||
<view
|
||||
class="font-600 flex-center h-80rpx"
|
||||
:class="[
|
||||
ledger.sales_growth_rate > 0 ? 'text-primary' : 'text-green',
|
||||
]"
|
||||
>{{ ledger.sales_growth_rate }}%</view
|
||||
>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<uv-tabs
|
||||
@change="tabChange1"
|
||||
:lineColor="'#ee2c37'"
|
||||
:list="[{ name: '销售统计' }, { name: '门店统计' }]"
|
||||
:scrollable="false"
|
||||
:current="tabIndex1"
|
||||
></uv-tabs>
|
||||
</view>
|
||||
<template v-if="tabIndex1 == 0">
|
||||
<List0 :height="boxHeight" :list="list"></List0>
|
||||
</template>
|
||||
<template v-if="tabIndex1 == 1">
|
||||
<List1 :list="list"></List1>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import StoreDown from '@/pages/home/components/store-down.vue'
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import { computed, reactive, ref } from 'vue'
|
||||
import { timeFormat } from '@climblee/uv-ui/libs/function/index'
|
||||
import { onShow, onReady } from '@dcloudio/uni-app'
|
||||
import { http } from '@/utils/request'
|
||||
import List0 from './components/list0.vue'
|
||||
import List1 from './components/list1.vue'
|
||||
import checkPermission from '@/utils/permission'
|
||||
import dayjs from 'dayjs'
|
||||
import { sys } from '@climblee/uv-ui/libs/function/index'
|
||||
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
const userStore = useUserStore()
|
||||
|
||||
const getRect = (selector, all) => {
|
||||
return new Promise((resolve) => {
|
||||
|
||||
uni
|
||||
.createSelectorQuery()
|
||||
[all ? 'selectAll' : 'select'](selector)
|
||||
.boundingClientRect((rect) => {
|
||||
if (all && Array.isArray(rect) && rect.length) {
|
||||
resolve(rect)
|
||||
}
|
||||
if (!all && rect) {
|
||||
resolve(rect)
|
||||
}
|
||||
})
|
||||
.exec()
|
||||
})
|
||||
}
|
||||
const isLotteryStore = computed(
|
||||
() => userStore.userInfo?.store?.is_lottery_store
|
||||
)
|
||||
const tabIndex1 = ref(0)
|
||||
const tabIndex = ref(0)
|
||||
const tabsList = ref(generateTimeArrayWithLastPeriod())
|
||||
const list = ref([])
|
||||
const boxHeight = ref(0)
|
||||
const currentTabs = computed(() => tabsList.value[tabIndex.value])
|
||||
const currentC = computed(() => {
|
||||
const ob = currentTabs.value.current
|
||||
return {
|
||||
start: timeFormat(ob.startDate),
|
||||
end: timeFormat(ob.endDate),
|
||||
}
|
||||
})
|
||||
const currentL = computed(() => {
|
||||
const ob = currentTabs.value.lastPeriod
|
||||
return {
|
||||
start: timeFormat(ob.startDate),
|
||||
end: timeFormat(ob.endDate),
|
||||
}
|
||||
})
|
||||
const offsetTop = computed(() => {
|
||||
return sys().statusBarHeight
|
||||
})
|
||||
|
||||
const shoreInfo = ref({})
|
||||
|
||||
if (!checkPermission(['admin'])) {
|
||||
shoreInfo.value = { store_id: userStore?.userInfo?.store?.id }
|
||||
}
|
||||
|
||||
const result = ref([])
|
||||
const ledger = ref({
|
||||
expenditure: '0',
|
||||
sales: '0',
|
||||
sales_growth_rate: '0',
|
||||
})
|
||||
|
||||
const activeName = ref('area')
|
||||
|
||||
onShow(() => {
|
||||
getCount()
|
||||
getList()
|
||||
})
|
||||
|
||||
onReady(() => {
|
||||
getBox()
|
||||
})
|
||||
|
||||
const getBox = async () => {
|
||||
getRect('.headBox').then((res) => {
|
||||
const th = checkPermission(['admin']) ? 44 : 0
|
||||
boxHeight.value =sys().windowHeight - res.height - th - 44 - 20 - sys().statusBarHeight - 3
|
||||
})
|
||||
}
|
||||
|
||||
const storeChange = (e) => {
|
||||
shoreInfo.value = e
|
||||
getCount()
|
||||
getList()
|
||||
}
|
||||
|
||||
const getCount = async () => {
|
||||
const resData = await http.get('/statistics/ledger', {
|
||||
params: {
|
||||
start_at: currentC.value.start,
|
||||
end_at: currentC.value.end,
|
||||
before_start_at: currentL.value.start,
|
||||
before_end_at: currentL.value.end,
|
||||
...shoreInfo.value,
|
||||
},
|
||||
})
|
||||
ledger.value = resData
|
||||
}
|
||||
|
||||
function generateTimeArrayWithLastPeriod() {
|
||||
const today = dayjs()
|
||||
const yesterday = today.subtract(1, 'day')
|
||||
|
||||
let currentWeekStart = today.startOf('week').add(1, 'day') // 本周一
|
||||
if (today.isBefore(currentWeekStart, 'day')) {
|
||||
currentWeekStart = currentWeekStart.subtract(1, 'week')
|
||||
}
|
||||
const currentWeekEnd = today
|
||||
|
||||
let lastWeekStart = currentWeekStart.subtract(1, 'week')
|
||||
const lastWeekEnd = currentWeekStart.subtract(1, 'day')
|
||||
|
||||
let currentMonthStart = today.startOf('month')
|
||||
if (today.isBefore(currentMonthStart, 'day')) {
|
||||
currentMonthStart = currentMonthStart.subtract(1, 'month')
|
||||
}
|
||||
const currentMonthEnd = today.endOf('day') // 本月最后一天到当天结束
|
||||
|
||||
let lastMonthStart = currentMonthStart.subtract(1, 'month')
|
||||
const lastMonthEnd = currentMonthStart.subtract(1, 'day')
|
||||
|
||||
const timeArray = [
|
||||
generateTimeRange('昨日', yesterday),
|
||||
generateTimeRange('本周', currentWeekStart, currentWeekEnd),
|
||||
generateTimeRange('上周', lastWeekStart, lastWeekEnd),
|
||||
generateTimeRange('本月', currentMonthStart, currentMonthEnd),
|
||||
generateTimeRange('上月', lastMonthStart, lastMonthEnd),
|
||||
]
|
||||
|
||||
const lastPeriodTimeRanges = {}
|
||||
|
||||
// 计算同期的上次开始和结束时间
|
||||
timeArray.forEach((timeRange) => {
|
||||
switch (timeRange.label) {
|
||||
case '昨日':
|
||||
lastPeriodTimeRanges['昨日'] = {
|
||||
startDate: dayjs(timeRange.current.startDate)
|
||||
.subtract(1, 'day')
|
||||
.toDate(),
|
||||
endDate: dayjs(timeRange.current.endDate).subtract(1, 'day').toDate(),
|
||||
}
|
||||
break
|
||||
case '本周':
|
||||
lastPeriodTimeRanges['本周'] = {
|
||||
startDate: dayjs(timeRange.current.startDate)
|
||||
.subtract(1, 'week')
|
||||
.toDate(),
|
||||
endDate: dayjs(timeRange.current.endDate)
|
||||
.subtract(1, 'week')
|
||||
.toDate(),
|
||||
}
|
||||
break
|
||||
case '上周':
|
||||
lastPeriodTimeRanges['上周'] = {
|
||||
startDate: dayjs(timeRange.current.startDate)
|
||||
.subtract(1, 'week')
|
||||
.toDate(),
|
||||
endDate: dayjs(timeRange.current.endDate)
|
||||
.subtract(1, 'week')
|
||||
.toDate(),
|
||||
}
|
||||
break
|
||||
case '本月':
|
||||
lastPeriodTimeRanges['本月'] = {
|
||||
startDate: dayjs(timeRange.current.startDate)
|
||||
.subtract(1, 'month')
|
||||
.toDate(),
|
||||
endDate: dayjs(timeRange.current.endDate)
|
||||
.subtract(1, 'month')
|
||||
.toDate(),
|
||||
}
|
||||
break
|
||||
case '上月':
|
||||
lastPeriodTimeRanges['上月'] = {
|
||||
startDate: dayjs(timeRange.current.startDate)
|
||||
.subtract(1, 'month')
|
||||
.toDate(),
|
||||
endDate: dayjs(timeRange.current.endDate)
|
||||
.subtract(1, 'month')
|
||||
.endOf('month'),
|
||||
}
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
})
|
||||
|
||||
// 更新 timeArray 中的 lastPeriod 字段
|
||||
timeArray.forEach((timeRange) => {
|
||||
timeRange.lastPeriod = lastPeriodTimeRanges[timeRange.label]
|
||||
})
|
||||
|
||||
return timeArray
|
||||
}
|
||||
|
||||
function generateTimeRange(label, startDate, endDate) {
|
||||
return {
|
||||
label,
|
||||
current: {
|
||||
startDate: startDate.toDate(),
|
||||
endDate: (endDate || startDate).toDate(),
|
||||
},
|
||||
lastPeriod: { startDate: null, endDate: null },
|
||||
}
|
||||
}
|
||||
|
||||
const tabChange = (e) => {
|
||||
list.value = []
|
||||
tabIndex.value = e.index
|
||||
getCount()
|
||||
getList()
|
||||
}
|
||||
|
||||
const tabChange1 = (e) => {
|
||||
list.value = []
|
||||
tabIndex1.value = e.index
|
||||
getList()
|
||||
}
|
||||
|
||||
const getList = async () => {
|
||||
const url = tabIndex1.value == 0 ? '/statistics/sales' : '/statistics/stores'
|
||||
let params = {
|
||||
start_at: currentC.value.start,
|
||||
end_at: currentC.value.end,
|
||||
}
|
||||
if (tabIndex1.value == 0) {
|
||||
params = {
|
||||
...params,
|
||||
...shoreInfo.value,
|
||||
}
|
||||
}
|
||||
|
||||
const resData = await http.get(url, {
|
||||
params: params,
|
||||
})
|
||||
list.value = resData
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.table {
|
||||
display: flex;
|
||||
// border: 1px solid;
|
||||
}
|
||||
.tr {
|
||||
border: 0.5px solid #f5f5f5;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,438 +1,153 @@
|
|||
<template>
|
||||
<view>
|
||||
<CuNavbar :isBack="false" title="数据报表"></CuNavbar>
|
||||
<uv-sticky
|
||||
customNavHeight="44px"
|
||||
:offset-top="offsetTop"
|
||||
bgColor="#fff"
|
||||
v-if="checkPermission(['admin'])"
|
||||
>
|
||||
<StoreDown color="#333333" @change="storeChange"></StoreDown>
|
||||
</uv-sticky>
|
||||
|
||||
<view class="card">
|
||||
<view class="headBox">
|
||||
<uv-tabs
|
||||
:lineColor="'#ee2c37'"
|
||||
:list="tabsList"
|
||||
:scrollable="false"
|
||||
:current="tabIndex"
|
||||
keyName="label"
|
||||
@change="tabChange"
|
||||
></uv-tabs>
|
||||
|
||||
<view class="h-40rpx flex-center" @click="openCalendars">
|
||||
<view class="text-center text-28rpx py-4rpx">{{ showDate }} </view>
|
||||
</view>
|
||||
|
||||
<view class="grid grid-cols-2 my-20rpx table1">
|
||||
<view class="text-center flex-1 tr" @click="openLogPopup('sales')">
|
||||
<view class="flex-center h-60rpx text-28rpx">销售金额</view>
|
||||
<view class="font-600 flex-center h-60rpx">{{ ledger.sales }}</view>
|
||||
</view>
|
||||
|
||||
<view class="text-center flex-1 tr" @click="openLogPopup('expenditure')">
|
||||
<view
|
||||
class="flex-center h-60rpx"
|
||||
v-if="isLotteryStore || checkPermission(['admin'])"
|
||||
>
|
||||
<view>兑奖金额</view>
|
||||
</view>
|
||||
<view class="flex-center h-60rpx text-28rpx" v-else>支出金额</view>
|
||||
<view class="font-600 flex-center h-60rpx">{{
|
||||
ledger.expenditure
|
||||
}}</view>
|
||||
</view>
|
||||
|
||||
<view class="text-center flex-1 tr">
|
||||
<view class="flex-center h-60rpx text-28rpx">销售涨幅</view>
|
||||
<view
|
||||
class="font-600 flex-center h-60rpx"
|
||||
:class="[
|
||||
ledger.sales_growth_rate > 0 ? 'text-primary' : 'text-green',
|
||||
]"
|
||||
>{{ ledger.sales_growth_rate }}%</view
|
||||
>
|
||||
</view>
|
||||
|
||||
<view class="text-center flex-1 tr">
|
||||
<view class="flex-center h-60rpx text-28rpx">新增客户</view>
|
||||
<view class="font-600 flex-center h-60rpx">{{
|
||||
ledger.new_customers
|
||||
}}</view>
|
||||
</view>
|
||||
</view>
|
||||
<uv-tabs
|
||||
@change="tabChange1"
|
||||
:lineColor="'#ee2c37'"
|
||||
:list="[{ name: '销售统计' }, { name: '门店统计' }]"
|
||||
:scrollable="false"
|
||||
:current="tabIndex1"
|
||||
></uv-tabs>
|
||||
</view>
|
||||
<template v-if="tabIndex1 == 0">
|
||||
<List0 :height="boxHeight" :list="list"></List0>
|
||||
</template>
|
||||
<template v-if="tabIndex1 == 1">
|
||||
<List1 :list="list"></List1>
|
||||
</template>
|
||||
<CuNavbar title="数据报表"></CuNavbar>
|
||||
<view>
|
||||
<uv-drop-down
|
||||
ref="dropDown"
|
||||
sign="dropDown_1"
|
||||
text-active-color="#3c9cff"
|
||||
:extra-icon="{ name: 'arrow-down-fill', color: '#666', size: '26rpx' }"
|
||||
:extra-active-icon="{
|
||||
name: 'arrow-up-fill',
|
||||
color: '#3c9cff',
|
||||
size: '26rpx',
|
||||
}"
|
||||
:defaultValue="['all', 'all']"
|
||||
:custom-style="{ padding: '0 30rpx' }"
|
||||
@click="selectMenu"
|
||||
>
|
||||
<uv-drop-down-item
|
||||
name="area"
|
||||
type="2"
|
||||
:label="dropDownData.area.label"
|
||||
:value="dropDownData.area.value"
|
||||
>
|
||||
</uv-drop-down-item>
|
||||
<uv-drop-down-item
|
||||
name="store"
|
||||
type="2"
|
||||
:label="dropDownData.store.label"
|
||||
:value="dropDownData.store.value"
|
||||
>
|
||||
</uv-drop-down-item>
|
||||
</uv-drop-down>
|
||||
</view>
|
||||
|
||||
<uv-calendars
|
||||
ref="calendars"
|
||||
mode="range"
|
||||
title="选择日期"
|
||||
start-text="开始"
|
||||
end-text="结束"
|
||||
:date="selected"
|
||||
:allowSameDay="true"
|
||||
@confirm="confirm"
|
||||
/>
|
||||
|
||||
<uv-popup ref="logPopup" mode="center" round="16" :closeable="true">
|
||||
<view class="w-600rpx">
|
||||
<view class="h-60rpx"></view>
|
||||
<view class="grid grid-cols-2 py-16rpx text-28rpx font-500">
|
||||
<view class="text-center">明细</view>
|
||||
<view class="text-center">金额</view>
|
||||
<view class="card">
|
||||
<uv-tabs
|
||||
:lineColor="'#ee2c37'"
|
||||
:list="tabsList"
|
||||
:scrollable="false"
|
||||
></uv-tabs>
|
||||
<view class="text-center text-28rpx"> 2024-03-21 至 2024-03-21 </view>
|
||||
<view class="flex my-20rpx items-center">
|
||||
<view class="text-center flex-1">
|
||||
<view>销售金额</view>
|
||||
<view class="font-600">991122</view>
|
||||
</view>
|
||||
<view class="h-60rpx">
|
||||
<uv-line direction="col"></uv-line>
|
||||
</view>
|
||||
<view class="text-center flex-1">
|
||||
<view>销售金额</view>
|
||||
<view class="font-600">991122</view>
|
||||
</view>
|
||||
<view class="h-60rpx">
|
||||
<uv-line direction="col"></uv-line>
|
||||
</view>
|
||||
<view class="text-center flex-1">
|
||||
<view>销售涨幅</view>
|
||||
<view class="text-primary font-600">+20%</view>
|
||||
</view>
|
||||
<scroll-view scroll-y class="min-h-200rpx max-h-1100rpx">
|
||||
<view v-for="(item,i) in lottery_types" :key="i" class="grid grid-cols-2 py-16rpx text-28rpx">
|
||||
<view class="text-center">{{item.name}}</view>
|
||||
<view class="text-center">{{item[activeName]}}</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</uv-popup>
|
||||
<uv-tabs
|
||||
:lineColor="'#ee2c37'"
|
||||
:list="[{ name: '销售统计' }, { name: '门店统计' }]"
|
||||
:scrollable="false"
|
||||
></uv-tabs>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import StoreDown from '@/pages/home/components/store-down.vue'
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import { computed, reactive, ref } from 'vue'
|
||||
import { timeFormat } from '@climblee/uv-ui/libs/function/index'
|
||||
import { onShow, onReady } from '@dcloudio/uni-app'
|
||||
import { http } from '@/utils/request'
|
||||
import List0 from './components/list0.vue'
|
||||
import List1 from './components/list1.vue'
|
||||
import checkPermission from '@/utils/permission'
|
||||
import dayjs from 'dayjs'
|
||||
import { sys } from '@climblee/uv-ui/libs/function/index'
|
||||
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
const userStore = useUserStore()
|
||||
const logPopup = ref(null)
|
||||
|
||||
const getRect = (selector, all) => {
|
||||
return new Promise((resolve) => {
|
||||
uni
|
||||
.createSelectorQuery()
|
||||
[all ? 'selectAll' : 'select'](selector)
|
||||
.boundingClientRect((rect) => {
|
||||
if (all && Array.isArray(rect) && rect.length) {
|
||||
resolve(rect)
|
||||
}
|
||||
if (!all && rect) {
|
||||
resolve(rect)
|
||||
}
|
||||
})
|
||||
.exec()
|
||||
})
|
||||
}
|
||||
const isLotteryStore = computed(
|
||||
() => userStore.userInfo?.store?.is_lottery_store
|
||||
)
|
||||
const selected = ref(null)
|
||||
const calendars = ref(null)
|
||||
const tabIndex1 = ref(0)
|
||||
const tabIndex = ref(0)
|
||||
const tabsList = ref(generateTimeArrayWithLastPeriod())
|
||||
const list = ref([])
|
||||
const boxHeight = ref(0)
|
||||
const currentTabs = computed(() => tabsList.value[tabIndex.value])
|
||||
const isCalendar = ref(false)
|
||||
const currentC = computed(() => {
|
||||
const ob = currentTabs.value.current
|
||||
return {
|
||||
start: timeFormat(ob.startDate),
|
||||
end: timeFormat(ob.endDate),
|
||||
}
|
||||
const tabsList = ref([
|
||||
{
|
||||
name: '昨日',
|
||||
},
|
||||
{
|
||||
name: '本周',
|
||||
},
|
||||
{
|
||||
name: '上周',
|
||||
},
|
||||
{
|
||||
name: '本月',
|
||||
},
|
||||
{
|
||||
name: '上月',
|
||||
},
|
||||
])
|
||||
const dropDownData = reactive({
|
||||
area: {
|
||||
label: '全部区域',
|
||||
value: 'all',
|
||||
activeIndex: 0,
|
||||
color: '#333',
|
||||
activeColor: '#2878ff',
|
||||
child: [
|
||||
{
|
||||
label: '全部区域',
|
||||
value: 'all',
|
||||
},
|
||||
{
|
||||
label: '重庆',
|
||||
value: 'cq',
|
||||
},
|
||||
{
|
||||
label: '北京',
|
||||
value: 'bj',
|
||||
},
|
||||
],
|
||||
},
|
||||
store: {
|
||||
label: '全部门店',
|
||||
value: 'all',
|
||||
activeIndex: 0,
|
||||
color: '#333',
|
||||
activeColor: '#2878ff',
|
||||
child: [
|
||||
{
|
||||
label: '全部门店',
|
||||
value: 'all',
|
||||
},
|
||||
{
|
||||
label: '门店1',
|
||||
value: 'new',
|
||||
},
|
||||
{
|
||||
label: '门店2',
|
||||
value: 'money',
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
|
||||
const showDate = computed(() => {
|
||||
let start = currentC.value.start
|
||||
let end = currentC.value.end
|
||||
if (isCalendar.value) {
|
||||
start = selected.value[0]
|
||||
end = selected.value[1]
|
||||
}
|
||||
if (start === end) return start
|
||||
return `${start} 至 ${end}`
|
||||
})
|
||||
const currentL = computed(() => {
|
||||
const ob = currentTabs.value.lastPeriod
|
||||
return {
|
||||
start: timeFormat(ob.startDate),
|
||||
end: timeFormat(ob.endDate),
|
||||
}
|
||||
})
|
||||
const offsetTop = computed(() => {
|
||||
return sys().statusBarHeight
|
||||
})
|
||||
const result = ref([])
|
||||
|
||||
const shoreInfo = ref({})
|
||||
const activeName = ref('area')
|
||||
|
||||
if (!checkPermission(['admin'])) {
|
||||
shoreInfo.value = { store_id: userStore?.userInfo?.store?.id }
|
||||
}
|
||||
|
||||
const ledger = ref({
|
||||
expenditure: '0',
|
||||
sales: '0',
|
||||
sales_growth_rate: '0',
|
||||
lottery_types:[]
|
||||
})
|
||||
|
||||
const activeName = ref('lottery_types')
|
||||
const lottery_types = computed(()=> ledger.value?.lottery_types || [])
|
||||
|
||||
onShow(() => {
|
||||
getCount()
|
||||
getList()
|
||||
})
|
||||
|
||||
onReady(() => {
|
||||
getBox()
|
||||
})
|
||||
|
||||
const openLogPopup = (type) => {
|
||||
activeName.value = type
|
||||
if(checkPermission(['admin']) || isLotteryStore.value) logPopup.value.open()
|
||||
|
||||
}
|
||||
const confirm = ({ range }) => {
|
||||
isCalendar.value = true
|
||||
const { before, after } = range
|
||||
selected.value = [before, after]
|
||||
getCount()
|
||||
getList()
|
||||
}
|
||||
|
||||
function calculatePreviousPeriodByDays(startDate, endDate) {
|
||||
const start = dayjs(startDate)
|
||||
const end = dayjs(endDate)
|
||||
|
||||
// 计算当前时间段的天数
|
||||
const daysDiff = end.diff(start, 'day') + 1
|
||||
|
||||
// 计算上一时间段的结束时间和开始时间
|
||||
const prevEnd = start.subtract(1, 'day')
|
||||
const prevStart = prevEnd.subtract(daysDiff - 1, 'day')
|
||||
|
||||
return {
|
||||
previousStart: prevStart.format('YYYY-MM-DD'),
|
||||
previousEnd: prevEnd.format('YYYY-MM-DD'),
|
||||
}
|
||||
}
|
||||
|
||||
const openCalendars = () => {
|
||||
calendars.value.open()
|
||||
}
|
||||
|
||||
const getBox = async () => {
|
||||
getRect('.headBox').then((res) => {
|
||||
const th = checkPermission(['admin']) ? 44 : 0
|
||||
boxHeight.value =
|
||||
sys().windowHeight - res.height - th - 44 - 20 - sys().statusBarHeight - 3
|
||||
})
|
||||
}
|
||||
|
||||
const storeChange = (e) => {
|
||||
shoreInfo.value = e
|
||||
getCount()
|
||||
getList()
|
||||
}
|
||||
|
||||
const getCount = async () => {
|
||||
const params = {
|
||||
start_at: currentC.value.start,
|
||||
end_at: currentC.value.end,
|
||||
before_start_at: currentL.value.start,
|
||||
before_end_at: currentL.value.end,
|
||||
}
|
||||
if (isCalendar.value) {
|
||||
params.start_at = selected.value[0]
|
||||
params.end_at = selected.value[1]
|
||||
const { previousStart, previousEnd } = calculatePreviousPeriodByDays(
|
||||
params.start_at,
|
||||
params.end_at
|
||||
const selectMenu = (e) => {
|
||||
const { name, active, type } = e
|
||||
activeName.value = name
|
||||
const find = result.value.find((item) => item.name == activeName.value)
|
||||
if (find) {
|
||||
const findIndex = dropDownData[activeName.value].child.findIndex(
|
||||
(item) => item.label == find.label && item.value == find.value
|
||||
)
|
||||
params.before_start_at = previousStart
|
||||
params.before_end_at = previousEnd
|
||||
dropDownData[activeName.value].activeIndex = findIndex
|
||||
} else {
|
||||
dropDownData[activeName.value].activeIndex = 0
|
||||
}
|
||||
|
||||
const resData = await http.get('/statistics/ledger', {
|
||||
params: {
|
||||
...params,
|
||||
...shoreInfo.value,
|
||||
},
|
||||
})
|
||||
ledger.value = resData
|
||||
}
|
||||
|
||||
function generateTimeArrayWithLastPeriod() {
|
||||
const today = dayjs()
|
||||
const yesterday = today.subtract(1, 'day')
|
||||
|
||||
let currentWeekStart = today.startOf('week').add(1, 'day') // 本周一
|
||||
if (today.isBefore(currentWeekStart, 'day')) {
|
||||
currentWeekStart = currentWeekStart.subtract(1, 'week')
|
||||
}
|
||||
const currentWeekEnd = today
|
||||
|
||||
let lastWeekStart = currentWeekStart.subtract(1, 'week')
|
||||
const lastWeekEnd = currentWeekStart.subtract(1, 'day')
|
||||
|
||||
let currentMonthStart = today.startOf('month')
|
||||
if (today.isBefore(currentMonthStart, 'day')) {
|
||||
currentMonthStart = currentMonthStart.subtract(1, 'month')
|
||||
}
|
||||
const currentMonthEnd = today.endOf('day') // 本月最后一天到当天结束
|
||||
|
||||
let lastMonthStart = currentMonthStart.subtract(1, 'month')
|
||||
const lastMonthEnd = currentMonthStart.subtract(1, 'day')
|
||||
|
||||
const timeArray = [
|
||||
generateTimeRange('昨日', yesterday),
|
||||
generateTimeRange('本周', currentWeekStart, currentWeekEnd),
|
||||
generateTimeRange('上周', lastWeekStart, lastWeekEnd),
|
||||
generateTimeRange('本月', currentMonthStart, currentMonthEnd),
|
||||
generateTimeRange('上月', lastMonthStart, lastMonthEnd),
|
||||
]
|
||||
|
||||
const lastPeriodTimeRanges = {}
|
||||
|
||||
// 计算同期的上次开始和结束时间
|
||||
timeArray.forEach((timeRange) => {
|
||||
switch (timeRange.label) {
|
||||
case '昨日':
|
||||
lastPeriodTimeRanges['昨日'] = {
|
||||
startDate: dayjs(timeRange.current.startDate)
|
||||
.subtract(1, 'day')
|
||||
.toDate(),
|
||||
endDate: dayjs(timeRange.current.endDate).subtract(1, 'day').toDate(),
|
||||
}
|
||||
break
|
||||
case '本周':
|
||||
lastPeriodTimeRanges['本周'] = {
|
||||
startDate: dayjs(timeRange.current.startDate)
|
||||
.subtract(1, 'week')
|
||||
.toDate(),
|
||||
endDate: dayjs(timeRange.current.endDate)
|
||||
.subtract(1, 'week')
|
||||
.toDate(),
|
||||
}
|
||||
break
|
||||
case '上周':
|
||||
lastPeriodTimeRanges['上周'] = {
|
||||
startDate: dayjs(timeRange.current.startDate)
|
||||
.subtract(1, 'week')
|
||||
.toDate(),
|
||||
endDate: dayjs(timeRange.current.endDate)
|
||||
.subtract(1, 'week')
|
||||
.toDate(),
|
||||
}
|
||||
break
|
||||
case '本月':
|
||||
lastPeriodTimeRanges['本月'] = {
|
||||
startDate: dayjs(timeRange.current.startDate)
|
||||
.subtract(1, 'month')
|
||||
.toDate(),
|
||||
endDate: dayjs(timeRange.current.endDate)
|
||||
.subtract(1, 'month')
|
||||
.toDate(),
|
||||
}
|
||||
break
|
||||
case '上月':
|
||||
lastPeriodTimeRanges['上月'] = {
|
||||
startDate: dayjs(timeRange.current.startDate)
|
||||
.subtract(1, 'month')
|
||||
.toDate(),
|
||||
endDate: dayjs(timeRange.current.endDate)
|
||||
.subtract(1, 'month')
|
||||
.endOf('month'),
|
||||
}
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
})
|
||||
|
||||
// 更新 timeArray 中的 lastPeriod 字段
|
||||
timeArray.forEach((timeRange) => {
|
||||
timeRange.lastPeriod = lastPeriodTimeRanges[timeRange.label]
|
||||
})
|
||||
|
||||
return timeArray
|
||||
}
|
||||
|
||||
function generateTimeRange(label, startDate, endDate) {
|
||||
return {
|
||||
label,
|
||||
current: {
|
||||
startDate: startDate.toDate(),
|
||||
endDate: (endDate || startDate).toDate(),
|
||||
},
|
||||
lastPeriod: { startDate: null, endDate: null },
|
||||
}
|
||||
}
|
||||
|
||||
const tabChange = (e) => {
|
||||
isCalendar.value = false
|
||||
list.value = []
|
||||
tabIndex.value = e.index
|
||||
selected.value = [currentC.value.start, currentC.value.end]
|
||||
getCount()
|
||||
getList()
|
||||
}
|
||||
|
||||
const tabChange1 = (e) => {
|
||||
list.value = []
|
||||
tabIndex1.value = e.index
|
||||
getList()
|
||||
}
|
||||
|
||||
const getList = async () => {
|
||||
const url = tabIndex1.value == 0 ? '/statistics/sales' : '/statistics/stores'
|
||||
let params = {
|
||||
start_at: currentC.value.start,
|
||||
end_at: currentC.value.end,
|
||||
}
|
||||
|
||||
if (isCalendar.value) {
|
||||
params.start_at = selected.value[0]
|
||||
params.end_at = selected.value[1]
|
||||
}
|
||||
|
||||
if (tabIndex1.value == 0) {
|
||||
params = {
|
||||
...params,
|
||||
...shoreInfo.value,
|
||||
}
|
||||
}
|
||||
|
||||
const resData = await http.get(url, {
|
||||
params: params,
|
||||
})
|
||||
list.value = resData
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.table1 {
|
||||
// display: flex;//
|
||||
border: 0.5px solid #f5f5f5;
|
||||
}
|
||||
.tr {
|
||||
border: 0.5px solid #f5f5f5;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,50 @@
|
|||
<template>
|
||||
<view
|
||||
class="card-shadow bg-white rounded-19rpx p-base space-y-10rpx"
|
||||
@click.stop="onClick"
|
||||
>
|
||||
<view class="flex items-center justify-between">
|
||||
<view class="text-30rpx">{{ item.name }}</view>
|
||||
<view
|
||||
:style="{
|
||||
color: statusFun(item.taskable.status, item.taskable_type, 'color'),
|
||||
}"
|
||||
class="text-24rpx"
|
||||
>{{ statusFun(item.taskable.status, item.taskable_type, 'name') }}</view
|
||||
>
|
||||
</view>
|
||||
<view class="text-24rpx text-hex-999999">
|
||||
任务时间:{{ timeFormat(item.start_at, 'yyyy年mm月dd日') }} -
|
||||
{{ timeFormat(item.end_at, 'yyyy年mm月dd日') }}
|
||||
</view>
|
||||
<template v-if="item.taskable.status == 2">
|
||||
<view class="py-10rpx">
|
||||
<uv-line></uv-line>
|
||||
</view>
|
||||
<view class="flex justify-end">
|
||||
<view @click.stop="onTask">
|
||||
<uv-button type="primary" size="mini">去完成</uv-button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import statusFun from '@/utils/status'
|
||||
import { timeFormat } from '@climblee/uv-ui/libs/function/index'
|
||||
const props = defineProps({
|
||||
item: Object,
|
||||
})
|
||||
|
||||
const onClick = () => {
|
||||
const type = props.item.taskable_type
|
||||
console.log(type)
|
||||
}
|
||||
|
||||
const onTask = (e) => {
|
||||
const type = props.item.taskable_type
|
||||
uni.navigateTo({
|
||||
url: `/pages/task/${type}_submit?id=${props.item.id}`,
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
<template>
|
||||
<view class="px-base">
|
||||
<CuNavbar title="任务详情"></CuNavbar>
|
||||
|
||||
<BaseCompApi :apiUrl="`/tasks/${id}`" :colums="baseColums">
|
||||
<!-- <template v-slot="{ slotName, data }">
|
||||
<view v-if="slotName == 'taskable.description'">
|
||||
{{ data }}
|
||||
</view>
|
||||
</template> -->
|
||||
</BaseCompApi>
|
||||
|
||||
<view class="h-100rpx">
|
||||
<view
|
||||
class="fixed bottom-0 left-0 right-0 h-120rpx bg-white flex items-center px-base space-x-30rpx"
|
||||
>
|
||||
<view class="flex-1">
|
||||
<uv-button color="#999999" shape="circle" plain block>
|
||||
拒绝
|
||||
</uv-button>
|
||||
</view>
|
||||
<view class="flex-1">
|
||||
<uv-button type="primary" shape="circle" block> 通过 </uv-button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { ref } from 'vue'
|
||||
import BaseCompApi from '@/components/base-comp/base-api.vue'
|
||||
import { timeFormat } from '@climblee/uv-ui/libs/function'
|
||||
const baseColums = [
|
||||
{
|
||||
title: '申请人',
|
||||
dataIndex: 'name',
|
||||
},
|
||||
{
|
||||
title: '所属门店',
|
||||
dataIndex: 'taskable.store.address',
|
||||
},
|
||||
{
|
||||
title: '电话号码',
|
||||
dataIndex: '',
|
||||
},
|
||||
{
|
||||
title: '申请时间',
|
||||
dataIndex: 'created_at',
|
||||
format: timeFormat,
|
||||
},
|
||||
{
|
||||
title: '清洁范围',
|
||||
dataIndex: 'taskable.description',
|
||||
labelPosition: 'top',
|
||||
},
|
||||
]
|
||||
const id = ref(null)
|
||||
|
||||
onLoad((opt) => {
|
||||
id.value = opt.id
|
||||
})
|
||||
</script>
|
||||
|
|
@ -1,119 +1,55 @@
|
|||
<template>
|
||||
<view class="px-base">
|
||||
<CuNavbar title="任务详情">
|
||||
<template v-if="actions.length > 0" #right>
|
||||
<uv-icon color="white" @click="open" name="more-dot-fill"></uv-icon>
|
||||
</template>
|
||||
</CuNavbar>
|
||||
<CuNavbar title="任务详情"></CuNavbar>
|
||||
<view
|
||||
class="mt-30rpx card-shadow bg-white rounded-19rpx px-base text-[#333333] text-27rpx"
|
||||
>
|
||||
<BaseData :data="data" :colums="baseColums" />
|
||||
<view class="py-20rpx flex items-center justify-between">
|
||||
<view>申请人</view>
|
||||
<view class="text-hex-999999">测试人</view>
|
||||
</view>
|
||||
<uv-line></uv-line>
|
||||
<view class="py-20rpx flex items-center justify-between">
|
||||
<view>所属门店</view>
|
||||
<view class="text-hex-999999">具体门店名称</view>
|
||||
</view>
|
||||
<uv-line></uv-line>
|
||||
<view class="py-20rpx flex items-center justify-between">
|
||||
<view>电话号码</view>
|
||||
<view class="text-hex-999999">具体门店名称</view>
|
||||
</view>
|
||||
<uv-line></uv-line>
|
||||
<view class="py-20rpx flex items-center justify-between">
|
||||
<view>申请时间</view>
|
||||
<view class="text-hex-999999">具体门店名称</view>
|
||||
</view>
|
||||
<uv-line></uv-line>
|
||||
<view class="py-20rpx">
|
||||
<view>申请范围</view>
|
||||
<view class="text-hex-999999 mt-20rpx">具体门店名称</view>
|
||||
</view>
|
||||
<uv-line></uv-line>
|
||||
<view class="py-20rpx">
|
||||
<view>清洁结果</view>
|
||||
<view class="text-hex-999999 mt-20rpx">
|
||||
<view class="bg-gray-50 b-solid w-130rpx h-130rpx"></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="h-100rpx">
|
||||
<view
|
||||
class="fixed bottom-0 left-0 right-0 h-120rpx bg-white flex items-center px-base space-x-30rpx"
|
||||
>
|
||||
<view class="flex-1">
|
||||
<uv-button color="#999999" shape="circle" plain block> 拒绝 </uv-button>
|
||||
</view>
|
||||
<view class="flex-1">
|
||||
<uv-button type="primary" shape="circle" block> 通过 </uv-button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<uv-action-sheet
|
||||
ref="pickerRef"
|
||||
:actions="actions"
|
||||
@select="confirmPicker"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { http } from '@/utils/request'
|
||||
import { ref, computed } from 'vue'
|
||||
import { timeFormat } from '@climblee/uv-ui/libs/function'
|
||||
import BaseData from '@/pages/audits/base-data'
|
||||
import statusFun from '@/utils/status'
|
||||
|
||||
const pickerRef = ref(null)
|
||||
const actions = ref([
|
||||
{ name: '修改', value: 'edit', disabled: false },
|
||||
{ name: '审核流程', value: 'check-logs', disabled: false },
|
||||
])
|
||||
|
||||
const baseColums = [
|
||||
{
|
||||
title: '审核状态',
|
||||
dataIndex: 'taskable.status',
|
||||
format: (value) => statusFun(value, 'task_hygienes', 'name'),
|
||||
},
|
||||
{
|
||||
title: '申请人',
|
||||
dataIndex: 'taskable.store_master.name',
|
||||
},
|
||||
{
|
||||
title: '所属门店',
|
||||
dataIndex: 'taskable.store.title',
|
||||
},
|
||||
{
|
||||
title: '电话号码',
|
||||
dataIndex: 'taskable.store_master.phone',
|
||||
},
|
||||
{
|
||||
title: '申请时间',
|
||||
dataIndex: 'created_format',
|
||||
isShow: (row) => {
|
||||
return row?.taskable?.status != 1
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '清洁范围',
|
||||
dataIndex: 'taskable.description',
|
||||
labelPosition: 'top',
|
||||
},
|
||||
{
|
||||
title: '清洁结果',
|
||||
dataIndex: 'taskable.photos',
|
||||
labelPosition: 'top',
|
||||
type: 'album',
|
||||
},
|
||||
{
|
||||
title: '未通过原因',
|
||||
dataIndex: 'taskable.workflow_check.check_remarks',
|
||||
labelPosition: 'top',
|
||||
isShow: (row) => {
|
||||
return row?.taskable?.status == 6
|
||||
},
|
||||
},
|
||||
]
|
||||
const id = ref(null)
|
||||
const data = ref({})
|
||||
|
||||
onLoad((opt) => {
|
||||
id.value = opt.id
|
||||
getDetail()
|
||||
})
|
||||
|
||||
const open = () => {
|
||||
pickerRef.value.open()
|
||||
}
|
||||
|
||||
const getDetail = async () => {
|
||||
const resdata = await http.get(`/tasks/${id.value}`)
|
||||
data.value = resdata
|
||||
actions.value[0].disabled = resdata?.taskable?.status != 6
|
||||
}
|
||||
const confirmPicker = (e) => {
|
||||
|
||||
if (e.value == 'edit') {
|
||||
uni.navigateTo({
|
||||
url: `/pages/task/task_hygienes_submit?id=${id.value}`,
|
||||
})
|
||||
} else if (e.value == 'check-logs') {
|
||||
return uni.navigateTo({
|
||||
url: `/pages/audits/log?id=${data.value.taskable.workflow_check.id}`,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const getValue = (obj, path) => {
|
||||
return path.split('.').reduce((acc, key) => (acc ? acc[key] : undefined), obj)
|
||||
}
|
||||
|
||||
const isFunction = (fn) => {
|
||||
return typeof fn === 'function'
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,74 @@
|
|||
<template>
|
||||
<view>
|
||||
<CuNavbar title="我的任务"></CuNavbar>
|
||||
<uv-sticky bgColor="#fff">
|
||||
<uv-tabs
|
||||
:activeStyle="{ color: '#ee2c37' }"
|
||||
:scrollable="false"
|
||||
lineColor="#ee2c37"
|
||||
:list="tabList"
|
||||
></uv-tabs>
|
||||
</uv-sticky>
|
||||
<mescroll-body @init="mescrollInit" @down="downCallback" @up="upCallback">
|
||||
<view class="px-base space-y-20rpx mt-30rpx">
|
||||
<view
|
||||
v-for="item in 4"
|
||||
class="card-shadow bg-white rounded-19rpx p-base space-y-10rpx"
|
||||
>
|
||||
<view class="text-30rpx">月度清洁任务</view>
|
||||
<view class="text-24rpx text-hex-999999">
|
||||
任务时间:2022年03月01号 - 2022年03月31号
|
||||
</view>
|
||||
<view class="text-24rpx text-hex-999999">待完成</view>
|
||||
</view>
|
||||
</view>
|
||||
</mescroll-body>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import { http } from '@/utils/request'
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import { computed, reactive, ref } from 'vue'
|
||||
import { onPageScroll, onReachBottom } from '@dcloudio/uni-app'
|
||||
import useMescroll from '@/uni_modules/mescroll-uni/hooks/useMescroll.js'
|
||||
const { mescrollInit, downCallback, getMescroll } = useMescroll(
|
||||
onPageScroll,
|
||||
onReachBottom
|
||||
)
|
||||
const list = ref([])
|
||||
const tabList = ref([
|
||||
{
|
||||
name: '任务列表',
|
||||
apiUrl: '/tasks',
|
||||
},
|
||||
{
|
||||
name: '任务审核',
|
||||
apiUrl: '/workflow',
|
||||
params:{
|
||||
|
||||
}
|
||||
},
|
||||
])
|
||||
|
||||
const upCallback = async (mescroll) => {
|
||||
const { size, num } = mescroll
|
||||
|
||||
try {
|
||||
const resData = await http.get('/tasks', {
|
||||
params: {
|
||||
per_page: size,
|
||||
page: num,
|
||||
},
|
||||
})
|
||||
const curPageData = resData.data || []
|
||||
if (num === 1) list.value = []
|
||||
list.value = list.value.concat(curPageData)
|
||||
mescroll.endSuccess(curPageData.length)
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
mescroll.endErr() // 请求失败, 结束加载
|
||||
} finally {
|
||||
// firstloading.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -22,24 +22,9 @@
|
|||
>
|
||||
<template v-slot="{ list }">
|
||||
<view class="space-y-15rpx p-base">
|
||||
<ListItem
|
||||
v-for="item in list"
|
||||
:key="item.id"
|
||||
:title="item.name"
|
||||
:status-text="
|
||||
statusFun(item.taskable.status, item.taskable_type, 'name')
|
||||
"
|
||||
:status-color="
|
||||
statusFun(item.taskable.status, item.taskable_type, 'color')
|
||||
"
|
||||
:body="[
|
||||
{
|
||||
label: '任务时间: ',
|
||||
value: item.start_format + '-' + item.end_format,
|
||||
},
|
||||
]"
|
||||
@click.stop="applyClick(item)"
|
||||
/>
|
||||
<view v-for="(item, i) in list" :key="i">
|
||||
<Item :item="item"></Item>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</MescrollItem>
|
||||
|
|
@ -50,44 +35,16 @@
|
|||
:index="tabIndex"
|
||||
:apiUrl="tabList[1].apiUrl"
|
||||
:params="tabList[1].params"
|
||||
>
|
||||
<template v-slot="{ list }">
|
||||
<view class="space-y-15rpx p-base">
|
||||
<ListItem
|
||||
v-for="item in list"
|
||||
:key="item.id"
|
||||
:title="item?.check?.subject?.task?.name"
|
||||
:status-text="
|
||||
statusFun(item.check_status, 'statusExpense2', 'name')
|
||||
"
|
||||
:status-color="
|
||||
statusFun(item.check_status, 'statusExpense2', 'color')
|
||||
"
|
||||
:body="[
|
||||
{
|
||||
label: '任务时间: ',
|
||||
value:
|
||||
item?.check?.subject?.task?.start_format +
|
||||
'-' +
|
||||
item?.check?.subject?.task?.end_format,
|
||||
},
|
||||
]"
|
||||
@click.stop="checkClick(item)"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
</MescrollItem>
|
||||
></MescrollItem>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import { computed, reactive, ref } from 'vue'
|
||||
import { onPageScroll, onReachBottom, onLoad } from '@dcloudio/uni-app'
|
||||
import Item from './components/item.vue'
|
||||
import { onPageScroll, onReachBottom, onShow } from '@dcloudio/uni-app'
|
||||
import useMescrollMore from '@/uni_modules/mescroll-uni/hooks/useMescrollMore.js'
|
||||
import MescrollItem from '@/components/mescroll-api/more.vue'
|
||||
import statusFun from '@/utils/status'
|
||||
import { timeFormat } from '@climblee/uv-ui/libs/function/index'
|
||||
import ListItem from '@/components/list-item/index'
|
||||
|
||||
const mescrollItem0 = ref(null)
|
||||
const mescrollItem1 = ref(null)
|
||||
|
|
@ -107,45 +64,13 @@ const tabList = ref([
|
|||
name: '任务审核',
|
||||
apiUrl: '/workflow',
|
||||
params: {
|
||||
subject_type: 'task_hygienes',
|
||||
include: 'check.subject.task',
|
||||
// aaa:111
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
onLoad(() => {
|
||||
uni.$on('refresh', () => {
|
||||
mescrollItem0?.value?.getMescroll()?.resetUpScroll()
|
||||
mescrollItem1?.value?.getMescroll()?.resetUpScroll()
|
||||
})
|
||||
})
|
||||
|
||||
const tabChange = ({ index }) => {
|
||||
tabIndex.value = index
|
||||
scrollToLastY()
|
||||
}
|
||||
|
||||
const applyClick = (item) => {
|
||||
const type = item.taskable_type
|
||||
const status = item.taskable.status
|
||||
|
||||
if(type==='task_hygienes' && status===1) return
|
||||
|
||||
let url
|
||||
if (status === 2 || status == 4 || type=='task_ledgers') {
|
||||
const date = status != 3 || status != 5 ? `&date=${item.taskable.date}` : ''
|
||||
url = `/pages/task/${type}_submit?id=${item.id}${date}`
|
||||
} else {
|
||||
url = `/pages/task/detail?id=${item.id}`
|
||||
}
|
||||
uni.navigateTo({
|
||||
url: url,
|
||||
})
|
||||
}
|
||||
|
||||
const checkClick = (item) => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/audits/detail?id=${item.id}&type=${item.check.subject_type}`,
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
>
|
||||
<uv-form-item label="清洁范围" required prop="content">
|
||||
<uv-input
|
||||
:border="`bottom`"
|
||||
border="bottom"
|
||||
placeholder="请输入清洁范围"
|
||||
v-model="form.content"
|
||||
></uv-input>
|
||||
|
|
|
|||
|
|
@ -21,25 +21,25 @@
|
|||
</uv-form-item>
|
||||
<uv-line color="#f5f5f5"></uv-line>
|
||||
<uv-form-item
|
||||
label="清洁结果"
|
||||
label="报销凭证"
|
||||
labelPosition="top"
|
||||
prop="photos"
|
||||
required
|
||||
>
|
||||
<view class="text-right w-full text-hex-999">{{ form.photos.length }}/{{ maxCount }}</view>
|
||||
<view class="w-full mt-15rpx">
|
||||
<uv-upload
|
||||
:maxCount="9"
|
||||
multiple
|
||||
:fileList="form.photos"
|
||||
@afterRead="afterRead"
|
||||
@delete="deletePic"
|
||||
name="photos"
|
||||
></uv-upload>
|
||||
</view>
|
||||
</uv-form-item>
|
||||
<view class="w-full">
|
||||
<uv-upload
|
||||
:maxCount="maxCount"
|
||||
multiple
|
||||
:fileList="form.photos"
|
||||
@afterRead="afterRead"
|
||||
@delete="deletePic"
|
||||
name="photos"
|
||||
></uv-upload>
|
||||
</view>
|
||||
</uv-form>
|
||||
</view>
|
||||
<view class="mt-20rpx">
|
||||
<view class="mt-100rpx">
|
||||
<uv-button type="primary" @click="submit">提交</uv-button>
|
||||
</view>
|
||||
|
||||
|
|
@ -60,41 +60,26 @@ import { http } from '@/utils/request'
|
|||
const formRef = ref(null)
|
||||
const modalRef = ref(null)
|
||||
const id = ref(0)
|
||||
const info = ref({})
|
||||
const loading = ref(false)
|
||||
const form = reactive({
|
||||
description: '',
|
||||
photos: [],
|
||||
})
|
||||
const maxCount = ref(9)
|
||||
const rules = reactive({
|
||||
description: [{ required: true, message: '请输入清洁范围' }],
|
||||
photos: {
|
||||
type: 'array',
|
||||
required: true,
|
||||
message: '请上传清洁结果',
|
||||
message: '请上传报销凭证',
|
||||
},
|
||||
})
|
||||
onLoad((options) => {
|
||||
id.value = options.id
|
||||
http.get(`/tasks/${id.value}`).then(res => {
|
||||
info.value = res
|
||||
if (res.taskable) {
|
||||
form.description = res.taskable.description
|
||||
if (res.taskable.photos && res.taskable.photos.length > 0) {
|
||||
form.photos = res.taskable.photos.map(item => {
|
||||
return {url: item}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
const submit = () => {
|
||||
formRef.value.validate().then((res) => {
|
||||
modalRef.value.open()
|
||||
}).catch(error => {
|
||||
console.log(error)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -105,6 +90,9 @@ const onSubmit = async () => {
|
|||
await http.request({
|
||||
url: `/tasks/${id.value}/submit`,
|
||||
method: 'POST',
|
||||
header: {
|
||||
Accept: 'application/json',
|
||||
},
|
||||
data: {
|
||||
task_hygiene: {
|
||||
description: form.description,
|
||||
|
|
@ -117,7 +105,7 @@ const onSubmit = async () => {
|
|||
icon: 'none',
|
||||
})
|
||||
formRef.value.resetFields()
|
||||
uni.$emit('refresh')
|
||||
uni.$emit('task:submit', resData)
|
||||
uni.navigateBack()
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
|
|
|
|||
|
|
@ -1,16 +1,8 @@
|
|||
<template>
|
||||
<view>
|
||||
<RevertPage :isBack="true" :dete="date"></RevertPage>
|
||||
<RevertPage :isBack="true"></RevertPage>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import { onLoad } from "@dcloudio/uni-app";
|
||||
import RevertPage from "@/pages/revert/base";
|
||||
import { ref } from "vue";
|
||||
|
||||
const date = ref("")
|
||||
|
||||
onLoad((opt) => {
|
||||
date.value = opt.date
|
||||
})
|
||||
import RevertPage from "@/pages/revert/index";
|
||||
</script>
|
||||
|
|
@ -1,110 +1,47 @@
|
|||
<template>
|
||||
<view>
|
||||
<CuNavbar></CuNavbar>
|
||||
<!-- 文章 -->
|
||||
<template v-if="info.type == 1">
|
||||
<view class="h-400rpx">
|
||||
<uv-image width="100%" height="100%" :src="info.cover_image" />
|
||||
</view>
|
||||
<uv-image :src="info.cover_image" width="200px" height="100px" />
|
||||
<view>{{ info.title }}</view>
|
||||
<view>{{ info.description }}</view>
|
||||
<view>{{ info.created_at }}</view>
|
||||
<uv-divider />
|
||||
<!-- 富文本 -->
|
||||
<view>{!! info.content !!}</view>
|
||||
</template>
|
||||
<!-- 视频 -->
|
||||
<template v-if="info.type == 2">
|
||||
<video class="w-full" :src="info.video" />
|
||||
<!-- 视频 -->
|
||||
<video :src="info.video" />
|
||||
</template>
|
||||
<view class="p-base space-y-10rpx">
|
||||
<view class="font-500 text-30rpx">{{ info.title }}</view>
|
||||
<view class="text-hex-999999">{{ info.description }}</view>
|
||||
<view class="text-hex-999 text-right">{{
|
||||
timeFormat(info.created_at)
|
||||
}}</view>
|
||||
</view>
|
||||
|
||||
<template v-if="info.type == 3">
|
||||
<view class="p-base space-y-8rpx">
|
||||
<view
|
||||
v-for="item in info.files"
|
||||
class="flex card-shadow bg-white rounded-19rpx p-base"
|
||||
:key="item.id"
|
||||
>
|
||||
<view class="line-clamp-1 flex-1">
|
||||
{{ item.name }}
|
||||
</view>
|
||||
<view @click="downloadFile(item.value)">
|
||||
<uv-icon size="40rpx" name="download"></uv-icon>
|
||||
</view>
|
||||
<view>{{ info.title }}</view>
|
||||
<view>{{ info.description }}</view>
|
||||
<view>{{ info.created_at }}</view>
|
||||
<uv-divider />
|
||||
<!-- 文件列表 -->
|
||||
<view>
|
||||
<view v-for="item in info.files" :key="item.id" @click="downloadFile(item)">{{ item.name }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<!-- 富文本 -->
|
||||
<template v-if="info.content">
|
||||
<uv-divider />
|
||||
<view>
|
||||
<uv-parse :content="info.content"></uv-parse>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<uv-modal
|
||||
ref="modalRef"
|
||||
title="提示"
|
||||
content="下载成功!是否打开"
|
||||
showCancelButton
|
||||
@confirm="confirm"
|
||||
>
|
||||
</uv-modal>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import CuNavbar from '@/components/cu-navbar/index'
|
||||
import { http } from '@/utils/request'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { ref } from 'vue'
|
||||
import { timeFormat } from '@climblee/uv-ui/libs/function'
|
||||
import { http } from '@/utils/request'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { ref } from 'vue'
|
||||
|
||||
const modalRef = ref(null)
|
||||
const id = ref('')
|
||||
const info = ref({})
|
||||
const tempFile = ref(null)
|
||||
onLoad((options) => {
|
||||
id.value = options.id
|
||||
http.get(`/train/books/${id.value}`).then((res) => {
|
||||
info.value = res
|
||||
})
|
||||
})
|
||||
const id = ref('');
|
||||
const info = ref({})
|
||||
onLoad((options) => {
|
||||
id.value = options.id
|
||||
http.get(`/train/books/${id.value}`).then(res => {
|
||||
info.value = res
|
||||
})
|
||||
})
|
||||
|
||||
const downloadFile = (url) => {
|
||||
const filetype = url.substring(url.lastIndexOf('.') + 1)
|
||||
const whiteFile = ['doc', 'xls', 'ppt', 'pdf', 'docx', 'xlsx', 'pptx']
|
||||
uni.downloadFile({
|
||||
url: url,
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200) {
|
||||
tempFile.value = res
|
||||
|
||||
if (whiteFile.includes(filetype)) {
|
||||
modalRef.value.open()
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: '下载成功',
|
||||
icon: 'none',
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
const confirm = () => {
|
||||
var filePath = encodeURI(tempFile.value.tempFilePath)
|
||||
uni.openDocument({
|
||||
filePath: encodeURI(filePath),
|
||||
// fileType: filetype,
|
||||
showMenu: true,
|
||||
})
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
page {
|
||||
background-color: #fff;
|
||||
}
|
||||
</style>
|
||||
const downloadFile = (item) => {
|
||||
// 文件名
|
||||
const name = item.name
|
||||
// 文件地址
|
||||
const url = item.url
|
||||
}
|
||||
</script>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue