init
21
.gitignore
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
.DS_Store
|
||||
dist
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.idea
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
20
index.html
Normal file
@ -0,0 +1,20 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<script>
|
||||
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||
|
||||
CSS.supports('top: constant(a)'))
|
||||
document.write(
|
||||
'<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
|
||||
(coverSupport ? ', viewport-fit=cover' : '') + '" />')
|
||||
</script>
|
||||
<title></title>
|
||||
<!--preload-links-->
|
||||
<!--app-context-->
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"><!--app-html--></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
68
package.json
Normal file
@ -0,0 +1,68 @@
|
||||
{
|
||||
"name": "uni-preset-vue",
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"dev:custom": "uni -p",
|
||||
"dev:h5": "uni",
|
||||
"dev:h5:ssr": "uni --ssr",
|
||||
"dev:mp-alipay": "uni -p mp-alipay",
|
||||
"dev:mp-baidu": "uni -p mp-baidu",
|
||||
"dev:mp-jd": "uni -p mp-jd",
|
||||
"dev:mp-kuaishou": "uni -p mp-kuaishou",
|
||||
"dev:mp-lark": "uni -p mp-lark",
|
||||
"dev:mp-qq": "uni -p mp-qq",
|
||||
"dev:mp-toutiao": "uni -p mp-toutiao",
|
||||
"dev:mp-weixin": "uni -p mp-weixin",
|
||||
"dev:mp-xhs": "uni -p mp-xhs",
|
||||
"dev:quickapp-webview": "uni -p quickapp-webview",
|
||||
"dev:quickapp-webview-huawei": "uni -p quickapp-webview-huawei",
|
||||
"dev:quickapp-webview-union": "uni -p quickapp-webview-union",
|
||||
"build:custom": "uni build -p",
|
||||
"build:h5": "uni build",
|
||||
"build:h5:ssr": "uni build --ssr",
|
||||
"build:mp-alipay": "uni build -p mp-alipay",
|
||||
"build:mp-baidu": "uni build -p mp-baidu",
|
||||
"build:mp-jd": "uni build -p mp-jd",
|
||||
"build:mp-kuaishou": "uni build -p mp-kuaishou",
|
||||
"build:mp-lark": "uni build -p mp-lark",
|
||||
"build:mp-qq": "uni build -p mp-qq",
|
||||
"build:mp-toutiao": "uni build -p mp-toutiao",
|
||||
"build:mp-weixin": "uni build -p mp-weixin",
|
||||
"build:mp-xhs": "uni build -p mp-xhs",
|
||||
"build:quickapp-webview": "uni build -p quickapp-webview",
|
||||
"build:quickapp-webview-huawei": "uni build -p quickapp-webview-huawei",
|
||||
"build:quickapp-webview-union": "uni build -p quickapp-webview-union",
|
||||
"type-check": "vue-tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@dcloudio/uni-app": "3.0.0-4030620241128001",
|
||||
"@dcloudio/uni-app-harmony": "3.0.0-4030620241128001",
|
||||
"@dcloudio/uni-app-plus": "3.0.0-4030620241128001",
|
||||
"@dcloudio/uni-components": "3.0.0-4030620241128001",
|
||||
"@dcloudio/uni-h5": "3.0.0-4030620241128001",
|
||||
"@dcloudio/uni-mp-alipay": "3.0.0-4030620241128001",
|
||||
"@dcloudio/uni-mp-baidu": "3.0.0-4030620241128001",
|
||||
"@dcloudio/uni-mp-jd": "3.0.0-4030620241128001",
|
||||
"@dcloudio/uni-mp-kuaishou": "3.0.0-4030620241128001",
|
||||
"@dcloudio/uni-mp-lark": "3.0.0-4030620241128001",
|
||||
"@dcloudio/uni-mp-qq": "3.0.0-4030620241128001",
|
||||
"@dcloudio/uni-mp-toutiao": "3.0.0-4030620241128001",
|
||||
"@dcloudio/uni-mp-weixin": "3.0.0-4030620241128001",
|
||||
"@dcloudio/uni-mp-xhs": "3.0.0-4030620241128001",
|
||||
"@dcloudio/uni-quickapp-webview": "3.0.0-4030620241128001",
|
||||
"vue": "^3.4.21",
|
||||
"vue-i18n": "^9.1.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@dcloudio/types": "^3.4.8",
|
||||
"@dcloudio/uni-automator": "3.0.0-4030620241128001",
|
||||
"@dcloudio/uni-cli-shared": "3.0.0-4030620241128001",
|
||||
"@dcloudio/uni-stacktracey": "3.0.0-4030620241128001",
|
||||
"@dcloudio/vite-plugin-uni": "3.0.0-4030620241128001",
|
||||
"@vue/tsconfig": "^0.1.3",
|
||||
"@vue/runtime-core": "^3.4.21",
|
||||
"typescript": "^4.9.4",
|
||||
"vite": "5.2.8",
|
||||
"vue-tsc": "^1.0.24"
|
||||
}
|
||||
}
|
||||
10
shims-uni.d.ts
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
/// <reference types='@dcloudio/types' />
|
||||
import 'vue'
|
||||
|
||||
declare module '@vue/runtime-core' {
|
||||
type Hooks = App.AppInstance & Page.PageInstance;
|
||||
|
||||
interface ComponentCustomOptions extends Hooks {
|
||||
|
||||
}
|
||||
}
|
||||
13
src/App.vue
Normal file
@ -0,0 +1,13 @@
|
||||
<script setup lang="ts">
|
||||
import { onLaunch, onShow, onHide } from "@dcloudio/uni-app";
|
||||
onLaunch(() => {
|
||||
console.log("App Launch");
|
||||
});
|
||||
onShow(() => {
|
||||
console.log("App Show");
|
||||
});
|
||||
onHide(() => {
|
||||
console.log("App Hide");
|
||||
});
|
||||
</script>
|
||||
<style></style>
|
||||
112
src/config.js
Normal file
@ -0,0 +1,112 @@
|
||||
export default {
|
||||
|
||||
// baseUrl: "http://localhost:8088",
|
||||
// picturePath: "http://localhost:8088/DBfile",
|
||||
|
||||
//baseUrl: "http://10.3.1.212:8089",
|
||||
//picturePath: "http://47.92.206.121/DBfile",
|
||||
//baseUrl: "https://zhukangservice.info",
|
||||
baseUrl: "https://zhukangservice.info/StretcherAPI",
|
||||
picturePath: "https://zhukangservice.info/StretcherAPI/DBfile",
|
||||
|
||||
// 数据字典获取URL
|
||||
dataDictionaryUrl: "/API/DataDictionary/getDataDictionary/",
|
||||
defaultHospId: "40288083894a5a3801898bf9db146c99",
|
||||
defaultOpenId: "10000000000000000000000000000001",
|
||||
|
||||
urls: {
|
||||
// 登录
|
||||
//login: "/User/login",
|
||||
login: "/API/stretchertransport/login",
|
||||
// 退出
|
||||
logout: "/API/stretchertransport/logout",
|
||||
|
||||
// 查询微信用户的OpenID
|
||||
queryOpenId: "/API/stretchertransport/weixin/queryOpenId/",
|
||||
|
||||
//查询全部
|
||||
queryMedicineNewTask: "/API/drugtransport/list",
|
||||
|
||||
//获取网格列表
|
||||
getGridFromRedis: "/API/stretchertransport/grid/redis/list",
|
||||
|
||||
// 获取APP滑动广告图片文件路径
|
||||
getAppSlipPicUrl: "/API/stretchertransport/appslippic/get",
|
||||
|
||||
//获取指定运单ID或运单号查找已接单的担架运单完整信息
|
||||
getStretcherTransportTaskById: "/API/stretchertransport/getbyid/",
|
||||
|
||||
//生成订单微信支付二维码
|
||||
getStretcherTransportPayQRcode: "/API/stretchertransport/pay/QRcode/create",
|
||||
|
||||
// 获取担架运送收费标准图片文件路径
|
||||
getStretcherTransportFeeImageUrl: "/API/stretchertransport/fee/pic/get",
|
||||
|
||||
// 获取担架运送收费标准图片文件路径
|
||||
getNewWaybillPromptWaveUrl: "/API/stretchertransport/newwaybillprompt/wav/get",
|
||||
|
||||
//查询担架运送新任务列表
|
||||
queryStretcherNewTask: "/API/stretchertransport/redis/list",
|
||||
|
||||
//查询担架运单列表
|
||||
queryStretcherTask: "/API/stretchertransport/list",
|
||||
|
||||
//从redis中获取指定条件的接单担架运单列表
|
||||
queryStretcherReceiptTask: "/API/stretchertransport/redis/receipt/list",
|
||||
|
||||
//担架运送接单
|
||||
receiptStretcherNewTask: "/API/stretchertransport/receipt",
|
||||
|
||||
//启动担架运单
|
||||
startStretcherTransport: "/API/stretchertransport/starttransport",
|
||||
|
||||
//完工担架运单
|
||||
finishStretcherTransport: "/API/stretchertransport/finish",
|
||||
|
||||
//完工担架运单
|
||||
confirmStretcherPay: "/API/stretchertransport/confirmpay",
|
||||
|
||||
//评价担架运单服务
|
||||
evaluateStretcherTransport: "/API/stretchertransport/evaluate",
|
||||
|
||||
// 药品运送接单
|
||||
receiptMedicineNewTask: "/API/drugtransport/receipt",
|
||||
// 分页查询药品工单
|
||||
pageQueryMedicineTask: "/API/drugtransport/page",
|
||||
// 开始运送
|
||||
startMedicineTransport: "/API/drugtransport/starttransport/",
|
||||
// 完单图片上传
|
||||
unloadPic: "/API/drugtransport/finishpic/upload/",
|
||||
// 完单签字图片上传
|
||||
unloadSign: "/API/drugtransport/signpic/upload/",
|
||||
// 完成要药品运送工单
|
||||
completeMedicineTask: "/API/drugtransport/finish",
|
||||
// 获取指定工单id
|
||||
getMedicineTaskById: "/API/drugtransport/getbyid/",
|
||||
// 取消药品运单
|
||||
cancelMedicineTask: "/API/drugtransport/cancel",
|
||||
// 查询药品类型列表
|
||||
getMedicineType: "/API/drugtransport/getdsordertype",
|
||||
|
||||
// 查询全部待接单标本
|
||||
querySampleNewTask: "/API/specimentransport/specimen/list",
|
||||
// 分页查询待接单标本
|
||||
pageQuerySampleNewTask: "/API/specimentransport/specimen/page",
|
||||
// 查询全部标本运单
|
||||
querySampleTasksheet: "/API/specimentransport/list",
|
||||
// 分页查询标本运单
|
||||
pageQuerySampleTasksheet: "/API/specimentransport/page",
|
||||
// 核验待运送标本
|
||||
receiptSampleNewTask: "/API/specimentransport/verificationSpecimens/",
|
||||
// 创建标本运单
|
||||
createSampleTaskSheet: "/API/specimentransport/create",
|
||||
// 分页查询药品工单
|
||||
pageQueryAcceptedSampleTask: "/API/specimentransport/page",
|
||||
// 获取指定工单id
|
||||
getSampleTaskById: "/API/specimentransport/getbyid/",
|
||||
// 取消标本运单
|
||||
cancelSample: "/API/specimentransport/cancel",
|
||||
// 标本完单图片上传
|
||||
unloadSpecimentPic: "/API/specimentransport/finishpic/upload/",
|
||||
},
|
||||
};
|
||||
8
src/constant/staffRole.js
Normal file
@ -0,0 +1,8 @@
|
||||
// 药品运送
|
||||
export const MEDICINE_CONVEY = new Set(['026', '0261']);
|
||||
|
||||
// 标本运送
|
||||
export const SAMPLE_CONVEY = new Set(['027', '0271']);
|
||||
|
||||
// 担架运送
|
||||
export const STRETCHER_CONVEY = new Set(['028', '0281']);
|
||||
5
src/constant/taskState.js
Normal file
@ -0,0 +1,5 @@
|
||||
export const APPLIED = '01'; // 申请
|
||||
export const DISPATCH = '02' //派工
|
||||
export const ACCEPTED = '03'; // 接单
|
||||
export const FINISHED = '06'; // 完成
|
||||
export const TRANSPORT = '11' // 运送
|
||||
47
src/constant/taskType.js
Normal file
@ -0,0 +1,47 @@
|
||||
const taskTypeMapping = {
|
||||
'药品运送': '031',
|
||||
|
||||
'异类药品运单': '0310',
|
||||
|
||||
'药品交接配送': '0311',
|
||||
|
||||
'药房退药确认': '0312',
|
||||
|
||||
'药房退药驳回': '0313',
|
||||
|
||||
'病区发起退药': '0314',
|
||||
|
||||
'病区撤销退药': '0315',
|
||||
|
||||
'取消药品运单': '0319',
|
||||
|
||||
'标本运送': '032',
|
||||
|
||||
'031': '药品运送',
|
||||
|
||||
'0310': '异类药品运单',
|
||||
|
||||
'0311': '药品交接配送',
|
||||
|
||||
'0312': '药房退药确认',
|
||||
|
||||
'0313': '药房退药驳回',
|
||||
|
||||
'0314': '病区发起退药',
|
||||
|
||||
'0315': '病区撤销退药',
|
||||
|
||||
'0319': '取消药品运单',
|
||||
|
||||
'032': '标本运送',
|
||||
|
||||
MEDICINE_CONVEY: '药品运送',
|
||||
|
||||
SAMPLE_CONVEY: '标本运送',
|
||||
|
||||
MEDICINE_NEW_CONVEY: '药品交接配送',
|
||||
|
||||
MEDICINE_RETURN: '病区发起退药'
|
||||
}
|
||||
|
||||
export default taskTypeMapping
|
||||
8
src/env.d.ts
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
/// <reference types="vite/client" />
|
||||
|
||||
declare module '*.vue' {
|
||||
import { DefineComponent } from 'vue'
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
|
||||
const component: DefineComponent<{}, {}, any>
|
||||
export default component
|
||||
}
|
||||
8
src/main.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { createSSRApp } from "vue";
|
||||
import App from "./App.vue";
|
||||
export function createApp() {
|
||||
const app = createSSRApp(App);
|
||||
return {
|
||||
app,
|
||||
};
|
||||
}
|
||||
73
src/manifest.json
Normal file
@ -0,0 +1,73 @@
|
||||
{
|
||||
"name" : "卓越智慧配送",
|
||||
"appid" : "__UNI__AF09C81",
|
||||
"description" : "",
|
||||
"versionName" : "1.0.0",
|
||||
"versionCode" : "100",
|
||||
"transformPx" : false,
|
||||
/* 5+App特有相关 */
|
||||
"app-plus" : {
|
||||
"usingComponents" : true,
|
||||
"nvueStyleCompiler" : "uni-app",
|
||||
"compilerVersion" : 3,
|
||||
"splashscreen" : {
|
||||
"alwaysShowBeforeRender" : true,
|
||||
"waiting" : true,
|
||||
"autoclose" : true,
|
||||
"delay" : 0
|
||||
},
|
||||
/* 模块配置 */
|
||||
"modules" : {},
|
||||
/* 应用发布信息 */
|
||||
"distribute" : {
|
||||
/* android打包配置 */
|
||||
"android" : {
|
||||
"permissions" : [
|
||||
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
|
||||
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
|
||||
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
|
||||
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
|
||||
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
|
||||
"<uses-feature android:name=\"android.hardware.camera\"/>",
|
||||
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
|
||||
]
|
||||
},
|
||||
/* ios打包配置 */
|
||||
"ios" : {},
|
||||
/* SDK配置 */
|
||||
"sdkConfigs" : {}
|
||||
}
|
||||
},
|
||||
/* 快应用特有相关 */
|
||||
"quickapp" : {},
|
||||
/* 小程序特有相关 */
|
||||
"mp-weixin" : {
|
||||
"appid" : "",
|
||||
"setting" : {
|
||||
"urlCheck" : false
|
||||
},
|
||||
"usingComponents" : true
|
||||
},
|
||||
"mp-alipay" : {
|
||||
"usingComponents" : true
|
||||
},
|
||||
"mp-baidu" : {
|
||||
"usingComponents" : true
|
||||
},
|
||||
"mp-toutiao" : {
|
||||
"usingComponents" : true
|
||||
},
|
||||
"uniStatistics" : {
|
||||
"enable" : false
|
||||
},
|
||||
"vueVersion" : "3",
|
||||
"locale" : "zh-Hans"
|
||||
}
|
||||
85
src/pages.json
Normal file
@ -0,0 +1,85 @@
|
||||
{
|
||||
"pages": [
|
||||
{
|
||||
"path": "pages/index/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "卓越智慧配送"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/login/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "登录"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/stretcher/apply/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "担架运送申请"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/stretcher/apply-agent/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "担架运送代申请"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/message/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "消息"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/task/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "任务"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/mine/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "我的"
|
||||
}
|
||||
}
|
||||
],
|
||||
"globalStyle": {
|
||||
"navigationBarTextStyle": "black",
|
||||
"navigationBarTitleText": "卓越智慧配送",
|
||||
"navigationBarBackgroundColor": "#F8F8F8",
|
||||
"backgroundColor": "#F8F8F8"
|
||||
},
|
||||
"tabBar": {
|
||||
"color": "#666666",
|
||||
"selectedColor": "#007AFF",
|
||||
"backgroundColor": "#ffffff",
|
||||
"borderStyle": "black",
|
||||
"height": "64px",
|
||||
"list": [
|
||||
{
|
||||
"pagePath": "pages/index/index",
|
||||
"text": "首页",
|
||||
"iconPath": "static/icons/home.png",
|
||||
"selectedIconPath": "static/icons/home.png"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/message/index",
|
||||
"text": "消息",
|
||||
"iconPath": "static/icons/messages.png",
|
||||
"selectedIconPath": "static/icons/messages.png"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/task/index",
|
||||
"text": "任务",
|
||||
"iconPath": "static/icons/tasks.png",
|
||||
"selectedIconPath": "static/icons/tasks.png"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/mine/index",
|
||||
"text": "我的",
|
||||
"iconPath": "static/icons/profile.png",
|
||||
"selectedIconPath": "static/icons/profile.png"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
333
src/pages/index/index.vue
Normal file
@ -0,0 +1,333 @@
|
||||
<template>
|
||||
<scroll-view scroll-y class="page">
|
||||
<!-- 顶部欢迎与Logo -->
|
||||
<view class="header card">
|
||||
<view class="header-left">
|
||||
<text class="hello">您好,欢迎使用</text>
|
||||
<text class="app-name">卓越智慧配送</text>
|
||||
<text class="sub">高效 · 可视 · 可追溯</text>
|
||||
</view>
|
||||
<view class="header-right">
|
||||
<image class="logo" src="/static/logo.png" mode="aspectFit" />
|
||||
<button v-if="!isLoggedIn" class="login-btn" @tap="goLogin">登录</button>
|
||||
<view v-else class="user-box">
|
||||
<text class="user-name">{{ staff?.name || '已登录' }}</text>
|
||||
<button class="logout-btn" @tap="logout">退出</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 顶部滑动轮播图 -->
|
||||
<view class="swiper-card card">
|
||||
<swiper
|
||||
class="swiper"
|
||||
:current="swiperIndex"
|
||||
@change="changeSwiper"
|
||||
previous-margin="50rpx"
|
||||
next-margin="50rpx"
|
||||
:indicator-dots="true"
|
||||
indicator-color="rgba(51,51,51,0.25)"
|
||||
indicator-active-color="#4b7aff"
|
||||
autoplay
|
||||
interval="3000"
|
||||
circular
|
||||
>
|
||||
<swiper-item v-for="(img, idx) in swiperImgs" :key="idx">
|
||||
<view class="swiper-item-wrap" :class="{ 'swiper-scale': swiperIndex !== idx }">
|
||||
<image class="swiper-img" :src="img" mode="aspectFill" />
|
||||
</view>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
</view>
|
||||
|
||||
<!-- 主操作 -->
|
||||
<view class="ops">
|
||||
<view class="op-btn" v-show="isPatient || isDoctor" @tap="goStretcherApply">
|
||||
<image class="op-icon" src="/static/icons/stretcher-loan.png" />
|
||||
<text class="op-text">担架申请</text>
|
||||
</view>
|
||||
<view class="op-btn" v-show="isPatient || isDoctor || isRider" @tap="goStretcherApplyFor">
|
||||
<image class="op-icon" src="/static/icons/stretcher-temp-loan.png" />
|
||||
<text class="op-text">担架代申请</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 资产管理:可折叠卡片,明确从属关系 -->
|
||||
<view class="section-card card">
|
||||
<view class="section-header" @tap="toggleAsset">
|
||||
<view class="section-left">
|
||||
<image class="section-icon" src="/static/icons/asset-management.png" />
|
||||
<view class="section-text">
|
||||
<text class="section-title-text">资产管理</text>
|
||||
<text class="section-sub">固定资产、借用、盘点、扫码、易耗品</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="chevron" :class="{ open: assetOpen }"></view>
|
||||
</view>
|
||||
<view class="asset-grid" v-show="assetOpen">
|
||||
<view class="grid-item" v-for="item in assetItems" :key="item.key" @tap="handleAsset(item.key)">
|
||||
<image class="grid-icon" :src="item.icon" />
|
||||
<text class="grid-text">{{ item.text }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 公告:担架收费标准 -->
|
||||
<view class="section-title">
|
||||
<text>公告 · 担架收费标准</text>
|
||||
</view>
|
||||
<view class="notice card" @tap="previewCharge">
|
||||
<image class="notice-img" src="/static/stretcher-charge-standard.png" mode="widthFix" />
|
||||
<text class="notice-tip">点击可放大查看</text>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue'
|
||||
// @ts-ignore JS模块无类型声明
|
||||
import queryService from '@/service/queryService.js'
|
||||
// @ts-ignore JS模块无类型声明
|
||||
import config from '@/config.js'
|
||||
// @ts-ignore JS模块无类型声明
|
||||
import * as staffRole from '@/constant/staffRole.js'
|
||||
// @ts-ignore JS模块无类型声明
|
||||
import util from '@/utils/util.js'
|
||||
// 资产管理展开状态
|
||||
const assetOpen = ref(true)
|
||||
|
||||
// 资产管理宫格项
|
||||
const assetItems = [
|
||||
{ key: 'fixed', text: '固定资产', icon: '/static/icons/fixed-assets.png' },
|
||||
{ key: 'mine', text: '我的借用', icon: '/static/icons/my-loans.png' },
|
||||
{ key: 'inventory', text: '资产盘点', icon: '/static/icons/asset-inventory.png' },
|
||||
{ key: 'scan', text: '扫码查看信息', icon: '/static/icons/scan-to-view-info.png' },
|
||||
{ key: 'plan', text: '易耗品领用计划', icon: '/static/icons/consumables-plan.png' },
|
||||
{ key: 'consumable', text: '易耗品盘点', icon: '/static/icons/consumables-inventory.png' }
|
||||
]
|
||||
|
||||
// 轮播图状态
|
||||
const swiperIndex = ref(0)
|
||||
const swiperImgs = ref<string[]>([
|
||||
'/static/logo.png',
|
||||
'/static/logo.png',
|
||||
'/static/logo.png'
|
||||
])
|
||||
|
||||
function changeSwiper(e: any) {
|
||||
swiperIndex.value = e.detail.current || 0
|
||||
}
|
||||
|
||||
async function loadSwiperImages() {
|
||||
try {
|
||||
const res = await queryService.getAppSlipPicUrl()
|
||||
if (res?.data?.code === 0) {
|
||||
const dataStr: string = res?.data?.data || ''
|
||||
const pics = dataStr ? dataStr.split(';').filter(Boolean) : []
|
||||
if (pics.length >= 3) {
|
||||
// 取最后三张,保持与老页面一致的顺序
|
||||
const last3 = pics.slice(-3)
|
||||
swiperImgs.value = last3.map(p => `${config.picturePath}${p}`)
|
||||
} else if (pics.length > 0) {
|
||||
// 不足3张时重复填充
|
||||
const filled: string[] = []
|
||||
while (filled.length < 3) {
|
||||
const next = pics[filled.length % pics.length]
|
||||
filled.push(`${config.picturePath}${next}`)
|
||||
}
|
||||
swiperImgs.value = filled
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
// 出错则保留默认占位图
|
||||
console.warn('加载轮播图失败:', err)
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadSwiperImages()
|
||||
syncLoginState()
|
||||
})
|
||||
|
||||
// 登录与角色态
|
||||
const isLoggedIn = ref(false)
|
||||
const staff = ref<any | null>(null)
|
||||
const isWeixin = ref(false)
|
||||
const isPatient = ref(true)
|
||||
const isDoctor = ref(false)
|
||||
const isRider = ref(false)
|
||||
|
||||
function syncLoginState() {
|
||||
staff.value = uni.getStorageSync('staff') || null
|
||||
isLoggedIn.value = !!staff.value
|
||||
// 平台
|
||||
// @ts-ignore
|
||||
isWeixin.value = process?.env?.VUE_APP_PLATFORM === 'mp-weixin'
|
||||
// 角色判定(简化:有担架运送角色则认为骑手,否则当作患者/医生)
|
||||
if (staff.value && Array.isArray(staff.value.role_ids)) {
|
||||
const set = staffRole.STRETCHER_CONVEY
|
||||
const hasRider = staff.value.role_ids.some((r: string) => set.has(r))
|
||||
isRider.value = hasRider
|
||||
isPatient.value = !hasRider
|
||||
isDoctor.value = !hasRider
|
||||
} else {
|
||||
isRider.value = false
|
||||
isPatient.value = true
|
||||
isDoctor.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function goLogin() {
|
||||
uni.navigateTo({ url: '/pages/login/index' })
|
||||
}
|
||||
function logout() {
|
||||
uni.setStorageSync('staff', null)
|
||||
uni.setStorageSync('token', null)
|
||||
isLoggedIn.value = false
|
||||
staff.value = null
|
||||
isRider.value = false
|
||||
isPatient.value = true
|
||||
isDoctor.value = false
|
||||
uni.showToast({ title: '已退出登录', icon: 'none' })
|
||||
}
|
||||
|
||||
// 导航占位:根据后续页面路由替换
|
||||
function goStretcherApply() {
|
||||
uni.navigateTo({ url: '/pages/stretcher/apply/index' })
|
||||
}
|
||||
function goStretcherApplyFor() {
|
||||
uni.navigateTo({ url: '/pages/stretcher/apply-agent/index' })
|
||||
}
|
||||
function toggleAsset() {
|
||||
assetOpen.value = !assetOpen.value
|
||||
}
|
||||
function handleAsset(key: string) {
|
||||
uni.showToast({ title: `打开:${assetItems.find(i => i.key === key)?.text}`, icon: 'none' })
|
||||
}
|
||||
function previewCharge() {
|
||||
uni.previewImage({
|
||||
urls: ['/static/stretcher-charge-standard.png']
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page {
|
||||
min-height: 100vh;
|
||||
background: #f5f7fb;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: #fff;
|
||||
border-radius: 20rpx;
|
||||
box-shadow: 0 8rpx 24rpx rgba(0,0,0,0.06);
|
||||
}
|
||||
|
||||
.header {
|
||||
margin: 32rpx;
|
||||
padding: 32rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.header-left {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10rpx;
|
||||
}
|
||||
.hello { color: #7a7a7a; font-size: 26rpx; }
|
||||
.app-name { color: #111; font-size: 40rpx; font-weight: 600; }
|
||||
.sub { color: #9a9aa0; font-size: 24rpx; }
|
||||
.logo { width: 120rpx; height: 120rpx; }
|
||||
.header-right { display: flex; align-items: center; gap: 12rpx; }
|
||||
.login-btn, .logout-btn { padding: 10rpx 20rpx; background: #3a5ddd; color: #fff; border-radius: 10rpx; font-size: 24rpx; }
|
||||
.logout-btn { background: #ef5350; }
|
||||
.user-box { display: flex; align-items: center; gap: 12rpx; }
|
||||
.user-name { font-size: 24rpx; color: #333; }
|
||||
|
||||
/* 轮播卡片 */
|
||||
.swiper-card { margin: 0 32rpx 24rpx; padding: 12rpx; }
|
||||
.swiper { width: 100%; height: 300rpx; }
|
||||
.swiper-item-wrap {
|
||||
width: 100%; height: 100%; border-radius: 24rpx; overflow: hidden;
|
||||
transition: transform 0.25s ease, box-shadow 0.25s ease;
|
||||
box-shadow: 0 6rpx 18rpx rgba(0,0,0,0.08);
|
||||
}
|
||||
.swiper-scale { transform: scale(0.95); box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.06); }
|
||||
.swiper-img { width: 100%; height: 100%; display: block; }
|
||||
|
||||
.ops {
|
||||
margin: 0 32rpx 24rpx;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 24rpx;
|
||||
}
|
||||
.op-btn {
|
||||
background: linear-gradient(180deg, #f9fbff 0%, #ffffff 100%);
|
||||
border-radius: 20rpx;
|
||||
padding: 28rpx 12rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 12rpx;
|
||||
box-shadow: 0 6rpx 16rpx rgba(0,0,0,0.04);
|
||||
}
|
||||
.op-icon { width: 80rpx; height: 80rpx; }
|
||||
.op-text { font-size: 26rpx; color: #333; }
|
||||
|
||||
.section-card { margin: 0 32rpx 24rpx; }
|
||||
.section-header {
|
||||
padding: 24rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.section-left { display: flex; align-items: center; gap: 16rpx; }
|
||||
.section-icon { width: 48rpx; height: 48rpx; }
|
||||
.section-text { display: flex; flex-direction: column; }
|
||||
.section-title-text { font-size: 30rpx; color: #222; font-weight: 600; }
|
||||
.section-sub { font-size: 22rpx; color: #9a9aa0; }
|
||||
.chevron {
|
||||
width: 24rpx;
|
||||
height: 24rpx;
|
||||
border-right: 4rpx solid #b5b6ba;
|
||||
border-bottom: 4rpx solid #b5b6ba;
|
||||
transform: rotate(45deg);
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
.chevron.open { transform: rotate(135deg); }
|
||||
|
||||
.asset-grid {
|
||||
padding: 0 24rpx 24rpx;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 20rpx;
|
||||
}
|
||||
.grid-item {
|
||||
background: #fafbff;
|
||||
border-radius: 16rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 24rpx 12rpx;
|
||||
gap: 10rpx;
|
||||
}
|
||||
.grid-icon { width: 64rpx; height: 64rpx; }
|
||||
.grid-text { font-size: 24rpx; color: #444; text-align: center; line-height: 1.4; }
|
||||
|
||||
.section-title {
|
||||
padding: 0 32rpx 12rpx;
|
||||
color: #666;
|
||||
font-size: 26rpx;
|
||||
}
|
||||
|
||||
.notice {
|
||||
margin: 0 32rpx 32rpx;
|
||||
padding: 20rpx;
|
||||
text-align: center;
|
||||
}
|
||||
.notice-img { width: 100%; border-radius: 12rpx; }
|
||||
.notice-tip { display: block; color: #9a9aa0; font-size: 22rpx; margin-top: 12rpx; }
|
||||
</style>
|
||||
128
src/pages/login/index.vue
Normal file
@ -0,0 +1,128 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<view class="card header">
|
||||
<text class="title">账号登录</text>
|
||||
<text class="sub">系统仅供内部使用,请使用内部账号密码登录</text>
|
||||
</view>
|
||||
|
||||
<view class="card form">
|
||||
<view class="field">
|
||||
<text class="label">用户名/电话</text>
|
||||
<input class="input" v-model="loginRequest.username" placeholder="请输入用户名或电话" :focus="usernameFocus" />
|
||||
</view>
|
||||
<view class="field">
|
||||
<text class="label">密码</text>
|
||||
<input class="input" v-model="loginRequest.password" placeholder="请输入密码" password />
|
||||
</view>
|
||||
<view class="actions">
|
||||
<button class="btn primary" @tap="onLogin">登录</button>
|
||||
<button class="btn" @tap="onCancel">取消</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { reactive, ref, onMounted } from 'vue'
|
||||
// @ts-ignore
|
||||
import md5 from '@/utils/md5.js'
|
||||
// @ts-ignore
|
||||
import util from '@/utils/util.js'
|
||||
// @ts-ignore
|
||||
import config from '@/config.js'
|
||||
|
||||
const usernameFocus = ref(true)
|
||||
const loginRequest = reactive({
|
||||
username: '',
|
||||
password: '',
|
||||
typecode: '007'
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
// 读取本地缓存的用户名和密码
|
||||
const userName = uni.getStorageSync('userName')
|
||||
const userPsw = uni.getStorageSync('userPsw')
|
||||
if (userName && userPsw) {
|
||||
loginRequest.username = userName
|
||||
loginRequest.password = userPsw
|
||||
}
|
||||
})
|
||||
|
||||
async function onLogin() {
|
||||
if (!loginRequest.username) {
|
||||
uni.showToast({ title: '用户名不能为空', icon: 'none' })
|
||||
return
|
||||
}
|
||||
if (!loginRequest.password) {
|
||||
uni.showToast({ title: '密码不能为空', icon: 'none' })
|
||||
return
|
||||
}
|
||||
// 本地保存登录信息
|
||||
uni.setStorageSync('userName', loginRequest.username)
|
||||
uni.setStorageSync('userPsw', loginRequest.password)
|
||||
|
||||
uni.showToast({ title: '登录中', icon: 'loading', duration: 2000 })
|
||||
// 清空旧身份
|
||||
uni.setStorageSync('staff', null)
|
||||
try {
|
||||
const res = await util.request({
|
||||
url: config.urls.login,
|
||||
method: 'POST',
|
||||
data: {
|
||||
username: loginRequest.username,
|
||||
password: md5.hexMD5(loginRequest.username + loginRequest.password),
|
||||
typecode: loginRequest.typecode
|
||||
}
|
||||
})
|
||||
if (res?.data?.code === 0) {
|
||||
const staff = res.data.data.userLoginInfo
|
||||
// 兼容旧逻辑,附加 role 别名
|
||||
uni.setStorageSync('staff', { ...staff, role: staff.role_ids })
|
||||
uni.setStorageSync('token', res.data.data.token)
|
||||
uni.showToast({ title: '登录成功', icon: 'success', duration: 1000 })
|
||||
// 跳转到首页(tabBar)
|
||||
setTimeout(() => {
|
||||
uni.switchTab({ url: '/pages/index/index' })
|
||||
}, 300)
|
||||
} else {
|
||||
uni.showToast({ title: res?.data?.msg || '登录失败', icon: 'error', duration: 3000 })
|
||||
}
|
||||
} catch (err:any) {
|
||||
// util.request 已有统一错误提示
|
||||
console.warn('login error', err)
|
||||
}
|
||||
}
|
||||
|
||||
function onCancel() {
|
||||
uni.switchTab({ url: '/pages/index/index' })
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page {
|
||||
min-height: 100vh;
|
||||
background: #f5f7fb;
|
||||
padding: 24rpx 0 40rpx;
|
||||
}
|
||||
.card {
|
||||
background: #fff;
|
||||
border-radius: 20rpx;
|
||||
margin: 0 32rpx 24rpx;
|
||||
box-shadow: 0 8rpx 24rpx rgba(0,0,0,0.06);
|
||||
}
|
||||
.header { padding: 28rpx 24rpx; }
|
||||
.title { font-size: 36rpx; color: #111; font-weight: 600; }
|
||||
.sub { display: block; margin-top: 8rpx; font-size: 24rpx; color: #888; }
|
||||
|
||||
.form { padding: 20rpx 24rpx; }
|
||||
.field { margin-bottom: 20rpx; }
|
||||
.label { display: block; color: #666; font-size: 26rpx; margin-bottom: 10rpx; }
|
||||
.input {
|
||||
width: 100%; height: 80rpx; padding: 0 20rpx;
|
||||
border: 2rpx solid #e6e8ef; border-radius: 12rpx; background: #fcfdff;
|
||||
}
|
||||
.actions { display: flex; gap: 20rpx; margin-top: 8rpx; }
|
||||
.btn { flex: 1; height: 84rpx; border-radius: 14rpx; background: #eef2ff; color: #3a5ddd; }
|
||||
.btn.primary { background: #3a5ddd; color: #fff; }
|
||||
</style>
|
||||
32
src/pages/message/index.vue
Normal file
@ -0,0 +1,32 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<view class="empty">
|
||||
<image src="/static/icons/messages.png" class="icon" />
|
||||
<text>暂无消息</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page {
|
||||
min-height: 100vh;
|
||||
background: #f7f8fa;
|
||||
}
|
||||
.empty {
|
||||
height: 60vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #999;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
.icon {
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
</style>
|
||||
32
src/pages/messages/index.vue
Normal file
@ -0,0 +1,32 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<view class="empty">
|
||||
<image src="/static/icons/messages.png" class="icon" />
|
||||
<text>暂无消息</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page {
|
||||
min-height: 100vh;
|
||||
background: #f7f8fa;
|
||||
}
|
||||
.empty {
|
||||
height: 60vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #999;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
.icon {
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
</style>
|
||||
75
src/pages/mine/index.vue
Normal file
@ -0,0 +1,75 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<view class="profile">
|
||||
<image class="avatar" src="/static/logo.png" />
|
||||
<view class="info" v-if="!isLoggedIn">
|
||||
<text class="name">未登录</text>
|
||||
<text class="sub" @tap="goLogin">点击登录/注册</text>
|
||||
</view>
|
||||
<view class="info" v-else>
|
||||
<text class="name">{{ staff?.name || '已登录' }}</text>
|
||||
<text class="sub">工号:{{ staff?.job_no || '-' }}</text>
|
||||
<view class="actions">
|
||||
<button class="btn" @tap="logout">退出登录</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue'
|
||||
|
||||
const isLoggedIn = ref(false)
|
||||
const staff = ref<any | null>(null)
|
||||
|
||||
function sync() {
|
||||
staff.value = uni.getStorageSync('staff') || null
|
||||
isLoggedIn.value = !!staff.value
|
||||
}
|
||||
|
||||
function goLogin() {
|
||||
uni.navigateTo({ url: '/pages/login/index' })
|
||||
}
|
||||
function logout() {
|
||||
uni.setStorageSync('staff', null)
|
||||
uni.setStorageSync('token', null)
|
||||
sync()
|
||||
uni.showToast({ title: '已退出登录', icon: 'none' })
|
||||
}
|
||||
|
||||
onMounted(sync)
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page {
|
||||
min-height: 100vh;
|
||||
background: #f7f8fa;
|
||||
}
|
||||
.profile {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 24rpx;
|
||||
padding: 40rpx 32rpx;
|
||||
background: #fff;
|
||||
}
|
||||
.avatar {
|
||||
width: 96rpx;
|
||||
height: 96rpx;
|
||||
border-radius: 50%;
|
||||
}
|
||||
.info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.name {
|
||||
font-size: 32rpx;
|
||||
color: #333;
|
||||
}
|
||||
.sub {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
.actions { margin-top: 16rpx; }
|
||||
.btn { padding: 12rpx 20rpx; background: #ef5350; color: #fff; border-radius: 10rpx; font-size: 24rpx; }
|
||||
</style>
|
||||
640
src/pages/stretcher/apply-agent/index.vue
Normal file
@ -0,0 +1,640 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<view class="card">
|
||||
<view class="title">担架运送代申请</view>
|
||||
|
||||
<!-- 代申报科室 -->
|
||||
<view class="form-item">
|
||||
<text class="label required">代申报科室</text>
|
||||
<picker mode="multiSelector" :range="needDeptMultiRange"
|
||||
:value="needDeptMultiValue" @columnchange="onNeedDeptColumnChange"
|
||||
@change="onNeedDeptChange">
|
||||
<view class="picker-value"
|
||||
:class="{ placeholder: !form.needcontactDept }">
|
||||
{{ currentNeedDeptName || '请选择代申报科室' }}
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
|
||||
<!-- 代申报人 -->
|
||||
<view class="form-item">
|
||||
<text class="label required">代申报人</text>
|
||||
<input class="input" type="text" v-model="form.needcontact"
|
||||
placeholder="请输入代申报人" />
|
||||
</view>
|
||||
|
||||
<!-- 代申报电话 -->
|
||||
<view class="form-item">
|
||||
<text class="label required">代申报电话</text>
|
||||
<input class="input" type="number" maxlength="20"
|
||||
v-model="form.needcontactTel" placeholder="请输入代申报电话" />
|
||||
</view>
|
||||
|
||||
<!-- 申报科室 -->
|
||||
<view class="form-item">
|
||||
<text class="label required">申报科室</text>
|
||||
<picker mode="multiSelector" :range="decDeptMultiRange"
|
||||
:value="decDeptMultiValue" @columnchange="onDecDeptColumnChange"
|
||||
@change="onDecDeptChange">
|
||||
<view class="picker-value" :class="{ placeholder: !form.decDept }">
|
||||
{{ currentDecDeptName || '请选择所在科室' }}
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
|
||||
<!-- 申报床号 -->
|
||||
<view class="form-item">
|
||||
<text class="label required">申报床号</text>
|
||||
<input class="input" type="text" v-model="form.decBedNo"
|
||||
placeholder="请输入床号" />
|
||||
</view>
|
||||
|
||||
<!-- 申报手机 -->
|
||||
<view class="form-item">
|
||||
<text class="label required">申报手机</text>
|
||||
<input class="input" type="number" maxlength="11" v-model="form.decTel"
|
||||
placeholder="请输入手机号码" />
|
||||
</view>
|
||||
|
||||
<!-- 运送工具 -->
|
||||
<view class="form-item">
|
||||
<text class="label required">运送工具</text>
|
||||
<picker mode="selector" :range="toolNames" @change="onPickTool">
|
||||
<view class="picker-value"
|
||||
:class="{ placeholder: !form.carryingtools }">
|
||||
{{ currentToolName || '请选择所需运送工具' }}
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
|
||||
<!-- 工具数量 -->
|
||||
<view class="form-item">
|
||||
<text class="label required">工具数量</text>
|
||||
<input class="input" type="number"
|
||||
v-model.number="form.carryingtoolsCount" placeholder="请输入工具数量" />
|
||||
</view>
|
||||
|
||||
<!-- 承运人数量 -->
|
||||
<view class="form-item">
|
||||
<text class="label required">承运人数量</text>
|
||||
<input class="input" type="number" v-model.number="form.outnumber"
|
||||
placeholder="请输入所需运送人员数量" />
|
||||
</view>
|
||||
|
||||
<!-- 是否预约 -->
|
||||
<view class="form-item">
|
||||
<text class="label">是否预约</text>
|
||||
<switch :checked="form.isOrdered" @change="onToggleOrdered" />
|
||||
</view>
|
||||
|
||||
<!-- 预约时间 -->
|
||||
<view v-if="form.isOrdered" class="form-item">
|
||||
<text class="label">预约时间</text>
|
||||
<picker mode="time" :value="form.orderedDatetime || ''"
|
||||
@change="onPickTime">
|
||||
<view class="picker-value"
|
||||
:class="{ placeholder: !form.orderedDatetime }">
|
||||
{{ form.orderedDatetime || '请选择' }}
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
|
||||
<!-- 支付方式(保留但界面可隐藏,按需要开启)-->
|
||||
<view class="form-item" v-if="showPayment">
|
||||
<text class="label required">支付方式</text>
|
||||
<picker mode="selector" :range="payNames" @change="onPickPay">
|
||||
<view class="picker-value"
|
||||
:class="{ placeholder: !form.paymentMethod }">
|
||||
{{ currentPayName || '请选择支付方式' }}
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
|
||||
<view class="btns">
|
||||
<button class="btn outline" :disabled="!isCancelSubmit"
|
||||
@tap="onCancelAgent">取消申请</button>
|
||||
<button class="btn primary" :disabled="!isSubmit"
|
||||
@tap="onSubmit">申请</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 等待接单浮层 -->
|
||||
<view v-if="isShowProgress" class="overlay">
|
||||
<view class="overlay-card">
|
||||
<text class="overlay-title">等待骑手接单</text>
|
||||
<text class="overlay-time">{{ countdownText }}</text>
|
||||
<button class="btn outline" @tap="onCancelAgent">取消申请</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, onUnmounted, reactive, ref } from 'vue'
|
||||
// @ts-ignore
|
||||
import util from '@/utils/util.js'
|
||||
// @ts-ignore
|
||||
import queryService from '@/service/queryService.js'
|
||||
// @ts-ignore
|
||||
import getService from '@/service/getService.js'
|
||||
// @ts-ignore
|
||||
import config from '@/config.js'
|
||||
|
||||
const showPayment = ref(true) // 如不需要可置为 false
|
||||
|
||||
const form = reactive({
|
||||
needcontactDept: null as any,
|
||||
needcontactDepts: null as any,
|
||||
needcontact: null as any,
|
||||
needcontactTel: null as any,
|
||||
decChannel: null as any,
|
||||
decDept: null as any,
|
||||
decDepts: null as any,
|
||||
decBedNo: null as any,
|
||||
decTel: null as any,
|
||||
carryingtools: null as any,
|
||||
carryingtoolsCount: 1,
|
||||
outnumber: 1,
|
||||
openid: null as any,
|
||||
isOrdered: false,
|
||||
orderedDatetime: null as any,
|
||||
paymentMethod: '01'
|
||||
})
|
||||
|
||||
const formData = reactive({
|
||||
decDeptDatas: [] as any[],
|
||||
needcontactDeptDatas: [] as any[],
|
||||
carryingtoolsDatas: [] as any[],
|
||||
paymentMethodDatas: [] as any[]
|
||||
})
|
||||
|
||||
// UI & 轮询
|
||||
const isSubmit = ref(true)
|
||||
const isCancelSubmit = ref(false)
|
||||
const isShowProgress = ref(false)
|
||||
const list = ref<any[] | null>(null)
|
||||
|
||||
const COUNTDOWN_MAX = 5 * 60 * 1000
|
||||
const countdown = ref(COUNTDOWN_MAX)
|
||||
let pollTimer: any = null
|
||||
let cdTimer: any = null
|
||||
|
||||
// 代申报科室(两列)
|
||||
const needDeptParents = ref<any[]>([])
|
||||
const needDeptChildrenMap = ref<Record<string, any[]>>({})
|
||||
const needDeptMultiRange = ref<string[][]>([[], []])
|
||||
const needDeptMultiValue = ref<number[]>([0, 0])
|
||||
|
||||
// 申报科室(两列)
|
||||
const decDeptParents = ref<any[]>([])
|
||||
const decDeptChildrenMap = ref<Record<string, any[]>>({})
|
||||
const decDeptMultiRange = ref<string[][]>([[], []])
|
||||
const decDeptMultiValue = ref<number[]>([0, 0])
|
||||
|
||||
const toolNames = computed(() => formData.carryingtoolsDatas.map(d => d.name || d.label || ''))
|
||||
const payNames = computed(() => formData.paymentMethodDatas.map(d => d.name || d.label || ''))
|
||||
|
||||
const currentNeedDeptName = computed(() => {
|
||||
if (!form.needcontactDept) return ''
|
||||
for (const p of needDeptParents.value) {
|
||||
const children = needDeptChildrenMap.value[p.id] || []
|
||||
const c = children.find((it: any) => it.id === form.needcontactDept)
|
||||
if (c) return c.gridFullname || c.gridName || c.name || c.label || ''
|
||||
}
|
||||
const p = needDeptParents.value.find((it: any) => it.id === form.needcontactDept)
|
||||
return p ? (p.gridFullname || p.gridName || p.name || p.label || '') : ''
|
||||
})
|
||||
|
||||
const currentDecDeptName = computed(() => {
|
||||
if (!form.decDept) return ''
|
||||
for (const p of decDeptParents.value) {
|
||||
const children = decDeptChildrenMap.value[p.id] || []
|
||||
const c = children.find((it: any) => it.id === form.decDept)
|
||||
if (c) return c.gridFullname || c.gridName || c.name || c.label || ''
|
||||
}
|
||||
const p = decDeptParents.value.find((it: any) => it.id === form.decDept)
|
||||
return p ? (p.gridFullname || p.gridName || p.name || p.label || '') : ''
|
||||
})
|
||||
|
||||
const currentToolName = computed(() => {
|
||||
const found = formData.carryingtoolsDatas.find(d => d.id === form.carryingtools)
|
||||
return found ? (found.name || found.label) : ''
|
||||
})
|
||||
const currentPayName = computed(() => {
|
||||
const found = formData.paymentMethodDatas.find(d => d.id === form.paymentMethod)
|
||||
return found ? (found.name || found.label) : ''
|
||||
})
|
||||
|
||||
const countdownText = computed(() => {
|
||||
const total = Math.max(0, countdown.value)
|
||||
const h = Math.floor(total / 3600000)
|
||||
const m = Math.floor((total % 3600000) / 60000)
|
||||
const s = Math.floor((total % 60000) / 1000)
|
||||
const pad = (n: number) => String(n).padStart(2, '0')
|
||||
return `${pad(h)}:${pad(m)}:${pad(s)}`
|
||||
})
|
||||
|
||||
function onNeedDeptColumnChange(e: any) {
|
||||
const { column, value } = e.detail
|
||||
if (column === 0) {
|
||||
needDeptMultiValue.value[0] = value
|
||||
const parent = needDeptParents.value[value]
|
||||
const children = (parent && needDeptChildrenMap.value[parent.id]) || []
|
||||
needDeptMultiRange.value[1] = children.length > 0
|
||||
? children.map((c: any) => c.gridFullname || c.gridName || c.name || c.label || '')
|
||||
: ['- 无子项 -']
|
||||
needDeptMultiValue.value[1] = 0
|
||||
}
|
||||
}
|
||||
function onNeedDeptChange(e: any) {
|
||||
const [pi, ci] = e.detail.value as number[]
|
||||
const parent = needDeptParents.value[pi]
|
||||
const children = (parent && needDeptChildrenMap.value[parent.id]) || []
|
||||
if (children.length > 0) {
|
||||
const child = children[ci]
|
||||
if (!child) return
|
||||
form.needcontactDept = child.id
|
||||
form.needcontactDepts = ['', child.id]
|
||||
} else {
|
||||
if (!parent) return
|
||||
form.needcontactDept = parent.id
|
||||
form.needcontactDepts = ['', parent.id]
|
||||
}
|
||||
}
|
||||
|
||||
function onDecDeptColumnChange(e: any) {
|
||||
const { column, value } = e.detail
|
||||
if (column === 0) {
|
||||
decDeptMultiValue.value[0] = value
|
||||
const parent = decDeptParents.value[value]
|
||||
const children = (parent && decDeptChildrenMap.value[parent.id]) || []
|
||||
decDeptMultiRange.value[1] = children.length > 0
|
||||
? children.map((c: any) => c.gridFullname || c.gridName || c.name || c.label || '')
|
||||
: ['- 无子项 -']
|
||||
decDeptMultiValue.value[1] = 0
|
||||
}
|
||||
}
|
||||
function onDecDeptChange(e: any) {
|
||||
const [pi, ci] = e.detail.value as number[]
|
||||
const parent = decDeptParents.value[pi]
|
||||
const children = (parent && decDeptChildrenMap.value[parent.id]) || []
|
||||
if (children.length > 0) {
|
||||
const child = children[ci]
|
||||
if (!child) return
|
||||
form.decDept = child.id
|
||||
form.decDepts = ['', child.id]
|
||||
} else {
|
||||
if (!parent) return
|
||||
form.decDept = parent.id
|
||||
form.decDepts = ['', parent.id]
|
||||
}
|
||||
}
|
||||
|
||||
function onPickTool(e: any) {
|
||||
const idx = Number(e.detail.value)
|
||||
const item = formData.carryingtoolsDatas[idx]
|
||||
if (!item) return
|
||||
form.carryingtools = item.id
|
||||
}
|
||||
function onPickPay(e: any) {
|
||||
const idx = Number(e.detail.value)
|
||||
const item = formData.paymentMethodDatas[idx]
|
||||
if (!item) return
|
||||
form.paymentMethod = item.id
|
||||
}
|
||||
function onPickTime(e: any) {
|
||||
form.orderedDatetime = e.detail.value
|
||||
}
|
||||
function onToggleOrdered(e: any) {
|
||||
form.isOrdered = !!e.detail.value
|
||||
}
|
||||
|
||||
function validate(): boolean {
|
||||
if (!form.needcontact) { uni.showToast({ title: '代申报人不能为空', icon: 'none' }); return false }
|
||||
if (!form.needcontactTel) { uni.showToast({ title: '代申报电话不能为空', icon: 'none' }); return false }
|
||||
if (!form.needcontactDept && (!form.needcontactDepts || (Array.isArray(form.needcontactDepts) && form.needcontactDepts.length <= 1))) {
|
||||
uni.showToast({ title: '代申报科室不能为空', icon: 'none' }); return false
|
||||
}
|
||||
if (!form.decDept && (!form.decDepts || (Array.isArray(form.decDepts) && form.decDepts.length <= 1))) {
|
||||
uni.showToast({ title: '申报科室不能为空', icon: 'none' }); return false
|
||||
}
|
||||
if (!form.decBedNo) { uni.showToast({ title: '床号不能为空', icon: 'none' }); return false }
|
||||
if (!form.decTel) { uni.showToast({ title: '申报电话不能为空', icon: 'none' }); return false }
|
||||
if (!form.carryingtools) { uni.showToast({ title: '运送工具不能为空', icon: 'none' }); return false }
|
||||
if (!form.carryingtoolsCount) { uni.showToast({ title: '工具数量不能为空', icon: 'none' }); return false }
|
||||
if (!form.outnumber) { uni.showToast({ title: '所需运送人员数量不能为空', icon: 'none' }); return false }
|
||||
if (showPayment.value && !form.paymentMethod) { uni.showToast({ title: '支付方式不能为空', icon: 'none' }); return false }
|
||||
if (form.isOrdered && !form.orderedDatetime) { uni.showToast({ title: '请选择预约时间', icon: 'none' }); return false }
|
||||
return true
|
||||
}
|
||||
|
||||
async function onSubmit() {
|
||||
if (!validate()) return
|
||||
|
||||
if (form.decDepts && Array.isArray(form.decDepts) && form.decDepts.length > 1) form.decDept = form.decDepts[1]
|
||||
if (form.needcontactDepts && Array.isArray(form.needcontactDepts) && form.needcontactDepts.length > 1) form.needcontactDept = form.needcontactDepts[1]
|
||||
|
||||
const openid = uni.getStorageSync('openid')
|
||||
form.openid = openid ? openid : config.defaultOpenId
|
||||
|
||||
const payload: any = { ...form }
|
||||
if (form.isOrdered) payload.orderedDatetime = toFullDateTime(form.orderedDatetime as any)
|
||||
else payload.orderedDatetime = null
|
||||
|
||||
try {
|
||||
const res = await util.request({ url: '/API/stretchertransport/create', method: 'POST', data: payload })
|
||||
if (res.data && res.data.code === 0) {
|
||||
isSubmit.value = false
|
||||
isCancelSubmit.value = true
|
||||
isShowProgress.value = true
|
||||
startPoll()
|
||||
startCountdown()
|
||||
uni.showToast({ title: '担架运送申请成功,等待骑手接单!', icon: 'none' })
|
||||
} else {
|
||||
throw new Error('create failed')
|
||||
}
|
||||
} catch (err) {
|
||||
uni.showToast({ title: '担架运送申请失败,请重新申请!', icon: 'none' })
|
||||
isShowProgress.value = false
|
||||
isSubmit.value = true
|
||||
isCancelSubmit.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function onCancel() {
|
||||
try {
|
||||
const res = await util.request({ url: `/API/stretchertransport/redis/delete/${form.decTel}`, method: 'GET' })
|
||||
if (res.data && res.data.code === 0) {
|
||||
isSubmit.value = true
|
||||
isCancelSubmit.value = false
|
||||
isShowProgress.value = false
|
||||
stopPoll()
|
||||
stopCountdown()
|
||||
uni.showToast({ title: '担架运送申请取消成功!', icon: 'none' })
|
||||
} else {
|
||||
throw new Error('cancel failed')
|
||||
}
|
||||
} catch (err) {
|
||||
uni.showToast({ title: '担架运送申请取消失败!', icon: 'none' })
|
||||
}
|
||||
}
|
||||
|
||||
async function onCancelAgent() {
|
||||
const res = await uni.showModal({ title: '确认取消申请提示', content: '您确定要取消本次申请吗?' })
|
||||
const result: any = Array.isArray(res) ? res[1] : (res as any)
|
||||
if (result && result.confirm) onCancel()
|
||||
}
|
||||
|
||||
function startPoll() {
|
||||
if (pollTimer) return
|
||||
pollTimer = setInterval(async () => {
|
||||
const data = { decDept: form.decDept, decBedNo: form.decBedNo, decTel: form.decTel }
|
||||
try {
|
||||
const res = await queryService.queryStretcherReceiptTask(data)
|
||||
if (res.data && res.data.code === 0) {
|
||||
list.value = res.data.data
|
||||
if (list.value && list.value.length > 0) {
|
||||
isShowProgress.value = false
|
||||
isCancelSubmit.value = false
|
||||
isSubmit.value = true
|
||||
stopPoll(); stopCountdown(); resetForm()
|
||||
uni.showToast({ title: '申请已被骑手接单!', icon: 'success', duration: 3000 })
|
||||
}
|
||||
}
|
||||
} catch { }
|
||||
}, 1000)
|
||||
}
|
||||
function stopPoll() { if (pollTimer) clearInterval(pollTimer); pollTimer = null }
|
||||
|
||||
function startCountdown() {
|
||||
countdown.value = COUNTDOWN_MAX
|
||||
if (cdTimer) clearInterval(cdTimer)
|
||||
cdTimer = setInterval(() => {
|
||||
countdown.value -= 1000
|
||||
if (countdown.value <= 0) onCountdownEnd()
|
||||
}, 1000)
|
||||
}
|
||||
function stopCountdown() { if (cdTimer) clearInterval(cdTimer); cdTimer = null }
|
||||
|
||||
function onCountdownEnd() {
|
||||
stopPoll(); stopCountdown()
|
||||
uni.showToast({ title: '申请未被接单,请重新申请!', icon: 'success', duration: 4000 })
|
||||
isShowProgress.value = false
|
||||
isCancelSubmit.value = false
|
||||
isSubmit.value = true
|
||||
}
|
||||
|
||||
function resetForm() {
|
||||
form.needcontactDept = null
|
||||
form.needcontactDepts = null
|
||||
form.needcontact = null
|
||||
form.needcontactTel = null
|
||||
form.decDept = null
|
||||
form.decDepts = null
|
||||
form.decBedNo = null
|
||||
form.decTel = null
|
||||
form.carryingtools = null
|
||||
form.carryingtoolsCount = 1
|
||||
form.outnumber = 1
|
||||
form.isOrdered = false
|
||||
form.orderedDatetime = null
|
||||
}
|
||||
|
||||
async function getCarryToolsType() {
|
||||
try {
|
||||
const res = await queryService.getDataDictionary('db_tasksheetcarryingtools_type')
|
||||
if (res.data && res.data.code === 0) {
|
||||
formData.carryingtoolsDatas = res.data.data.dictionaryList || []
|
||||
if (formData.carryingtoolsDatas.length > 0) form.carryingtools = formData.carryingtoolsDatas[0].id
|
||||
} else uni.showToast({ title: '获取运送工具类别失败!', icon: 'none' })
|
||||
} catch { uni.showToast({ title: '获取运送工具类别失败!', icon: 'none' }) }
|
||||
}
|
||||
async function getPaymentMethodType() {
|
||||
try {
|
||||
const res = await queryService.getDataDictionary('db_payment_mode_type')
|
||||
if (res.data && res.data.code === 0) {
|
||||
formData.paymentMethodDatas = res.data.data.dictionaryList || []
|
||||
if (formData.paymentMethodDatas.length > 0) form.paymentMethod = formData.paymentMethodDatas[0].id
|
||||
} else uni.showToast({ title: '获取支付方式列表失败!', icon: 'none' })
|
||||
} catch { uni.showToast({ title: '获取支付方式列表失败!', icon: 'none' }) }
|
||||
}
|
||||
async function getGrids() {
|
||||
try {
|
||||
const res = await queryService.getGrids()
|
||||
if (res.data && res.data.code === 0) {
|
||||
const list = res.data.data || []
|
||||
formData.decDeptDatas = list
|
||||
formData.needcontactDeptDatas = list
|
||||
|
||||
// 代申报科室
|
||||
needDeptParents.value = list
|
||||
needDeptChildrenMap.value = {}
|
||||
needDeptParents.value.forEach((p: any) => { needDeptChildrenMap.value[p.id] = Array.isArray(p.children) ? p.children : [] })
|
||||
needDeptMultiRange.value[0] = needDeptParents.value.map((p: any) => p.gridFullname || p.gridName || p.name || p.label || '')
|
||||
const ndFirstParent = needDeptParents.value[0]
|
||||
const ndFirstChildren = ndFirstParent ? (needDeptChildrenMap.value[ndFirstParent.id] || []) : []
|
||||
needDeptMultiRange.value[1] = ndFirstChildren.length > 0 ? ndFirstChildren.map((c: any) => c.gridFullname || c.gridName || c.name || c.label || '') : ['无子项']
|
||||
needDeptMultiValue.value = [0, 0]
|
||||
if (ndFirstParent) {
|
||||
if (ndFirstChildren.length > 0) { form.needcontactDept = ndFirstChildren[0].id; form.needcontactDepts = ['', ndFirstChildren[0].id] }
|
||||
else { form.needcontactDept = ndFirstParent.id; form.needcontactDepts = ['', ndFirstParent.id] }
|
||||
}
|
||||
|
||||
// 申报科室
|
||||
decDeptParents.value = list
|
||||
decDeptChildrenMap.value = {}
|
||||
decDeptParents.value.forEach((p: any) => { decDeptChildrenMap.value[p.id] = Array.isArray(p.children) ? p.children : [] })
|
||||
decDeptMultiRange.value[0] = decDeptParents.value.map((p: any) => p.gridFullname || p.gridName || p.name || p.label || '')
|
||||
const dFirstParent = decDeptParents.value[0]
|
||||
const dFirstChildren = dFirstParent ? (decDeptChildrenMap.value[dFirstParent.id] || []) : []
|
||||
decDeptMultiRange.value[1] = dFirstChildren.length > 0 ? dFirstChildren.map((c: any) => c.gridFullname || c.gridName || c.name || c.label || '') : ['无子项']
|
||||
decDeptMultiValue.value = [0, 0]
|
||||
if (dFirstParent) {
|
||||
if (dFirstChildren.length > 0) { form.decDept = dFirstChildren[0].id; form.decDepts = ['', dFirstChildren[0].id] }
|
||||
else { form.decDept = dFirstParent.id; form.decDepts = ['', dFirstParent.id] }
|
||||
}
|
||||
} else uni.showToast({ title: '获取网格列表失败!', icon: 'none' })
|
||||
} catch { uni.showToast({ title: '获取网格列表失败!', icon: 'none' }) }
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
// #ifdef MP-WEIXIN
|
||||
const openid = uni.getStorageSync('openid')
|
||||
if (!openid) { try { getService.getOpenId && getService.getOpenId() } catch { } }
|
||||
// #endif
|
||||
await Promise.all([getCarryToolsType(), getPaymentMethodType(), getGrids()])
|
||||
})
|
||||
|
||||
onUnmounted(() => { stopPoll(); stopCountdown() })
|
||||
|
||||
function toFullDateTime(timeStr: string): string {
|
||||
const now = new Date()
|
||||
const yyyy = now.getFullYear()
|
||||
const MM = String(now.getMonth() + 1).padStart(2, '0')
|
||||
const dd = String(now.getDate()).padStart(2, '0')
|
||||
if (!timeStr) return `${yyyy}-${MM}-${dd} 00:00:00`
|
||||
const parts = String(timeStr).split(':')
|
||||
const h = String(parts[0] ?? '00').padStart(2, '0')
|
||||
const m = String(parts[1] ?? '00').padStart(2, '0')
|
||||
const s = String(parts[2] ?? '00').padStart(2, '0')
|
||||
return `${yyyy}-${MM}-${dd} ${h}:${m}:${s}`
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page {
|
||||
min-height: 100vh;
|
||||
background: #f5f7fb;
|
||||
}
|
||||
|
||||
.card {
|
||||
margin: 24rpx;
|
||||
padding: 24rpx;
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 34rpx;
|
||||
font-weight: 600;
|
||||
margin-bottom: 12rpx;
|
||||
color: #111;
|
||||
}
|
||||
|
||||
.form-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 20rpx 0;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.label {
|
||||
color: #333;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.required::before {
|
||||
content: '*';
|
||||
color: #ff4d4f;
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
|
||||
.input {
|
||||
text-align: right;
|
||||
flex: 1;
|
||||
margin-left: 24rpx;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.picker-value {
|
||||
flex: 1;
|
||||
text-align: right;
|
||||
margin-left: 24rpx;
|
||||
color: #333;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.picker-value.placeholder {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.btns {
|
||||
display: flex;
|
||||
gap: 20rpx;
|
||||
margin-top: 24rpx;
|
||||
}
|
||||
|
||||
.btn {
|
||||
flex: 1;
|
||||
padding: 0 20rpx;
|
||||
border-radius: 12rpx;
|
||||
font-size: 30rpx;
|
||||
}
|
||||
|
||||
.btn.primary {
|
||||
background: #007aff;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.btn.outline {
|
||||
background: #fff;
|
||||
color: #007aff;
|
||||
border: 2rpx solid #007aff;
|
||||
}
|
||||
|
||||
.overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0, 0, 0, 0.35);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
.overlay-card {
|
||||
width: 80%;
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 32rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.overlay-title {
|
||||
display: block;
|
||||
font-size: 30rpx;
|
||||
color: #333;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.overlay-time {
|
||||
display: block;
|
||||
font-size: 40rpx;
|
||||
color: #007aff;
|
||||
margin-bottom: 16rpx;
|
||||
font-weight: 600;
|
||||
}
|
||||
</style>
|
||||
629
src/pages/stretcher/apply/index.vue
Normal file
@ -0,0 +1,629 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<view class="card">
|
||||
<view class="title">担架运送申请</view>
|
||||
|
||||
<!-- 申报科室 -->
|
||||
<view class="form-item">
|
||||
<text class="label required">申报科室</text>
|
||||
<picker mode="multiSelector" :range="deptMultiRange"
|
||||
:value="deptMultiValue" @columnchange="onDeptColumnChange"
|
||||
@change="onDeptChange">
|
||||
<view class="picker-value" :class="{ placeholder: !form.decDept }">
|
||||
{{ currentDeptName || '请选择所在科室' }}
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
|
||||
<!-- 申报床号 -->
|
||||
<view class="form-item">
|
||||
<text class="label required">申报床号</text>
|
||||
<input class="input" type="text" v-model="form.decBedNo"
|
||||
placeholder="请输入床号" />
|
||||
</view>
|
||||
|
||||
<!-- 申报手机 -->
|
||||
<view class="form-item">
|
||||
<text class="label required">申报手机</text>
|
||||
<input class="input" type="number" maxlength="11" v-model="form.decTel"
|
||||
placeholder="请输入手机号码" />
|
||||
</view>
|
||||
|
||||
<!-- 运送工具 -->
|
||||
<view class="form-item">
|
||||
<text class="label required">运送工具</text>
|
||||
<picker mode="selector" :range="toolNames" @change="onPickTool">
|
||||
<view class="picker-value"
|
||||
:class="{ placeholder: !form.carryingtools }">
|
||||
{{ currentToolName || '请选择所需运送工具' }}
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
|
||||
<!-- 工具数量 -->
|
||||
<view class="form-item">
|
||||
<text class="label required">工具数量</text>
|
||||
<input class="input" type="number"
|
||||
v-model.number="form.carryingtoolsCount" placeholder="请输入工具数量" />
|
||||
</view>
|
||||
|
||||
<!-- 承运人数量 -->
|
||||
<view class="form-item">
|
||||
<text class="label required">承运人数量</text>
|
||||
<input class="input" type="number" v-model.number="form.outnumber"
|
||||
placeholder="请输入所需运送人员数量" />
|
||||
</view>
|
||||
|
||||
<!-- 是否预约 -->
|
||||
<view class="form-item">
|
||||
<text class="label">是否预约</text>
|
||||
<switch :checked="form.isOrdered" @change="onToggleOrdered" />
|
||||
</view>
|
||||
|
||||
<!-- 预约时间 -->
|
||||
<view v-if="form.isOrdered" class="form-item">
|
||||
<text class="label">预约时间</text>
|
||||
<picker mode="time" :value="form.orderedDatetime || ''"
|
||||
@change="onPickTime">
|
||||
<view class="picker-value"
|
||||
:class="{ placeholder: !form.orderedDatetime }">
|
||||
{{ form.orderedDatetime || '请选择' }}
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
|
||||
<!-- 支付方式 -->
|
||||
<view class="form-item">
|
||||
<text class="label required">支付方式</text>
|
||||
<picker mode="selector" :range="payNames" @change="onPickPay">
|
||||
<view class="picker-value"
|
||||
:class="{ placeholder: !form.paymentMethod }">
|
||||
{{ currentPayName || '请选择支付方式' }}
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
|
||||
<view class="btns">
|
||||
<button class="btn outline" :disabled="!isCancelSubmit"
|
||||
@tap="onCancelAgent">取消申请</button>
|
||||
<button class="btn primary" :disabled="!isSubmit"
|
||||
@tap="onSubmit">申请</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 等待接单浮层 -->
|
||||
<view v-if="isShowProgress" class="overlay">
|
||||
<view class="overlay-card">
|
||||
<text class="overlay-title">等待骑手接单</text>
|
||||
<text class="overlay-time">{{ countdownText }}</text>
|
||||
<button class="btn outline" @tap="onCancelAgent">取消申请</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, onUnmounted, reactive, ref } from 'vue'
|
||||
// JS 服务以 any 导入,避免类型声明缺失导致报错
|
||||
// @ts-ignore
|
||||
import util from '@/utils/util.js'
|
||||
// @ts-ignore
|
||||
import queryService from '@/service/queryService.js'
|
||||
// @ts-ignore
|
||||
import getService from '@/service/getService.js'
|
||||
// @ts-ignore
|
||||
import config from '@/config.js'
|
||||
|
||||
// 表单数据(字段需与旧版保持一致)
|
||||
const form = reactive({
|
||||
needcontactDept: null as any,
|
||||
needcontact: null as any,
|
||||
needcontactTel: null as any,
|
||||
decChannel: null as any,
|
||||
decDepts: null as any,
|
||||
decDept: null as any,
|
||||
decBedNo: null as any,
|
||||
decTel: null as any,
|
||||
openid: null as any,
|
||||
carryingtools: null as any,
|
||||
carryingtoolsCount: 1,
|
||||
outnumber: 1,
|
||||
isOrdered: false,
|
||||
orderedDatetime: null as any,
|
||||
paymentMethod: '01'
|
||||
})
|
||||
|
||||
// 选项数据
|
||||
const formData = reactive({
|
||||
decDeptDatas: [] as Array<any>,
|
||||
carryingtoolsDatas: [] as Array<any>,
|
||||
paymentMethodDatas: [] as Array<any>
|
||||
})
|
||||
|
||||
// UI & 轮询相关
|
||||
const isSubmit = ref(true)
|
||||
const isCancelSubmit = ref(false)
|
||||
const isShowProgress = ref(false)
|
||||
const list = ref<any[] | null>(null)
|
||||
|
||||
const COUNTDOWN_MAX = 5 * 60 * 1000 // 5 分钟
|
||||
const countdown = ref(COUNTDOWN_MAX)
|
||||
let pollTimer: any = null
|
||||
let cdTimer: any = null
|
||||
|
||||
// 申报科室两列联动:左列父级、右列子级(无子项则显示占位)
|
||||
const deptMultiRange = ref<string[][]>([[], []])
|
||||
const deptParents = ref<any[]>([])
|
||||
const deptChildrenMap = ref<Record<string, any[]>>({}) // parentId -> children[]
|
||||
const deptMultiValue = ref<number[]>([0, 0])
|
||||
const toolNames = computed(() => formData.carryingtoolsDatas.map(d => d.name || d.label || ''))
|
||||
const payNames = computed(() => formData.paymentMethodDatas.map(d => d.name || d.label || ''))
|
||||
|
||||
const currentDeptName = computed(() => {
|
||||
if (!form.decDept) return ''
|
||||
// 优先在子集里找
|
||||
for (const p of deptParents.value) {
|
||||
const children = deptChildrenMap.value[p.id] || []
|
||||
const c = children.find((it: any) => it.id === form.decDept)
|
||||
if (c) return c.gridFullname || c.gridName || c.name || c.label || ''
|
||||
}
|
||||
// 子集中没有,则在父集中找
|
||||
const p = deptParents.value.find((it: any) => it.id === form.decDept)
|
||||
return p ? (p.gridFullname || p.gridName || p.name || p.label || '') : ''
|
||||
})
|
||||
const currentToolName = computed(() => {
|
||||
const found = formData.carryingtoolsDatas.find(d => d.id === form.carryingtools)
|
||||
return found ? (found.name || found.label) : ''
|
||||
})
|
||||
const currentPayName = computed(() => {
|
||||
const found = formData.paymentMethodDatas.find(d => d.id === form.paymentMethod)
|
||||
return found ? (found.name || found.label) : ''
|
||||
})
|
||||
|
||||
const countdownText = computed(() => {
|
||||
const total = Math.max(0, countdown.value)
|
||||
const h = Math.floor(total / 3600000)
|
||||
const m = Math.floor((total % 3600000) / 60000)
|
||||
const s = Math.floor((total % 60000) / 1000)
|
||||
const pad = (n: number) => String(n).padStart(2, '0')
|
||||
return `${pad(h)}:${pad(m)}:${pad(s)}`
|
||||
})
|
||||
|
||||
function onDeptColumnChange(e: any) {
|
||||
const { column, value } = e.detail
|
||||
// 切换父列,联动更新子列
|
||||
if (column === 0) {
|
||||
deptMultiValue.value[0] = value
|
||||
const parent = deptParents.value[value]
|
||||
const children = (parent && deptChildrenMap.value[parent.id]) || []
|
||||
deptMultiRange.value[1] = children.length > 0
|
||||
? children.map((c: any) => c.gridFullname || c.gridName || c.name || c.label || '')
|
||||
: ['- 无子项 -']
|
||||
deptMultiValue.value[1] = 0
|
||||
}
|
||||
}
|
||||
|
||||
function onDeptChange(e: any) {
|
||||
const [pi, ci] = e.detail.value as number[]
|
||||
const parent = deptParents.value[pi]
|
||||
const children = (parent && deptChildrenMap.value[parent.id]) || []
|
||||
if (children.length > 0) {
|
||||
const child = children[ci]
|
||||
if (!child) return
|
||||
form.decDept = child.id
|
||||
form.decDepts = ['', child.id]
|
||||
} else {
|
||||
if (!parent) return
|
||||
form.decDept = parent.id
|
||||
form.decDepts = ['', parent.id]
|
||||
}
|
||||
}
|
||||
|
||||
function onPickTool(e: any) {
|
||||
const idx = Number(e.detail.value)
|
||||
const item = formData.carryingtoolsDatas[idx]
|
||||
if (!item) return
|
||||
form.carryingtools = item.id
|
||||
}
|
||||
|
||||
function onPickPay(e: any) {
|
||||
const idx = Number(e.detail.value)
|
||||
const item = formData.paymentMethodDatas[idx]
|
||||
if (!item) return
|
||||
form.paymentMethod = item.id
|
||||
}
|
||||
|
||||
function onPickTime(e: any) {
|
||||
form.orderedDatetime = e.detail.value
|
||||
}
|
||||
|
||||
function onToggleOrdered(e: any) {
|
||||
form.isOrdered = !!e.detail.value
|
||||
}
|
||||
|
||||
function validate(): boolean {
|
||||
// 简单校验,保持与旧版规则一致
|
||||
if (!form.decDept && (!form.decDepts || (Array.isArray(form.decDepts) && form.decDepts.length <= 1))) {
|
||||
uni.showToast({ title: '申报科室不能为空', icon: 'none' })
|
||||
return false
|
||||
}
|
||||
if (!form.decBedNo) {
|
||||
uni.showToast({ title: '床号不能为空', icon: 'none' })
|
||||
return false
|
||||
}
|
||||
if (!form.decTel) {
|
||||
uni.showToast({ title: '申报电话不能为空', icon: 'none' })
|
||||
return false
|
||||
}
|
||||
if (!form.carryingtools) {
|
||||
uni.showToast({ title: '运送工具不能为空', icon: 'none' })
|
||||
return false
|
||||
}
|
||||
if (!form.carryingtoolsCount) {
|
||||
uni.showToast({ title: '工具数量不能为空', icon: 'none' })
|
||||
return false
|
||||
}
|
||||
if (!form.outnumber) {
|
||||
uni.showToast({ title: '所需运送人员数量不能为空', icon: 'none' })
|
||||
return false
|
||||
}
|
||||
if (!form.paymentMethod) {
|
||||
uni.showToast({ title: '支付方式不能为空', icon: 'none' })
|
||||
return false
|
||||
}
|
||||
if (form.isOrdered && !form.orderedDatetime) {
|
||||
uni.showToast({ title: '请选择预约时间', icon: 'none' })
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
async function onSubmit() {
|
||||
if (!validate()) return
|
||||
|
||||
// 兼容旧逻辑:若 decDepts 长度>1,则取第二位作为 decDept
|
||||
if (form.decDepts && Array.isArray(form.decDepts) && form.decDepts.length > 1) {
|
||||
form.decDept = form.decDepts[1]
|
||||
}
|
||||
|
||||
const openid = uni.getStorageSync('openid')
|
||||
form.openid = openid ? openid : config.defaultOpenId
|
||||
|
||||
// 组装后端要求的预约时间格式:yyyy-MM-dd HH:mm:ss
|
||||
const payload: any = { ...form }
|
||||
if (form.isOrdered) {
|
||||
payload.orderedDatetime = toFullDateTime(form.orderedDatetime as any)
|
||||
} else {
|
||||
payload.orderedDatetime = null
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await util.request({ url: '/API/stretchertransport/create', method: 'POST', data: payload })
|
||||
if (res.data && res.data.code === 0) {
|
||||
isSubmit.value = false
|
||||
isCancelSubmit.value = true
|
||||
isShowProgress.value = true
|
||||
startPoll()
|
||||
startCountdown()
|
||||
uni.showToast({ title: '担架运送申请成功,等待骑手接单!', icon: 'none' })
|
||||
} else {
|
||||
throw new Error('create failed')
|
||||
}
|
||||
} catch (err) {
|
||||
uni.showToast({ title: '担架运送申请失败,请重新申请!', icon: 'none' })
|
||||
isShowProgress.value = false
|
||||
isSubmit.value = true
|
||||
isCancelSubmit.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function onCancel() {
|
||||
try {
|
||||
const res = await util.request({ url: `/API/stretchertransport/redis/delete/${form.decTel}`, method: 'GET' })
|
||||
if (res.data && res.data.code === 0) {
|
||||
isSubmit.value = true
|
||||
isCancelSubmit.value = false
|
||||
isShowProgress.value = false
|
||||
stopPoll()
|
||||
stopCountdown()
|
||||
uni.showToast({ title: '担架运送申请取消成功!', icon: 'none' })
|
||||
} else {
|
||||
throw new Error('cancel failed')
|
||||
}
|
||||
} catch (err) {
|
||||
uni.showToast({ title: '担架运送申请取消失败!', icon: 'none' })
|
||||
}
|
||||
}
|
||||
|
||||
async function onCancelAgent() {
|
||||
const res = await uni.showModal({ title: '确认取消申请提示', content: '您确定要取消本次申请吗?' })
|
||||
// res: [error, result] in promise? In uni-app promise, returns [err, res]? Using any below
|
||||
const result: any = Array.isArray(res) ? res[1] : (res as any)
|
||||
if (result && result.confirm) {
|
||||
onCancel()
|
||||
}
|
||||
}
|
||||
|
||||
function startPoll() {
|
||||
if (pollTimer) return
|
||||
pollTimer = setInterval(async () => {
|
||||
const data = { decDept: form.decDept, decBedNo: form.decBedNo, decTel: form.decTel }
|
||||
try {
|
||||
const res = await queryService.queryStretcherReceiptTask(data)
|
||||
if (res.data && res.data.code === 0) {
|
||||
list.value = res.data.data
|
||||
if (list.value && list.value.length > 0) {
|
||||
// 接单成功
|
||||
isShowProgress.value = false
|
||||
isCancelSubmit.value = false
|
||||
isSubmit.value = true
|
||||
stopPoll()
|
||||
stopCountdown()
|
||||
resetForm()
|
||||
uni.showToast({ title: '申请已被骑手接单!', icon: 'success', duration: 3000 })
|
||||
}
|
||||
}
|
||||
} catch { }
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
function stopPoll() {
|
||||
if (pollTimer) clearInterval(pollTimer)
|
||||
pollTimer = null
|
||||
}
|
||||
|
||||
function startCountdown() {
|
||||
countdown.value = COUNTDOWN_MAX
|
||||
if (cdTimer) clearInterval(cdTimer)
|
||||
cdTimer = setInterval(() => {
|
||||
countdown.value -= 1000
|
||||
if (countdown.value <= 0) {
|
||||
onCountdownEnd()
|
||||
}
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
function stopCountdown() {
|
||||
if (cdTimer) clearInterval(cdTimer)
|
||||
cdTimer = null
|
||||
}
|
||||
|
||||
function onCountdownEnd() {
|
||||
stopPoll()
|
||||
stopCountdown()
|
||||
uni.showToast({ title: '申请未被接单,请重新申请!', icon: 'success', duration: 4000 })
|
||||
isShowProgress.value = false
|
||||
isCancelSubmit.value = false
|
||||
isSubmit.value = true
|
||||
}
|
||||
|
||||
function resetForm() {
|
||||
form.decDepts = null
|
||||
form.decDept = null
|
||||
form.decBedNo = null
|
||||
form.decTel = null
|
||||
form.carryingtools = null
|
||||
form.carryingtoolsCount = 1
|
||||
form.outnumber = 1
|
||||
form.isOrdered = false
|
||||
form.orderedDatetime = null
|
||||
}
|
||||
|
||||
async function getCarryToolsType() {
|
||||
try {
|
||||
const res = await queryService.getDataDictionary('db_tasksheetcarryingtools_type')
|
||||
if (res.data && res.data.code === 0) {
|
||||
formData.carryingtoolsDatas = res.data.data.dictionaryList || []
|
||||
if (formData.carryingtoolsDatas.length > 0) {
|
||||
form.carryingtools = formData.carryingtoolsDatas[0].id
|
||||
}
|
||||
} else {
|
||||
uni.showToast({ title: '获取运送工具类别失败!', icon: 'none' })
|
||||
}
|
||||
} catch {
|
||||
uni.showToast({ title: '获取运送工具类别失败!', icon: 'none' })
|
||||
}
|
||||
}
|
||||
|
||||
async function getPaymentMethodType() {
|
||||
try {
|
||||
const res = await queryService.getDataDictionary('db_payment_mode_type')
|
||||
if (res.data && res.data.code === 0) {
|
||||
formData.paymentMethodDatas = res.data.data.dictionaryList || []
|
||||
if (formData.paymentMethodDatas.length > 0) {
|
||||
form.paymentMethod = formData.paymentMethodDatas[0].id
|
||||
}
|
||||
} else {
|
||||
uni.showToast({ title: '获取支付方式列表失败!', icon: 'none' })
|
||||
}
|
||||
} catch {
|
||||
uni.showToast({ title: '获取支付方式列表失败!', icon: 'none' })
|
||||
}
|
||||
}
|
||||
|
||||
async function getGrids() {
|
||||
try {
|
||||
const res = await queryService.getGrids()
|
||||
if (res.data && res.data.code === 0) {
|
||||
formData.decDeptDatas = res.data.data || []
|
||||
// 构建父子结构
|
||||
deptParents.value = formData.decDeptDatas
|
||||
deptChildrenMap.value = {}
|
||||
deptParents.value.forEach((p: any) => {
|
||||
deptChildrenMap.value[p.id] = Array.isArray(p.children) ? p.children : []
|
||||
})
|
||||
// 初始化两列
|
||||
deptMultiRange.value[0] = deptParents.value.map((p: any) => p.gridFullname || p.gridName || p.name || p.label || '')
|
||||
const firstParent = deptParents.value[0]
|
||||
const firstChildren = firstParent ? (deptChildrenMap.value[firstParent.id] || []) : []
|
||||
deptMultiRange.value[1] = firstChildren.length > 0
|
||||
? firstChildren.map((c: any) => c.gridFullname || c.gridName || c.name || c.label || '')
|
||||
: ['无子项']
|
||||
deptMultiValue.value = [0, 0]
|
||||
|
||||
// 默认选择:若有子项选第一个子项,否则选第一个父项
|
||||
if (firstParent) {
|
||||
if (firstChildren.length > 0) {
|
||||
form.decDept = firstChildren[0].id
|
||||
form.decDepts = ['', firstChildren[0].id]
|
||||
} else {
|
||||
form.decDept = firstParent.id
|
||||
form.decDepts = ['', firstParent.id]
|
||||
}
|
||||
}
|
||||
} else {
|
||||
uni.showToast({ title: '获取网格列表失败!', icon: 'none' })
|
||||
}
|
||||
} catch {
|
||||
uni.showToast({ title: '获取网格列表失败!', icon: 'none' })
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
// 获取 openid(仅在微信小程序)
|
||||
// #ifdef MP-WEIXIN
|
||||
const openid = uni.getStorageSync('openid')
|
||||
if (!openid) {
|
||||
try { getService.getOpenId && getService.getOpenId() } catch { }
|
||||
}
|
||||
// #endif
|
||||
|
||||
await Promise.all([getCarryToolsType(), getPaymentMethodType(), getGrids()])
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
stopPoll()
|
||||
stopCountdown()
|
||||
})
|
||||
|
||||
function toFullDateTime(timeStr: string): string {
|
||||
const now = new Date()
|
||||
const yyyy = now.getFullYear()
|
||||
const MM = String(now.getMonth() + 1).padStart(2, '0')
|
||||
const dd = String(now.getDate()).padStart(2, '0')
|
||||
if (!timeStr) return `${yyyy}-${MM}-${dd} 00:00:00`
|
||||
const parts = String(timeStr).split(':')
|
||||
const h = String(parts[0] ?? '00').padStart(2, '0')
|
||||
const m = String(parts[1] ?? '00').padStart(2, '0')
|
||||
const s = String(parts[2] ?? '00').padStart(2, '0')
|
||||
return `${yyyy}-${MM}-${dd} ${h}:${m}:${s}`
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page {
|
||||
min-height: 100vh;
|
||||
background: #f5f7fb;
|
||||
}
|
||||
|
||||
.card {
|
||||
margin: 24rpx;
|
||||
padding: 24rpx;
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 34rpx;
|
||||
font-weight: 600;
|
||||
margin-bottom: 12rpx;
|
||||
color: #111;
|
||||
}
|
||||
|
||||
.form-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 20rpx 0;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.label {
|
||||
color: #333;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.required::before {
|
||||
content: '*';
|
||||
color: #ff4d4f;
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
|
||||
.input {
|
||||
text-align: right;
|
||||
flex: 1;
|
||||
margin-left: 24rpx;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.picker-value {
|
||||
flex: 1;
|
||||
text-align: right;
|
||||
margin-left: 24rpx;
|
||||
color: #333;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.picker-value.placeholder {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.btns {
|
||||
display: flex;
|
||||
gap: 20rpx;
|
||||
margin-top: 24rpx;
|
||||
}
|
||||
|
||||
.btn {
|
||||
flex: 1;
|
||||
padding: 0 20rpx;
|
||||
border-radius: 12rpx;
|
||||
font-size: 30rpx;
|
||||
}
|
||||
|
||||
.btn.primary {
|
||||
background: #007aff;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.btn.outline {
|
||||
background: #fff;
|
||||
color: #007aff;
|
||||
border: 2rpx solid #007aff;
|
||||
}
|
||||
|
||||
.overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0, 0, 0, 0.35);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
.overlay-card {
|
||||
width: 80%;
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 32rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.overlay-title {
|
||||
display: block;
|
||||
font-size: 30rpx;
|
||||
color: #333;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.overlay-time {
|
||||
display: block;
|
||||
font-size: 40rpx;
|
||||
color: #007aff;
|
||||
margin-bottom: 16rpx;
|
||||
font-weight: 600;
|
||||
}
|
||||
</style>
|
||||
32
src/pages/task/index.vue
Normal file
@ -0,0 +1,32 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<view class="empty">
|
||||
<image src="/static/icons/tasks.png" class="icon" />
|
||||
<text>暂无任务</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page {
|
||||
min-height: 100vh;
|
||||
background: #f7f8fa;
|
||||
}
|
||||
.empty {
|
||||
height: 60vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #999;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
.icon {
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
</style>
|
||||
32
src/pages/tasks/index.vue
Normal file
@ -0,0 +1,32 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<view class="empty">
|
||||
<image src="/static/icons/tasks.png" class="icon" />
|
||||
<text>暂无任务</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page {
|
||||
min-height: 100vh;
|
||||
background: #f7f8fa;
|
||||
}
|
||||
.empty {
|
||||
height: 60vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #999;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
.icon {
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
</style>
|
||||
45
src/service/getService.js
Normal file
@ -0,0 +1,45 @@
|
||||
import config from '../config.js';
|
||||
import util from '../utils/util.js';
|
||||
import queryService from '@/service/queryService.js';
|
||||
|
||||
export default {
|
||||
|
||||
// 获取微信用户的OpenID
|
||||
getOpenId() {
|
||||
let code = null;
|
||||
uni.login({
|
||||
provider: 'weixin',
|
||||
//onlyAuthorize: true, // 微信登录仅请求授权认证
|
||||
success: function (loginRes) {
|
||||
//console.log('login success: ' + JSON.stringify(loginRes));
|
||||
code = loginRes.code;
|
||||
//console.log('code: ' + code);
|
||||
|
||||
queryService.queryOpenId(code).then(res => {
|
||||
if(res.data.code == 0){
|
||||
//console.log('save openId: ' + res.data.data);
|
||||
uni.setStorageSync('openid', res.data.data);
|
||||
//code = res.data.data;
|
||||
//return code;
|
||||
}else{
|
||||
uni.showToast({
|
||||
title: "获取用户OpenID失败!",
|
||||
icon: 'none',
|
||||
duration: 4000 // 提示的延迟时间,单位毫秒,默认:1500
|
||||
});
|
||||
//return null;
|
||||
}
|
||||
});
|
||||
},
|
||||
fail:function(e){
|
||||
console.log('微信登录失败:',e);
|
||||
uni.showToast({
|
||||
title: "微信登录失败:" + e,
|
||||
icon: 'error',
|
||||
duration: 4000 // 提示的延迟时间,单位毫秒,默认:1500
|
||||
});
|
||||
//return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
490
src/service/queryService.js
Normal file
@ -0,0 +1,490 @@
|
||||
import config from '../config.js';
|
||||
import util from '../utils/util.js';
|
||||
import * as taskState from '../constant/taskState.js';
|
||||
import taskType from '../constant/taskType.js';
|
||||
|
||||
const queryTaskListUrlMapper = {
|
||||
'药品运送': config.urls.queryMedicineNewTask,
|
||||
|
||||
'标本运送': config.urls.querySampleTasksheet,
|
||||
}
|
||||
|
||||
const pageQueryTaskUrlMapper = {
|
||||
'药品运送': config.urls.pageQueryMedicineTask,
|
||||
|
||||
'标本运送': config.urls.pageQuerySampleTasksheet,
|
||||
}
|
||||
|
||||
|
||||
const getTaskByIdUrlMapper = {
|
||||
'药品运送': config.urls.getMedicineTaskById ,
|
||||
|
||||
'标本运送': config.urls.getSampleTaskById,
|
||||
}
|
||||
|
||||
|
||||
export default {
|
||||
/**
|
||||
* 获取指定名称的数据字典
|
||||
* @param {Object} name
|
||||
*/
|
||||
getDataDictionary(name) {
|
||||
return util.request({
|
||||
url: config.dataDictionaryUrl + name,
|
||||
method: 'GET'
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
// 获取微信用户的OpenID
|
||||
queryOpenId(code){
|
||||
return util.request({
|
||||
url: config.urls.queryOpenId + code,
|
||||
method: 'GET'
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 查询全部科室网格列表
|
||||
* @param {string} type
|
||||
* @param {object} params
|
||||
*/
|
||||
getGrids() {
|
||||
const staff = uni.getStorageSync("staff");
|
||||
return util.request({
|
||||
url: config.urls.getGridFromRedis,
|
||||
data: {
|
||||
abbre: null,
|
||||
gridCode: null,
|
||||
hospId: (staff==null || staff==undefined || staff == '')?config.defaultHospId:staff.hosp_id
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取担架运送收费标准图片
|
||||
*/
|
||||
getStretcherTransportFeeImageUrl() {
|
||||
return util.request({
|
||||
url: config.urls.getStretcherTransportFeeImageUrl,
|
||||
method: 'GET'
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取新运单提示音
|
||||
*/
|
||||
getNewWaybillPromptWaveUrl() {
|
||||
return util.request({
|
||||
url: config.urls.getNewWaybillPromptWaveUrl,
|
||||
method: 'GET'
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 生成订单微信支付二维码
|
||||
* @param {Object} params
|
||||
*/
|
||||
getStretcherTransportPayQRcode(params) {
|
||||
return util.request({
|
||||
url: config.urls.getStretcherTransportPayQRcode,
|
||||
data: {
|
||||
orderDec: params.orderDec,
|
||||
orderNo: params.orderNo,
|
||||
productId: params.productId,
|
||||
totalFree: params.totalFree
|
||||
},
|
||||
method: 'POST'
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* 获取APP滑动广告图片
|
||||
*/
|
||||
getAppSlipPicUrl() {
|
||||
return util.request({
|
||||
url: config.urls.getAppSlipPicUrl,
|
||||
method: 'GET'
|
||||
});
|
||||
},
|
||||
|
||||
// 根据id查询担架运单对象
|
||||
getStretcherTaskById(id){
|
||||
return util.request({
|
||||
url: config.urls.getStretcherTransportTaskById + id,
|
||||
method: 'GET'
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 查询担架新运单列表
|
||||
* @param {object} params
|
||||
*/
|
||||
queryStretcherNewTask(params) {
|
||||
const staff = uni.getStorageSync("staff");
|
||||
params.userId = (staff==null || staff==undefined || staff == '')?null:staff.id
|
||||
return util.request({
|
||||
url: config.urls.queryStretcherNewTask,
|
||||
data: params
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 列表查询刚接单的担架运送任务
|
||||
* @param {Object} params
|
||||
*/
|
||||
queryStretcherReceiptTask(params){
|
||||
return util.request({
|
||||
url: config.urls.queryStretcherReceiptTask,
|
||||
data: {
|
||||
decDept: params.decDept || null,
|
||||
decTel: params.decTel || null,
|
||||
decBedNo: params.decBedNo || null,
|
||||
index: 0,
|
||||
page: 0,
|
||||
size: 0,
|
||||
sort: null,
|
||||
hospId: null
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 列表查询担架运单
|
||||
* @param {Object} params
|
||||
*/
|
||||
queryStretcherTask(params){
|
||||
const staff = uni.getStorageSync("staff");
|
||||
return util.request({
|
||||
url: config.urls.queryStretcherTask,
|
||||
data: {
|
||||
decDept: params.decDept || null,
|
||||
decTel: params.decTel || null,
|
||||
decBedNo: params.decBedNo || null,
|
||||
needcontactTel: params.needcontactTel || null,
|
||||
openid: params.openid || null,
|
||||
decendDatetime: params.endTime || null,
|
||||
decstartDatetime: params.startTime || null,
|
||||
index: 0,
|
||||
page: 0,
|
||||
size: 0,
|
||||
sort: null,
|
||||
tasksheetStates: params.tasksheetStates || null,
|
||||
undertakePerson: (staff==null || staff==undefined || staff == '')?null:staff.id,
|
||||
hospId: null
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 担架运送接单
|
||||
* @param {Object} params
|
||||
*/
|
||||
receiptStretcherNewTask(params){
|
||||
const staff = uni.getStorageSync("staff");
|
||||
return util.request({
|
||||
url: config.urls.receiptStretcherNewTask,
|
||||
data: {
|
||||
id: params.id,
|
||||
acceptancePerson: (staff==null || staff==undefined || staff == '')?null:staff.id,
|
||||
decBedNo: params.decBedNo,
|
||||
decDept: null,
|
||||
delTel: params.delTel,
|
||||
exteamId: null,
|
||||
undertakePersons: null
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 启运担架运单
|
||||
* @param {Object} params
|
||||
*/
|
||||
startStretcherTransport(params){
|
||||
const staff = uni.getStorageSync("staff");
|
||||
return util.request({
|
||||
url: config.urls.startStretcherTransport,
|
||||
data: {
|
||||
acceptancePerson: (staff==null || staff==undefined || staff == '')?null:staff.id,
|
||||
sheetId: params.sheetId,
|
||||
smsStartCode: params.smsStartCode
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 完工担架运单
|
||||
* @param {Object} params
|
||||
*/
|
||||
finishStretcherTransport(params){
|
||||
const staff = uni.getStorageSync("staff");
|
||||
return util.request({
|
||||
url: config.urls.finishStretcherTransport,
|
||||
data: {
|
||||
acceptancePerson: (staff==null || staff==undefined || staff == '')?null:staff.id,
|
||||
finishWord: params.finishWord,
|
||||
sheetId: params.sheetId,
|
||||
smsFinishCode: params.smsFinishCode
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 确认现金支付
|
||||
* @param {Object} params
|
||||
*/
|
||||
confirmStretcherPay(params){
|
||||
const staff = uni.getStorageSync("staff");
|
||||
return util.request({
|
||||
url: config.urls.confirmStretcherPay,
|
||||
data: {
|
||||
acceptancePerson: (staff==null || staff==undefined || staff == '')?null:staff.id,
|
||||
paymentMethod: params.paymentMethod,
|
||||
serviceFee: params.serviceFee,
|
||||
sheetId: params.sheetId
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 评价担架运单服务
|
||||
* @param {Object} params
|
||||
*/
|
||||
evaluateStretcherTransport(params){
|
||||
//const staff = uni.getStorageSync("staff");
|
||||
return util.request({
|
||||
url: config.urls.evaluateStretcherTransport,
|
||||
data: {
|
||||
id: params.id,
|
||||
satisfactionContent: params.satisfactionContent,
|
||||
satisfactionEvaluation: params.satisfactionEvaluation || "5",
|
||||
tasksheetType: null
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 查询全部订单
|
||||
* @param {string} type
|
||||
* @param {object} params
|
||||
*/
|
||||
queryNewTask(type, params) {
|
||||
const staff = uni.getStorageSync("staff");
|
||||
return util.request({
|
||||
url: queryTaskListUrlMapper[type],
|
||||
data: {
|
||||
decendDatetime: params.endTime || null,
|
||||
decstartDatetime: params.startTime || null,
|
||||
index: 0,
|
||||
page: null,
|
||||
size: null,
|
||||
sort: null,
|
||||
tasksheetStates: params.tasksheetStates || null,
|
||||
tasksheetType: taskType[type],
|
||||
undertakePerson: (staff==null || staff==undefined || staff == '')?null:staff.id
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 分页查询运单
|
||||
* @param {string} type
|
||||
* @param {object} params
|
||||
*/
|
||||
pageQueryTask(type, params){
|
||||
return util.request({
|
||||
url: pageQueryTaskUrlMapper[type],
|
||||
data: {
|
||||
decendDatetime: params.endTime || null,
|
||||
decstartDatetime: params.startTime || null,
|
||||
index: 0,
|
||||
orderNo: params.orderNo || null,
|
||||
page: params.pageNo || 1,
|
||||
size: params.pageSize || 10,
|
||||
sort: null,
|
||||
tasksheetStates: params.tasksheetStates || null,
|
||||
tasksheetType: params.tasksheetType || null,
|
||||
undertakePerson: params.undertakePerson || null,
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 分页查询未接单标本
|
||||
* @param {Object} params
|
||||
*/
|
||||
pageQuerySpecimen(params){
|
||||
return util.request({
|
||||
url: config.urls.pageQuerySampleNewTask,
|
||||
data: {
|
||||
decendDatetime: params.endTime || null,
|
||||
decstartDatetime: params.startTime || null,
|
||||
index: 0,
|
||||
page: params.pageNo || 1,
|
||||
size: params.pageSize || 10,
|
||||
sheetId: null,
|
||||
sort: null,
|
||||
tasksheetState: params.tasksheetState || null,
|
||||
undertakePerson: params.undertakePerson || null,
|
||||
urgentDegrees: params.urgentDegrees || null
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 查询全部未接单标本
|
||||
* @param {Object} params
|
||||
*/
|
||||
querySpecimen(params){
|
||||
return util.request({
|
||||
url: config.urls.querySampleNewTask,
|
||||
data: {
|
||||
decendDatetime: params.endTime || null,
|
||||
decstartDatetime: params.startTime || null,
|
||||
index: 0,
|
||||
page: null,
|
||||
size: null,
|
||||
sheetId: null,
|
||||
sort: null,
|
||||
tasksheetState: params.tasksheetState || null,
|
||||
undertakePerson: params.undertakePerson || null,
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 药品运送接单
|
||||
* @param {string} type
|
||||
* @param {Object} data
|
||||
*/
|
||||
receiptMedicineNewTask(params){
|
||||
const staff = uni.getStorageSync("staff");
|
||||
return util.request({
|
||||
url: config.urls.receiptMedicineNewTask,
|
||||
data: {
|
||||
acceptancePerson: params.acceptancePerson,
|
||||
dsordertype: params.dsordertype,
|
||||
tasksheetType: params.tasksheetType,
|
||||
id: params.id,
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 启动运单
|
||||
* @param {Object} taskId
|
||||
*/
|
||||
startMedicineTransport(taskId){
|
||||
return util.request({
|
||||
url: config.urls.startMedicineTransport + taskId,
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 完成药品运送
|
||||
* @param {Object} type
|
||||
* @param {Object} taskId
|
||||
*/
|
||||
completeMedicineTask(type, taskId){
|
||||
const staff = uni.getStorageSync("staff");
|
||||
return util.request({
|
||||
url: config.urls.completeMedicineTask,
|
||||
data: {
|
||||
acceptancePerson: (staff==null || staff==undefined || staff == '')?null:staff.id,
|
||||
finishWord: "完成送药",
|
||||
id: taskId,
|
||||
serviceItem: null,
|
||||
serviceItemType: null,
|
||||
materialconsumerecordSaveRequestList: null,
|
||||
sheetId: taskId,
|
||||
tasksheetType: taskType[type]
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 根据id查询
|
||||
getTaskById(type, id){
|
||||
console.log('getTaskByIdUrlMapper[type] + id',getTaskByIdUrlMapper[type] + id)
|
||||
return util.request({
|
||||
url: getTaskByIdUrlMapper[type] + id,
|
||||
method: 'GET'
|
||||
});
|
||||
},
|
||||
/**
|
||||
* 根据sheedID查询运单下接收的标本
|
||||
* @param {Object} params
|
||||
*/
|
||||
querySheetBySheetTd(sheetId){
|
||||
return util.request({
|
||||
url: config.urls.querySampleNewTask,
|
||||
data: {
|
||||
decendDatetime: null,
|
||||
decstartDatetime: null,
|
||||
index: 0,
|
||||
page: null,
|
||||
size: null,
|
||||
sheetId: sheetId || null,
|
||||
sort: null,
|
||||
tasksheetState: null,
|
||||
undertakePerson: null,
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 扫码接收标本
|
||||
* @param {Object} id
|
||||
*/
|
||||
receiptSampleNewTask(id){
|
||||
return util.request({
|
||||
url: config.urls.receiptSampleNewTask + id,
|
||||
method: 'GET'
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
queryBarcodeFuzzySearch(params){
|
||||
return util.request({
|
||||
url: config.urls.querySampleNewTask,
|
||||
data: {
|
||||
barCode: params.barCode || null,
|
||||
decendDatetime: params.endTime || null,
|
||||
decstartDatetime: params.startTime || null,
|
||||
index: 0,
|
||||
page: null,
|
||||
size: null,
|
||||
sheetId: null,
|
||||
sort: null,
|
||||
tasksheetState: params.tasksheetState || null,
|
||||
undertakePerson: params.undertakePerson || null,
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 创建标本运单
|
||||
* @param {Object} dtos
|
||||
* @param {Object} source
|
||||
*/
|
||||
createSampleTaskSheet(dtos, source){
|
||||
return util.request({
|
||||
url: config.urls.createSampleTaskSheet,
|
||||
data: {
|
||||
dtos: dtos,
|
||||
source: source,
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 获得药品类型列表
|
||||
*/
|
||||
getMedicinetype(){
|
||||
return util.request({
|
||||
url: config.urls.getMedicineType,
|
||||
method: 'GET'
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
20
src/service/unpload.js
Normal file
@ -0,0 +1,20 @@
|
||||
import util from "../utils/util.js";
|
||||
import config from "../config.js";
|
||||
|
||||
export default {
|
||||
// 上传文件
|
||||
upload(filePath) {
|
||||
if (!filePath) {
|
||||
return null;
|
||||
}
|
||||
return util.upload({
|
||||
url: config.urls.unloadSign,
|
||||
filePath: filePath,
|
||||
})
|
||||
.then((res) => {
|
||||
res.data =
|
||||
typeof res.data == "string" ? JSON.parse(res.data) : res.data;
|
||||
return res;
|
||||
});
|
||||
},
|
||||
};
|
||||
6
src/shime-uni.d.ts
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
export {}
|
||||
|
||||
declare module "vue" {
|
||||
type Hooks = App.AppInstance & Page.PageInstance;
|
||||
interface ComponentCustomOptions extends Hooks {}
|
||||
}
|
||||
BIN
src/static/icons/asset-inventory.png
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
src/static/icons/asset-management.png
Normal file
|
After Width: | Height: | Size: 68 KiB |
BIN
src/static/icons/consumables-inventory.png
Normal file
|
After Width: | Height: | Size: 62 KiB |
BIN
src/static/icons/consumables-plan.png
Normal file
|
After Width: | Height: | Size: 57 KiB |
BIN
src/static/icons/fixed-assets.png
Normal file
|
After Width: | Height: | Size: 58 KiB |
BIN
src/static/icons/home.png
Normal file
|
After Width: | Height: | Size: 46 KiB |
BIN
src/static/icons/messages.png
Normal file
|
After Width: | Height: | Size: 46 KiB |
BIN
src/static/icons/my-loans.png
Normal file
|
After Width: | Height: | Size: 45 KiB |
BIN
src/static/icons/profile.png
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
src/static/icons/scan-to-view-info.png
Normal file
|
After Width: | Height: | Size: 66 KiB |
BIN
src/static/icons/stretcher-loan.png
Normal file
|
After Width: | Height: | Size: 43 KiB |
BIN
src/static/icons/stretcher-temp-loan.png
Normal file
|
After Width: | Height: | Size: 65 KiB |
BIN
src/static/icons/tasks.png
Normal file
|
After Width: | Height: | Size: 61 KiB |
BIN
src/static/icons/图标.psd
Normal file
BIN
src/static/logo.png
Normal file
|
After Width: | Height: | Size: 518 KiB |
BIN
src/static/stretcher-charge-standard.png
Normal file
|
After Width: | Height: | Size: 619 KiB |
17
src/types/externals.d.ts
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
// 声明外部 JS 模块,避免 TS 提示缺少声明文件
|
||||
declare module '@/utils/util.js' {
|
||||
const v: any
|
||||
export default v
|
||||
}
|
||||
declare module '@/service/queryService.js' {
|
||||
const v: any
|
||||
export default v
|
||||
}
|
||||
declare module '@/service/getService.js' {
|
||||
const v: any
|
||||
export default v
|
||||
}
|
||||
declare module '@/config.js' {
|
||||
const v: any
|
||||
export default v
|
||||
}
|
||||
76
src/uni.scss
Normal file
@ -0,0 +1,76 @@
|
||||
/**
|
||||
* 这里是uni-app内置的常用样式变量
|
||||
*
|
||||
* uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量
|
||||
* 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能
|
||||
*
|
||||
* 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件
|
||||
*/
|
||||
|
||||
/* 颜色变量 */
|
||||
|
||||
/* 行为相关颜色 */
|
||||
$uni-color-primary: #007aff;
|
||||
$uni-color-success: #4cd964;
|
||||
$uni-color-warning: #f0ad4e;
|
||||
$uni-color-error: #dd524d;
|
||||
|
||||
/* 文字基本颜色 */
|
||||
$uni-text-color: #333; // 基本色
|
||||
$uni-text-color-inverse: #fff; // 反色
|
||||
$uni-text-color-grey: #999; // 辅助灰色,如加载更多的提示信息
|
||||
$uni-text-color-placeholder: #808080;
|
||||
$uni-text-color-disable: #c0c0c0;
|
||||
|
||||
/* 背景颜色 */
|
||||
$uni-bg-color: #fff;
|
||||
$uni-bg-color-grey: #f8f8f8;
|
||||
$uni-bg-color-hover: #f1f1f1; // 点击状态颜色
|
||||
$uni-bg-color-mask: rgba(0, 0, 0, 0.4); // 遮罩颜色
|
||||
|
||||
/* 边框颜色 */
|
||||
$uni-border-color: #c8c7cc;
|
||||
|
||||
/* 尺寸变量 */
|
||||
|
||||
/* 文字尺寸 */
|
||||
$uni-font-size-sm: 12px;
|
||||
$uni-font-size-base: 14px;
|
||||
$uni-font-size-lg: 16;
|
||||
|
||||
/* 图片尺寸 */
|
||||
$uni-img-size-sm: 20px;
|
||||
$uni-img-size-base: 26px;
|
||||
$uni-img-size-lg: 40px;
|
||||
|
||||
/* Border Radius */
|
||||
$uni-border-radius-sm: 2px;
|
||||
$uni-border-radius-base: 3px;
|
||||
$uni-border-radius-lg: 6px;
|
||||
$uni-border-radius-circle: 50%;
|
||||
|
||||
/* 水平间距 */
|
||||
$uni-spacing-row-sm: 5px;
|
||||
$uni-spacing-row-base: 10px;
|
||||
$uni-spacing-row-lg: 15px;
|
||||
|
||||
/* 垂直间距 */
|
||||
$uni-spacing-col-sm: 4px;
|
||||
$uni-spacing-col-base: 8px;
|
||||
$uni-spacing-col-lg: 12px;
|
||||
|
||||
/* 透明度 */
|
||||
$uni-opacity-disabled: 0.3; // 组件禁用态的透明度
|
||||
|
||||
/* 文章场景相关 */
|
||||
$uni-color-title: #2c405a; // 文章标题颜色
|
||||
$uni-font-size-title: 20px;
|
||||
$uni-color-subtitle: #555; // 二级标题颜色
|
||||
$uni-font-size-subtitle: 18px;
|
||||
$uni-color-paragraph: #3f536e; // 文章段落颜色
|
||||
$uni-font-size-paragraph: 15px;
|
||||
428
src/utils/md5.js
Normal file
@ -0,0 +1,428 @@
|
||||
/*
|
||||
* A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
|
||||
* Digest Algorithm, as defined in RFC 1321.
|
||||
* Version 1.1 Copyright (C) Paul Johnston 1999 - 2002.
|
||||
* Code also contributed by Greg Holt
|
||||
* See http://pajhome.org.uk/site/legal.html for details.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Add integers, wrapping at 2^32. This uses 16-bit operations internally
|
||||
* to work around bugs in some JS interpreters.
|
||||
*/
|
||||
|
||||
function safe_add(x, y) {
|
||||
|
||||
|
||||
var lsw = (x & 0xFFFF) + (y & 0xFFFF)
|
||||
|
||||
|
||||
var msw = (x >> 16) + (y >> 16) + (lsw >> 16)
|
||||
|
||||
|
||||
return (msw << 16) | (lsw & 0xFFFF)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Bitwise rotate a 32-bit number to the left.
|
||||
*/
|
||||
|
||||
function rol(num, cnt) {
|
||||
|
||||
|
||||
return (num << cnt) | (num >>> (32 - cnt))
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* These functions implement the four basic operations the algorithm uses.
|
||||
*/
|
||||
|
||||
function cmn(q, a, b, x, s, t) {
|
||||
|
||||
|
||||
return safe_add(rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b)
|
||||
|
||||
}
|
||||
|
||||
function ff(a, b, c, d, x, s, t) {
|
||||
|
||||
|
||||
return cmn((b & c) | ((~b) & d), a, b, x, s, t)
|
||||
|
||||
}
|
||||
|
||||
function gg(a, b, c, d, x, s, t) {
|
||||
|
||||
|
||||
return cmn((b & d) | (c & (~d)), a, b, x, s, t)
|
||||
|
||||
}
|
||||
|
||||
function hh(a, b, c, d, x, s, t) {
|
||||
|
||||
|
||||
return cmn(b ^ c ^ d, a, b, x, s, t)
|
||||
|
||||
}
|
||||
|
||||
function ii(a, b, c, d, x, s, t) {
|
||||
|
||||
|
||||
return cmn(c ^ (b | (~d)), a, b, x, s, t)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Calculate the MD5 of an array of little-endian words, producing an array
|
||||
* of little-endian words.
|
||||
*/
|
||||
|
||||
function coreMD5(x) {
|
||||
|
||||
|
||||
var a = 1732584193
|
||||
|
||||
|
||||
var b = -271733879
|
||||
|
||||
|
||||
var c = -1732584194
|
||||
|
||||
|
||||
var d = 271733878
|
||||
|
||||
|
||||
|
||||
|
||||
for (var i = 0; i < x.length; i += 16) {
|
||||
|
||||
|
||||
var olda = a
|
||||
|
||||
|
||||
var oldb = b
|
||||
|
||||
|
||||
var oldc = c
|
||||
|
||||
|
||||
var oldd = d
|
||||
|
||||
|
||||
|
||||
a = ff(a, b, c, d, x[i + 0], 7, -680876936)
|
||||
|
||||
d = ff(d, a, b, c, x[i + 1], 12, -389564586)
|
||||
|
||||
c = ff(c, d, a, b, x[i + 2], 17, 606105819)
|
||||
|
||||
b = ff(b, c, d, a, x[i + 3], 22, -1044525330)
|
||||
|
||||
a = ff(a, b, c, d, x[i + 4], 7, -176418897)
|
||||
|
||||
d = ff(d, a, b, c, x[i + 5], 12, 1200080426)
|
||||
|
||||
c = ff(c, d, a, b, x[i + 6], 17, -1473231341)
|
||||
|
||||
b = ff(b, c, d, a, x[i + 7], 22, -45705983)
|
||||
|
||||
a = ff(a, b, c, d, x[i + 8], 7, 1770035416)
|
||||
|
||||
d = ff(d, a, b, c, x[i + 9], 12, -1958414417)
|
||||
|
||||
c = ff(c, d, a, b, x[i + 10], 17, -42063)
|
||||
|
||||
b = ff(b, c, d, a, x[i + 11], 22, -1990404162)
|
||||
|
||||
a = ff(a, b, c, d, x[i + 12], 7, 1804603682)
|
||||
|
||||
d = ff(d, a, b, c, x[i + 13], 12, -40341101)
|
||||
|
||||
c = ff(c, d, a, b, x[i + 14], 17, -1502002290)
|
||||
|
||||
b = ff(b, c, d, a, x[i + 15], 22, 1236535329)
|
||||
|
||||
|
||||
|
||||
a = gg(a, b, c, d, x[i + 1], 5, -165796510)
|
||||
|
||||
d = gg(d, a, b, c, x[i + 6], 9, -1069501632)
|
||||
|
||||
c = gg(c, d, a, b, x[i + 11], 14, 643717713)
|
||||
|
||||
b = gg(b, c, d, a, x[i + 0], 20, -373897302)
|
||||
|
||||
a = gg(a, b, c, d, x[i + 5], 5, -701558691)
|
||||
|
||||
d = gg(d, a, b, c, x[i + 10], 9, 38016083)
|
||||
|
||||
c = gg(c, d, a, b, x[i + 15], 14, -660478335)
|
||||
|
||||
b = gg(b, c, d, a, x[i + 4], 20, -405537848)
|
||||
|
||||
a = gg(a, b, c, d, x[i + 9], 5, 568446438)
|
||||
|
||||
d = gg(d, a, b, c, x[i + 14], 9, -1019803690)
|
||||
|
||||
c = gg(c, d, a, b, x[i + 3], 14, -187363961)
|
||||
|
||||
b = gg(b, c, d, a, x[i + 8], 20, 1163531501)
|
||||
|
||||
a = gg(a, b, c, d, x[i + 13], 5, -1444681467)
|
||||
|
||||
d = gg(d, a, b, c, x[i + 2], 9, -51403784)
|
||||
|
||||
c = gg(c, d, a, b, x[i + 7], 14, 1735328473)
|
||||
|
||||
b = gg(b, c, d, a, x[i + 12], 20, -1926607734)
|
||||
|
||||
|
||||
|
||||
a = hh(a, b, c, d, x[i + 5], 4, -378558)
|
||||
|
||||
d = hh(d, a, b, c, x[i + 8], 11, -2022574463)
|
||||
|
||||
c = hh(c, d, a, b, x[i + 11], 16, 1839030562)
|
||||
|
||||
b = hh(b, c, d, a, x[i + 14], 23, -35309556)
|
||||
|
||||
a = hh(a, b, c, d, x[i + 1], 4, -1530992060)
|
||||
|
||||
d = hh(d, a, b, c, x[i + 4], 11, 1272893353)
|
||||
|
||||
c = hh(c, d, a, b, x[i + 7], 16, -155497632)
|
||||
|
||||
b = hh(b, c, d, a, x[i + 10], 23, -1094730640)
|
||||
|
||||
a = hh(a, b, c, d, x[i + 13], 4, 681279174)
|
||||
|
||||
d = hh(d, a, b, c, x[i + 0], 11, -358537222)
|
||||
|
||||
c = hh(c, d, a, b, x[i + 3], 16, -722521979)
|
||||
|
||||
b = hh(b, c, d, a, x[i + 6], 23, 76029189)
|
||||
|
||||
a = hh(a, b, c, d, x[i + 9], 4, -640364487)
|
||||
|
||||
d = hh(d, a, b, c, x[i + 12], 11, -421815835)
|
||||
|
||||
c = hh(c, d, a, b, x[i + 15], 16, 530742520)
|
||||
|
||||
b = hh(b, c, d, a, x[i + 2], 23, -995338651)
|
||||
|
||||
|
||||
|
||||
a = ii(a, b, c, d, x[i + 0], 6, -198630844)
|
||||
|
||||
d = ii(d, a, b, c, x[i + 7], 10, 1126891415)
|
||||
|
||||
c = ii(c, d, a, b, x[i + 14], 15, -1416354905)
|
||||
|
||||
b = ii(b, c, d, a, x[i + 5], 21, -57434055)
|
||||
|
||||
a = ii(a, b, c, d, x[i + 12], 6, 1700485571)
|
||||
|
||||
d = ii(d, a, b, c, x[i + 3], 10, -1894986606)
|
||||
|
||||
c = ii(c, d, a, b, x[i + 10], 15, -1051523)
|
||||
|
||||
b = ii(b, c, d, a, x[i + 1], 21, -2054922799)
|
||||
|
||||
a = ii(a, b, c, d, x[i + 8], 6, 1873313359)
|
||||
|
||||
d = ii(d, a, b, c, x[i + 15], 10, -30611744)
|
||||
|
||||
c = ii(c, d, a, b, x[i + 6], 15, -1560198380)
|
||||
|
||||
b = ii(b, c, d, a, x[i + 13], 21, 1309151649)
|
||||
|
||||
a = ii(a, b, c, d, x[i + 4], 6, -145523070)
|
||||
|
||||
d = ii(d, a, b, c, x[i + 11], 10, -1120210379)
|
||||
|
||||
c = ii(c, d, a, b, x[i + 2], 15, 718787259)
|
||||
|
||||
b = ii(b, c, d, a, x[i + 9], 21, -343485551)
|
||||
|
||||
|
||||
|
||||
a = safe_add(a, olda)
|
||||
|
||||
b = safe_add(b, oldb)
|
||||
|
||||
c = safe_add(c, oldc)
|
||||
|
||||
d = safe_add(d, oldd)
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
return [a, b, c, d]
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Convert an array of little-endian words to a hex string.
|
||||
*/
|
||||
|
||||
function binl2hex(binarray) {
|
||||
|
||||
|
||||
var hex_tab = "0123456789abcdef"
|
||||
|
||||
|
||||
var str = ""
|
||||
|
||||
|
||||
for (var i = 0; i < binarray.length * 4; i++) {
|
||||
|
||||
|
||||
str += hex_tab.charAt((binarray[i >> 2] >> ((i % 4) * 8 + 4)) & 0xF) +
|
||||
|
||||
hex_tab.charAt((binarray[i >> 2] >> ((i % 4) * 8)) & 0xF)
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
return str
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Convert an array of little-endian words to a base64 encoded string.
|
||||
*/
|
||||
|
||||
function binl2b64(binarray) {
|
||||
|
||||
|
||||
var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
|
||||
|
||||
|
||||
var str = ""
|
||||
|
||||
|
||||
for (var i = 0; i < binarray.length * 32; i += 6) {
|
||||
|
||||
|
||||
str += tab.charAt(((binarray[i >> 5] << (i % 32)) & 0x3F) |
|
||||
|
||||
((binarray[i >> 5 + 1] >> (32 - i % 32)) & 0x3F))
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
return str
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Convert an 8-bit character string to a sequence of 16-word blocks, stored
|
||||
* as an array, and append appropriate padding for MD4/5 calculation.
|
||||
* If any of the characters are >255, the high byte is silently ignored.
|
||||
*/
|
||||
|
||||
function str2binl(str) {
|
||||
|
||||
|
||||
var nblk = ((str.length + 8) >> 6) + 1 // number of 16-word blocks
|
||||
|
||||
|
||||
var blks = new Array(nblk * 16)
|
||||
|
||||
|
||||
for (var i = 0; i < nblk * 16; i++) blks[i] = 0
|
||||
|
||||
for (var i = 0; i < str.length; i++)
|
||||
|
||||
blks[i >> 2] |= (str.charCodeAt(i) & 0xFF) << ((i % 4) * 8)
|
||||
|
||||
blks[i >> 2] |= 0x80 << ((i % 4) * 8)
|
||||
|
||||
blks[nblk * 16 - 2] = str.length * 8
|
||||
|
||||
|
||||
return blks
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Convert a wide-character string to a sequence of 16-word blocks, stored as
|
||||
* an array, and append appropriate padding for MD4/5 calculation.
|
||||
*/
|
||||
|
||||
function strw2binl(str) {
|
||||
|
||||
|
||||
var nblk = ((str.length + 4) >> 5) + 1 // number of 16-word blocks
|
||||
|
||||
|
||||
var blks = new Array(nblk * 16)
|
||||
|
||||
|
||||
for (var i = 0; i < nblk * 16; i++) blks[i] = 0
|
||||
|
||||
for (var i = 0; i < str.length; i++)
|
||||
|
||||
blks[i >> 1] |= str.charCodeAt(i) << ((i % 2) * 16)
|
||||
|
||||
blks[i >> 1] |= 0x80 << ((i % 2) * 16)
|
||||
|
||||
blks[nblk * 16 - 2] = str.length * 16
|
||||
|
||||
|
||||
return blks
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* External interface
|
||||
*/
|
||||
|
||||
function hexMD5(str) {
|
||||
return binl2hex(coreMD5(str2binl(str)))
|
||||
}
|
||||
|
||||
function hexMD5w(str) {
|
||||
return binl2hex(coreMD5(strw2binl(str)))
|
||||
}
|
||||
|
||||
function b64MD5(str) {
|
||||
return binl2b64(coreMD5(str2binl(str)))
|
||||
}
|
||||
|
||||
function b64MD5w(str) {
|
||||
return binl2b64(coreMD5(strw2binl(str)))
|
||||
}
|
||||
|
||||
/* Backward compatibility */
|
||||
|
||||
function calcMD5(str) {
|
||||
return binl2hex(coreMD5(str2binl(str)))
|
||||
}
|
||||
|
||||
export default {
|
||||
hexMD5: hexMD5
|
||||
}
|
||||
266
src/utils/util.js
Normal file
@ -0,0 +1,266 @@
|
||||
import config from '../config.js';
|
||||
|
||||
const getStateCreateTime = (stateList, type) => {
|
||||
if(stateList && stateList.length != 0){
|
||||
const task = stateList.find(item => item.tasksheetState === type);
|
||||
return task?.createTime;
|
||||
}else{
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
const formatTime = date => {
|
||||
date = new Date(date);
|
||||
const hour = date.getHours()
|
||||
const minute = date.getMinutes()
|
||||
const second = date.getSeconds()
|
||||
|
||||
return `${formatNumber(hour)}:${formatNumber(minute)}:${formatNumber(second)}`
|
||||
}
|
||||
|
||||
const formatNumber = n => {
|
||||
n = n.toString()
|
||||
return n[1] ? n : '0' + n
|
||||
}
|
||||
|
||||
const formatDate = date => {
|
||||
date = new Date(date);
|
||||
const year = date.getFullYear()
|
||||
const month = date.getMonth() + 1
|
||||
const day = date.getDate()
|
||||
|
||||
return `${year}-${formatNumber(month)}-${formatNumber(day)}`
|
||||
}
|
||||
|
||||
const formatDateTime = date => {
|
||||
return `${formatDate(date)} ${formatTime(date)}`
|
||||
}
|
||||
|
||||
let loadingCount = 0;
|
||||
let noError = true;
|
||||
let timer = null;
|
||||
const request = option => {
|
||||
if (noError && loadingCount == 0) {
|
||||
// uni.showLoading({
|
||||
// title: '加载中',
|
||||
// mask: true
|
||||
// });
|
||||
}
|
||||
if (timer) {
|
||||
loadingCount--;
|
||||
clearTimeout(timer);
|
||||
timer = null;
|
||||
}
|
||||
loadingCount++;
|
||||
// console.log("request00:",config.baseUrl + option.url);
|
||||
return new Promise((resolve, reject) => {
|
||||
const commonSuccess = res => {
|
||||
if (typeof res.data == 'object') {
|
||||
let data = res.data.data || res.data.tableData;
|
||||
res.data.tableData = data;
|
||||
}
|
||||
if (res.data.Token) {
|
||||
uni.setStorageSync("token", res.data.Token);
|
||||
}
|
||||
if (res.statusCode != 200 || (res.data.code != undefined && res.data.code != 0 &&res.data.code != 1002)) {
|
||||
res.statusCode = res.statusCode == 200 ? 500 : res.statusCode;
|
||||
if (option.fail) {
|
||||
option.fail(res);
|
||||
}
|
||||
return reject(res);
|
||||
}
|
||||
timer = setTimeout(() => {
|
||||
loadingCount--;
|
||||
// console.log("success loadingCount:", loadingCount);
|
||||
if (loadingCount == 0) {
|
||||
if (noError) {
|
||||
// uni.hideLoading();
|
||||
}
|
||||
noError = true;
|
||||
timer = null;
|
||||
}
|
||||
}, 300);
|
||||
if (option.success) {
|
||||
option.success(res);
|
||||
}
|
||||
resolve(res);
|
||||
}
|
||||
const commonFail = err => {
|
||||
noError = false;
|
||||
// uni.hideLoading();
|
||||
if (--loadingCount == 0) {
|
||||
noError = true;
|
||||
}
|
||||
if (option.fail) {
|
||||
option.fail(err);
|
||||
}
|
||||
uni.showToast({
|
||||
title: "网络错误: " + JSON.stringify(err),
|
||||
icon: 'error', // 图标,有效值为 'success', 'loading', 'none'
|
||||
duration: 3000 // 提示的延迟时间,单位毫秒,默认:1500
|
||||
});
|
||||
console.warn(`request: ${option.url}, ${JSON.stringify(err)}`);
|
||||
reject(err);
|
||||
}
|
||||
//console.log("request0:",config.baseUrl + option.url);
|
||||
let staff = uni.getStorageSync('staff');
|
||||
let staffisnull = (staff == null || staff == undefined || staff == '');
|
||||
uni.request({
|
||||
url: config.baseUrl + option.url,
|
||||
data: option.data,
|
||||
header: option.header || {
|
||||
'content-type': 'application/json',
|
||||
'Authorization': staffisnull?null:`Bearer ${uni.getStorageSync('token')}`,
|
||||
'hosp-ID': staffisnull?config.defaultHospId:staff.hosp_id,
|
||||
'user-ID': staffisnull?null:staff.id,
|
||||
'datetime': formatDateTime(new Date),
|
||||
'createby': staffisnull?null:staff.id,
|
||||
},
|
||||
method: option.method || 'POST',
|
||||
success: commonSuccess,
|
||||
fail: commonFail,
|
||||
complete: option.complete,
|
||||
});
|
||||
}).catch((err) => {
|
||||
noError = false;
|
||||
// uni.hideLoading();
|
||||
if (--loadingCount == 0) {
|
||||
noError = true;
|
||||
}
|
||||
//console.log("error loadingcount:", uni.getStorageSync('staff') == null?null:uni.getStorageSync('staff').hosp_id);
|
||||
//console.log("err:",err.data.message,"staff:",uni.getStorageSync('staff'));
|
||||
if (err?.data?.message.includes("非法token")) {
|
||||
//初始化
|
||||
uni.setStorageSync('staff', null);
|
||||
uni.setStorageSync('openid', null);
|
||||
uni.setStorageSync('token', null);
|
||||
|
||||
uni.showToast({
|
||||
title: "非法用户或登录过期,请重新登录。",
|
||||
icon: 'error', // 图标,有效值为 'success', 'loading', 'none'
|
||||
duration: 3000 // 提示的延迟时间,单位毫秒,默认:1500
|
||||
});
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: "网络通信错误:" + JSON.stringify(err?.data?.msg || err),
|
||||
icon: 'error', // 图标,有效值为 'success', 'loading', 'none'
|
||||
duration: 3000 // 提示的延迟时间,单位毫秒,默认:1500
|
||||
});
|
||||
}
|
||||
return err;
|
||||
});
|
||||
}
|
||||
|
||||
const upload = option => {
|
||||
if (timer) {
|
||||
loadingCount--;
|
||||
clearTimeout(timer);
|
||||
timer = null;
|
||||
}
|
||||
loadingCount++;
|
||||
return new Promise((resolve, reject) => {
|
||||
const ret = {
|
||||
data: `{"mydata": {"filename": ""}}`,
|
||||
};
|
||||
const commonSuccess = (res) => {
|
||||
timer = setTimeout(() => {
|
||||
loadingCount--;
|
||||
if (loadingCount == 0) {
|
||||
uni.hideLoading();
|
||||
timer = null;
|
||||
}
|
||||
}, 300);
|
||||
if (option.success) {
|
||||
option.success(res);
|
||||
}
|
||||
resolve(res);
|
||||
};
|
||||
var commonFail = (err) => {
|
||||
noError = false;
|
||||
uni.hideLoading();
|
||||
loadingCount--;
|
||||
uni.showToast({
|
||||
title: "网络错误: " + JSON.stringify(err),
|
||||
icon: 'error', // 图标,有效值为 'success', 'loading', 'none'
|
||||
duration: 3000 // 提示的延迟时间,单位毫秒,默认:1500
|
||||
});
|
||||
reject(err);
|
||||
};
|
||||
if (!option.filePath) {
|
||||
uni.hideLoading();
|
||||
return resolve(ret);
|
||||
}
|
||||
let staff = uni.getStorageSync('staff');
|
||||
let staffisnull = (staff == null || staff == undefined || staff == '');
|
||||
uni.uploadFile({
|
||||
url: config.baseUrl + option.url,
|
||||
header: {
|
||||
Authorization: staffisnull?null:`Bearer ${uni.getStorageSync('token')}`,
|
||||
'hosp-ID': staffisnull?config.defaultHospId:staff.hosp_id,
|
||||
'user-ID': staffisnull?null:staff.id
|
||||
},
|
||||
filePath: option.filePath,
|
||||
name: "file" || option.name,
|
||||
success: commonSuccess,
|
||||
fail: commonFail,
|
||||
complete: option.complete,
|
||||
});
|
||||
}).catch((err) => {
|
||||
console.log('err',err)
|
||||
noError = false;
|
||||
uni.hideLoading();
|
||||
if (--loadingCount == 0) {
|
||||
noError = true;
|
||||
}
|
||||
uni.showToast({
|
||||
title: "网络错误: " + JSON.stringify(err),
|
||||
icon: 'error', // 图标,有效值为 'success', 'loading', 'none'
|
||||
duration: 3000 // 提示的延迟时间,单位毫秒,默认:1500
|
||||
});
|
||||
return err;
|
||||
});
|
||||
}
|
||||
|
||||
function areArraysEqualById(arr1, arr2) {
|
||||
// 如果数组长度不相等,直接返回 false
|
||||
if (arr1.length !== arr2.length) return false;
|
||||
|
||||
// 创建两个 Map 用于存储每个数组的元素 id 及其出现的次数
|
||||
const map1 = new Map();
|
||||
const map2 = new Map();
|
||||
|
||||
// 遍历第一个数组,将元素 id 存储到 map1 中
|
||||
for (let item of arr1) {
|
||||
map1.set(item.id, (map1.get(item.id) || 0) + 1);
|
||||
}
|
||||
|
||||
// 遍历第二个数组,将元素 id 存储到 map2 中
|
||||
for (let item of arr2) {
|
||||
map2.set(item.id, (map2.get(item.id) || 0) + 1);
|
||||
}
|
||||
|
||||
// 比较两个 map 的键值对
|
||||
if (map1.size !== map2.size) return false;
|
||||
|
||||
for (let [key, value] of map1) {
|
||||
if (map2.get(key) !== value) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//判断对象是否未空
|
||||
function isNull(e) {
|
||||
return e==null || e==undefined || e=='';
|
||||
}
|
||||
|
||||
export default {
|
||||
request: request,
|
||||
formatTime: formatTime,
|
||||
formatDate: formatDate,
|
||||
formatDateTime: formatDateTime,
|
||||
upload: upload,
|
||||
areArraysEqualById: areArraysEqualById,
|
||||
getStateCreateTime: getStateCreateTime,
|
||||
isNull
|
||||
}
|
||||
13
tsconfig.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"extends": "@vue/tsconfig/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"sourceMap": true,
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
},
|
||||
"lib": ["esnext", "dom"],
|
||||
"types": ["@dcloudio/types"]
|
||||
},
|
||||
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"]
|
||||
}
|
||||
12
vite.config.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { defineConfig } from "vite";
|
||||
import uni from "@dcloudio/vite-plugin-uni";
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [uni()],
|
||||
|
||||
// set publicDir: 'static',
|
||||
publicDir: "static",
|
||||
|
||||
|
||||
});
|
||||