Browse Source

fix: vue3

master
zhang_li 8 months ago
parent
commit
311497d2c9
  1. 71
      .commitlintrc.js
  2. 3
      .env.development
  3. 4
      .env.production
  4. 2
      .eslintignore
  5. 49
      .eslintrc.json
  6. 31
      .gitignore
  7. 9
      .prettierrc.js
  8. 21
      LICENSE
  9. 260
      README.md
  10. 25
      index.html
  11. 101
      package.json
  12. 6034
      pnpm-lock.yaml
  13. 70
      src/App.vue
  14. 11
      src/api/dept.js
  15. 38
      src/api/device.js
  16. 20
      src/api/dict.js
  17. 112
      src/api/http.ts
  18. 9
      src/api/index.js
  19. 5
      src/api/location.js
  20. 41
      src/api/login.js
  21. 21
      src/api/mold.js
  22. 35
      src/api/overhaulOrder.js
  23. 47
      src/api/repairOrder.js
  24. 17
      src/api/spareParts.js
  25. 18
      src/api/sparePartsApplication.js
  26. 14
      src/api/sparePartsApplicationApprove.js
  27. 10
      src/api/sparePartsServiceWorkOrderList.js
  28. 19
      src/api/spotCheckOrder.js
  29. 40
      src/api/upkeepOrder.js
  30. 11
      src/api/upload.js
  31. 86
      src/api/uploadHttp.ts
  32. 5
      src/api/user.js
  33. 85
      src/components/search/index.vue
  34. 469
      src/components/verifition/Verify.vue
  35. 14
      src/components/verifition/utils/ase.js
  36. 17
      src/components/verifition/utils/request.js
  37. 555
      src/components/verifition/verifyPoint/verifyPoint.vue
  38. 661
      src/components/verifition/verifySlider/verifySlider.vue
  39. 13
      src/env.d.ts
  40. 41
      src/main.ts
  41. 82
      src/manifest.json
  42. 296
      src/pages.json
  43. 219
      src/pages/device/index.vue
  44. 489
      src/pages/deviceReport/addForm.vue
  45. 228
      src/pages/deviceReport/index.vue
  46. 236
      src/pages/deviceReport/myDeviceReport.vue
  47. 331
      src/pages/index.vue
  48. 220
      src/pages/login.vue
  49. 190
      src/pages/mine/agreement.vue
  50. 148
      src/pages/mine/changePassword.vue
  51. 349
      src/pages/mine/index.vue
  52. 90
      src/pages/mine/privacyPolicy.vue
  53. 162
      src/pages/mold/index.vue
  54. 440
      src/pages/overhaulOrder/addForm.vue
  55. 631
      src/pages/overhaulOrder/addServiceRecord.vue
  56. 459
      src/pages/overhaulOrder/detail.vue
  57. 233
      src/pages/overhaulOrder/index.vue
  58. 259
      src/pages/overhaulOrder/reqairOrderList.vue
  59. 466
      src/pages/repairOrder/addForm.vue
  60. 502
      src/pages/repairOrder/addServiceRecord.vue
  61. 762
      src/pages/repairOrder/detail.vue
  62. 235
      src/pages/repairOrder/index.vue
  63. 229
      src/pages/repairOrder/myOrder.vue
  64. 565
      src/pages/repairOrder/transfer.vue
  65. 225
      src/pages/spareParts/index.vue
  66. 497
      src/pages/sparePartsApplication/addForm.vue
  67. 307
      src/pages/sparePartsApplication/detail.vue
  68. 182
      src/pages/sparePartsApplication/index.vue
  69. 169
      src/pages/sparePartsApplication/mySparePartsApplication.vue
  70. 198
      src/pages/sparePartsApplicationApprove/index.vue
  71. 169
      src/pages/sparePartsApplicationApprove/mySparePartsApplicationApprove.vue
  72. 478
      src/pages/sparePartsServiceWorkOrderList/addForm.vue
  73. 175
      src/pages/sparePartsServiceWorkOrderList/mySparePartsService.vue
  74. 354
      src/pages/spotCheckOrder/addForm.vue
  75. 216
      src/pages/spotCheckOrder/myOrder.vue
  76. 627
      src/pages/upkeepOrder/addServiceRecord.vue
  77. 484
      src/pages/upkeepOrder/detail.vue
  78. 224
      src/pages/upkeepOrder/index.vue
  79. 228
      src/pages/upkeepOrder/myOrder.vue
  80. 60
      src/plugins/auth.js
  81. 17
      src/plugins/index.js
  82. 73
      src/plugins/modal.js
  83. 32
      src/plugins/tab.js
  84. 19
      src/plugins/time.js
  85. BIN
      src/static/icon/screen.png
  86. BIN
      src/static/images/banner/icon1.png
  87. BIN
      src/static/images/banner/icon2.png
  88. BIN
      src/static/images/banner/icon3.png
  89. BIN
      src/static/images/banner/icon4.png
  90. BIN
      src/static/images/banner/icon5.png
  91. BIN
      src/static/images/banner/icon6.png
  92. BIN
      src/static/images/banner/icon7.png
  93. 12
      src/static/images/banner/login_banner.svg
  94. BIN
      src/static/images/banner/logo-banner.png
  95. 6
      src/static/images/banner/u2335.svg
  96. 6
      src/static/images/banner/u2450.svg
  97. 6
      src/static/images/banner/u253_selected.svg
  98. BIN
      src/static/images/bg.jpg
  99. BIN
      src/static/images/default.jpg
  100. 1
      src/static/images/icon1.svg

71
.commitlintrc.js

@ -0,0 +1,71 @@
// @ts-check
/** @type {import('cz-git').UserConfig} */
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
'body-leading-blank': [2, 'always'],
'footer-leading-blank': [1, 'always'],
'header-max-length': [2, 'always', 108],
'subject-empty': [2, 'never'],
'type-empty': [2, 'never'],
'subject-case': [0],
'type-enum': [
2,
'always',
[
'feat',
'fix',
'perf',
'style',
'docs',
'test',
'refactor',
'build',
'ci',
'chore',
'revert',
'wip',
'workflow',
'types',
'release'
]
]
},
prompt: {
// 中英文对照版
// messages: {
// type: '选择你要提交的类型 :',
// scope: '选择一个提交范围 (可选):',
// customScope: '请输入自定义的提交范围 :',
// subject: '填写简短精炼的变更描述 :\n',
// body: '填写更加详细的变更描述 (可选)。使用 "|" 换行 :\n',
// breaking: '列举非兼容性重大的变更 (可选)。使用 "|" 换行 :\n',
// footerPrefixsSelect: '选择关联issue前缀 (可选):',
// customFooterPrefixs: '输入自定义issue前缀 :',
// footer: '列举关联issue (可选) 例如: #31, #I3244 :\n',
// confirmCommit: '是否提交或修改commit ?'
// },
// types: [
// { value: 'feat', name: 'feat: 新增功能' },
// { value: 'fix', name: 'fix: 修复缺陷' },
// { value: 'docs', name: 'docs: 文档变更' },
// { value: 'style', name: 'style: 代码格式' },
// { value: 'refactor', name: 'refactor: 代码重构' },
// { value: 'perf', name: 'perf: 性能优化' },
// { value: 'test', name: 'test: 添加疏漏测试或已有测试改动' },
// {
// value: 'build',
// name: 'build: 构建流程、外部依赖变更 (如升级 npm 包、修改打包配置等)'
// },
// { value: 'ci', name: 'ci: 修改 CI 配置、脚本' },
// { value: 'revert', name: 'revert: 回滚 commit' },
// {
// value: 'chore',
// name: 'chore: 对构建过程或辅助工具和库的更改 (不影响源文件、测试用例)'
// },
// { value: 'wip', name: 'wip: 正在开发中' },
// { value: 'workflow', name: 'workflow: 工作流程改进' },
// { value: 'types', name: 'types: 类型定义文件修改' }
// ]
}
}

3
.env.development

@ -0,0 +1,3 @@
VITE_BASE_URL=http://192.168.0.106:12080/admin-api
VITE_BASE_URL_IMAGE=http://localhost:12080/admin-api

4
.env.production

@ -0,0 +1,4 @@
# VITE_BASE_URL=http://dev.ccwin-in.com:23111/app
# VITE_BASE_URL_IMAGE=http://dev.ccwin-in.com:23111
VITE_BASE_URL=https://tmsapp.hongxianggroup.com.cn
VITE_BASE_URL_IMAGE=https://tmsapp.hongxianggroup.com.cn

2
.eslintignore

@ -0,0 +1,2 @@
dist
*.nvue

49
.eslintrc.json

@ -0,0 +1,49 @@
{
"parser": "vue-eslint-parser",
"env": {
"browser": true,
"commonjs": true,
"es2021": true
},
"parserOptions": {
"ecmaVersion": 2021,
"parser": "@typescript-eslint/parser",
"sourceType": "module",
"ecmaFeatures": {
"jsx": true
}
},
"extends": [
"airbnb-base",
"eslint:recommended",
"plugin:prettier/recommended",
"plugin:vue/vue3-essential",
"plugin:@typescript-eslint/recommended"
],
"plugins": ["vue", "@typescript-eslint", "todo-ddl"],
"rules": {
"@typescript-eslint/ban-types": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/explicit-module-boundary-types": "off",
"import/extensions": "off",
"quotes": ["warn", "single"],
"semi": ["warn", "never"],
"import/no-unresolved": "off",
"todo-ddl/diy": "warn",
"import/prefer-default-export": "off",
"no-param-reassign": "warn",
"import/no-extraneous-dependencies": "off",
"max-len": "warn",
"no-restricted-syntax": "off",
"no-bitwise": "off",
"camelcase": "off",
"no-case-declarations": "off",
"@typescript-eslint/no-namespace": "off",
"no-undef": "off",
"no-promise-executor-return": "off",
"vue/multi-word-component-names": "off",
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/ban-ts-comment": "off",
"linebreak-style": "off"
}
}

31
.gitignore

@ -0,0 +1,31 @@
.DS_Store
node_modules/
unpackage/
dist/
wxcomponents
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Editor directories and files
.project
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw*
.hbuilderx
.gitee
.github
package-lock.json
yarn.lock

9
.prettierrc.js

@ -0,0 +1,9 @@
module.exports = {
printWidth: 700, // 一行的字符数,如果超过会进行换行,默认为80
tabWidth: 2, // 一个 tab 代表几个空格数,默认为 2 个
useTabs: false, //是否使用 tab 进行缩进,默认为false,表示用空格进行缩减
singleQuote: true, // 字符串是否使用单引号,默认为 false,使用双引号
semi: false, // 行尾是否使用分号,默认为true
trailingComma: 'none', // 是否使用尾逗号
bracketSpacing: true // 对象大括号直接是否有空格,默认为 true,效果:{ a: 1 }
}

21
LICENSE

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021 sugar
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

260
README.md

@ -0,0 +1,260 @@
# uni-vue3-ts-template
uni-app Vue3 + TypeScript + Vite + Pinia + Unocss 模板项目
支持小程序,H5,App
![图片](https://img.cdn.sugarat.top/mdImg/MTY1MzIxODc4OTk1OQ==653218789959)
![Unocss](https://fastly.jsdelivr.net/gh/MellowCo/image-host/2022/202211121156442.png)
| H5 | 微信小程序 | App(iOS) | App(Android) |
| :-------------------------------------------------------------------------: | :-------------------------------------------------------------------------: | :-------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------: |
| ![图片](https://img.cdn.sugarat.top/mdImg/MTY1MzE5Mzc4MzUyMQ==653193783521) | ![图片](https://img.cdn.sugarat.top/mdImg/MTY1MzE5Mzc1Mzk1MQ==653193753951) | ![图片](https://img.cdn.sugarat.top/mdImg/MTY1MzIxMDc2NTcwNg==653210765706) | <img src="https://img.cdn.sugarat.top/mdImg/MTY1MzIxMzkyOTQxNg==653213929416" width="360"/> |
其它模板
* Vue3的uni-app 纯js模板:[uni-app-template](https://github.com/ATQQ/uni-app-template)
* Vue3的Web应用模板:[vite-vue3-template](https://github.com/ATQQ/vite-vue3-template)
## Env Suggest
**Node >= 14.19**
**pnpm 7**
**Registry taobao - https://registry.npmmirror.com/**
## Use This Template
```sh
npx degit atqq/uni-vue3-ts-template#main my-uni-vue3-ts-vite-project
```
## Feature
### Prod
* [x] [Vue3](https://vuejs.org/)
* [x] [Pinia](https://pinia.vuejs.org/) - replace vuex
* [x] [Axios](https://github.com/axios/axios)
* UI/组件库
* [x] [uView](https://vkuviewdoc.fsq.pub/) - vk-uview-ui
* [ ] [uni-ui](https://github.com/dcloudio/uni-ui) - 待接入
### Dev
* [x] [Vite](https://github.com/vitejs/vite)
* [x] [TypeScript](https://github.com/microsoft/TypeScript/#readme)
* [x] [Sass](https://github.com/sass/sass)
* [x] [Less](https://github.com/less/less.js)
* [x] [Eslint](https://eslint.org/)
* [x] [Prettier](https://prettier.io/)
* [x] [Vitest](https://vitest.dev/) - replace jest
* [x] [unocss](https://github.com/unocss/unocss) - 即时按需原子 css 引擎
* [x] GitHooks [simple-git-hooks](https://github.com/toplenboren/simple-git-hooks#readme)
* ~~LintStaged~~
* ~~StyleLint~~
## 使用
### 安装依赖
**建议使用pnpm,依赖安装速度更快**
```sh
npm i -g pnpm
```
```sh
pnpm install
```
**MAC M1(ARM芯片),其它操作系统无需关注**,正常运行需要手动安装 `esbuild-darwin-64`即可
```sh
pnpm add esbuild-darwin-64@0.15.13 -D
```
## 本地启动
### 微信小程序
```sh
# 构建出产物
pnpm dev:mp-weixin
```
> **Q1:** 如果dev的时候发现报错,可以尝试删除`node_modules`之后再在命令行中运行`pnpm install --shamefully-hoist`重新安装依赖再`pnpm dev:mp-weixin`
>
> [详细参考文档](https://pnpm.io/zh/faq#%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%883)
> **Q2:** 如果运行白屏,有报错信息 “app.js错误ReferenceError: regeneratorRuntime is not defined”
>
> 参考[解决方案](https://blog.csdn.net/FUFCY/article/details/125160828) 给微信小程序IDE开启**增强编译选项**
然后将编译结果`dist/dev/mp-weixin`导入微信开发者工具即可运行
<details>
<summary>点击查看 导入详细步骤</summary>
![图片](https://img.cdn.sugarat.top/mdImg/MTYzNzQxNjc3MjA4Mw==637416772083)
![图片](https://img.cdn.sugarat.top/mdImg/MTYzNzQxNjg4MTUwNA==637416881504)
![图片](https://img.cdn.sugarat.top/mdImg/MTYzNzQxNjY3OTY0NQ==637416679645)
</details>
### H5
```sh
# CSR
pnpm dev:h5
# SSR
pnpm dev:h5:ssr
```
根据提示,打开对应地址即可访问
![图片](https://img.cdn.sugarat.top/mdImg/MTY1MzIxMTE0MDEzMg==653211140132)
### App
>**Q1:** 如启动到App侧有报错?
>请更新至最新的HBuilderX-Alpha客户端
#### 安装一些必要工具
需要使用 `uni-app` 官方提供的 [HBuilderX](https://www.dcloud.io/hbuilderx.html) 启动项目
**Android模拟器在MacOSX、Windows上都可以安装;iOS模拟器只能在MacOSX上安装。**
先安装相关模拟器,[详细参考文档](https://hx.dcloud.net.cn/Tutorial/App/installSimulator)
* 安卓:[夜神模拟器](https://www.yeshen.com/blog/)
* iOS:Mac上安装Xcode
准备就绪后,使用 HBuilderX 打开项目
#### iOS模拟器运行
通过顶部菜单栏,找到运行入口
![图片](https://img.cdn.sugarat.top/mdImg/MTY1MzIxMjk1MTgzNw==653212951837)
选择一个目标设备,点击启动即可
![图片](https://img.cdn.sugarat.top/mdImg/MTY1MzIxMjk3NDM0NQ==653212974345)
#### Android模拟器运行
这里以[夜神模拟器](https://www.yeshen.com/blog/)为例
<details>
<summary>点击查看 详细步骤</summary>
先通过 HBuilderX 修改模拟器端口为 `62001`
![图片](https://img.cdn.sugarat.top/mdImg/MTY1MzIxNDAzMjIwNg==653214032206)
打开夜神模拟器
![图片](https://img.cdn.sugarat.top/mdImg/MTY1MzIxNDA5OTYxNg==653214099616)
选择运行到 Android 基座
![图片](https://img.cdn.sugarat.top/mdImg/MTY1MzIxNDEzMzI0OA==653214133248)
选择已经打开的模拟器,点击运行即可
![图片](https://img.cdn.sugarat.top/mdImg/MTY1MzIxNDIxNjczNw==653214216737)
![图片](https://img.cdn.sugarat.top/mdImg/MTY1MzIxMzkyOTQxNg==653213929416)
</details>
## 打包构建
### 微信小程序
```
pnpm build:mp-weixin
```
### H5
```sh
# CSR
pnpm build:h5
# SSR
pnpm build:h5:ssr
```
### App
基于 `HBuilderX` 参考[官方文档](https://hx.dcloud.net.cn/Tutorial/App/SafePack)进行进一步的操作
其它更多运行脚本 查看 [package.json](./package.json)中的scripts
## css预处理
### 已配置`scss`和`less`全局变量
```typescript
// vite.config.ts
export default defineConfig({
// ......
css: {
preprocessorOptions: {
scss: {
additionalData: '@import "@/static/styles/variables.scss";'
},
less: {
additionalData: '@import "@/static/styles/variables.less";'
}
}
}
})
```
`additionalData`的值是文件的路径,可以按照自己业务需求去修改,**如果项目样式变量分的比较细,可以使用一个样式文件引入多个变量样式文件,然后在这里引入入口文件**
## 别名配置
如果我们想要在`import`的时候 src 的路径简写成`@`,下面的就是配置 vite 的别名,[属性类型请查看vite文档](https://vitejs.cn/config/#resolve-alias)
- `@` 代替 `./src`
- `@components`代替`./src/components`
```typescript
// vite.config.ts
export default defineConfig({
// ......
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
'@components': path.resolve(__dirname, './src/components')
}
}
})
```
例子:
```diff
// pages/index/index.vue
- import Hello from '../../components/hello/index.vue'
+ import Hello from '@/components/hello/index.vue'
// 或者
+ import Hello from '@components/hello/index.vue'
```
### ts
如果是使用ts开发,这样还不够,ts不会识别路径的别名,显示找不到模块的报错,这个时候需要修改 `tsconfig.json` 文件,纠正下路径才可以。
```diff
// tsconfig.json
{
// ......
"compilerOptions": {
// ......
+ "baseUrl": "./",
+ "paths": {
+ "@/*": ["src/*"],
+ "@components/*": ["src/components/*"]
}
},
}
```
添加 `baseUrl``paths` 参数,就可以完美解决编辑器的报错提示了!
## 原子化css
* [unocss](https://github.com/unocss/unocss) - 即时按需原子 css 引擎
* [unocss-preset-weapp](https://github.com/MellowCo/unocss-preset-weapp) - 兼容小程序 unocss 预设
> 支持小程序,h5,app
![](https://fastly.jsdelivr.net/gh/MellowCo/image-host/2022/202211121156442.png)

25
index.html

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

101
package.json

@ -0,0 +1,101 @@
{
"name": "闻荫APP",
"version": "1.0.0",
"private": true,
"scripts": {
"dev:app": "uni -p app",
"dev:custom": "uni -p",
"dev:h5": "uni",
"dev:h5:ssr": "uni --ssr",
"dev:mp-alipay": "uni -p mp-alipay",
"dev:mp-baidu": "uni -p mp-baidu",
"dev:mp-kuaishou": "uni -p mp-kuaishou",
"dev:mp-lark": "uni -p mp-lark",
"dev:mp-qq": "uni -p mp-qq",
"dev:mp-toutiao": "uni -p mp-toutiao",
"dev:mp-weixin": "uni -p mp-weixin",
"dev:quickapp-webview": "uni -p quickapp-webview",
"dev:quickapp-webview-huawei": "uni -p quickapp-webview-huawei",
"dev:quickapp-webview-union": "uni -p quickapp-webview-union",
"build:app": "uni build -p app",
"build:custom": "uni build -p",
"build:h5": "uni build",
"build:h5:ssr": "uni build --ssr",
"build:mp-alipay": "uni build -p mp-alipay",
"build:mp-baidu": "uni build -p mp-baidu",
"build:mp-kuaishou": "uni build -p mp-kuaishou",
"build:mp-lark": "uni build -p mp-lark",
"build:mp-qq": "uni build -p mp-qq",
"build:mp-toutiao": "uni build -p mp-toutiao",
"build:mp-weixin": "uni build -p mp-weixin",
"build:quickapp-webview": "uni build -p quickapp-webview",
"build:quickapp-webview-huawei": "uni build -p quickapp-webview-huawei",
"build:quickapp-webview-union": "uni build -p quickapp-webview-union",
"lint": "eslint --ext .ts,.js,.vue --fix ./",
"test": "vitest",
"test:ui": "vitest --ui",
"test:coverage": "vitest run --coverage",
"cz": "git add . && czg",
"postinstall": "simple-git-hooks",
"updatehooks": "git config core.hooksPath .git/hooks/ && rm -rf .git/hooks && npx simple-git-hooks"
},
"dependencies": {
"@dcloudio/uni-app": "3.0.0-alpha-3060920221114001",
"@dcloudio/uni-app-plus": "3.0.0-alpha-3060920221114001",
"@dcloudio/uni-components": "3.0.0-alpha-3060920221114001",
"@dcloudio/uni-h5": "3.0.0-alpha-3060920221114001",
"@dcloudio/uni-mp-alipay": "3.0.0-alpha-3060920221114001",
"@dcloudio/uni-mp-baidu": "3.0.0-alpha-3060920221114001",
"@dcloudio/uni-mp-kuaishou": "3.0.0-alpha-3060920221114001",
"@dcloudio/uni-mp-lark": "3.0.0-alpha-3060920221114001",
"@dcloudio/uni-mp-qq": "3.0.0-alpha-3060920221114001",
"@dcloudio/uni-mp-toutiao": "3.0.0-alpha-3060920221114001",
"@dcloudio/uni-mp-weixin": "3.0.0-alpha-3060920221114001",
"@dcloudio/uni-quickapp-webview": "3.0.0-alpha-3060920221114001",
"axios": "^0.27.2",
"cz-git": "^1.4.1",
"or": "^0.2.0",
"pinia": "^2.0.35",
"vk-uview-ui": "^1.3.7",
"vue": "^3.2.41",
"vue-demi": "latest",
"vue-i18n": "^9.1.9",
"vuex": "^4.0.2"
},
"devDependencies": {
"@commitlint/cli": "^17.4.2",
"@commitlint/config-conventional": "^17.4.2",
"@dcloudio/types": "^3.0.16",
"@dcloudio/uni-automator": "3.0.0-alpha-3060920221114001",
"@dcloudio/uni-cli-shared": "3.0.0-alpha-3060920221114001",
"@dcloudio/uni-stacktracey": "3.0.0-alpha-3060920221114001",
"@dcloudio/vite-plugin-uni": "3.0.0-alpha-3060920221114001",
"@types/node": "^17.0.45",
"@typescript-eslint/eslint-plugin": "^5.30.3",
"@typescript-eslint/parser": "^5.30.3",
"@vitejs/plugin-vue": "^2.3.3",
"@vitest/ui": "^0.10.5",
"c8": "^7.11.3",
"czg": "^1.4.1",
"eslint": "^8.19.0",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-todo-ddl": "^1.1.1",
"eslint-plugin-vue": "^9.1.1",
"less": "^4.1.3",
"prettier": "^2.7.1",
"sass": "^1.53.0",
"simple-git-hooks": "^2.8.1",
"typescript": "^4.7.4",
"unocss": "^0.46.4",
"unocss-preset-weapp": "^0.2.1",
"vite": "^3.1.8",
"vite-plugin-eslint": "^1.6.1",
"vitest": "^0.16.0"
},
"simple-git-hooks": {
"commit-msg": "npx --no-install commitlint --edit \"$1\""
}
}

6034
pnpm-lock.yaml

File diff suppressed because it is too large

70
src/App.vue

@ -0,0 +1,70 @@
<script setup lang="ts">
import {
onLaunch,
onShow,
onHide
} from '@dcloudio/uni-app'
import {
getCurrentInstance
} from 'vue'
import {
getAccessToken
} from '@/utils/auth'
const { proxy } = getCurrentInstance()
import { storeToRefs } from 'pinia'
import { useCountStore } from '@/store'
// store
const store = useCountStore()
onLaunch(async () => {
// #ifdef MP-WEIXIN
if (uni.canIUse('getUpdateManager')) {
const updateManager = uni.getUpdateManager()
updateManager.onCheckForUpdate(function (res) {
if (res.hasUpdate) {
updateManager.onUpdateReady(function () {
uni.showModal({
title: '更新提示',
content: '新版本已经准备好,是否重启应用?',
success: function (res) {
if (res.confirm) {
updateManager.applyUpdate()
}
}
})
})
updateManager.onUpdateFailed(function () {
uni.showModal({
title: '已经有新版本了哟~',
content: '新版本已经上线啦~,请您删除当前小程序,重新搜索打开哟~'
})
})
}
})
} else {
uni.showModal({
title: '提示',
content: '当前微信版本过低,无法使用该功能,请升级到最新微信版本后重试。'
})
}
// #endif
if (getAccessToken()) {
await store.GetPermissionInfo().then(res => {
}).catch(() => { })
await store.GetInfo().then(res => {
}).catch(() => { })
}
// onLaunchonLoad
proxy.$isResolve();
})
onShow(() => {
})
onHide(() => {
})
</script>
<style lang="scss">
@import 'vk-uview-ui/index.scss';
</style>

11
src/api/dept.js

@ -0,0 +1,11 @@
import http from './http'
// 获取人员列表
export function getSelecUser(params) {
return http.get('/system/dept/selecUserByType',{params})
}
// 获取厂区列表
export function getFactoryAreaList(params) {
return http.get('/system/dept/selectAllFactoryArea',{params})
}

38
src/api/device.js

@ -0,0 +1,38 @@
import http from './http'
// 根据设备号查询信息
export function getDeviceDetailsByNumber(params) {
return http.get('/eam/device-accounts/getDetailsByNumber',{params})
}
// 根据厂区查询设备
export function getDeviceByFactoryAreaNumber(factoryAreaNumber) {
return http.get('/eam/device-accounts/selectData?factoryAreaNumber='+factoryAreaNumber)
}
// 添加报修
export function deviceRepairCreate(data) {
return http.post('/eam/device-repair-request/create',data)
}
// 报修列表
export function deviceRepairPage(params) {
return http.get('/eam/device-repair-request/getAppPage',{params})
}
// 撤销
export function rejected(id) {
return http.delete('/eam/device-repair-request/rejected?id='+id)
}
// 设备列表
export function deviceList(params) {
return http.get('/eam/device-accounts/selectData',{params})
}
// 设备分页列表
export function devicePage(params) {
return http.get('/eam/device-accounts/getAppPage',{params})
}
// 根据设备号码获取二级列表
export function getSubList(params) {
return http.get('/eam/device-mold-items/getListByNumber',{params})
}
// 新增申领备件时获取备件列表
export function getApplyDeviceList() {
return http.get('/eam/device-accounts/selectAll')
}

20
src/api/dict.js

@ -0,0 +1,20 @@
import http from './http'
// 获取字典
export function getDictList(type) {
return http.get('/eam/device-maintenance-job-main/getDictList?type=' + type)
}
export async function getDict(type) {
let data =[]
await getDictList(type).then((res) => {
if (res.code == 0) {
data = res.data.map(item=>{
return {
label:item.label,
value:item.code,
}
})
} else {}
}).catch((err) => {})
return data
}

112
src/api/http.ts

@ -0,0 +1,112 @@
import axios from 'axios'
import { getFullURL } from '@/utils/http'
import { getAccessToken, removeToken } from '@/utils/auth'
const instance = axios.create({
baseURL: import.meta.env.VITE_BASE_URL,
adapter(config) {
const { url, method, data, params, headers, baseURL, paramsSerializer } =
config
return new Promise((resolve, reject) => {
uni.request({
method: method!.toUpperCase() as any,
url: getFullURL(baseURL || '', url!, params, paramsSerializer),
header: headers,
data,
dataType: 'json',
responseType: config.responseType,
success: (res : any) => {
resolve(res)
},
fail: (error : any) => {
reject(error)
}
})
})
}
})
/**
*
*/
instance.interceptors.request.use((config) => {
const { method, params, url } = config
// 附带鉴权的token
const headers : any = {
token: getAccessToken(),
'Authorization': 'Bearer ' + getAccessToken()
}
if (uni.getStorageSync('openId')) {
headers['openId'] = uni.getStorageSync('openId')
}
// 不缓存get请求
if (method === 'get') {
headers['Cache-Control'] = 'no-cache'
}
// delete请求参数放入body中
if (method === 'delete') {
headers['Content-type'] = 'application/json;'
Object.assign(config, {
data: params,
params: {}
})
}
return {
...config,
headers
}
})
/**
*
*/
instance.interceptors.response.use((v) => {
const code = v.data?.code || 200
if (code === 401) {
// alert('即将跳转登录页。。。', '登录过期')
// setTimeout(redirectHome, 1500)
removeToken()
uni.showModal({
title: '系统提示',
content: '登录状态已过期,您可以继续留在该页面,或者重新登录',
cancelText: '关闭',
confirmText: '重新登录',
success: function (res) {
if (res.confirm) {
uni.reLaunch({ url: '/pages/login' })
}
}
})
return v.data
} else if (code === 500) {
uni.showToast({
title: v.data.msg,
icon: 'none'
})
return v.data
} else if (code !== 200) {
uni.showToast({
title: v.data.msg,
icon: 'none'
})
return v.data
}
// @ts-ignore
if ((v.status || v.statusCode) === 200) {
return v.data
}else{
}
return Promise.reject(v)
},error=>{
console.log(error)
uni.showToast({
title: '网络错误',
icon: 'none'
})
})
export default instance

9
src/api/index.js

@ -0,0 +1,9 @@
import http from './http'
// 获取首页数量信息
export function getCounts() {
return http.get('/eam/device-accounts/getCounts')
}
// 获取首页代办信息
export function getToDoCountsByUser() {
return http.get('/eam/device-accounts/getToDoCountsByUser')
}

5
src/api/location.js

@ -0,0 +1,5 @@
import http from './http'
// 获取库位
export function getLocation(number) {
return http.get('/eam/location/scanCodeByNumber?number='+number)
}

41
src/api/login.js

@ -0,0 +1,41 @@
import http from './http'
// 登录方法
export function login(username, password, captchaVerification, tenantName, rememberMe, code, uuid) {
const data = {
username,
password,
captchaVerification,
tenantName,
rememberMe,
code,
uuid,
}
return http.post('/system/auth/login', data)
}
// 获取用户详细信息
export function getInfo() {
return http.get('/system/user/profile/get')
}
// 获取权限
export function getPermissionInfo() {
return http.get('/system/auth/get-permission-info')
}
// 退出方法
export function logout() {
return http.post('/system/auth/logout')
}

21
src/api/mold.js

@ -0,0 +1,21 @@
import http from './http'
// 根据模具号查询信息
export function getMoldDetailsByNumber(params) {
return http.get('/eam/mold-accounts/getDetailsByNumber',{params})
}
// 根据厂区查询模具
export function getMoldByFactoryAreaNumber(factoryAreaNumber) {
return http.get('/eam/mold-accounts/selectData?factoryAreaNumber='+factoryAreaNumber)
}
// 模具分页列表
export function moldPage(params) {
return http.get('/eam/mold-accounts/getAppPage',{params})
}
// 模具列表
export function moldList(params) {
return http.get('/eam/mold-accounts/selectData',{params})
}
// 新增申领备件时获取模具列表
export function getApplyMoldList() {
return http.get('/eam/item-accounts/selectAll')
}

35
src/api/overhaulOrder.js

@ -0,0 +1,35 @@
import http from './http'
// 添加工单
export function overhaulOrderCreate(data) {
return http.post('/eam/device-inspection-job-main/create',data)
}
// 编辑工单
export function overhaulOrderUpdate(data) {
return http.put('/eam/device-inspection-job-main/updat',data)
}
// 报修列表
export function overhaulOrderPage(params) {
return http.get('/eam/device-inspection-job-main/getAppPage',{params})
}
// 操作工单
export function orderClick(params) {
return http.get('/eam/device-inspection-job-main/onClick',{params})
}
// 添加维修工单子项维修内容
export function overhaulOrderDetailCreate(data) {
return http.post('/eam/device-inspection-job-detail/create',data)
}
// 编辑维修工单子项维修内容
export function overhaulOrderDetailUpdate(data) {
return http.put('/eam/device-inspection-job-detail/update',data)
}
// 获得维修工单子列表
export function overhaulOrderDetailList(params) {
return http.get('/eam/device-inspection-job-detail/selectListByNumber',{params})
}
// 删除维修工单子
export function overhaulOrderDetailDelete(id) {
return http.delete('/eam/device-inspection-job-detail/delete?id='+id)
}

47
src/api/repairOrder.js

@ -0,0 +1,47 @@
import http from './http'
// 添加工单
export function repairOrderCreate(data) {
return http.post('/eam/device-maintenance-job-main/create',data)
}
// 编辑工单
export function repairOrderUpdate(data) {
return http.put('/eam/device-maintenance-job-main/update',data)
}
// 工单列表
export function repairOrderPage(params) {
return http.get('/eam/device-maintenance-job-main/getAppPage',{params})
}
// 操作工单
export function orderClick(params) {
return http.get('/eam/device-maintenance-job-main/orderClick',{params})
}
// 添加维修工单子项维修内容
export function repairOrderDetailCreate(data) {
return http.post('/eam/device-maintenance-job-detail/create',data)
}
// 编辑维修工单子项维修内容
export function repairOrderDetailUpdate(data) {
return http.put('/eam/device-maintenance-job-detail/update',data)
}
// 获得维修工单子列表
export function repairOrderDetailList(params) {
return http.get('/eam/device-maintenance-job-detail/selectListByNumber',{params})
}
// 删除维修工单子
export function repairOrderDetailDelete(id) {
return http.delete( '/eam/device-maintenance-job-detail/delete?id='+id)
}
//转办
export function transfer(params) {
return http.get('/eam/device-maintenance-job-main/turnTo',{params})
}
// 获取采取临时措施的维修工单
export function repairOrderList(params) {
return http.get('/eam/device-maintenance-job-main/getList',{params})
}
// 获取维修工单的报修信息
export function getDeviceRepairDetailsByNumber(params) {
return http.get('/eam/device-repair-request/getDetailsByNumber',{params})
}

17
src/api/spareParts.js

@ -0,0 +1,17 @@
import http from './http'
// 获取tabs备件列表
export function getSparePartsPage(params) {
return http.get('/eam/item/getAppPage',{params})
}
// 获取备件列表
export function getSparePartsList(params) {
return http.get('/eam/item/getListByNumber',{params})
}
// 新增申领备件时获取备件列表
export function getApplySparePartsList() {
return http.get('/eam/item/getApplyList')
}
// 新增备件维修获取备件列表
export function getServiceSparePartsList() {
return http.get('/eam/item/getItemMaintainList')
}

18
src/api/sparePartsApplication.js

@ -0,0 +1,18 @@
import http from './http'
// 备件领用列表
export function sparePartsApplicationPage(params) {
return http.get('/eam/item-apply-request-main/getAppPage',{params})
}
// 领用备件
export function sparePartsApplicationCreate(data) {
return http.post('/eam/item-apply-request-main/create',data)
}
// 撤回领用备件
export function sparePartsApplicationCancle(id) {
return http.get('/eam/item-apply-request-main/backout?id=' + id)
}
// 领用备件详情
export function sparePartsApplicationDetail(number) {
return http.get('/eam/item-apply-request-main/appGetByNumber?number=' + number)
}

14
src/api/sparePartsApplicationApprove.js

@ -0,0 +1,14 @@
import http from './http'
// 备件领用审批列表
export function sparePartsApplicationApprovePage(params) {
return http.get('/eam/item-apply-request-main/getAppApprovePage',{params})
}
// 通过申请
export function sparePartsApplicationAgree(id) {
return http.get('/eam/item-apply-request-main/agree?id='+id)
}
// 驳回申请
export function sparePartsApplicationReject(id) {
return http.get('/eam/item-apply-request-main/disAgree?id='+id)
}

10
src/api/sparePartsServiceWorkOrderList.js

@ -0,0 +1,10 @@
import http from './http'
// 领用备件
export function sparePartsServiceWorkOrderListCreate(data) {
return http.post('/eam/item-maintenance-record/create',data)
}
// 备件维修列表
export function sparePartsServiceWorkOrderListPage(params) {
return http.get('/eam/item-maintenance-record/getAppPage',{params})
}

19
src/api/spotCheckOrder.js

@ -0,0 +1,19 @@
import http from './http'
// 添加工单
export function spotCheckOrderCreate(data) {
return http.post('/eam/device-spot-inspection-record-main/create',data)
}
// 编辑工单
export function spotCheckOrderUpdate(data) {
return http.put('/eam/device-spot-inspection-record-main/update',data)
}
// 工单列表
export function spotCheckOrderPage(params) {
return http.get('/eam/device-spot-inspection-record-main/getAppPage',{params})
}
// 操作工单
export function orderClick(params) {
return http.get('/eam/device-spot-inspection-record-main/onClick',{params})
}

40
src/api/upkeepOrder.js

@ -0,0 +1,40 @@
import http from './http'
// 添加工单
export function upkeepOrderCreate(data) {
return http.post('/eam/device-maintain-job-main/create',data)
}
// 编辑工单
export function upkeepOrderUpdate(data) {
return http.put('/eam/device-maintain-job-main/update',data)
}
// 工单列表
export function upkeepOrderPage(params) {
return http.get('/eam/device-maintain-job-main/getAppPage',{params})
}
// 接单
export function orderClick(params) {
return http.get('/eam/device-maintain-job-main/orderClick',{params})
}
// 完成保养工单
export function orderClickFinish(params) {
return http.get('/eam/device-maintain-job-main/orderClickFinish',{params})
}
// 添加维修工单子项维修内容
export function upkeepOrderDetailCreate(data) {
return http.post('/eam/device-maintain-job-detail/create',data)
}
// 编辑维修工单子项维修内容
export function upkeepOrderDetailUpdate(data) {
return http.put('/eam/device-maintain-job-detail/update',data)
}
// 获得维修工单子列表
export function upkeepOrderDetailList(params) {
return http.get('/eam/device-maintain-job-detail/selectListByNumber',{params})
}
// 删除维修工单子
export function upkeepOrderDetailDelete(id) {
return http.delete('/eam/device-maintain-job-detail/delete?id='+id)
}

11
src/api/upload.js

@ -0,0 +1,11 @@
import upload from '@/api/uploadHttp'
// import request from '@/utils/request'
// 上传
export function uploadFile(data) {
return upload({
url: '/infra/file/upload',
method: 'post',
filePath:data.filePath,
name: data.name
})
}

86
src/api/uploadHttp.ts

@ -0,0 +1,86 @@
import axios from 'axios'
import { getFullURL } from '@/utils/http'
import { getAccessToken } from '@/utils/auth'
// const baseURL1 = import.meta.env.VITE_BASE_URL
const upload = axios.create({
baseURL: import.meta.env.VITE_BASE_URL,
adapter(config) {
const { url, method, data, params, headers, baseURL, paramsSerializer, filePath } =
config
headers['tenant-id'] = '1';
return new Promise((resolve, reject) => {
uni.uploadFile({
url: getFullURL(baseURL || '', url!, params, paramsSerializer),
filePath: filePath,
name: 'file',
header: headers,
formData: {
'user': 'test'
},
success: (res) => {
resolve(res)
},
fail: (error) => {
reject(error)
}
})
})
}
})
/**
*
*/
upload.interceptors.request.use((config) => {
const { method, params, url } = config
// 附带鉴权的token
const headers : any = {
token: getAccessToken(),
'Authorization': 'Bearer ' + getAccessToken()
}
if (uni.getStorageSync('openId')) {
headers['openId'] = uni.getStorageSync('openId')
}
// 不缓存get请求
if (method === 'get') {
headers['Cache-Control'] = 'no-cache'
}
// delete请求参数放入body中
if (method === 'delete') {
headers['Content-type'] = 'application/json;'
Object.assign(config, {
data: params,
params: {}
})
}
console.log(11, headers)
return {
...config,
headers
}
})
/**
*
*/
upload.interceptors.response.use((v) => {
if (v.data?.code === 401) {
// alert('即将跳转登录页。。。', '登录过期')
// setTimeout(redirectHome, 1500)
return v.data
}
// @ts-ignore
if ((v.status || v.statusCode) === 200) {
return v.data
}
// alert(v.statusText, '网络错误')
return Promise.reject(v)
})
export default upload

5
src/api/user.js

@ -0,0 +1,5 @@
import http from './http'
// 用户密码重置
export function updateUserPassword(data) {
return http.put('/eam/device-accounts/getDetailsByNumber',data)
}

85
src/components/search/index.vue

@ -0,0 +1,85 @@
<template>
<view class="content">
<view class="screen-input">
<u-search
v-model='keyWord'
:show-action='false'
:bg-color="searchData.bgBolor ||'white'"
:border-color="searchData.borderColor ||'#E4E4E4'"
:shape="searchData.shape ||'square'"
:height="searchData.height || 80"
:placeholder="searchData.placeholder ||'请输入设备名称'"
:clearabled="true"
@search='search'
@clear='clear'
>
</u-search>
</view>
<view class="screen-btn" @click="screen" v-if="isShowScreen">
<image src="../../static/icon/screen.png" mode="widthFix"></image>
<view>筛选</view>
</view>
</view>
</template>
<script>
export default {
props: {
searchData:{
type: Object,
default:()=>{return {}},
require:false
},
isShowScreen: {
type: Boolean,
default:()=>{return true},
require:false
},
},
data() {
return {
keyWord: '',
}
},
methods: {
//
search() {
this.$emit('search', this.keyWord)
},
//
clear() {
this.$emit('search', '')
},
//
screen() {
this.$emit('screen')
}
}
}
</script>
<style lang="scss" scoped>
.content {
padding: 20rpx;
display: flex;
align-items: center;
background: white;
.screen-input {
flex: 1;
width: 0px;
}
.screen-btn {
display: flex;
align-items: center;
margin-left:20rpx;
image {
width: 30rpx;
margin-right: 6rpx;
}
}
}
</style>

469
src/components/verifition/Verify.vue

File diff suppressed because one or more lines are too long

14
src/components/verifition/utils/ase.js

@ -0,0 +1,14 @@
import CryptoJS from 'crypto-js'
/**
* @word 要加密的内容
* @keyWord String 服务器随机返回的关键字
* */
export function aesEncrypt(word, keyWord = "XwKsGlMcdPMEhR1B") {
var key = CryptoJS.enc.Utf8.parse(keyWord);
var srcs = CryptoJS.enc.Utf8.parse(word);
var encrypted = CryptoJS.AES.encrypt(srcs, key, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
});
return encrypted.toString();
}

17
src/components/verifition/utils/request.js

@ -0,0 +1,17 @@
import config from '@/config'
const baseUrl = config.baseUrl
export const myRequest = (option = {}) => {
return new Promise((reslove, reject) => {
uni.request({
url: baseUrl + option.url,
data: option.data,
method: option.method || "GET",
success: (result) => {
reslove(result)
},
fail: (error) => {
reject(error)
}
})
})
}

555
src/components/verifition/verifyPoint/verifyPoint.vue

File diff suppressed because one or more lines are too long

661
src/components/verifition/verifySlider/verifySlider.vue

File diff suppressed because one or more lines are too long

13
src/env.d.ts

@ -0,0 +1,13 @@
/// <reference types="vite/client" />
declare module '*.vue' {
import { DefineComponent } from 'vue'
const component: DefineComponent<{}, {}, any>
export default component
}
interface ImportMetaEnv {
VITE_TITLE: string
VITE_BASE_URL: string
}

41
src/main.ts

@ -0,0 +1,41 @@
import { createSSRApp } from 'vue'
import * as Pinia from 'pinia'
// @ts-ignore
import uView from 'vk-uview-ui'
import App from './App.vue'
import tab from './plugins/tab'
import modal from './plugins/modal'
import time from './plugins/time'
// unocss
import 'uno.css'
import { accessTimeInAnHour, getNowFormatDate } from "./utils/dateTime";
export function createApp() {
const app = createSSRApp(App)
app.use(Pinia.createPinia())
app.use(uView)
// 解决onLaunch和onLoad异步问题
app.config.globalProperties.$onLaunched = new Promise(resolve => {
app.config.globalProperties.$isResolve = resolve
})
// 页签操作
app.config.globalProperties.$tab = tab
// 模态框对象
app.config.globalProperties.$modal = modal
// 时间对象
app.config.globalProperties.$time = time
return {
app,
// uni-app 官方文档示例 https://zh.uniapp.dcloud.io/tutorial/vue3-pinia.html#%E7%8A%B6%E6%80%81%E7%AE%A1%E7%90%86-pinia
Pinia // 此处必须将 Pinia 返回
}
}

82
src/manifest.json

@ -0,0 +1,82 @@
{
"name" : "鸿翔",
"appid" : "__UNI__DA78BC9",
"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" : {
"dSYMs" : false
},
/* SDK */
"sdkConfigs" : {
"ad" : {}
}
}
},
/* */
"quickapp" : {},
/* */
"mp-weixin" : {
"appid" : "wx6176535b0b0153f0",
"setting" : {
"urlCheck" : false
},
"usingComponents" : true
},
"mp-alipay" : {
"usingComponents" : true
},
"mp-baidu" : {
"usingComponents" : true
},
"mp-toutiao" : {
"usingComponents" : true
},
"uniStatistics" : {
"enable" : false
},
"vueVersion" : "3",
"h5" : {
"template" : "index.html",
"devServer" : {
"port" : 9020
}
}
}

296
src/pages.json

@ -0,0 +1,296 @@
{
"pages": [
//pageshttps://uniapp.dcloud.io/collocation/pages
{
"path": "pages/index",
"style": {
"navigationBarTitleText": "首页",
"navigationStyle": "custom",
"navigationBarTextStyle": "white"
}
}, {
"path": "pages/device/index",
"style": {
"navigationBarTitleText": "设备列表",
"navigationBarBackgroundColor": "#409eff",
"navigationBarTextStyle": "white"
}
}, {
"path": "pages/mold/index",
"style": {
"navigationBarTitleText": "模具",
"navigationBarBackgroundColor": "#409eff",
"navigationBarTextStyle": "white"
}
}, {
"path": "pages/spareParts/index",
"style": {
"navigationBarTitleText": "备件",
"navigationBarBackgroundColor": "#409eff",
"navigationBarTextStyle": "white"
}
}, {
"path": "pages/mine/index",
"style": {
"navigationStyle": "custom"
}
},{
"path": "pages/login",
"style": {
"navigationStyle": "custom"
}
},{
"path": "pages/deviceReport/index",
"style": {
"navigationBarTitleText": "设备报修",
"navigationStyle": "custom"
}
},{
"path": "pages/deviceReport/addForm",
"style": {
"navigationBarTitleText": "添加报修",
"navigationBarBackgroundColor": "#409eff",
"navigationBarTextStyle": "white"
}
},{
"path": "pages/deviceReport/myDeviceReport",
"style": {
"navigationBarTitleText": "我的报修",
"navigationStyle": "custom"
}
},{
"path": "pages/repairOrder/index",
"style": {
"navigationBarTitleText": "维修工单",
"navigationStyle": "custom"
}
},{
"path": "pages/repairOrder/addForm",
"style": {
"navigationBarTitleText": "添加维修工单",
"navigationBarBackgroundColor": "#409eff",
"navigationBarTextStyle": "white"
}
},{
"path": "pages/repairOrder/detail",
"style": {
"navigationBarTitleText": "维修工单详情",
"navigationBarBackgroundColor": "#409eff",
"navigationBarTextStyle": "white"
}
},{
"path": "pages/repairOrder/myOrder",
"style": {
"navigationBarTitleText": "我的维修工单",
"navigationStyle": "custom"
}
},{
"path": "pages/repairOrder/addServiceRecord",
"style": {
"navigationBarTitleText": "添加维修内容",
"navigationBarBackgroundColor": "#409eff",
"navigationBarTextStyle": "white"
}
},{
"path": "pages/repairOrder/transfer",
"style": {
"navigationBarTitleText": "转办",
"navigationBarBackgroundColor": "#409eff",
"navigationBarTextStyle": "white"
}
},{
"path": "pages/overhaulOrder/index",
"style": {
"navigationBarTitleText": "检修工单",
"navigationStyle": "custom"
}
},{
"path": "pages/overhaulOrder/addForm",
"style": {
"navigationBarTitleText": "添加检修工单",
"navigationBarBackgroundColor": "#409eff",
"navigationBarTextStyle": "white"
}
},{
"path": "pages/overhaulOrder/detail",
"style": {
"navigationBarTitleText": "检修工单详情",
"navigationBarBackgroundColor": "#409eff",
"navigationBarTextStyle": "white"
}
},{
"path": "pages/overhaulOrder/addServiceRecord",
"style": {
"navigationBarTitleText": "添加检修内容",
"navigationBarBackgroundColor": "#409eff",
"navigationBarTextStyle": "white"
}
},{
"path": "pages/overhaulOrder/reqairOrderList",
"style": {
"navigationBarTitleText": "选择维修工单",
"navigationBarBackgroundColor": "#409eff",
"navigationBarTextStyle": "white"
}
},{
"path": "pages/spotCheckOrder/addForm",
"style": {
"navigationBarTitleText": "添加点检工单",
"navigationBarBackgroundColor": "#409eff",
"navigationBarTextStyle": "white"
}
},{
"path": "pages/spotCheckOrder/myOrder",
"style": {
"navigationBarTitleText": "我的点检工单",
"navigationStyle": "custom"
}
},{
"path": "pages/upkeepOrder/index",
"style": {
"navigationBarTitleText": "保养工单",
"navigationStyle": "custom"
}
},{
"path": "pages/upkeepOrder/detail",
"style": {
"navigationBarTitleText": "保养工单详情",
"navigationBarBackgroundColor": "#409eff",
"navigationBarTextStyle": "white"
}
},{
"path": "pages/upkeepOrder/addServiceRecord",
"style": {
"navigationBarTitleText": "添加保养内容",
"navigationBarBackgroundColor": "#409eff",
"navigationBarTextStyle": "white"
}
},{
"path": "pages/upkeepOrder/myOrder",
"style": {
"navigationBarTitleText": "我的保养工单",
"navigationStyle": "custom"
}
},{
"path": "pages/sparePartsApplication/index",
"style": {
"navigationBarTitleText": "领用申请",
"navigationStyle": "custom",
"navigationBarTextStyle": "white"
}
},{
"path": "pages/sparePartsApplication/addForm",
"style": {
"navigationBarTitleText": "领用备件",
"navigationBarBackgroundColor": "#409eff",
"navigationBarTextStyle": "white"
}
},{
"path": "pages/sparePartsApplication/detail",
"style": {
"navigationBarTitleText": "详情",
"navigationBarBackgroundColor": "#409eff",
"navigationBarTextStyle": "white"
}
},{
"path": "pages/sparePartsApplication/mySparePartsApplication",
"style": {
"navigationBarTitleText": "我的领用",
"navigationBarBackgroundColor": "#409eff",
"navigationBarTextStyle": "white"
}
},{
"path": "pages/sparePartsServiceWorkOrderList/addForm",
"style": {
"navigationBarTitleText": "添加备件维修工单",
"navigationBarBackgroundColor": "#409eff",
"navigationBarTextStyle": "white"
}
},{
"path": "pages/sparePartsServiceWorkOrderList/mySparePartsService",
"style": {
"navigationBarTitleText": "我的备件维修",
"navigationBarBackgroundColor": "#409eff",
"navigationBarTextStyle": "white"
}
},{
"path": "pages/sparePartsApplicationApprove/index",
"style": {
"navigationBarTitleText": "领用申请审批",
"navigationStyle": "custom",
"navigationBarTextStyle": "white"
}
},{
"path": "pages/sparePartsApplicationApprove/mySparePartsApplicationApprove",
"style": {
"navigationBarTitleText": "我的领用审批",
"navigationBarBackgroundColor": "#409eff",
"navigationBarTextStyle": "white"
}
},{
"path": "pages/mine/changePassword",
"style": {
"navigationBarTitleText": "修改密码",
"navigationBarBackgroundColor": "#409eff",
"navigationBarTextStyle": "white"
}
},{
"path": "pages/mine/agreement",
"style": {
"navigationBarTitleText": "用户协议",
"navigationBarBackgroundColor": "#409eff",
"navigationBarTextStyle": "white"
}
},{
"path": "pages/mine/privacyPolicy",
"style": {
"navigationBarTitleText": "隐私政策",
"navigationBarBackgroundColor": "#409eff",
"navigationBarTextStyle": "white"
}
}
],
"tabBar": {
"color": "#8f9bb3",
"selectedColor": "#409eff",
"borderStyle": "white",
"backgroundColor": "#ffffff",
"list": [{
"pagePath": "pages/index",
"iconPath": "static/images/tabbar/tab_icon1.png",
"selectedIconPath": "static/images/tabbar/tab_act_icon1.png",
"text": "首页"
}, {
"pagePath": "pages/device/index",
"iconPath": "static/images/tabbar/tab_icon2.png",
"selectedIconPath": "static/images/tabbar/tab_act_icon2.png",
"text": "设备"
}, {
"pagePath": "pages/mold/index",
"iconPath": "static/images/tabbar/tab_icon3.png",
"selectedIconPath": "static/images/tabbar/tab_act_icon3.png",
"text": "模具"
}, {
"pagePath": "pages/spareParts/index",
"iconPath": "static/images/tabbar/tab_icon4.png",
"selectedIconPath": "static/images/tabbar/tab_act_icon4.png",
"text": "备件"
}, {
"pagePath": "pages/mine/index",
"iconPath": "static/images/tabbar/tab_icon5.png",
"selectedIconPath": "static/images/tabbar/tab_act_icon5.png",
"text": "我的"
}]
},
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "",
"navigationBarBackgroundColor": "#fff",
"backgroundColorBottom": "#f5f5f5"
},
"easycom": {
"custom": {
"^u-(.*)": "vk-uview-ui/components/u-$1/u-$1.vue"
}
}
}

219
src/pages/device/index.vue

@ -0,0 +1,219 @@
<template>
<!-- 设备 -->
<view class="work-container">
<view class="cartNull" v-show="!token">
还没有登录<navigator open-type="navigate" url="/pages/login">先登录</navigator>
</view>
<view class="" v-show='token'>
<Search @search='search' @screen='screen' :isShowScreen='false' />
<view class="list">
<view class="item" v-for="(item,index) in list" :key='index'>
<u-image :src="item.images" width='160' height="160">
<template v-slot:error>
<view class="image-error">
<u-icon name="photo" color="#c7c7c7" size="38"></u-icon>
<view style="font-size: 24rpx;">暂无图片</view>
</view>
</template>
</u-image>
<view class="text">
<view class="title">
{{item.name}}
</view>
<view class="dec1">
{{item.number}}
</view>
<view class="dec2">
{{item.factoryAreaName}}
</view>
</view>
</view>
</view>
<view style="height: 94rpx;padding-top: 30rpx;">
<u-loadmore :status="status" v-if="status != 'loadmore'" />
</view>
</view>
<view style="height: constant(safe-area-inset-bottom); height: env(safe-area-inset-bottom);"></view>
</view>
</template>
<script setup lang="ts">
import {
onShow,
onReachBottom
} from '@dcloudio/uni-app'
import {
ref,
getCurrentInstance
} from 'vue'
import {
getAccessToken
} from '@/utils/auth'
import * as deviceApi from "@/api/device.js"
import Search from '../../components/search/index.vue'
const { proxy } = getCurrentInstance()
const params = ref({
pageNo: 1,
pageSize: 10,
type: '',
name: ''
})
const status = ref('loadmore') //
const list = ref([])
const token = ref('')
//
function search(keyWord) {
params.value.name = keyWord
params.value.pageNo = 1
list.value = []
status.value = 'loadmore'
getList()
}
function screen() {
proxy.$tab.navigateTo(`/pages/device/screen`)
}
function getList() {
if (status.value == 'nomore') return;
status.value = 'loading';
proxy.$modal.loading('加载中')
console.log('params.value',params.value)
deviceApi.devicePage(params.value).then((res) => {
proxy.$modal.closeLoading()
if (res.data.list.length > 0) {
list.value = list.value.concat(res.data.list);
params.value.pageNo++;
status.value = 'loadmore'
} else {
status.value = 'nomore'
}
}).catch(() => { })
}
onShow(() => {
if (getAccessToken()) {
token.value = getAccessToken()
params.value.pageNo = 1
list.value = []
status.value = 'loadmore'
getList()
}
})
onReachBottom(() => {
getList()
})
// onReachBottom() {
// this.getList()
// }
// export default {
// data() {
// return {
// params: {
// pageNo: 1,
// pageSize: 10,
// type: '',
// name:''
// },
// status: 'loadmore', //
// list: [],
// token:''
// }
// },
// methods: {
// //
// search(keyWord) {
// this.params.name = keyWord
// this.params.pageNo = 1
// this.list = []
// this.status = 'loadmore'
// this.getList()
// },
// //
// screen() {
// this.$tab.navigateTo(`/pages/device/screen`)
// },
// //
// getList() {
// if (this.status == 'nomore') return;
// this.status = 'loading';
// this.$modal.loading('')
// deviceApi.devicePage(this.params).then((res) => {
// this.$modal.closeLoading()
// if (res.data.list.length > 0) {
// this.list = this.list.concat(res.data.list);
// this.params.pageNo++;
// this.status = 'loadmore'
// } else {
// this.status = 'nomore'
// }
// }).catch(()=>{})
// },
// },
// onShow() {
// if (getAccessToken()) {
// this.token = getAccessToken()
// this.params.pageNo = 1
// this.list = []
// this.status = 'loadmore'
// this.getList()
// }
// },
// onReachBottom() {
// this.getList()
// }
// }
</script>
<style lang="scss" scoped>
.work-container{
min-height: 100vh;
background: #f5f5f5;
}
.list {
padding-bottom: 20rpx;
.item {
margin-top: 20rpx;
background: white;
padding: 30rpx;
display: flex;
align-items: center;
.text {
margin-left: 20rpx;
.title {
font-size: 32rpx;
font-weight: bold;
}
.dec1 {
font-size: 28rpx;
margin-top: 16rpx;
color: #acacac;
}
.dec2 {
font-size: 28rpx;
margin-top: 6rpx;
color: #acacac;
}
}
}
}
.image-error {
text-align: center;
}
.cartNull {
text-align: center;
padding: 500rpx 40rpx 0;
font-size: 28rpx;
color: #888;
}
.cartNull navigator {
color: #2979ff;
}
</style>

489
src/pages/deviceReport/addForm.vue

@ -0,0 +1,489 @@
<template>
<!-- 添加设备报修 -->
<view class="add-form-container">
<u-form :model="form" ref="formRef" label-width="160rpx">
<u-form-item label="故障描述" prop="describes" required>
<u-input v-model="form.describes" placeholder="请输入故障描述" />
</u-form-item>
<!-- <u-form-item label="所属厂区" prop="factoryAreaNumber" required>
<view class="select"
@click="openSingleColumn('factoryAreaNumber',form.factoryAreaNumber,factoryAreaList)">
<view class="input" v-if='form.factoryAreaNumber'>
{{selectFormat(form.factoryAreaNumber,factoryAreaList)}}
</view>
<view class="placeholder" v-else>
{{`请选择所属厂区`}}
</view>
<u-icon name="arrow-right" color="#aaaaaa" size="28"></u-icon>
</view>
</u-form-item> -->
<u-form-item label="类型" prop="type" required>
<view class="select" @click="openSingleColumn('type',form.type,appDeviceMoldType)">
<view class="input" v-if='form.type'>
{{selectFormat(form.type,appDeviceMoldType)}}
</view>
<view class="placeholder" v-else>
{{`请选择类型`}}
</view>
<u-icon name="arrow-right" color="#aaaaaa" size="28"></u-icon>
</view>
</u-form-item>
<!-- <u-form-item :label="`${type=='DEVICE'||type == 'TECH'?'设备' : '模具'}`" prop="deviceNumber" required>
<view class="select" @click="openSingleColumn('deviceNumber',form.deviceNumber,deviceList)">
<view class="input" v-if='form.deviceNumber'>
{{selectFormat(form.deviceNumber,deviceList)}}
</view>
<view class="placeholder" v-else>
{{`请选择${type=='DEVICE'||type == 'TECH'?'设备' : '模具'}`}}
</view>
<u-icon name="arrow-right" color="#aaaaaa" size="28"></u-icon>
</view>
</u-form-item> -->
<u-form-item :label="`${type=='DEVICE'||type == 'TECH'?'设备' : '模具'}编码`" prop="deviceNumber" required>
<u-input v-model="form.deviceNumber" :placeholder="`请输入${type=='DEVICE'||type == 'TECH'?'设备' : '模具'}编码`"
@blur="blur()" />
<view class="right-button" @click="chickRightButton">
扫描
</view>
</u-form-item>
<u-form-item :label="`${type=='DEVICE'||type == 'TECH'?'设备' : '模具'}名称`" prop="deviceNumber" required
class="disabled">
<u-input v-model="form.deviceName" :placeholder="`根据${type=='DEVICE'||type == 'TECH'?'设备' : '模具'}编码获得`"
disabled />
</u-form-item>
<u-form-item :label="`厂区编码`" prop="factoryAreaNumber" required class="disabled">
<u-input v-model="form.factoryAreaNumber"
:placeholder="`根据${type=='DEVICE'||type == 'TECH'?'设备' : '模具'}编码获得`" disabled />
</u-form-item>
<u-form-item :label="`厂区名称`" prop="factoryAreaName" required class="disabled">
<u-input v-model="form.factoryAreaName"
:placeholder="`根据${type=='DEVICE'||type == 'TECH'?'设备' : '模具'}编码获得`" disabled />
</u-form-item>
<view class="image" style="margin-top: 20rpx;">
<view class="image-list" v-if='imgList.length>0'>
<view class="image-item" v-for="(item,index) in imgList" :key="index">
<image :src="item" mode=""></image>
<u-icon name="close-circle-fill" color="red" class="close" size="36" @click="delImage(index)">
</u-icon>
</view>
</view>
<view class="image-item image-item1" @click="chooseImage" v-if='imgList.length<3'>
<image src="../../static/images/photo.png" mode=""></image>
</view>
</view>
</u-form>
<view class="footer">
<view class="btns">
<button class="reset" @click="reset">重置</button>
<button class="sure" @click="submit" :loading='loading' :disabled='loading'>确定</button>
</view>
<view style="height: constant(safe-area-inset-bottom); height: env(safe-area-inset-bottom);"></view>
</view>
<u-select v-model="singleColumnShow" mode="single-column" :default-value='singleColumnDefaultValue'
:list="singleColumnList" @confirm="chooseSingleColumn" @cancle='singleColumnShow = false'></u-select>
</view>
</template>
<script setup lang="ts">
import {
onLoad,
} from '@dcloudio/uni-app'
import {
ref,
getCurrentInstance
} from 'vue'
import * as deviceApi from "@/api/device.js"
import * as moldApi from "@/api/mold.js"
import * as dictApi from "@/api/dict.js"
import * as uploadApi from "@/api/upload.js"
import * as deptApi from "@/api/dept.js"
const { proxy } = getCurrentInstance()
const loading = ref(false)
const type = ref('')
const appDeviceMoldType = ref([])
const factoryAreaList = ref([])
const form = ref({
describes: "",
deviceNumber: '',
deviceName: '',
factoryAreaName: '',
factoryAreaNumber: '',
type: ''
})
const singleColumnShow = ref(false)
const singleColumnDefaultValue = ref([])
const singleColumnList = ref([])
const imgList = ref([])
function chickRightButton(field) {
if (!form.value.type) {
proxy.$modal.showToast('请先选择类型')
return;
}
uni.scanCode({
success: function (res) {
form.value.deviceNumber = res.result
getDetailsByNumber()
}
});
}
function blur() {
if (form.value.deviceNumber) {
getDetailsByNumber()
} else {
form.value.deviceName = ''
form.value.factoryAreaName = ''
form.value.factoryAreaNumber = ''
}
}
//
function getFactoryAreaList() {
deptApi.getFactoryAreaList().then((res) => {
if (res.data && res.data.length > 0) {
res.data.map(item => {
item.value = item.id
item.label = item.name
})
factoryAreaList.value = res.data
} else {
factoryAreaList.value = []
}
}).catch(() => { })
}
// /
function getDetailsByNumber() {
if (type.value == 'DEVICE' || type.value == 'TECH') {
deviceApi.getDeviceDetailsByNumber({
number: form.value.deviceNumber,
type: type.value,
flag:1
}).then((res) => {
console.log(res)
if (!res.data) {
form.value.deviceName = ''
form.value.factoryAreaName = ''
form.value.factoryAreaNumber = ''
return;
}
form.value.deviceName = res.data.name
form.value.factoryAreaName = res.data.factoryAreaName
form.value.factoryAreaNumber = res.data.factoryAreaNumber
}).catch((err) => {
console.log(err)
form.value.deviceName = ''
form.value.factoryAreaName = ''
form.value.factoryAreaNumber = ''
})
} else if (type.value == 'MOLD') {
moldApi.getMoldDetailsByNumber({
number: form.value.deviceNumber,
flag:1
}).then((res) => {
if (!res.data) {
form.value.deviceName = ''
form.value.factoryAreaName = ''
form.value.factoryAreaNumber = ''
return;
}
form.value.deviceName = res.data.name
form.value.factoryAreaName = res.data.factoryAreaName
form.value.factoryAreaNumber = res.data.factoryAreaNumber
}).catch((err) => {
console.log(err)
form.value.deviceName = ''
form.value.factoryAreaName = ''
form.value.factoryAreaNumber = ''
})
}
}
//
function submit() {
//
if (!form.value.describes) {
proxy.$modal.showToast('请输入故障描述')
return;
}
if (!form.value.factoryAreaNumber) {
proxy.$modal.showToast(`请选择选择所属厂区`)
return;
}
if (!form.value.deviceNumber) {
proxy.$modal.showToast(`请选择${type.value == 'DEVICE' || type.value == 'TECH' ? '设备' : '模具'}`)
return;
}
if (!form.value.type) {
proxy.$modal.showToast(`请选择类型'}`)
return;
}
const data = {
describes: form.value.describes,
deviceNumber: form.value.deviceNumber,
factoryAreaNumber: form.value.factoryAreaNumber,
type: type.value,
filePathList: imgList.value,
}
proxy.$modal.confirm('是否添加报修').then(() => {
proxy.$modal.loading('加载中')
loading.value = true
deviceApi.deviceRepairCreate(data).then((res) => {
proxy.$modal.closeLoading()
if (res.data) {
proxy.$modal.showToast('添加成功')
setTimeout(() => {
proxy.$tab.navigateBack()
loading.value = false
}, 1500)
} else {
proxy.$modal.showToast('添加失败')
loading.value = false
}
}).catch(() => {
proxy.$modal.closeLoading()
loading.value = false
})
})
}
//
function reset() {
form.value = {}
imgList.value = []
}
function selectFormat(val, array) {
let str = array.filter(item => item.value == val)[0].label
return str
}
//
function openSingleColumn(fieldName, val, list) {
singleColumnList.value = list
field.value = fieldName
if (val) {
singleColumnDefaultValue.value = [list.findIndex(item => item.value == val)]
} else {
singleColumnDefaultValue.value = []
}
singleColumnShow.value = true
}
//
function chooseSingleColumn(e) {
form.value[field.value] = e[0].value
if (field.value == 'factoryAreaNumber') {
form.value.deviceNumber = ''
form.value.deviceName = ''
getDetailsByNumber()
}
if (field.value == 'type') {
type.value = form.value[field.value]
getDetailsByNumber()
}
singleColumnShow = false
proxy.$emit('singleColumn', field.value, form.value[field.value])
}
function chooseImage() {
uni.chooseImage({
count: 1, // 9
sizeType: ['compressed'], //
sourceType: ['album', 'camera'], //
success: (res) => {
let filePath = res.tempFilePaths[0]
proxy.$modal.loading()
uploadApi.uploadFile({
filePath: filePath,
name: 'file',
formData: {
'user': 'test'
},
}).then(ret => {
proxy.$modal.closeLoading()
imgList.value.push(ret.data)
}).catch((err) => {
proxy.$modal.closeLoading()
});
},
});
}
//
function delImage(index) {
imgList.value.splice(index, 1)
}
onLoad(async (option) => {
if (option.type) type.value = option.type;
appDeviceMoldType.value = await dictApi.getDict('app_device_mold_type')
if (type.value == 'DEVICE') {
appDeviceMoldType.value = appDeviceMoldType.value.filter((item => item.value != "MOLD"))
uni.setNavigationBarTitle({
title: '设备报修'
})
} else {
uni.setNavigationBarTitle({
title: '模具报修'
})
appDeviceMoldTyp.value =appDeviceMoldType.value.filter((item => item.value == "MOLD"))
}
form.value.type = appDeviceMoldType.value[0].value
getFactoryAreaList()
})
</script>
<style lang="scss" scoped>
.add-form-container {
min-height: calc(100vh - 140rpx);
background: white;
padding: 0px 0rpx 140rpx;
}
.u-form-item {
padding: 20rpx 30rpx;
}
.disabled {
background: #f5f5f5;
}
.list {
padding-bottom: 20rpx;
.item {
margin-top: 20rpx;
background: white;
padding: 30rpx;
display: flex;
align-items: center;
image {
width: 160rpx;
height: 160rpx;
margin-right: 20rpx;
}
.title {
font-size: 32rpx;
font-weight: bold;
}
.dec1 {
font-size: 28rpx;
margin-top: 16rpx;
color: #acacac;
}
.dec2 {
font-size: 28rpx;
margin-top: 6rpx;
color: #acacac;
}
}
}
.select {
display: flex;
align-items: center;
height: 72rpx;
width: 100%;
.input {
flex: 1;
font-size: 28rpx;
color: #000000;
}
.placeholder {
flex: 1;
font-size: 28rpx;
color: rgb(192, 196, 204);
}
}
.footer {
position: fixed;
bottom: 0px;
left: 0px;
width: 100%;
}
.btns {
display: flex;
button {
flex: 1;
}
.sure {
background: #409eff;
color: white;
border-radius: 0px;
&::after {
border: 1px solid #409eff;
border-radius: 0px;
}
}
.reset {
background: #F5F5F5;
border-radius: 0px;
&::after {
border-radius: 0px;
}
}
}
.right-button {
background: #409eff;
color: white;
padding: 0rpx 30rpx;
border-radius: 16rpx;
text-align: center;
font-size: 28rpx;
}
.image {
padding: 0px 30rpx;
padding-bottom: 30rpx;
display: flex;
align-items: center;
flex-wrap: wrap;
.image-list {
display: flex;
align-items: center;
flex-wrap: wrap;
}
}
.image-item {
width: 210rpx;
height: 210rpx;
margin-right: 20rpx;
position: relative;
border: 1px solid rgba(230, 230, 230, 0.5);
margin-bottom: 20rpx;
border-radius: 20rpx;
overflow: hidden;
image {
width: 100%;
height: 100%;
}
.close {
position: absolute;
right: 0px;
top: 0px;
}
}
.image-item1 {
border: none;
margin-right: 0px;
image {
width: 100%;
height: 100%;
}
}
</style>

228
src/pages/deviceReport/index.vue

@ -0,0 +1,228 @@
<template>
<!-- 设备报修 -->
<view class="container">
<u-navbar back-icon-color='#fff' :background="{ background: '#409eff'}" back-text="" title-color='#fff'
title="设备报修">
<template v-slot:right>
<u-icon name="plus" color="#fff" size="36" style="padding-right: 30rpx;" @click="addForm"></u-icon>
</template>
</u-navbar>
<view class="list">
<view class="item" v-for="(item,index) in list" :key="index">
<view class="title">
<view class="title-txt">
{{item.describes}}
</view>
<view class="time">
{{`${$time.formatDate(item.createTime)}`}}
</view>
</view>
<view class="dec">
报修单号:<span>{{item.number}}</span>
</view>
<view class="dec">
类型:<span>{{item.type=='DEVICE'?'设备':item.type=='TECH'?'工艺':'模具'}}</span>
</view>
<view class="dec">
{{`${params.type=='DEVICE'?'设备' : '模具'}`}}编号:<span>{{item.deviceNumber}}</span>
</view>
<view class="dec">
{{`${params.type=='DEVICE'?'设备' : '模具'}`}}名称:<span>{{item.name}}</span>
</view>
<view class="dec">
所属厂区:<span>{{item.factoryAreaName}}</span>
</view>
<view class="images">
<image :src="cur" mode="" v-for="(cur,key) in item.filePathList" :key='key'
@click="previewImage(key,item.filePathList)"></image>
</view>
<view class="bottom">
<view class="status">
<u-tag :text="item.result" bg-color='rgba(255,255,255,0)' color='#2ba471' border-color='#2ba471'
type="primary" shape='circle' />
</view>
<view class="button">
<u-button shape="circle" type="primary" size="mini" style="min-width: 120rpx;"
v-if="item.isCancel == 0" @click="cancle(item)">撤销</u-button>
</view>
</view>
</view>
</view>
<view style="height: 94rpx;padding-top: 30rpx;">
<u-loadmore :status="status" v-if="status != 'loadmore'" />
</view>
<view style="height: constant(safe-area-inset-bottom); height: env(safe-area-inset-bottom);"></view>
</view>
</template>
<script setup lang="ts">
import {
onLoad,
onShow,
onReachBottom
} from '@dcloudio/uni-app'
import {
ref,
getCurrentInstance
} from 'vue'
import * as deviceApi from "@/api/device.js"
const { proxy } = getCurrentInstance()
const params = ref({
pageNo: 1,
pageSize: 10,
type: '',
name: ''
})
const status = ref('loadmore') //
const list = ref([])
const type = ref()
function addForm() {
proxy.$tab.navigateTo(`/pages/deviceReport/addForm?type=${params.value.type}`)
}
async function getList() {
if (status.value == 'nomore') return;
status.value = 'loading';
proxy.$modal.loading('加载中')
await deviceApi.deviceRepairPage(params.value).then((res) => {
proxy.$modal.closeLoading()
if (res.data.list.length > 0) {
list.value = list.value.concat(res.data.list);
params.value.pageNo++;
status.value = 'loadmore'
} else {
status.value = 'nomore'
}
}).catch(() => { })
}
function cancle(item) {
proxy.$modal.confirm('确定撤销报修吗?').then(() => {
proxy.$modal.loading('加载中')
deviceApi.rejected(item.id).then(async (res) => {
proxy.$modal.closeLoading()
params.value.pageNo = 1
list.value = []
status.value = 'loadmore'
await getList()
proxy.$modal.showToast('撤销成功')
}).catch(() => { })
})
}
function previewImage(current, array) {
uni.previewImage({
urls: array,
current: current,
longPressActions: {
itemList: ['发送给朋友', '保存图片', '收藏'],
success: function (data) {
console.log('选中了第' + (data.tapIndex + 1) + '个按钮,第' + (data.index + 1) + '张图片');
},
fail: function (err) {
// console.log(err.errMsg);
}
}
});
}
onLoad((option) => {
if (option.type) params.value.type = option.type;
if (type.value == 'DEVICE') {
uni.setNavigationBarTitle({
title: '设备报修'
})
} else {
uni.setNavigationBarTitle({
title: '模具报修'
})
}
})
onShow(() => {
params.value.pageNo = 1
list.value = []
status.value = 'loadmore'
getList()
})
onReachBottom(() => {
getList()
})
</script>
<style lang="scss" scoped>
.container{
min-height: 100vh;
background: #f5f5f5;
}
.list {
background: #f5f5f5;
margin-top: 20rpx;
.item {
padding: 30rpx 30rpx 0px 30rpx;
margin-top: 20rpx;
background: white;
.title {
display: flex;
align-items: center;
padding-bottom: 20rpx;
.title-txt {
color: #409eff;
font-weight: bold;
font-size: 36rpx;
width: 0px;
flex: 1;
}
.time {
color: #919191;
}
}
.dec {
padding-bottom: 20rpx;
span {
color: #999999;
}
}
.last {
padding-bottom: 30rpx;
}
.bottom {
display: flex;
justify-content: space-between;
align-items: center;
border-top: 1px solid #E4E4E4;
padding: 20rpx 0px;
position: relative;
.status {
flex: 1;
}
.button {
position: absolute;
right: 0rpx;
}
}
}
}
.images {
display: flex;
width: 100%;
image {
width: 30%;
margin-right: 20rpx;
height: 200rpx;
border-radius: 10rpx;
}
}
</style>

236
src/pages/deviceReport/myDeviceReport.vue

@ -0,0 +1,236 @@
<template>
<!-- 设备报修 -->
<view class="container">
<u-navbar back-icon-color='#fff' :background="{ background: '#409eff'}" back-text="" title-color='#fff'
title="我的报修">
</u-navbar>
<view class="list">
<view class="item" v-for="(item,index) in list" :key="index">
<view class="title">
<view class="title-txt">
{{item.describes}}
</view>
<view class="time">
{{`${$time.formatDate(item.createTime)}`}}
</view>
</view>
<view class="dec">
报修单号:<span>{{item.number}}</span>
</view>
<view class="dec">
{{`${params.type=='DEVICE'?'设备' : '模具'}`}}编号:<span>{{item.deviceNumber}}</span>
</view>
<view class="dec">
{{`${params.type=='DEVICE'?'设备' : '模具'}`}}名称:<span>{{item.name}}</span>
</view>
<view class="dec">
所属厂区:<span>{{item.factoryAreaName}}</span>
</view>
<view class="images">
<image :src="cur" mode="" v-for="(cur,key) in item.filePathList" :key='key'
@click="previewImage(key,item.filePathList)"></image>
</view>
<view class="bottom">
<view class="status">
<u-tag :text="item.result" bg-color='rgba(255,255,255,0)' color='#2ba471' border-color='#2ba471'
type="primary" shape='circle' />
</view>
<!-- <view class="button">
<u-button shape="circle" type="primary" size="mini" style="min-width: 120rpx;"
v-if="item.isCancel == 0" @click="cancle(item)">撤销</u-button>
</view> -->
</view>
</view>
<view style="height: 94rpx;padding-top: 30rpx;">
<u-loadmore :status="status" v-if="status != 'loadmore'" />
</view>
</view>
<view style="height: constant(safe-area-inset-bottom); height: env(safe-area-inset-bottom);"></view>
</view>
</template>
<script setup lang="ts">
import {
onShow,
onReachBottom
} from '@dcloudio/uni-app'
import {
ref,
getCurrentInstance
} from 'vue'
import * as deviceApi from "@/api/device.js"
const { proxy } = getCurrentInstance()
const params = ref({
pageNo: 1,
pageSize: 10,
flag: 1,
})
const status = ref('loadmore') //
const list = ref([])
async function getList() {
if (status.value == 'nomore') return;
status.value = 'loading';
proxy.$modal.loading('加载中')
await deviceApi.deviceRepairPage(params.value).then((res) => {
proxy.$modal.closeLoading()
if (res.data.list.length > 0) {
list.value = list.value.concat(res.data.list);
params.value.pageNo++;
status.value = 'loadmore'
} else {
status.value = 'nomore'
}
}).catch(() => { })
}
function previewImage(current, array) {
uni.previewImage({
urls: array,
current: current,
longPressActions: {
itemList: ['发送给朋友', '保存图片', '收藏'],
success: function (data) {
console.log('选中了第' + (data.tapIndex + 1) + '个按钮,第' + (data.index + 1) + '张图片');
},
fail: function (err) {
// console.log(err.errMsg);
}
}
});
}
onShow(() => {
params.value.pageNo = 1
list.value = []
status.value = 'loadmore'
getList()
})
onReachBottom(() => {
getList()
})
</script>
<style lang="scss" scoped>
.list {
margin-top: 20rpx;
.item {
padding: 30rpx 30rpx 0px 30rpx;
margin-top: 20rpx;
background: white;
.title {
display: flex;
align-items: center;
padding-bottom: 20rpx;
.title-txt {
color: #409eff;
font-weight: bold;
font-size: 36rpx;
width: 0px;
flex: 1;
}
.time {
color: #919191;
}
}
.dec {
padding-bottom: 20rpx;
span {
color: #999999;
}
}
.last {
padding-bottom: 30rpx;
}
.bottom {
display: flex;
justify-content: space-between;
align-items: center;
border-top: 1px solid #E4E4E4;
padding: 20rpx 0px;
height: 90rpx;
}
}
}
.list {
background: #f5f5f5;
margin-top: 20rpx;
.item {
padding: 30rpx 30rpx 0px 30rpx;
margin-top: 20rpx;
background: white;
.title {
display: flex;
align-items: center;
padding-bottom: 20rpx;
.title-txt {
color: #409eff;
font-weight: bold;
font-size: 36rpx;
width: 0px;
flex: 1;
}
.time {
color: #919191;
}
}
.dec {
padding-bottom: 20rpx;
span {
color: #999999;
}
}
.last {
padding-bottom: 30rpx;
}
.bottom {
display: flex;
justify-content: space-between;
align-items: center;
border-top: 1px solid #E4E4E4;
padding: 20rpx 0px;
position: relative;
.status {
flex: 1;
}
.button {
position: absolute;
right: 0rpx;
}
}
}
}
.images {
display: flex;
width: 100%;
image {
width: 30%;
margin-right: 20rpx;
height: 200rpx;
border-radius: 10rpx;
}
}
</style>

331
src/pages/index.vue

@ -0,0 +1,331 @@
<template>
<view class="index-page">
<u-navbar back-icon-color='#fff' back-icon-name=''
:background="{ background: 'rgba(64, 158,255,'+bgOpacity+')'}" back-text="" title-color='#f0f0f0'
:immersive='true' :border-bottom='false' title="首页">
</u-navbar>
<view class="top">
<image src="../static/images/mobile_bg.png" class="bg" mode=""></image>
<view class="top-box">
<view class="number">
<view class="number-item">
<view>{{counts.allCount || 0}}</view>
<view>设备总数</view>
</view>
<view class="number-item">
<view>{{counts.breakDownCount || 0}}</view>
<view>故障中设备</view>
</view>
<view class="number-item">
<view>{{counts.repairCount || 0}}</view>
<view>已报修设备</view>
</view>
</view>
<view class="status">
<view class="status-item">
<view>{{counts1.gongdan || 0}}</view>
<view>待接单</view>
</view>
<view class="status-item">
<view>{{counts1.yanzheng || 0}}</view>
<view>待验证</view>
</view>
<view class="status-item">
<view>{{counts1.shenpi || 0}}</view>
<view>待审核</view>
</view>
</view>
</view>
</view>
<view class="box">
<view class="" v-if="deviceMenus.length>0">
<view class="title">设备维护</view>
<u-row gutter="16" style="padding:0px 20rpx ;">
<u-col span="3" v-for="(item,index) in store.deviceMenus" :key='index'>
<view class="icon-item" @click="open('/pages/deviceReport/index?type=DEVICE')"
v-if="item.path =='deviceRequest'">
<image src="../static/images/icon4.svg" mode=""></image>
<view>设备报修</view>
</view>
<view class="icon-item" @click="open('/pages/repairOrder/index?type=DEVICE')"
v-if="item.path =='deviceMaintenanceJob'">
<image src="../static/images/icon5.svg" mode=""></image>
<view>维修工单</view>
</view>
<view class="icon-item" @click="open('/pages/overhaulOrder/index?type=DEVICE')"
v-if="item.path =='deviceInspectionJob'">
<image src="../static/images/icon3.svg" mode=""></image>
<view>检修工单</view>
</view>
<view class="icon-item" @click="open('/pages/spotCheckOrder/addForm?type=DEVICE')"
v-if="item.path =='deviceSpotInspectionRecord'">
<image src="../static/images/icon2.svg" mode=""></image>
<view>点检工单</view>
</view>
<view class="icon-item" @click="open('/pages/upkeepOrder/index?type=DEVICE')"
v-if="item.path =='deviceMaintainJob'">
<image src="../static/images/icon1.svg" mode=""></image>
<view>保养工单</view>
</view>
</u-col>
</u-row>
</view>
<view class="" v-if="moldMenus.length>0">
<view class="title">模具维护</view>
<u-row gutter="16">
<u-col span="3" v-for="(item,index) in moldMenus" :key='index'>
<view class="icon-item" @click="open('/pages/deviceReport/index?type=MOLD')"
v-if="item.path =='moldRequest'">
<image src="../static/images/icon4.svg" mode=""></image>
<view>模具报修</view>
</view>
<view class="icon-item" @click="open('/pages/repairOrder/index?type=MOLD')"
v-if="item.path =='moldMaintenanceJob'">
<image src="../static/images/icon5.svg" mode=""></image>
<view>维修工单</view>
</view>
<view class="icon-item" @click="open('/pages/overhaulOrder/index?type=MOLD')"
v-if="item.path =='moldInspectionJob'">
<image src="../static/images/icon2.svg" mode=""></image>
<view>检修工单</view>
</view>
<view class="icon-item" @click="open('/pages/upkeepOrder/index?type=MOLD')"
v-if="item.path =='moldMaintainJob'">
<image src="../static/images/icon1.svg" mode=""></image>
<view>保养工单</view>
</view>
</u-col>
</u-row>
</view>
<view class="" v-if="thchMenus.length>0">
<view class="title">备件管理</view>
<u-row gutter="16">
<u-col span="3" v-for="(item,index) in thchMenus" :key='index'>
<view class="icon-item" @click="open('/pages/sparePartsApplication/index?from=2')"
v-if="item.path =='itemRequest'">
<image src="../static/images/icon6.png" mode=""></image>
<view>领用申请</view>
</view>
<view class="icon-item" @click="open('/pages/sparePartsApplicationApprove/index?from=3')"
v-if="item.path =='itemApprove'">
<image src="../static/images/icon7.png" mode=""></image>
<view>领用申请审批 </view>
</view>
<view class="icon-item"
@click="open('/pages/sparePartsServiceWorkOrderList/addForm?type=DEVICE')"
v-if="item.path =='itemMaintenanceRecord'">
<image src="../static/images/icon5.svg" mode=""></image>
<view>维修工单</view>
</view>
</u-col>
</u-row>
</view>
</view>
</view>
</template>
<script setup lang="ts">
import {
onShow,
onPageScroll,
onLoad
} from '@dcloudio/uni-app'
import {
getCounts,
getToDoCountsByUser
} from '@/api/index'
import {
ref,
getCurrentInstance
} from 'vue'
import {
getAccessToken
} from '@/utils/auth'
import { storeToRefs } from 'pinia'
import { useCountStore } from '@/store'
const { proxy } = getCurrentInstance()
// store
const store = useCountStore()
const bgOpacity = ref(0)
const counts = ref({
allCount: "",
breakDownCount: '',
repairCount: ''
})
const counts1 = ref({
gongdan: '',
yanzheng: '',
shenpi: ''
})
const deviceMenus = ref([])
const moldMenus = ref([])
const thchMenus = ref([])
//
function getCounts1() {
getCounts().then(res => {
counts.value = res.data
}).catch(() => { })
}
function getToDoCountsByUser1() {
getToDoCountsByUser().then(res => {
counts1.value = res.data
}).catch(() => { })
}
function open(url) {
proxy.$tab.navigateTo(url)
}
onLoad(async()=>{
// onLaunchonLoad
await proxy.$onLaunched;
deviceMenus.value = store.deviceMenus
moldMenus.value = store.moldMenus
thchMenus.value = store.thchMenus
})
onShow(async () => {
if (getAccessToken()) {
getCounts1()
getToDoCountsByUser1()
}
})
onPageScroll((e) => {
if (e.scrollTop > 0) {
bgOpacity.value = e.scrollTop / 200;
} else {
bgOpacity.value = 0
}
})
</script>
<style scoped lang="scss">
.index-content {
background-color: white;
min-height: 100vh;
}
.index-page {
background: white;
}
.bg {
width: 100%;
}
.top {
position: relative;
image {
height: calc(var(--status-bar-height) + 410rpx);
}
}
.top-box {
position: absolute;
width: 100%;
bottom: 0px;
.number {
padding: 30rpx 80rpx 50rpx;
display: flex;
align-items: center;
justify-content: space-between;
.number-item {
text-align: center;
view {
&:nth-child(1) {
color: white;
font-size: 40rpx;
font-weight: bold;
}
&:nth-child(2) {
color: rgba(255, 255, 255, 0.7);
font-size: 28rpx;
margin-top: 10rpx;
}
}
}
}
.status {
margin: 0px 40rpx;
padding: 40rpx 0rpx;
background: white;
border-radius: 20rpx 20rpx 0px 0px;
display: flex;
align-items: center;
justify-content: space-between;
.status-item {
text-align: center;
position: relative;
flex: 1;
view {
&:nth-child(1) {
color: black;
font-size: 40rpx;
font-weight: bold;
}
&:nth-child(2) {
color: rgba(0, 0, 0, 0.5);
font-size: 28rpx;
margin-top: 10rpx;
}
}
&::after {
content: "";
border-right: 1px solid #dedede;
position: absolute;
height: 60rpx;
right: 0px;
top: 50%;
margin-top: -30rpx;
}
&:nth-last-child(1)::after {
border: none;
}
}
}
}
.box {
.title {
font-size: 32rpx;
font-weight: bold;
padding: 50rpx 50rpx 30rpx;
}
.icon-item {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
margin: 20rpx 0px;
image {
width: 80rpx;
height: 80rpx;
}
view {
margin-top: 20rpx;
color: #999999;
}
}
}
</style>

220
src/pages/login.vue

@ -0,0 +1,220 @@
<template>
<view class="normal-login-container">
<view class="logo-img">
<u-icon name="close" size="40" class="icon" @click="$tab.reLaunch('/pages/index')"></u-icon>
<view class="logo-title">
<view>智慧设备管理综合系统</view>
<view>让设备管理更智能更高效</view>
</view>
<image src="../static/images/banner/logo-banner.png" mode="widthFix"></image>
</view>
<view class="box">
<view class="box-shadow">
</view>
<view class="logo-content">
<text class="title">您好欢迎登录</text>
</view>
<view class="login-form-content">
<view class="input-item-label">登录账号</view>
<view class="input-item flex align-center">
<input v-model="loginForm.username" class="input" type="text" placeholder="请输入账号" maxlength="30"
style="height: 100%;" />
</view>
<view class="input-item-label">登录密码</view>
<view class="input-item flex align-center">
<input v-model="loginForm.password" type="password" class="input" placeholder="请输入密码" maxlength="20"
style="height: 100%;" />
</view>
<view class="action-btn">
<button @click="handleLogin" class="login-btn cu-btn block bg-blue lg ">登录</button>
</view>
</view>
<view class="xieyi text-center">
<text class="text-grey1">登录即代表同意</text>
<text @click="handleUserAgrement" class="text-blue">用户协议</text>
<text @click="handlePrivacy" class="text-blue">隐私协议</text>
</view>
</view>
</view>
</template>
<script setup lang="ts">
import * as loginApi from "@/api/login"
import {
ref,
getCurrentInstance
} from 'vue'
const { proxy } = getCurrentInstance()
let loginForm = ref({
tenantName: "闻荫源码",
username: "admin",
password: "123456",
captchaVerification: "",
rememberMe: false,
code: '1',
uuid: "APP"
})
import { storeToRefs } from 'pinia'
import { useCountStore } from '@/store'
// store
const store = useCountStore()
async function handleLogin(params) {
if (loginForm.value.username === "") {
proxy.$modal.msgError("请输入您的账号")
} else if (loginForm.value.password === "") {
proxy.$modal.msgError("请输入您的密码")
} else {
await pwdLogin()
}
}
async function pwdLogin() {
proxy.$modal.loading("登录中,请耐心等待...")
//
store.Login(loginForm.value).then(async (res) => {
proxy.$modal.closeLoading()
await loginSuccess()
}).catch(() => { })
}
//
async function loginSuccess(result) {
await store.GetPermissionInfo().then(res => {
}).catch(() => {})
await store.GetInfo().then(res => {
proxy.$tab.reLaunch('/pages/index')
}).catch(() => {})
}
</script>
<style lang="scss" scoped>
page {
background-color: #ffffff;
}
.normal-login-container {
width: 100%;
.logo-content {
width: 100%;
font-size: 40rpx;
padding: 50rpx 80rpx 0rpx;
.title {
font-weight: bold;
color: #000000;
}
}
.box {
position: relative;
}
.box-shadow {
box-shadow: 0px -10rpx 16rpx rgba(64, 158, 254, 0.5);
width: 100%;
position: absolute;
height: 30rpx;
border-radius: 30rpx 30rpx 0px 0px;
}
.logo-img {
background-color: #fafcff;
height: calc(var(--status-bar-height) + 400rpx);
position: relative;
.icon {
position: absolute;
top: calc(var(--status-bar-height) + 20rpx);
left: 40rpx;
}
.logo-title {
position: absolute;
left: 50rpx;
top: calc(var(--status-bar-height) + 80rpx);
z-index: 11;
view {
&:nth-child(1) {
color: #409eff;
font-weight: bold;
font-size: 36rpx;
}
&:nth-child(2) {
color: #999999;
font-size: 24rpx;
}
}
}
image {
width: 75%;
display: block;
position: absolute;
bottom: 0px;
right: 0px;
}
}
.login-form-content {
margin: 40rpx auto;
width: 80%;
.input-item-label {
font-size: 30rpx;
// font-weight: bold;
color: #888888;
}
.input-item {
margin: 20rpx auto 40rpx;
border: 1px solid #E4E4E4;
padding: 0px 20rpx;
height: 90rpx;
.icon {
font-size: 38rpx;
margin-left: 20rpx;
color: #999;
}
.input {
width: 100%;
font-size: 28rpx;
line-height: 40rpx;
text-align: left;
}
}
.login-btn {
margin-top: 80rpx;
height: 80rpx;
background: #409eff;
color: white;
}
}
.xieyi {
color: #333;
margin-top: 40rpx;
font-size: 24rpx;
}
.easyinput {
width: 100%;
}
}
.login-code-img {
height: 90rpx;
}
</style>

190
src/pages/mine/agreement.vue

@ -0,0 +1,190 @@
<template>
<view class="content">
<view class="gray-bg">
</view>
<view style='padding: 30rpx;background: white;'>
<view class="text">
鸿翔供应链管理北京有限公司遵守中华人民共和国民法典等法律法规之规定尊重并保护服务用户的个人隐私权益为了给用户提供准确个性化服务鸿翔供应链管理北京有限公司会按照本协议的约定使用和披露您的个人信息但鸿翔供应链管理北京有限公司承诺以勤勉审慎义务对待上述信息除本协议另有约定外在未征得用户事先许可的情况下鸿翔供应链管理北京有限公司不会将这些信息对外披露或向第三方提供鸿翔供应链管理北京有限公司会不时更新本隐私权政策并将及时对全体用户公示修改内容 您在同意鸿翔供应链管理北京有限公司服务使用协议之时即视为您已经同意本隐私权政策全部内容本隐私权政策属于鸿翔供应链管理北京有限公司服务使用协议的组成部分
</view>
<view class="text">隐私政策需列举说明业务逻辑与权限的关系<br />
1.我们获取您的电话信息用于注册鸿翔TMS的账号等信息我们不会泄漏您的信息我们会保证您的隐私安全<br />
2.我们获取您的相机权限用于账号的头像更改等信息我们不会泄漏您的信息我们会保证您的隐私安全<br />
3.我们获取您的相册权限用于账号的相关信息上传我们不会泄漏您的信息我们会保证您的隐私安全<br /></view>
<view class="text">
隐私政策需说明获取个人隐私信息的用途<br />
1.我们需要获取您的电话信息用于注册鸿翔TMS的账号等信息我们不会泄漏您的信息我们会保证您的隐私安全<br />
2.我们需要获取您的相机权限用于账号的头像更改等信息我们不会泄漏您的信息我们会保证您的隐私安全<br />
3.我们需要获取您的相册权限用于账号的相关信息上传我们不会泄漏您的信息我们会保证您的隐私安全<br /></view>
<view class="text">
隐私保护承诺<br />
1.鸿翔TMS禁止未经用户授权或者无视现行法律依据私自收集传输或使用用户隐私数据如位置通信录的行为<br />
2.鸿翔TMS包含防病毒或安全防护功能并依法依约说明所收集或传输的相关用户数据以及这些用户数据的用途分享的对象和其他相关信息<br />
3.如对用户个人信息进行转移应告知用户如何使用转移的信息以及在何处使用该信息<br />
4.对用户身份标识鉴权及其他个人信息的收集存储转移应采取确保数据机密性和完整性的加密措施<br />
5.使用第三方支付交易过程中不得记录用户交易类鉴权信息不得向第三方泄露与用户特定交易无关的用户个人信息<br />
6.处理财务信息付款信息或身份信息的鸿翔TMS不得披露任何用户个人数据<br />
7.不得使用任何与功能无关的敏感隐私权限或数据<br />
8.不得篡改鸿翔TMS内的用户个人信息,不得访问或者篡改第三方鸿翔TMS内的用户个人信息<br />
1. 适用范围 <br />
a) 注册服务帐号时需根据要求提供的个人注册信息 <br />
b) 使用网络服务访问平台网页时将自动接收并记录用户浏览器和计算机上的信息包括但不限于用户的IP地址浏览器的类型使用的语言访问时间软硬件特征信息及用户需求的网页记录等数据 <br />
c)通过合法途径从商业伙伴处取得的用户个人信息不适用本隐私权政策 在使用平台提供的搜索服务时输入的关键字信息 收集到的用户在平台上发布的有关信息数据 违反法律规定或违反协议规则的行为及鸿翔供应链管理北京有限公司平台已对用户采取的措施 <br />
2. 信息使用 <br />
a) 未经许可鸿翔TMS不向任何无关第三方披露或交易用户的个人信息第三方和鸿翔TMS含吉鸿翔TMS关联公司单独或共同为用户提供服务服务结束后第三方也禁止访问包括其以前能够访问的所有的资料<br />
b) 鸿翔TMS禁止第三方收集编辑出售或者无偿传播用户的个人信息第三方或用户如从事上述行为一经发现鸿翔TMS有权立即终止与该其的服务或合作 <br />
c) 为做好服务鸿翔TMS可能通过用户资料向其提供相关信息包括但不限于向用户发出产品和服务信息与鸿翔TMS的关联公司共享信息以便向用户发送相关产品和服务的信息后者需要用户的同意<br />
3. 信息披露 <br />
在如下情况下鸿翔TMS有权根据用户意愿或政策法规披露用户的信息 <br />
a) 经用户同意向第三方披露 <br />
b) 为提供用户需求的产品或服务而必须和第三方分享用户的个人信息<br /> 
c) 根据政策法规或司法行政部门要求对外披露信息<br />
d) 用户违反政策法规鸿翔TMS服务协议或相关规则的可向第三方披露 <br /> 
e)适格知识产权权利人投诉应被投诉人要求向投诉人披露<br />
f) 在平台上创建交易如交易一方履行或部分履行了交易义务并提出信息披露请求的鸿翔TMS有权决定向该用户提供其交易对方的联络方式等必要信息<br />
g)根据法律法规或者网站政策应当披露的其他情况  <br />
4. 信息存储和交换  <br />
收集的用户信息和资料将保存在鸿翔TMS或关联公司的服务器上这些信息和资料可能传送至用户所在国家地区上述信息可能在境外被访问存储和展示 <br />
5. 信息安全  <br />
a)用户帐号均有安全保护功能请妥善保管用户名及密码信息鸿翔TMS将通过对用户密码进行加密等安全措施确保用户的信息不丢失不被滥用和变造尽管有前述安全措施但同时也请用户注意在信息网络上不存在完善的安全措施<br />
 
b)在使用鸿翔TMS网络服务进行网上交易时用户不可避免的要向交易对方或潜在的交易对方披露个人信息如联络方式或者邮政地址请用户妥善保护个人信息如发现信息泄密特别是用户名及密码发生泄露请用户立即联络鸿翔TMS客服以便鸿翔TMS公司采取相应措施<br />
</view>
<view class="text">
鸿翔TMS电子商务平台(简称平台")由鸿翔供应链管理(北京)有限公司及关联公司(包括但不限于分公司、控股公司、合作公司)运营,平台按照本注册协议向用户提供相关服务。请用户接受平台服务前认真、仔细研读注册协议。理解并认同注册协议是成为平台用户(以下简称为"用户")的前提。用户注册为平台用户时,点击对应页面相关提示按钮,表示用户已仔细研读并明确同意遵守注册协议及经援(参)引并入其中的全部条款、规则、指南等文件要求,表明用户同意受上述文件规范和约束(合称"注册协议")并给予相关授权<br />
平台有权依照政策法规或服务需要对注册协议进行修改和完善除另有规定外平台相关文件制度指南等变更或修改在修订内容在平台发布之时立即生效用户对本平台的继续使用即视为用户接受并认同变更或修改用户不同意注册协议(包括相关文件制度指南等修改部分)规定则请用户停止注册已经注册的请即刻注销平台不再提供相应服务为了便于用户知晓和理解平台条款及服务条件,用户应经常审阅注册协议以及经援引而成为平台规则的相关规定
</view>
<view class="text">
服务内容<br />
1.单独或与第三方共同为用户提供各项服务包括但不限于为用户提供下载链接超链接服务银行信用卡链接或将用户提交至平台的信息反馈至第三方产品服务商银行信用卡中心便于为用户提供产品试用办理信用卡等服务<br />
2.平台具体服务内容处于动态更新状态服务内容由平台提供包括但不限于图文信息链接等通过数据分析平台有权以电子邮件短信电话或站内信等方式为用户提供活动信息和服务参考以便于向用户提供精准服务<br />
3.平台服务仅供个人用户使用未经平台书面授权或许可任何人均不得利用平台信息含用户信息用于商业目的<br />
4.用户使用平台服务所需的设备以及网络资源等(包括但不限于电脑手机或其他接入互联网或与移动网有关的装置设备)和所产生的相关费用(包括但不限于话费网费等)均由用户自行负担<br />
5.平台对提供的服务拥有最终解释权<br />
</view>
<view class="text">
信息提供和隐私保护<br />
1.用户访问使用平台或接受平台服务时应当提供真实个人信息并应该根据变动情况及时更新尊重用户隐私是平台运营规则的重要内容之一平台将通过技术手段内控管理等手段提供隐私保护服务功能<br />
2.平台不负责审核用户提供个人信息的真实性准确性完整性因用户信息不真实不准确或不完整而引发的任何责任及其后果均由用户自行承担用户承诺因以上原因造成不利法律后果的平台免责发现用户提供的个人信息存在虚假不准确不完整等情况平台有权单方面决定终止向用户提供服务且无须承担任何法律责任<br />
3.用户同意平台为提供服务履约处理纠纷强化交易安全等原因对用户自行披露的平台收集包括通过第三方收集的相关信息用户储存在平台的非公开信息以及其他资料(以下简称资料")享有保存整理加工使用及披露的权利,具体方式包括但不限于:<br />
(1)平台公司含关联公司合作公司等采取存储整理加工使用公示反馈等手段使用用户资料信息<br />
(2)人工或程序自动获取评估整理存储用户资料;<br />
(3)利用用户在平台或第三方处留存的联系方式身份证件用户ID等资料用于注册登录本平台<br />
4参考和使用用户信息提升网站平台的服务水平通过用户的联系方式传递平台服务和管理等方面信息<br />
5同意对用户资料进行分析整合并向为用户服务的第三方提供必要信息与用户进行电话核实信息时同意平台对进行录音<br />
(6)用户违反与平台协议规则指南等文件平台有权与其他用户签订协议时披露该用户的资料及违约事实将该用户的违约信息写入黑名单并与第三方共享数据以上信息可供平台及第三方审核追索之用<br />
(7)其他使用及披露用户个人资料的情况<br />
用户同意本条款且该条款不因用户终止使用平台服务而失效,用户同意平台使用上述信息免责<br />
4.用户同意并授权平台与其第三方进行联合开发升级平台系统并可通过本协议获得用户的信息并加以使用平台要求第三方对用户信息予以保密<br />
5.用户理解并同意注册成为平台会员时平台有权调取并保存用户手机内的信息平台有权将上述信息发送给第三方合作机构用于用户资质评估<br />
6.用户授权平台完成了信息获取事宜用户再次登陆平台接受服务时平台可将获取的信息推送至为用户提供服务的机构<br />
7.鉴于技术限制用户知晓平台无法确保信息绝对不被泄露<br />
8.平台不向第三方恶意出售或免费提供用户信息但下列情况除外:<br />
(1)获得用户授权<br />
(2)配合司法机关或政府相关部门<br />
(3)维护平台合法权益<br />
(4)维护社会公众利益<br />
(5)确保本平台业务和系统的完整与操作<br />
(6)其他合法情况<br />
</view>
<view class="text">
使用准则<br />
1.使用本平台服务过程中用户必须遵守国家法律法规不通过平台发布复制上传散播分发存储创建或以其它方式公开含有以下内容的信息:<br />
(1)危害国家安全损害国家荣誉和利益的
(2)扰乱社会秩序破坏社会稳定的<br />
(3)散布淫秽色情赌博暴力等信息教唆犯罪或散步欺诈性及其它有违社会公序良俗的讯息数据信息文本音乐声音照片图形代码等<br />
(4)侵害他人合法权益的<br />
(5)可能侵犯他人知识产权商业信息的<br />
6第三方信息包括但不限于地址联系方式电子邮件地址身份证号以及信用卡卡号等<br />
(7)病毒不可靠数据或其它具有破坏性危害性的信息或数据<br />
8与平台服务不相关的内容<br />
(9)平台认定不适当的的言论信息限制或妨碍他人使用或接受平台服务或者可能使平台或平台关联方其他用户遭受干扰或损失的<br />
(10)其他违反现行法律法规及公序良俗行为的<br />
2.用户不得利用平台从事危害互联网信息网络安全的行为:<br />
(1)未经准许进入或使用互联网信息网络资源<br />
(2)未经准许删除修改或者增加互联网信息网络功能<br />
(3)未经准许对互联网信息网络中存储处理或者传输的数据和应用程序进行删除修改或者增加<br />
(4)制作传播计算机或手机病毒等破坏性程序<br />
(5)其他危害互联网信息网络安全行为<br />
3.平台保留在任何时候为任何理由而不经通知的过滤移除筛查或编辑处理网站和平台上发布或存储的任何内容的权利用户须自行负责备份和替换在网站和平台上发布或存储的任何内容由此而产生的备份或替换费用由用户自行承担<br />
4.用户须对使用平台服务过程中的行为承担法律责任<br />
5.用户的操作行为可能影响平台或系统运行的平台有权暂停或终止用户操作直至潜在风险或者问题得到解决<br />
</view>
<view class="text">
免责声明<br />
1.平台具有开放性用户将文字影音资料等上传至互联网上上述信息及资料可能会被第三方使用用户能够充分意识和了解此类风险的存在用户对在论坛个人主页或其它互动区域提供的陈述声明或内容自行承担责任用户承诺使用平台服务所存在的风险或产生的一切后果完全由用户自行承担平台对上述风险或后果不承担任何责任<br />
2.用户违反注册协议包括平台规则指南等违反法律法规和公序良俗侵犯他人权利的经由该用户自行承担法律责任平台不承担任何责任平台对任何第三方通过平台发送服务或包含在服务中的任何内容不承担责任<br />
3.对用户或任何第三方发布存储或上传的信息等或由该信息等导致的损失或损害均由用户或第三方承担责任平台不承担任何责任<br />
4.第三方通过平台对用户造成的侵权行为均应由第三方负责平台不承担责任<br />
5.黑客行为病毒因用户过错造成损失由于与平台网站链接的其它网站含APP软件等所造成用户信息泄露或其他非平台原因造成的损失平台均不承担责任用户发现任何非法使用用户帐号或安全漏洞的情况应当立即与本平台联系<br />
6.非平台原因造成的网络服务中断或其他缺陷平台不承担任何责任<br />
7.平台服务无法完全满足用户的要求服务过程中可能会出现中断平台不能完全保证服务的及时性准确性安全性等<br />
8.因使用平台而引起或与使用平台有关的而产生的依照法律和协议和规定应当由平台承担的责任限额包括但不限于合同保证侵权产品责任严格责任或其它原因均不得超过用户因当次访问或使用网站平台而向平台支付的服务费用<br />
9.平台提供免费的信息搜索和推荐服务用户在接受第三方服务过程中遇到的任何预先收费均可能是诈骗行为请保持警惕避免损失<br />
</view>
<view class="text">
服务变更中断或终止<br />
1.出现升级等需要而暂停网络服务调整服务内容等情况时平台可尽量在网站上进行通告如因因用户未能及时浏览通告等原因而造成的损失平台不承担任何责任<br />
2.用户同意平台根据实际情况随时调整各项服务内容种类形式或平台有权决定授权第三方向用户提供原是平台提供的服务等因业务调整给用户造成的损失平台不承担责任本平台保留随时变更中断或终止平台全部或部分服务的权利<br />
3.发生下列情形之一平台有权单方面中断或终止向用户提供服务且无需通知的权利平台无需对用户或第三方承担责任:<br />
(1)用户提供资料不真实;<br />
(2)用户违反本注册协议;<br />
(3)未经平台书面同意将平台或相关信息用于商业目的而使用<br />
4.用户可通知平台终止提供服务或直接取消平台服务自终止或取消服务之日起平台不再向用户承担任何责任<br />
</view>
<view class="text">
知识产权及其它权利
1.依找法律规定和协议约定用户可以利用平台相关信息此处信息仅限于用户自有或者用户依法有权使用的<br />
2.用户对在平台发布共享传播的信息作如下声明和承诺:<br />
(1)用户依法对上述信息具有所有权或使用权;<br />
2信息内容合法的真实的准确的不具有误导性;<br />
(3)不违反注册协议和平台制度及相关文件不侵犯任他人合法权益<br />
3.未经授权用户不得在平台上复制传播使用存储其他权利主体的信息包括但不限于影音资料文字程序代码等<br />
4.用户在平台存储使用具有合法使用权限的信息包括但不限于影音资料文字程序代码等平台对上述信息可享有如下权利:<br />
(1)平台有权使用上述信息包括但不限于复制修改改编翻译传播发表等及上述信息衍生的相关产品平台享有无限制性包括但不限于空间无限制时间无限制的通过任何载体或媒介(包含现有的或今后可能产生的)公开展示和表演此等内容的权利;<br />
(2)平台及关联方有权将使用上述信息的全部权利或部分权利转让给第三方;<br />
(3)第三方侵犯用户的权益用户有权依法追究其责任(平台无义务配合用户向第三方追责同时平台对用户不承担责任) ;<br />
5.用户在平台发布的信息为非保密信息平台没有义务将其为用户保密信息对待在不限制前述规定的前提下平台保留以适当的方式使用上述信息的权利包括但不限于删除编辑更改不予采纳或拒绝发布等平台无义务就用户提交的内容而向用户支付金钱或提供其他优惠待遇和政策相关信息在平台发布平台不保证向用户提供对在平台发布的内容进行编辑删除或作其它修改的服务<br />
6.第三方就用户行为向平台发出维权通知的平台有权在不事先通知用户的情况下自行移除删减相关信息同时平台有权保留相关数据用户承诺不因平台行为而主张任何赔偿如平台因此遭受损失则用户应向平台赔偿损失(包括但不限于赔偿律师代理费等各类直接及间接损失和费用)<br />
7.用户认为第6款指向内容并未侵犯第三方权利可向平台以书面方式释明书面释明应包含如下内容:用户信息及联系方式和未侵权的相关证据信息发布位置位置等平台收到该书面通知后有权决定是否予以采信或否定<br />
8.用户承诺第7款中书面通知存在瑕疵的用户负责承担全部法律责任如平台因此遭受损失用户承担全部赔偿责任包含律师代理费等直接损失和间接损失<br />
</view>
<view class="text">
特别约定<br />
1.用户在平台上有任何违反国家法律法规或侵犯任何第三方的合法权益的行为时平台有权采取对用户采取注销封号删除信息暂停服务等权利且此种情况下平台无需承担任何责任<br />
2.用户利用平台从事任何违法或侵权行为,由用户自行承担全部责任因此给平台或任何第三方造成损失的用户应承担全部责任<br />
3.用户同意平台或平台关联公司通过重要页面的公告通告电子邮件以及常规信件的形式向其传送与本平台服务有关的任何通知和通告<br />
4.发生与平台服务相关投诉或被投诉的用户应立即与平台联系<br />
5.除非平台更新协议用户在确认同意或签署本协议后其效力将及于用户此时及未来登陆平台时所有操作<br />
6.用户在协议项下对平台的授权即视为对平台及平台之关联公司的授权平台及平台关联公司有权根据用户的授权及协议约定执行相关操作<br />
7.发生争议各方一致同意由平台公司注册地人民法院管辖<br />
8.本注册协议最终解释权归本平台所有<br />
</view>
</view>
<view style="height: constant(safe-area-inset-bottom); height: env(safe-area-inset-bottom);"></view>
</view>
</template>
<script setup lang="ts">
</script>
<style scoped>
.gray-bg {
width: 100%;
height: 20rpx;
background: rgba(245, 245, 245);
}
.text {
margin-top: 20rpx;
}
view {
font-size: 30rpx;
}
</style>

148
src/pages/mine/changePassword.vue

@ -0,0 +1,148 @@
<template>
<view>
<view class="box">
<view class="item">
<!-- <image src="../../static/icon/user_password_icon_blue.png"></image> -->
<view class="item2 padd35">
<input type="text" v-model="oldPassword" placeholder="请输入原密码" />
</view>
</view>
<view class="item">
<!-- <image src="../../static/icon/user_password_icon_red.png"></image> -->
<view class="item2 padd35">
<input type="text" v-model="newPassword" placeholder="请输入新密码" />
</view>
</view>
<view class="item">
<!-- <image src="../../static/icon/user_password_icon.png"></image> -->
<view class="item2 padd35">
<input type="text" v-model="confirmPassword" placeholder="请确认新密码" />
</view>
</view>
</view>
<view class="btn" @click="submit">确认</view>
</view>
</template>
<script setup lang="ts">
import {
ref,
getCurrentInstance
} from 'vue'
import * as userApi from "@/api/user.js"
const { proxy } = getCurrentInstance()
const newPassword = ref('')
const oldPassword = ref('')
const confirmPassword = ref('')
const loading = ref(false)
function submit() {
if (!oldPassword.value) {
proxy.$modal.showToast('请输入原密码');
return;
}
if (!newPassword.value) {
proxy.$modal.showToast('请输入新密码');
return;
}
if (!confirmPassword.value) {
proxy.$modal.showToast('请确认新密码');
return;
}
if (confirmPassword.value != newPassword.value) {
proxy.$modal.showToast('两次输入的密码不一致,请重新输入');
return;
}
proxy.$modal.confirm('是否修改密码').then(() => {
proxy.$modal.loading('加载中')
loading.value = true
userApi.updateUserPassword({
newPassword: newPassword.value,
oldPassword: oldPassword.value,
}).then(res => {
if (res.data) {
proxy.$modal.showToast('修改成功')
setTimeout(() => {
proxy.$tab.navigateBack()
loading.value = false
}, 1500)
} else {
proxy.$modal.showToast('修改失败')
loading.value = false
}
}).catch(() => {
proxy.$modal.closeLoading()
loading.value = false
})
})
}
</script>
<style lang="scss">
page {
background-color: #f8f9fb;
}
.box {
width: 94vw;
margin: 20rpx auto;
border-radius: 20rpx;
overflow: hidden;
}
.item {
background-color: #FFFFFF;
padding: 0rpx 30rpx;
display: flex;
align-items: center;
image {
width: 44rpx;
height: 44rpx;
margin-right: 30rpx;
}
.item2 {
display: flex;
align-items: center;
justify-content: space-between;
flex: 1;
border-bottom: 1rpx solid #efefef;
padding: 25rpx 0rpx;
input {
font-size: 28rpx;
}
view {
color: #1a4f9f;
border: 1rpx solid #1a4f9f;
font-size: 30rpx;
border-radius: 50rpx;
padding: 10rpx 18rpx;
}
}
}
.btn {
width: calc(100vw - 80rpx);
position: fixed;
bottom: 200rpx;
left: 40rpx;
background-color: rgb(64, 158, 255);
color: #FFFFFF;
height: 90rpx;
line-height: 90rpx;
text-align: center;
border-radius: 50rpx;
font-size: 32rpx;
}
.noborder {
border-bottom: none !important;
}
.padd35 {
padding: 35rpx 0 !important;
}
</style>

349
src/pages/mine/index.vue

@ -0,0 +1,349 @@
<template>
<view class="mine-container">
<u-navbar back-icon-color='#fff' back-icon-name=''
:background="{ background: 'rgba(64, 158,255,'+bgOpacity+')'}" back-text="" title-color='#fff'
:immersive='true' :border-bottom='false' title="个人中心">
</u-navbar>
<view class="header-section">
<image src="../../static/images/bg.jpg" class="bg" mode=""></image>
<view class="info" v-if="store.name">
<image :src="store.avatar" class="cu-avatar" mode="" v-if="store.avatar"></image>
<view class="cu-avatar" v-else>
<u-icon name="account-fill" color="#d4d4d4" size="100"></u-icon>
</view>
<view class="user-info">
<view class="name">{{store.name}} <span v-if="store.post">{{store.post.name}}</span></view>
<view class="tips">{{store.dept.name}}</view>
</view>
</view>
<view class="info" v-else>
<view class="cu-avatar">
<u-icon name="account-fill" color="#d4d4d4" size="100"></u-icon>
</view>
<view class="user-info" @click="handleLogin">
<view class="name">点击登录</view>
</view>
</view>
</view>
<view class="content-section">
<view class="mine-actions grid col-3 text-center">
<view class="action-item" @click="handleDeviceReport">
<image src="../../static/images/banner/icon1.png" mode="widthFix"></image>
<text class="text">我的报修</text>
</view>
<view class="action-item" @click="handleRepairOrder">
<image src="../../static/images/banner/icon2.png" mode="widthFix"></image>
<text class="text">我的维修</text>
</view>
<view class="action-item" @click="handleUpkeepOrder">
<image src="../../static/images/banner/icon3.png" mode="widthFix"></image>
<text class="text">我的保养</text>
</view>
<view class="action-item action-item1" @click="handleSpotCheckOrder">
<image src="../../static/images/banner/icon4.png" mode="widthFix"></image>
<text class="text">巡检点检</text>
</view>
<view class="action-item action-item1" @click="handleSparePartsApplication">
<image src="../../static/images/banner/icon5.png" mode="widthFix"></image>
<text class="text">我的领用</text>
</view>
<view class="action-item action-item1" @click="handleSparePartsApplicationApprove"
v-if="store.role == 'all_approve' || store.role == 'normal_approve'">
<image src="../../static/images/banner/icon7.png" mode="widthFix"></image>
<text class="text">领用审批</text>
</view>
<view class="action-item action-item1" @click="handleSparePartsService">
<image src="../../static/images/banner/icon6.png" mode="widthFix"></image>
<text class="text">备件维修</text>
</view>
</view>
<view class="menu-list">
<view class="list-cell list-cell-arrow" @click="handleEditPassword">
<view class="menu-item-box">
<u-icon name="lock" color="#2979ff" size="32"></u-icon>
<view style="margin-left: 10rpx;">修改密码</view>
</view>
</view>
<view class="list-cell list-cell-arrow" @click="handleAgreement">
<view class="menu-item-box">
<u-icon name="error-circle" color="#2979ff" size="32"></u-icon>
<view style="margin-left: 10rpx;">用户协议</view>
</view>
</view>
<view class="list-cell list-cell-arrow" @click="handlePrivacyPolicy">
<view class="menu-item-box">
<u-icon name="file-text-fill" color="#2979ff" size="32"></u-icon>
<view style="margin-left: 10rpx;">隐私政策</view>
</view>
</view>
<!-- <view class="list-cell list-cell-arrow" @click="handleHelp">
<view class="menu-item-box">
<u-icon name="info-circle" color="#2979ff" size="32"></u-icon>
<view style="margin-left: 10rpx;">版本更新</view>
</view>
</view> -->
<!-- <view class="list-cell list-cell-arrow" @click="handleAbout">
<view class="menu-item-box">
<u-icon name="heart" color="#2979ff" size="32"></u-icon>
<view style="margin-left: 10rpx;">关于我们</view>
</view>
</view> -->
</view>
<view class="btn" @click="handleLogout" v-if="store">退出登录</view>
</view>
</view>
</template>
<script setup lang="ts">
import {
ref,
getCurrentInstance
} from 'vue'
import { useCountStore } from '@/store'
const { proxy } = getCurrentInstance()
// store
const store = useCountStore()
const name = ref(store.name)
const bgOpacity = ref(0)
const user = ref()
function handleToInfo() {
proxy.$tab.navigateTo('/pages/mine/info/index')
}
function handleDeviceReport() {
proxy.$tab.navigateTo('/pages/deviceReport/myDeviceReport')
}
function handleRepairOrder() {
proxy.$tab.navigateTo('/pages/repairOrder/myOrder')
}
function handleUpkeepOrder() {
proxy.$tab.navigateTo('/pages/upkeepOrder/myOrder')
}
function handleSpotCheckOrder() {
proxy.$tab.navigateTo('/pages/spotCheckOrder/myOrder')
}
function handleSparePartsApplication() {
proxy.$tab.navigateTo('/pages/sparePartsApplication/mySparePartsApplication?flag=1')
}
function handleSparePartsApplicationApprove() {
proxy.$tab.navigateTo('/pages/sparePartsApplicationApprove/mySparePartsApplicationApprove?flag=1')
}
function handleSparePartsService() {
proxy.$tab.navigateTo('/pages/sparePartsServiceWorkOrderList/mySparePartsService')
}
function handleAgreement() {
proxy.$tab.navigateTo('/pages/mine/agreement')
}
function handlePrivacyPolicy() {
proxy.$tab.navigateTo('/pages/mine/privacyPolicy')
}
function handleLogout() {
proxy.$modal.confirm('确定注销并退出系统吗?').then(() => {
store.LogOut().then(() => {
proxy.$tab.reLaunch('/pages/login')
}).catch(() => { })
}).catch(() => { })
}
function handleLogin() {
proxy.$tab.navigateTo('/pages/login')
}
function handleEditPassword() {
proxy.$tab.navigateTo('/pages/mine/changePassword')
}
</script>
<style lang="scss">
page {
background-color: #f5f6f7;
}
.mine-container {
width: 100%;
height: 100%;
.header-section {
color: white;
position: relative;
image {
width: 100%;
height: calc(var(--status-bar-height) + 370rpx);
}
.info {
position: absolute;
top: calc(var(--status-bar-height) + 110rpx);
left: 80rpx;
right: 80rpx;
display: flex;
align-items: center;
}
.cu-avatar {
border: 4rpx solid #eaeaea;
width: 140rpx;
height: 140rpx;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
background: white;
.icon {
font-size: 80rpx;
color: #f5f5f5;
}
}
.user-info {
margin-left: 30rpx;
flex: 1;
.name {
line-height: 60rpx;
font-size: 36rpx;
font-weight: bold;
line-height: 60rpx;
margin-right: 20rpx;
span {
font-weight: normal;
font-size: 28rpx;
padding-left: 20rpx;
}
}
.tips {
padding: 10rpx 20rpx;
background: #3952ae;
color: white;
border-radius: 50rpx;
font-size: 24rpx;
display: inline-block;
}
}
}
.content-section {
position: relative;
top: -100rpx;
.mine-actions {
margin: 30rpx 30rpx;
padding: 40rpx 0px;
border-radius: 16rpx;
background-color: white;
display: flex;
flex-wrap: wrap;
.action-item {
width: calc(100% / 3);
image {
width: 80rpx;
}
.text {
display: block;
font-size: 26rpx;
}
}
.action-item1 {
margin-top: 26rpx;
}
}
}
}
.btn {
width: calc(100vw - 60rpx);
margin: 0 auto;
background-color: rgb(64, 158, 255);
color: #FFFFFF;
height: 90rpx;
line-height: 90rpx;
text-align: center;
border-radius: 10rpx;
font-size: 32rpx;
}
.list-cell-arrow::before {
content: ' ';
height: 10px;
width: 10px;
border-width: 2px 2px 0 0;
border-color: #c0c0c0;
border-style: solid;
-webkit-transform: matrix(0.5, 0.5, -0.5, 0.5, 0, 0);
transform: matrix(0.5, 0.5, -0.5, 0.5, 0, 0);
position: absolute;
top: 50%;
margin-top: -6px;
right: 30rpx;
}
.list-cell {
position: relative;
width: 100%;
box-sizing: border-box;
background-color: #fff;
color: #333;
padding: 26rpx 30rpx;
}
.list-cell:first-child {
border-radius: 8rpx 8rpx 0 0;
}
.list-cell:last-child {
border-radius: 0 0 8rpx 8rpx;
}
.list-cell::after {
content: '';
position: absolute;
border-bottom: 1px solid #eaeef1;
-webkit-transform: scaleY(0.5) translateZ(0);
transform: scaleY(0.5) translateZ(0);
transform-origin: 0 100%;
bottom: 0;
right: 0;
left: 0;
pointer-events: none;
}
.menu-list {
margin: 15px 15px;
.menu-item-box {
width: 100%;
display: flex;
align-items: center;
.menu-icon {
color: #007AFF;
font-size: 16px;
margin-right: 5px;
}
.text-right {
margin-left: auto;
margin-right: 34rpx;
color: #999;
}
}
}
</style>

90
src/pages/mine/privacyPolicy.vue

@ -0,0 +1,90 @@
<template>
<view class="content">
<view class="gray-bg">
</view>
<view style='padding: 30rpx;background: white;'>
<view class="text">
鸿翔供应链管理北京有限公司遵守中华人民共和国民法典等法律法规之规定尊重并保护服务用户的个人隐私权益为了给用户提供准确个性化服务鸿翔供应链管理北京有限公司会按照本协议的约定使用和披露您的个人信息但鸿翔供应链管理北京有限公司承诺以勤勉审慎义务对待上述信息除本协议另有约定外在未征得用户事先许可的情况下鸿翔供应链管理北京有限公司不会将这些信息对外披露或向第三方提供鸿翔供应链管理北京有限公司会不时更新本隐私权政策并将及时对全体用户公示修改内容 您在同意鸿翔供应链管理北京有限公司服务使用协议之时即视为您已经同意本隐私权政策全部内容本隐私权政策属于鸿翔供应链管理北京有限公司服务使用协议的组成部分 
</view>
<view class="text">
隐私政策需列举说明业务逻辑与权限的关系<br/>
1.我们获取您的电话信息用于注册鸿翔TMS的账号等信息我们不会泄漏您的信息我们会保证您的隐私安全<br/>
2.我们获取您的相机权限用于账号的头像更改等信息我们不会泄漏您的信息我们会保证您的隐私安全<br/>
3.我们获取您的相册权限用于账号的相关信息上传我们不会泄漏您的信息我们会保证您的隐私安全<br/>
</view>
<view class="text">
隐私政策需说明获取个人隐私信息的用途<br/>
1.我们需要获取您的电话信息用于注册鸿翔TMS的账号等信息我们不会泄漏您的信息我们会保证您的隐私安全<br/>
2.我们需要获取您的相机权限用于账号的头像更改等信息我们不会泄漏您的信息我们会保证您的隐私安全<br/>
3.我们需要获取您的相册权限用于账号的相关信息上传我们不会泄漏您的信息我们会保证您的隐私安全<br/>
</view>
<view class="text">
隐私保护承诺<br/>
1.鸿翔TMS禁止未经用户授权或者无视现行法律依据私自收集传输或使用用户隐私数据如位置通信录的行为<br/>
2.鸿翔TMS包含防病毒或安全防护功能并依法依约说明所收集或传输的相关用户数据以及这些用户数据的用途分享的对象和其他相关信息<br/>
3.如对用户个人信息进行转移应告知用户如何使用转移的信息以及在何处使用该信息<br/>
4.对用户身份标识鉴权及其他个人信息的收集存储转移应采取确保数据机密性和完整性的加密措施<br/>
5.使用第三方支付交易过程中不得记录用户交易类鉴权信息不得向第三方泄露与用户特定交易无关的用户个人信息<br/>
6.处理财务信息付款信息或身份信息的鸿翔TMS不得披露任何用户个人数据<br/>
7.不得使用任何与功能无关的敏感隐私权限或数据<br/>
8.不得篡改鸿翔TMS内的用户个人信息,不得访问或者篡改第三方鸿翔TMS内的用户个人信息<br/>
</view>
<view class="text">
1. 适用范围 <br/>
a) 注册服务帐号时需根据要求提供的个人注册信息 <br/>
b) 使用网络服务访问平台网页时将自动接收并记录用户浏览器和计算机上的信息包括但不限于用户的IP地址浏览器的类型使用的语言访问时间软硬件特征信息及用户需求的网页记录等数据 <br/>
c)通过合法途径从商业伙伴处取得的用户个人信息不适用本隐私权政策 在使用平台提供的搜索服务时输入的关键字信息 收集到的用户在平台上发布的有关信息数据 违反法律规定或违反协议规则的行为及鸿翔供应链管理北京有限公司平台已对用户采取的措施<br/> 
2. 信息使用 <br/>
a) 未经许可鸿翔TMS不向任何无关第三方披露或交易用户的个人信息第三方和鸿翔TMS含吉鸿翔TMS关联公司单独或共同为用户提供服务服务结束后第三方也禁止访问包括其以前能够访问的所有的资料<br/>
b) 鸿翔TMS禁止第三方收集编辑出售或者无偿传播用户的个人信息第三方或用户如从事上述行为一经发现鸿翔TMS有权立即终止与该其的服务或合作 <br/>
c) 为做好服务鸿翔TMS可能通过用户资料向其提供相关信息包括但不限于向用户发出产品和服务信息与鸿翔TMS的关联公司共享信息以便向用户发送相关产品和服务的信息后者需要用户的同意<br/>
3. 信息披露 <br/>
在如下情况下鸿翔TMS有权根据用户意愿或政策法规披露用户的信息<br/> 
a) 经用户同意向第三方披露 <br/>
b) 为提供用户需求的产品或服务而必须和第三方分享用户的个人信息<br/> 
c) 根据政策法规或司法行政部门要求对外披露信息<br/>
d) 用户违反政策法规鸿翔TMS服务协议或相关规则的可向第三方披露  <br/>
e)适格知识产权权利人投诉应被投诉人要求向投诉人披露<br/>
f) 在平台上创建交易如交易一方履行或部分履行了交易义务并提出信息披露请求的鸿翔TMS有权决定向该用户提供其交易对方的联络方式等必要信息<br/>
g)根据法律法规或者网站政策应当披露的其他情况<br/>  
4. 信息存储和交换  <br/>
收集的用户信息和资料将保存在鸿翔TMS或关联公司的服务器上这些信息和资料可能传送至用户所在国家地区上述信息可能在境外被访问存储和展示<br/> 
5. Cookie的使用 <br/>
a) 用户未拒绝接受cookies的情况下鸿翔TMS在用户计算机上设定或取用cookies以便您能登录或使用依赖于cookies的平台服务或功能鸿翔TMS使用cookies可为用户提供更加周到的个性化服务包括推广服务<br/>
 b) 用户有权选择接受或拒绝接受cookies用户可以通过修改浏览器设置的方式拒绝接受cookies但如果用户选择拒绝接受cookies则可能无法登录或使用依赖于cookies的网络服务或功能 <br/>
c) 通过鸿翔TMS所设cookies所取得的有关信息将适用本政策<br/>  
6. 信息安全  <br/>
a)用户帐号均有安全保护功能请妥善保管用户名及密码信息鸿翔TMS将通过对用户密码进行加密等安全措施确保用户的信息不丢失不被滥用和变造尽管有前述安全措施但同时也请用户注意在信息网络上不存在完善的安全措施  <br/>
b) 在使用鸿翔TMS网络服务进行网上交易时用户不可避免的要向交易对方或潜在的交易对方披露个人信息如联络方式或者邮政地址请用户妥善保护个人信息如发现信息泄密特别是用户名及密码发生泄露请用户立即联络鸿翔TMS客服以便鸿翔TMS公司采取相应措施<br/>
</view>
</view>
<view style="height: constant(safe-area-inset-bottom); height: env(safe-area-inset-bottom);"></view>
</view>
</template>
<script setup lang="ts">
</script>
<style>
page {
/* background: rgba(245, 245, 245); */
border-top: 1px solid rgba(230, 230, 230, 0.5);
}
.gray-bg {
width: 100%;
height: 20rpx;
background: rgba(245, 245, 245);
}
.text {
margin-top: 20rpx;
}
view {
font-size: 30rpx;
}
</style>

162
src/pages/mold/index.vue

@ -0,0 +1,162 @@
<template>
<!-- 设备 -->
<view class="work-container">
<view class="cartNull" v-show="!token">
还没有登录<navigator open-type="navigate" url="/pages/login">先登录</navigator>
</view>
<view class="" v-show='token'>
<Search :searchData='searchData' @search='search' @screen='screen' :isShowScreen='false'/>
<view class="list">
<view class="item" v-for="(item,index) in list" :key='index'>
<u-image :src="item.images" width='160'
height="160">
<template v-slot:error>
<view class="image-error">
<u-icon name="photo" color="#c7c7c7" size="38"></u-icon>
<view style="font-size: 24rpx;">暂无图片</view>
</view>
</template>
</u-image>
<view class="text">
<view class="title">
{{item.name}}
</view>
<view class="dec1">
{{item.number}}
</view>
<view class="dec2">
{{item.factoryAreaName}}
</view>
</view>
</view>
</view>
<view style="height: 94rpx;padding-top: 30rpx;">
<u-loadmore :status="status" v-if="status != 'loadmore'" />
</view>
</view>
<view style="height: constant(safe-area-inset-bottom); height: env(safe-area-inset-bottom);"></view>
</view>
</template>
<script setup lang="ts">
import {
onShow,
onReachBottom
} from '@dcloudio/uni-app'
import {
ref,
getCurrentInstance
} from 'vue'
import {
getAccessToken
} from '@/utils/auth'
import * as moldApi from "@/api/mold.js"
import Search from '../../components/search/index.vue'
const { proxy } = getCurrentInstance()
const params = ref({
pageNo: 1,
pageSize: 10,
type: '',
name: ''
})
const status = ref('loadmore') //
const list = ref([])
const token = ref('')
const searchData = ref({
placeholder:'请输入模具名称'
})
//
function search(keyWord) {
params.value.name = keyWord
params.value.pageNo = 1
list.value = []
status.value = 'loadmore'
getList()
}
function screen() {
proxy.$tab.navigateTo(`/pages/device/screen`)
}
function getList() {
if (status.value == 'nomore') return;
status.value = 'loading';
proxy.$modal.loading('加载中')
moldApi.moldPage(params.value).then((res) => {
proxy.$modal.closeLoading()
if (res.data.list.length > 0) {
list.value = list.value.concat(res.data.list);
params.value.pageNo++;
status.value = 'loadmore'
} else {
status.value = 'nomore'
}
}).catch(() => { })
}
onShow(() => {
if (getAccessToken()) {
token.value = getAccessToken()
params.value.pageNo = 1
list.value = []
status.value = 'loadmore'
getList()
}
})
onReachBottom(() => {
getList()
})
</script>
<style lang="scss" scoped>
.work-container{
min-height: 100vh;
background: #f5f5f5;
}
.list {
padding-bottom: 20rpx;
.item {
margin-top: 20rpx;
background: white;
padding: 30rpx;
display: flex;
align-items: center;
.text {
margin-left: 20rpx;
.title {
font-size: 32rpx;
font-weight: bold;
}
.dec1 {
font-size: 28rpx;
margin-top: 16rpx;
color: #acacac;
}
.dec2 {
font-size: 28rpx;
margin-top: 6rpx;
color: #acacac;
}
}
}
}
.image-error {
text-align: center;
}
.cartNull {
text-align: center;
padding: 500rpx 40rpx 0;
font-size: 28rpx;
color: #888;
}
.cartNull navigator {
color: #2979ff;
}
</style>

440
src/pages/overhaulOrder/addForm.vue

@ -0,0 +1,440 @@
<template>
<!-- 添加维修工单 -->
<view class="add-form-container">
<u-form :model="form" ref="formRef" label-width="160rpx">
<u-form-item label="检修描述" prop="describes" required :class="form.id?'disabled':''">
<u-input v-model="form.describes" placeholder="请输入检修描述" :disabled="form&&form.id?true:false" />
</u-form-item>
<u-form-item label="维修工单" prop="maintenanceNumber" :class="form.id?'disabled':''">
<view class="select" @click="openOrder">
<view class="input" v-if='form.maintenanceNumber'>
{{form.maintenanceNumber}}
</view>
<view class="placeholder" v-else>
{{`请选择维修工单`}}
</view>
<u-icon name="arrow-right" color="#aaaaaa" size="28" v-if="!form.id"></u-icon>
</view>
</u-form-item>
<!-- <u-form-item :label="`${type=='DEVICE'?'设备' : '模具'}名称`" prop="factoryAreaName" required :class="isDisabled?'disabled':''">
<view class="select" @click="openSingleColumn('deviceNumber',form.deviceNumber,deviceList)">
<view class="input" v-if='form.deviceName'>
{{form.deviceName}}
</view>
<view class="placeholder" v-else>
{{`请输入${type=='DEVICE'?'设备' : '模具'}名称`}}
</view>
<u-icon name="arrow-right" color="#aaaaaa" size="28" v-if="!form.id"></u-icon>
</view>
</u-form-item> -->
<u-form-item label="类型" prop="deviceNumber" required class="disabled">
{{type =='DEVICE'||type == 'TECH'?'设备' : '模具'}}
</u-form-item>
<u-form-item :label="`${type=='DEVICE'||type == 'TECH'?'设备' : '模具'}编码`" prop="deviceNumber" required
:class="isDisabled?'disabled':''">
<u-input v-model="form.deviceNumber" :placeholder="`请输入${type=='DEVICE'||type == 'TECH'?'设备' : '模具'}编码`"
@blur="blur()" />
<view class="right-button" @click="chickRightButton" v-show="!isDisabled">
扫描
</view>
</u-form-item>
<u-form-item :label="`${type=='DEVICE'||type == 'TECH'?'设备' : '模具'}名称`" prop="deviceNumber" required
class="disabled">
<u-input v-model="form.deviceName" :placeholder="`根据${type=='DEVICE'||type == 'TECH'?'设备' : '模具'}编码获得`"
disabled />
</u-form-item>
<u-form-item label="所属厂区" prop="factoryAreaName" class="disabled">
<u-input v-model="form.factoryAreaName" placeholder="请输入所属厂区" disabled />
</u-form-item>
<u-form-item label="故障类型" prop="faultType" required>
<view class="select" @click="openSingleColumn('faultType',form.faultType,faultType)">
<view class="input" v-if='form.faultType'>
{{form.faultTypeName}}
</view>
<view class="placeholder" v-else>
{{`请选择故障类型`}}
</view>
<u-icon name="arrow-right" color="#aaaaaa" size="28"></u-icon>
</view>
</u-form-item>
</u-form>
<view class="footer">
<view class="btns">
<button class="reset" @click="reset">重置</button>
<button class="sure" @click="submit" :loading='loading' :disabled='loading'>确定</button>
</view>
<view style="height: constant(safe-area-inset-bottom); height: env(safe-area-inset-bottom);"></view>
</view>
<u-select v-model="singleColumnShow" mode="single-column" :default-value='singleColumnDefaultValue'
:list="singleColumnList" @confirm="chooseSingleColumn" @cancle='singleColumnShow = false'></u-select>
</view>
</template>
<script setup lang="ts">
import {
onLoad
} from '@dcloudio/uni-app'
import {
ref,
getCurrentInstance
} from 'vue'
import * as overhaulOrderApi from "@/api/overhaulOrder.js"
import * as moldApi from "@/api/mold.js"
import * as dictApi from "@/api/dict.js"
import * as repairOrderApi from "@/api/repairOrder.js"
import * as deviceApi from "@/api/device.js"
const { proxy } = getCurrentInstance()
const loading = ref(false)
const type = ref('')
const form = ref({
id: '',
describes: "",
maintenanceNumber: '',
factoryAreaNumber: '',
factoryAreaName: '',
faultType: '',
deviceName: '',
deviceNumber: '',
faultTypeName: ''
})
const singleColumnShow = ref(false)
const singleColumnDefaultValue = ref([])
const singleColumnList = ref([])
const field = ref('')
const faultType = ref([])
const isDisabled = ref(false)
const choosesingleColumnItem = ref([])
function submit() {
//
if (!form.value.describes) {
proxy.$modal.showToast('请输入故障描述')
return;
}
if (!form.value.deviceNumber) {
proxy.$modal.showToast('请选择设备名称或者维修工单')
return;
}
if (!form.value.faultType) {
proxy.$modal.showToast('请选择故障类型')
return;
}
const data = {
id: form.value && form.value.id ? form.value.id : '',
describes: form.value.describes,
maintenanceNumber: form.value.maintenanceNumber,
deviceNumber: form.value.deviceNumber,
factoryAreaNumber: form.value.factoryAreaNumber,
type: type.value,
faultType: form.value.faultType,
}
if (form.value.id) {
proxy.$modal.confirm('是否修改检修工单').then(() => {
proxy.$modal.loading('加载中')
loading.value = true
overhaulOrderApi.overhaulOrderUpdate(data).then((res) => {
proxy.$modal.closeLoading()
if (res.data) {
proxy.$modal.showToast('修改成功')
setTimeout(() => {
proxy.$tab.navigateBack()
loading.value = false
}, 1500)
} else {
proxy.$modal.showToast('添加失败')
loading.value = false
}
}).catch(() => {
proxy.$modal.closeLoading()
loading.value = false
})
})
} else {
proxy.$modal.confirm('是否添加检修工单').then(() => {
proxy.$modal.loading('加载中')
loading.value = true
overhaulOrderApi.overhaulOrderCreate(data).then((res) => {
proxy.$modal.closeLoading()
if (res.data) {
proxy.$modal.showToast('添加成功')
setTimeout(() => {
proxy.$tab.navigateBack()
loading.value = false
}, 1500)
} else {
proxy.$modal.showToast('添加失败')
loading.value = false
}
}).catch(() => {
proxy.$modal.closeLoading()
loading.value = false
})
})
}
}
//
function reset() {
form.value = {
id: '',
describes: "",
maintenanceNumber: '',
factoryAreaNumber:'',
factoryAreaName:'',
faultType: '',
deviceName:'',
deviceNumber:'',
faultTypeName:''
}
isDisabled.value = false
}
//
function openSingleColumn(fieldName, val, list) {
if (fieldName == 'maintenanceNumber' && form.value.id) return;
if (fieldName == 'deviceNumber' && isDisabled.value) return;
singleColumnList.value = list
field.value = fieldName
if (val) {
singleColumnDefaultValue.value = [list.findIndex(item => item.value == val)]
} else {
singleColumnDefaultValue.value = []
}
singleColumnShow.value = true
}
//
function chooseSingleColumn(e) {
form.value[field.value] = e[0].value
if (field.value == 'deviceNumber') {
choosesingleColumnItem.value = singleColumnList.value.filter(item => item.number == e[0].value)
form.value.deviceName = choosesingleColumnItem.value[0].name
form.value.factoryAreaName = choosesingleColumnItem.value[0].factoryAreaName
form.value.factoryAreaNumber = choosesingleColumnItem.value[0].factoryAreaNumber
} else if (field.value == 'faultType') {
form.value.faultTypeName = e[0].label
}
singleColumnShow.value = false
}
//
function chickRightButton(field) {
if (!form.value.type) {
proxy.$modal.showToast('请先选择类型')
return;
}
uni.scanCode({
success: function (res) {
form.value.deviceNumber = res.result
getDetailsByNumber()
}
});
}
function blur() {
if (form.value.deviceNumber) {
getDetailsByNumber()
} else {
form.value.deviceName = ''
form.value.factoryAreaName = ''
form.value.factoryAreaNumber = ''
}
}
// /
function getDetailsByNumber() {
if (type.value == 'DEVICE' || type.value == 'TECH') {
deviceApi.getDeviceDetailsByNumber({
number: form.value.deviceNumber,
type: type.value
}).then((res) => {
if (!res.data) {
form.value.deviceName = ''
form.value.factoryAreaName = ''
form.value.factoryAreaNumber = ''
return;
}
form.value.deviceName = res.data.name
form.value.factoryAreaName = res.data.factoryAreaName
form.value.factoryAreaNumber = res.data.factoryAreaNumber
}).catch(() => {
form.value.deviceName = ''
form.value.factoryAreaName = ''
form.value.factoryAreaNumber = ''
})
} else if (type.value == 'MOLD') {
moldApi.getMoldDetailsByNumber({
number: form.value.deviceNumber
}).then((res) => {
if (!res.data) {
form.value.deviceName = ''
form.value.factoryAreaName = ''
form.value.factoryAreaNumber = ''
return;
}
form.value.deviceName = res.data.name
form.value.factoryAreaName = res.data.factoryAreaName
form.value.factoryAreaNumber = res.data.factoryAreaNumber
}).catch(() => {
form.value.deviceName = ''
form.value.factoryAreaName = ''
form.value.factoryAreaNumber = ''
})
}
}
function openOrder() {
proxy.$tab.navigateTo(`/pages/overhaulOrder/reqairOrderList?type=` + type.value)
}
onLoad(async (option) => {
if (option.type) type.value = option.type;
if (option.data) {
let data = JSON.parse(decodeURIComponent(option.data))
form.value = {
id: data.id,
describes: data.describes,
maintenanceNumber: data.maintenanceNumber,
deviceName: data.name,
deviceNumber: data.deviceNumber,
factoryAreaName: data.factoryAreaName,
faultType: data.faultType,
}
isDisabled.value = form.value.maintenanceNumber || form.value.id ? true : false
};
faultType.value = await dictApi.getDict('fault_type')
uni.$on('chooseOrder', data => {
if (data) {
form.value.maintenanceNumber = data.number
form.value.deviceName = data.name
form.value.deviceNumber = data.deviceNumber
form.value.deviceName = data.name
form.value.factoryAreaName = data.factoryAreaName
form.value.factoryAreaNumber = data.factoryAreaNumber
isDisabled.value = true
} else {
form.value.maintenanceNumber = ''
form.value.deviceName = ''
form.value.deviceNumber = ''
form.value.deviceName = ''
form.value.factoryAreaName = ''
form.value.factoryAreaNumber = ''
isDisabled.value = false
}
})
})
</script>
<style lang="scss" scoped>
.add-form-container {
min-height: calc(100vh - 140rpx);
background: white;
padding: 0px 0rpx 140rpx;
}
.u-form-item {
padding: 20rpx 30rpx;
}
.disabled {
background: #f5f5f5;
}
.list {
padding-bottom: 20rpx;
.item {
margin-top: 20rpx;
background: white;
padding: 30rpx;
display: flex;
align-items: center;
image {
width: 160rpx;
height: 160rpx;
margin-right: 20rpx;
}
.title {
font-size: 32rpx;
font-weight: bold;
}
.dec1 {
font-size: 28rpx;
margin-top: 16rpx;
color: #acacac;
}
.dec2 {
font-size: 28rpx;
margin-top: 6rpx;
color: #acacac;
}
}
}
.footer {
position: fixed;
bottom: 0px;
left: 0px;
width: 100%;
}
.btns {
display: flex;
button {
flex: 1;
}
.sure {
background: #409eff;
color: white;
border-radius: 0px;
&::after {
border: 1px solid #409eff;
border-radius: 0px;
}
}
.reset {
background: #F5F5F5;
border-radius: 0px;
&::after {
border-radius: 0px;
}
}
}
.right-button {
background: #409eff;
color: white;
padding: 0rpx 30rpx;
border-radius: 16rpx;
text-align: center;
font-size: 28rpx;
}
.select {
display: flex;
align-items: center;
height: 72rpx;
width: 100%;
.input {
flex: 1;
font-size: 28rpx;
color: #000000;
}
.placeholder {
flex: 1;
font-size: 28rpx;
color: rgb(192, 196, 204);
}
}
</style>

631
src/pages/overhaulOrder/addServiceRecord.vue

@ -0,0 +1,631 @@
<template>
<!-- 添加检修工单 -->
<view class="add-form-container">
<u-form :model="form" ref="formRef" label-width="160rpx">
<u-form-item label="检修描述" prop="name" required>
<u-input v-model="form.name" placeholder="请输入检修描述" maxlength="50" />
</u-form-item>
<u-form-item label="预估人数" prop="peoples" required>
<u-input v-model="form.peoples" type="number" placeholder="请输入预估人数" maxlength="50" />
</u-form-item>
<u-form-item label="预估分钟" prop="estimatedMinutes" required>
<u-input v-model="form.estimatedMinutes" type="number" placeholder="请输入预估分钟" maxlength="50" />
</u-form-item>
<u-form-item label="实际分钟" prop="actualMinutes" required>
<u-input v-model="form.actualMinutes" type="number" placeholder="请输入实际分钟" maxlength="50" />
</u-form-item>
<u-form-item label="责任人" prop="chargePeoples" required>
<view class="select" @click="openSelecUser">
<view class="input" v-if='form.chargePeoples'>
{{selectFormatCheck(form.chargePeoples,selecUserList)}}
</view>
<view class="placeholder" v-else>
请选择维修人员
</view>
<u-icon name="arrow-right" color="#aaaaaa" size="28"></u-icon>
</view>
</u-form-item>
<u-form-item label="完成情况" prop="status" required>
<view class="select" @click="openSingleColumn('status',form.status,jxDetailsStatus,'form')">
<view class="input" v-if='form.status'>
{{form.statusTxt}}
</view>
<view class="placeholder" v-else>
{{`请选择完成情况`}}
</view>
<u-icon name="arrow-right" color="#aaaaaa" size="28" v-if="!form.id"></u-icon>
</view>
</u-form-item>
<u-form-item label="完成时间" prop="completionTime" required v-if='form.status === 0||form.status === "0"'>
<view class="select" @click="openDatetime('completionTime',formatDate,params,formatValue)">
<view class="input" v-if='formatDate'>
{{formatDate}}
</view>
<view class="placeholder" v-else>
{{`请选择完成时间`}}
</view>
<u-icon name="arrow-right" color="#aaaaaa" size="28"></u-icon>
</view>
</u-form-item>
<u-form-item label="工程师确认" prop="engineer">
<u-input v-model="form.engineer" placeholder="请输入工程师确认" maxlength="50" />
</u-form-item>
<u-form-item label="未完成原因" prop="uncompleted" required v-if='form.status === 1||form.status === "1"'>
<u-input type='textarea' v-model="form.uncompleted" placeholder="请输入未完成原因" maxlength="200" />
</u-form-item>
</u-form>
<view class="list">
<view class="title">
<span></span>备件
</view>
<view class="item " v-for="(item,index) in form.itemNumbers" :key="index">
<view class="item-box">
<view class="spare-title">
<view class="title-txt">
{{item.name}}
</view>
</view>
<u-row gutter="16">
<u-col :span="12">
<view class="dec">
<view class="">
数量:{{item.qty}}
</view>
</view>
</u-col>
</u-row>
</view>
<u-icon name="minus-circle" color="#aaaaaa" size="60" @click="delSpareParts(index)"></u-icon>
</view>
<view class="add-btn">
<u-button type="primary" @click="open"><u-icon name="plus-circle" color="#ffffff"
size="36"></u-icon>添加备件</u-button>
</view>
</view>
<view class="footer">
<view class="btns">
<button class="reset" @click="reset">重置</button>
<button class="sure" @click="submit" :loading='loading' :disabled='loading'>确定</button>
</view>
<view style="height: constant(safe-area-inset-bottom); height: env(safe-area-inset-bottom);"></view>
</view>
<!-- 添加备件 -->
<u-popup v-model="isPopupShow" mode="center" border-radius="14">
<view class="popup-title">添加备件</view>
<view class="popup">
<u-form :model="form1" ref="form1Ref" label-width="160rpx">
<u-form-item :label="`备件`" prop="number" required>
<view class="select" @click="openSingleColumn('number',form1.number,sparePartsList,'form1')">
<view class="input" v-if='form1.number'>
{{selectFormat(form1.number,sparePartsList)}}
</view>
<view class="placeholder" v-else>
请选择备件
</view>
<u-icon name="arrow-right" color="#aaaaaa" size="28"></u-icon>
</view>
</u-form-item>
<u-form-item label="数量" prop="qty" required>
<u-input v-model="form1.qty" type="number" placeholder="请输入数量" />
</u-form-item>
</u-form>
</view>
<view class="popup-footer">
<view @click="isPopupShow = false">取消</view>
<view class="sure" @click="addSpare">确认</view>
</view>
</u-popup>
<!-- 选择维修人员 -->
<u-popup v-model="isShowSelecUser" mode="center" border-radius="14">
<view class="popup-title">选择维修人员</view>
<view class="popup">
<u-checkbox-group @change="checkboxGroupChange">
<u-checkbox v-model="item.checked" v-for="(item, index) in selecUserList" :key="index"
:name="item.id">{{item.name}}</u-checkbox>
</u-checkbox-group>
</view>
<view class="popup-footer">
<view @click="isShowSelecUser = false">取消</view>
<view class="sure" @click="chooseUser">确认</view>
</view>
</u-popup>
<u-select v-model="singleColumnShow" mode="single-column" :default-value='singleColumnDefaultValue'
:list="singleColumnList" @confirm="chooseSingleColumn" @cancle='singleColumnShow = false'></u-select>
<u-picker mode="time" v-model="datetimeShow" :default-time='datetimeDefaultValue' :params="params"
@confirm='chooseDatetime'></u-picker>
</view>
</template>
<script setup lang="ts">
import {
onLoad
} from '@dcloudio/uni-app'
import {
ref,
getCurrentInstance
} from 'vue'
import * as overhaulOrderApi from "@/api/overhaulOrder.js"
import * as sparePartsApi from "@/api/spareParts.js"
import * as deptApi from "@/api/dept.js"
import * as dictApi from "@/api/dict.js"
const { proxy} = getCurrentInstance()
const loading = ref(false)
const type = ref('')
//
const isPopupShow = ref(false)
const sparePartsList = ref([])
const singleColumnShow = ref(false)
const singleColumnDefaultValue = ref([])
const singleColumnList = ref([])
const field = ref('')
const selecUserList = ref([])//
const isShowSelecUser = ref(false)
const jxDetailsStatus = ref([])//
const formatDate = ref('')//
const form = ref({
number: '',
name: '',
peoples: null,
estimatedMinutes: '',
actualMinutes: '',
chargePeoples: '',
status:null,
completionTime: '',
engineer: '',
uncompleted: '',
itemNumbers: []
})
const form1 = ref({
number: "",
name: "",
qty: 0
})
//
const datetimeShow = ref(false)
const params = ref({
year: true,
month: true,
day: true,
hour: true,
minute: true,
second: true,
timestamp: true,
})
const datetimeDefaultValue = ref('')
const formatValue = ref('YYYY-MM-DD hh:mm:ss')
const factoryAreaNumber = ref('')
const chooseUserList = ref([])
//
function submit() {
//
if (!form.value.name) {
proxy.$modal.showToast('请输入检修描述')
return;
}
if (!form.value.peoples || form.value.peoples == 0) {
proxy.$modal.showToast('请输入预估人数')
return;
}
if (form.value.peoples > 100) {
proxy.$modal.showToast('预估人数不得超出100')
return;
}
if (!form.value.estimatedMinutes || form.value.estimatedMinutes == 0) {
proxy.$modal.showToast(`请输入预估分钟`)
return;
}
if (!form.value.actualMinutes) {
proxy.$modal.showToast('请输入实际分钟')
return;
}
if (!form.value.chargePeoples) {
proxy.$modal.showToast('请选择负责人')
return;
}
if (!form.value.status) {
proxy.$modal.showToast('请选择完成情况')
return;
}
if (form.value.status == 0) {
if (!form.value.completionTime) {
proxy.$modal.showToast('请选择完成时间')
return;
}
}
if (form.value.status == 1) {
if (!form.value.uncompleted) {
proxy.$modal.showToast('请输入未完成原因')
return;
}
}
if (form.value.id) {
proxy.$modal.confirm('是否修改检修内容').then(() => {
proxy.$modal.loading('加载中')
loading.value = true
overhaulOrderApi.overhaulOrderDetailUpdate(form.value).then((res) => {
proxy.$modal.closeLoading()
if (res.data) {
proxy.$modal.showToast('修改成功')
setTimeout(() => {
proxy.$tab.navigateBack()
loading.value = false
}, 1500)
} else {
proxy.$modal.showToast('添加失败')
loading.value = false
}
}).catch(() => {
proxy.$modal.closeLoading()
loading.value = false
})
})
} else {
proxy.$modal.confirm('是否添加检修内容').then(() => {
proxy.$modal.loading('加载中')
loading.value = true
overhaulOrderApi.overhaulOrderDetailCreate(form.value).then((res) => {
proxy.$modal.closeLoading()
if (res.data) {
proxy.$modal.showToast('添加成功')
setTimeout(() => {
proxy.$tab.navigateBack()
loading.value = false
}, 1500)
} else {
proxy.$modal.showToast('添加失败')
loading.value = false
}
}).catch(() => {
proxy.$modal.closeLoading()
loading.value = false
})
})
}
}
//
function reset() {
form.value = {
number: '',
name: '',
peoples: null,
estimatedMinutes: '',
actualMinutes: '',
chargePeoples: '',
status:null,
completionTime: '',
engineer: '',
uncompleted: '',
itemNumbers: []
}
}
//
async function getSelecUser() {
let data = {
classType: type.value,
factoryAreaNumber: factoryAreaNumber.value,
flag: 0
}
let arr = []
if (form.value.chargePeoples) {
arr = form.value.chargePeoples.split(',')
}
await deptApi.getSelecUser(data).then(res => {
res.data.forEach(item => {
item.checked = false
arr.forEach(cur => {
if (item.id == cur) {
item.checked = true
}
})
})
selecUserList.value = res.data
}).catch(() => { })
}
//
function openSelecUser() {
isShowSelecUser.value = true
}
function checkboxGroupChange(e) {
chooseUserList.value = e
}
//
function selectFormatCheck(val, array) {
const arr = val.split(',').map(Number)
let str = array.filter(item => arr.includes(item.id)).map(item => item.name).join(',')
return str
}
//
function chooseUser() {
form.value.chargePeoples = chooseUserList.value.join(',')
isShowSelecUser.value = false
}
const whichForm = ref()
//
function openSingleColumn(fieldName, val, list, from) {
if (fieldName == 'deviceNumber' && form.value.id) return;
whichForm.value = from
singleColumnList.value = list
field.value = fieldName
if (val) {
singleColumnDefaultValue.value = [list.findIndex(item => item.value == val)]
} else {
singleColumnDefaultValue.value = []
}
singleColumnShow.value = true
}
//
function chooseSingleColumn(e) {
if(whichForm.value == 'form'){
form.value[field.value] = e[0].value
if(field.value=='status'){
form.value.statusTxt = e[0].label
}
}else if(whichForm.value == 'form1'){
form1.value[field.value] = e[0].value
if(field.value=='number'){
form1.value.name = e[0].label
}
}
singleColumnShow.value = false
}
//
async function getSparePartsList() {
await sparePartsApi.getSparePartsList().then(res => {
res.data.map(item => {
item.value = item.number
item.label = item.name
})
sparePartsList.value = res.data
}).catch(() => { })
}
//
function open() {
form1.value = {
number: "",
name:'',
qty: 0
}
isPopupShow.value = true
}
//
function addSpare() {
if (!form1.value.number) {
proxy.$modal.showToast('请选择备件')
return;
}
if (!form1.value.qty || form1.value.qty == 0) {
proxy.$modal.showToast('请输入数量')
return;
}
if (form.value.itemNumbers && form.value.itemNumbers.length > 0) {
let arr = form.value.itemNumbers.filter(item => item.number == form1.value.number)
if (arr && arr.length > 0) {
proxy.$modal.showToast('该备件已添加')
return;
}
}
form.value.itemNumbers.push(form1.value)
isPopupShow.value = false
}
//
function delSpareParts(index) {
form.value.itemNumbers.splice(index, 1)
}
function openDatetime(fieldName, val, params, format) {
params.value = params
formatValue.value = format
field.value = fieldName
form.value[field.value] = val ? val : ''
datetimeDefaultValue.value = val ? val : proxy.$time.formatDate()
datetimeShow.value = true
}
//
function chooseDatetime(e) {
let array1 = []
let array2 = []
if (formatValue.value.indexOf('YYYY') > -1) {
array1.push(e.year)
}
if (formatValue.value.indexOf('MM') > -1) {
array1.push(e.month)
}
if (formatValue.value.indexOf('DD') > -1) {
array1.push(e.day)
}
if (formatValue.value.indexOf('hh') > -1) {
array2.push(e.hour)
}
if (formatValue.value.indexOf('mm') > -1) {
array2.push(e.minute)
}
if (formatValue.value.indexOf('ss') > -1) {
array2.push(e.second)
}
let str = array1.join('-') + ' ' + array2.join(':')
formatDate.value = str
form.value[field.value] = e.timestamp
}
onLoad(async(option) => {
if (option.type) type.value = option.type;
if (option.factoryAreaNumber) factoryAreaNumber.value = option.factoryAreaNumber;
if (option.number) form.value.number = option.number;
if (option.data && JSON.parse(decodeURIComponent(option.data)) && JSON.parse(decodeURIComponent(option
.data)).id) {
form.value = JSON.parse(decodeURIComponent(option.data))
form.value.itemNumbers = form.value.items
formatDate.value = form.value.completionTime ? proxy.$time.formatDate(form.value.completionTime * 1000) : ''
};
jxDetailsStatus.value = await dictApi.getDict('jx_details_status')
await getSelecUser()
await getSparePartsList()
})
</script>
<style lang="scss" scoped>
.add-form-container {
min-height: calc(100vh - 140rpx);
background: white;
padding: 0px 30rpx 140rpx;
}
.footer {
position: fixed;
bottom: 0px;
left: 0px;
width: 100%;
z-index: 22;
}
.btns {
display: flex;
button {
flex: 1;
}
.sure {
background: #409eff;
color: white;
border-radius: 0px;
&::after {
border: 1px solid #409eff;
border-radius: 0px;
}
}
.reset {
background: #F5F5F5;
border-radius: 0px;
&::after {
border-radius: 0px;
}
}
}
.right-button {
background: #409eff;
color: white;
padding: 0rpx 30rpx;
border-radius: 16rpx;
text-align: center;
font-size: 28rpx;
}
.select {
display: flex;
align-items: center;
height: 72rpx;
width: 100%;
.input {
flex: 1;
font-size: 28rpx;
color: #000000;
}
.placeholder {
flex: 1;
font-size: 28rpx;
color: rgb(192, 196, 204);
}
}
.title {
padding: 32rpx 0px;
position: relative;
span {
position: absolute;
left: -16rpx;
color: #fa3534;
padding-top: 6rpx;
}
}
.list {
.item {
display: flex;
margin-bottom: 20rpx;
.item-box {
background: #F5F5F5;
border-radius: 12rpx;
flex: 1;
width: 0rpx;
}
.spare-title {
padding: 20rpx 30rpx;
border-bottom: 1px solid #e4e4e4;
.title-txt {
color: #409eff;
font-size: 30rpx;
font-weight: bold;
}
}
.dec {
color: #9c9c9c;
padding: 20rpx 30rpx 20rpx;
}
}
}
.add-btn {
display: flex;
justify-content: flex-start;
align-items: center;
}
.popup-title {
text-align: center;
font-size: 32rpx;
font-weight: bold;
color: #409eff;
padding: 30rpx 30rpx 0px
}
.popup {
width: 600rpx;
padding: 30rpx 60rpx 30rpx;
}
.popup-footer {
display: flex;
border-top: 1px solid #e4e4e4;
view {
line-height: 100rpx;
flex: 1;
text-align: center;
&.sure {
color: #409eff;
}
}
}
::v-deep .u-checkbox-group {
display: grid !important;
}
</style>

459
src/pages/overhaulOrder/detail.vue

@ -0,0 +1,459 @@
<template>
<!-- 详情 -->
<view class="detail-container">
<view class="info">
<view class="title">
<view>检修工单</view>
</view>
<view class="dec">
<view class="dec-item">
<view>工单单号</view>
<view>{{data.number}}</view>
</view>
<view class="dec-item">
<view>维修工单</view>
<view>{{data.maintenanceNumber}}</view>
</view>
<view class="dec-item">
<view>故障类型</view>
<view>{{data.faultTypeName}}</view>
</view>
<view class="dec-item" v-if="data.createTime">
<view>创建时间</view>
<view>{{$time.formatDate(data.createTime)}}</view>
</view>
<view class="dec-item">
<view>检修人员</view>
<view>{{data.maintenanceName}}</view>
</view>
</view>
</view>
<div class="line"></div>
<view class="info" style="padding-bottom: 130rpx;">
<view class="tab">
<u-tabs :list="list" :is-scroll="false" bar-height="2" bar-width="250" v-model="current"
@change="change"></u-tabs>
</view>
<view>
<view class="title">
<view>{{changeItem.name}}</view>
</view>
<view class="dec" v-if="current == 0">
<view class="dec-item">
<view>设备编号</view>
<view>{{data.number}}</view>
</view>
<view class="dec-item">
<view>设备名称</view>
<view>{{data.name}}</view>
</view>
<view class="dec-item">
<view>所属厂区</view>
<view>{{data.factoryAreaName}}</view>
</view>
<view class="dec-item">
<view>设备类型</view>
<view>{{data.type == 'DEVICE'?'设备':data.type == 'TECH'?'工艺':'模具'}}</view>
</view>
</view>
<view class="list" v-if="current == 1">
<view class="item " v-for="(item,index) in serviceList" :key="index"
@click="addSubForm('updata',item)">
<view class="item-box">
<view class="spare-title">
<view class="title-txt">
{{item.name}}
</view>
<u-icon name="trash" color="#aaaaaa" size="40"
@click.native.stop="delService(item)"></u-icon>
</view>
<view class="dec2">
<view>预估人数</view>
<view>{{item.peoples}}</view>
</view>
<view class="dec2">
<view>预估分钟</view>
<view>{{item.estimatedMinutes}}分钟</view>
</view>
<view class="dec2">
<view>实际分钟</view>
<view>{{item.actualMinutes}}分钟</view>
</view>
<view class="dec2">
<view>责任人</view>
<view>{{item.chargePeoplesName}}</view>
</view>
<view class="dec2">
<view>完成情况</view>
<view>
{{item.status===0 || item.status === '0'? '完成':item.status===1 ||item.status === '1'?'未完成':''}}
</view>
</view>
<view class="dec2" v-if='item.status === 0 || item.status === "0"'>
<view>完成时间</view>
<view>{{$time.formatDate(item.completionTime*1000)}}</view>
</view>
<view class="dec2">
<view>工程师确认</view>
<view>{{item.engineer}}</view>
</view>
<view class="dec2" v-if="item.status === 1 || item.status === '1'">
<view>未完成原因</view>
<view>{{item.uncompleted}}</view>
</view>
<view class="" v-show="item.items&&item.items.length>0">
<view class="dec2">
备件
</view>
<view class="items" v-for="(cur,key) in item.items" :key="key">
<view class="items-name">
{{cur.name}}
</view>
<view class="items-dec">
备件编号{{cur.number}}
</view>
<view class="items-dec">
数量{{cur.qty}}
</view>
</view>
</view>
</view>
<!-- <u-icon name="minus-circle" color="#aaaaaa" size="60" ></u-icon> -->
</view>
<view class="add-btn" v-if="data.status == 'PROCCED'">
<u-button type="primary" @click="addSubForm('creat')"><u-icon name="plus-circle" color="#ffffff"
size="36"></u-icon>添加检修内容</u-button>
</view>
</view>
</view>
</view>
<view class="footer">
<view class="btns">
<u-button type="primary" v-if="data.status == 'PROCCED'" @click="orderClick()" :loading='loading'
:disabled='loading'>完成</u-button>
</view>
<view style="height: constant(safe-area-inset-bottom); height: env(safe-area-inset-bottom);"></view>
</view>
</view>
</template>
<script setup lang="ts">
import {
onLoad,
onShow
} from '@dcloudio/uni-app'
import {
ref,
getCurrentInstance
} from 'vue'
import * as overhaulOrderApi from "@/api/overhaulOrder.js"
import { useCountStore } from '@/store'
const { proxy } = getCurrentInstance()
// store
const store = useCountStore()
const list = ref([{
name: '设备信息'
}, {
name: '检修内容'
}])
const current = ref(0)
const changeItem = ref({
name: '设备信息',
value: 1
})
const data = ref()
const loading = ref(false)
const type = ref('')
const serviceList = ref([])
function change(index) {
current.value = index
changeItem.value = list.value[current.value]
}
//
function addSubForm(clickType, item) {
if (data.value.status == 'PENDING') {
proxy.$modal.showToast('请先接单')
return
}
if (clickType == 'updata') {
proxy.$tab.navigateTo(
`/pages/overhaulOrder/addServiceRecord?type=${type.value}&factoryAreaNumber=${data.value.factoryAreaNumber}&number=${data.value.number}&data=${encodeURIComponent(JSON.stringify(item))}`
)
} else {
proxy.$tab.navigateTo(
`/pages/overhaulOrder/addServiceRecord?type=${type.value}&factoryAreaNumber=${data.value.factoryAreaNumber}&number=${data.value.number}`
)
}
}
// APP
function orderClick() {
if (!serviceList.value || serviceList.value && serviceList.value.length == 0) {
proxy.$modal.showToast('请添加检修内容')
return;
}
const paramseData = {
// number: data.number,
// status: data.status,
id: data.value.id,
// requestNumber: ''
}
let tips = '是否完成'
proxy.$modal.confirm(tips).then(() => {
proxy.$modal.loading('加载中')
loading.value = true
overhaulOrderApi.orderClick(paramseData).then((res) => {
if (res.data) {
proxy.$modal.showToast('操作成功')
setTimeout(() => {
proxy.$tab.navigateBack()
loading.value = false
}, 1500)
} else {
proxy.$modal.showToast('操作失败')
loading.value = false
}
}).catch(() => {
proxy.$modal.closeLoading()
loading.value = false
})
})
}
//
function getOverhaulOrderDetailList() {
overhaulOrderApi.overhaulOrderDetailList({
number: data.value.number
}).then((res) => {
if (res.data) {
serviceList.value = res.data
}
}).catch(() => { })
}
//
function delService(item) {
proxy.$modal.confirm('确定删除维修内容吗?').then(() => {
proxy.$modal.loading('加载中')
overhaulOrderApi.overhaulOrderDetailDelete(item.id).then((res) => {
proxy.$modal.closeLoading()
getOverhaulOrderDetailList()
}).catch(() => { })
})
}
onLoad(async (option) => {
if (option.type) type.value = option.type;
if (option.data) {
data.value = JSON.parse(decodeURIComponent(option.data))
}
changeItem.value = list.value[current.value]
})
onShow(() => {
getOverhaulOrderDetailList()
})
</script>
<style lang="scss" scoped>
.detail-container {
min-height: 100vh;
background: white;
}
.line {
background: #f5f5f5;
height: 20rpx;
}
.info {
background: white;
}
.tab {
border-bottom: 1px solid #e4e4e4;
}
.title {
display: flex;
align-items: center;
padding: 20rpx 30rpx;
border-bottom: 1px solid #e4e4e4;
view {
&:nth-child(1) {
flex: 1;
border-left: 10rpx solid #409eff;
padding-left: 20rpx;
font-weight: bold;
}
}
}
.dec {
padding: 30rpx;
.dec-item {
padding-bottom: 30rpx;
display: flex;
view {
&:nth-child(1) {
width: 160rpx;
}
&:nth-child(2) {
color: #888888;
flex: 1;
width: 0px;
word-wrap: break-word;
}
}
}
}
.dec2 {
padding: 10rpx 30rpx;
display: flex;
view {
&:nth-child(1) {
width: 180rpx;
}
&:nth-child(2) {
color: #888888;
flex: 1;
width: 0px;
word-wrap: break-word;
}
}
}
.items {
margin: 20rpx 30rpx;
border-radius: 12rpx;
background: #F5F5F5;
padding-bottom: 20rpx;
.items-name {
padding: 20rpx;
border-bottom: 1px solid #dedede;
}
.items-dec {
padding: 0px 20rpx;
margin-top: 20rpx;
}
}
.popup-title {
text-align: center;
font-size: 32rpx;
font-weight: bold;
color: #409eff;
padding: 30rpx
}
.popup {
width: 600rpx;
padding: 0rpx 60rpx 0rpx;
}
.popup-footer {
display: flex;
border-top: 1px solid #e4e4e4;
view {
line-height: 100rpx;
flex: 1;
text-align: center;
&.sure {
color: #409eff;
}
}
}
.footer {
position: fixed;
bottom: 0px;
left: 0px;
width: 100%;
background: white;
z-index: 22;
}
.btns {
display: flex;
padding: 20rpx;
box-shadow: 0px -2rpx 20rpx rgba(0, 0, 0, 0.1);
button {
flex: 1;
margin: 0px 10rpx;
}
.sure {
background: #409eff;
color: white;
border-radius: 8rpx;
&::after {
border: 1px solid #409eff;
border-radius: 0px;
}
}
}
.list {
padding: 20rpx;
.item {
display: flex;
margin-bottom: 20rpx;
.item-box {
border-radius: 12rpx;
border: 1px solid #dedede;
border-radius: 12rpx;
flex: 1;
width: 0rpx;
}
.spare-title {
padding: 20rpx 30rpx;
border-bottom: 1px solid #e4e4e4;
display: flex;
.title-txt {
color: #409eff;
font-size: 30rpx;
font-weight: bold;
flex: 1;
}
}
.dec {
color: #9c9c9c;
padding: 0rpx 30rpx 20rpx;
}
}
}
.add-btn {
display: flex;
justify-content: flex-start;
align-items: center;
}
</style>

233
src/pages/overhaulOrder/index.vue

@ -0,0 +1,233 @@
<template>
<!-- 检修工单 -->
<view class="container">
<u-navbar back-icon-color='#fff' :background="{ background: '#409eff'}" back-text="" title-color='#fff'
title="检修工单">
<template v-slot:right>
<u-icon name="plus" color="#fff" size="36" style="padding-right: 30rpx;" @click="addForm"></u-icon>
</template>
</u-navbar>
<!-- <Search @search='search' @screen='screen'/> -->
<view class="list">
<view class="item" v-for="(item,index) in list" :key="index" >
<view class="" @click="itemClick(item,index)">
<view class="title">
<view class="title-txt">
{{item.describes}}
</view>
<u-tag text="待接单" v-if="item.status == 'PENDING'" bg-color='rgba(255,255,255,0)' color='#fe8463' border-color='#fe8463' type="primary" shape='circle'/>
<u-tag text="已撤回" v-else-if="item.status=='REJECTED'" bg-color='rgba(255,255,255,0)' color='#d7d7d7' border-color='#d7d7d7 ' type="warning" shape='circle'/>
<u-tag text="已转办" v-else-if="item.status=='TRANSFERRED'" bg-color='rgba(255,255,255,0)' color='#e01f54' border-color='#e01f54' type="success" shape='circle'/>
<u-tag text="已接单" v-else-if="item.status=='PECEIVED'" bg-color='rgba(255,255,255,0)' color='#005eaa' border-color='#005eaa ' type="error" shape='circle'/>
<u-tag text="已验证" v-else-if="item.status=='VERIFIED'" bg-color='rgba(255,255,255,0)' color='#2EC7C9' border-color='#2EC7C9' type="info" shape='circle'/>
<u-tag text="已完成" v-else-if="item.status=='COMPLETED'" bg-color='rgba(255,255,255,0)' color='#2ba471' border-color='#2ba471' type="info" shape='circle'/>
</view>
<view class="dec">
检修单号:<span>{{item.number}}</span>
</view>
<view class="dec" v-if="item.maintenanceNumber">
维修工单:<span>{{item.maintenanceNumber}}</span>
</view>
<view class="dec">
{{`${params.type=='DEVICE'?'设备' : '模具'}`}}编号:<span>{{item.deviceNumber}}</span>
</view>
<view class="dec">
{{`${params.type=='DEVICE'?'设备' : '模具'}`}}名称:<span>{{item.name}}</span>
</view>
<view class="dec">
所属厂区:<span>{{item.factoryAreaName}}</span>
</view>
<view class="dec">
故障类型:<span>{{item.faultTypeName}}</span>
</view>
</view>
<view class="bottom">
<view class="time" style="flex: 1;">
{{`${$time.formatDate(item.createTime)}`}}
</view>
<!-- <view class="status">
<u-button shape="circle" type="primary" size="mini" style="min-width: 120rpx;" @click="addForm(item)">编辑</u-button>
</view> -->
</view>
</view>
</view>
<view style="height: 94rpx;padding-top: 30rpx;">
<u-loadmore :status="status" v-if="status != 'loadmore'" />
</view>
<view style="height: constant(safe-area-inset-bottom); height: env(safe-area-inset-bottom);"></view>
</view>
</template>
<script setup lang="ts">
import {
onLoad,
onShow,
onReachBottom
} from '@dcloudio/uni-app'
import {
ref,
getCurrentInstance
} from 'vue'
import * as overhaulOrderApi from "@/api/overhaulOrder.js"
const { proxy } = getCurrentInstance()
const params = ref({
pageNo: 1,
pageSize: 10,
type: '',
})
const status = ref('loadmore') //
const list = ref([])
function itemClick(item, index) {
proxy.$tab.navigateTo(`/pages/overhaulOrder/detail?type=${params.value.type}&data=${encodeURIComponent(JSON.stringify(item))}`)
}
function addForm(item) {
proxy.$tab.navigateTo(`/pages/overhaulOrder/addForm?type=${params.value.type}&data=${encodeURIComponent(JSON.stringify(item))}`)
}
async function getList() {
if (status.value == 'nomore') return;
status.value = 'loading';
proxy.$modal.loading('加载中')
await overhaulOrderApi.overhaulOrderPage(params.value).then((res) => {
proxy.$modal.closeLoading()
if (res.data.list.length > 0) {
list.value = list.value.concat(res.data.list);
params.value.pageNo++;
status.value = 'loadmore'
} else {
status.value = 'nomore'
}
}).catch(() => {
proxy.$modal.closeLoading()
})
}
onLoad((option) => {
if (option.type) params.value.type = option.type;
})
onShow(() => {
params.value.pageNo = 1
list.value = []
status.value = 'loadmore'
getList()
})
onReachBottom(() => {
getList()
})
</script>
<style lang="scss" scoped>
.container{
background: #f5f5f5;
min-height: 100vh;
}
.list {
background: #f5f5f5;
margin-top: 20rpx;
.item {
padding: 30rpx 30rpx 0px 30rpx;
margin-top: 20rpx;
background: white;
.title {
display: flex;
align-items: center;
padding-bottom: 20rpx;
.title-txt {
color: #409eff;
font-weight: bold;
font-size: 36rpx;
width: 0px;
flex: 1;
}
.time {
color: #919191;
}
}
.dec {
padding-bottom: 20rpx;
span {
color: #999999;
}
}
.last {
padding-bottom: 30rpx;
}
.bottom {
display: flex;
justify-content: space-between;
align-items: center;
border-top: 1px solid #E4E4E4;
padding: 20rpx 0px;
}
}
}
.list {
background: #f5f5f5;
margin-top: 20rpx;
.item {
padding: 30rpx 30rpx 0px 30rpx;
margin-top: 20rpx;
background: white;
.title {
display: flex;
align-items: center;
padding-bottom: 20rpx;
.title-txt {
color: #409eff;
font-weight: bold;
font-size: 36rpx;
width: 0px;
flex: 1;
}
.time {
color: #919191;
}
}
.dec {
padding-bottom: 20rpx;
span {
color: #999999;
}
}
.last {
padding-bottom: 30rpx;
}
.bottom {
display: flex;
justify-content: space-between;
align-items: center;
border-top: 1px solid #E4E4E4;
padding: 20rpx 0px;
position: relative;
.button {
position: absolute;
right: 0rpx;
}
}
}
}
</style>

259
src/pages/overhaulOrder/reqairOrderList.vue

@ -0,0 +1,259 @@
<template>
<!-- 维修工单 -->
<view class="container">
<view class="list">
<view class="item" v-for="(item,index) in repairOrderList" :key="index" @click="chooseItem(item)">
<u-checkbox v-model="item.checked" shape="circle" style="margin-top: 8rpx;"></u-checkbox>
<view class="right">
<view class="title">
<view class="title-txt">
{{item.describes}}
</view>
<u-tag text="待接单" v-if="item.status == 'PENDING'" bg-color='rgba(255,255,255,0)' color='#fe8463'
border-color='#fe8463' type="primary" shape='circle' />
<u-tag text="已撤回" v-else-if="item.status=='REJECTED'" bg-color='rgba(255,255,255,0)'
color='#d7d7d7' border-color='#d7d7d7 ' type="warning" shape='circle' />
<u-tag text="已转办" v-else-if="item.status=='TRANSFERRED'" bg-color='rgba(255,255,255,0)'
color='#e01f54' border-color='#e01f54' type="success" shape='circle' />
<u-tag text="已接单" v-else-if="item.status=='PECEIVED'" bg-color='rgba(255,255,255,0)'
color='#005eaa' border-color='#005eaa ' type="error" shape='circle' />
<u-tag text="已验证" v-else-if="item.status=='VERIFIED'" bg-color='rgba(255,255,255,0)'
color='#2EC7C9' border-color='#2EC7C9' type="info" shape='circle' />
<u-tag text="已完成" v-else-if="item.status=='COMPLETED'" bg-color='rgba(255,255,255,0)'
color='#2ba471' border-color='#2ba471' type="info" shape='circle' />
</view>
<view class="dec">
工单单号:<span>{{item.number}}</span>
</view>
<view class="dec">
类型:<span>{{item.type=='DEVICE'?'设备':item.type=='TECH'?'工艺':'模具'}}</span>
</view>
<view class="dec">
{{`${type=='DEVICE'?'设备' : '模具'}`}}编号:<span>{{item.deviceNumber}}</span>
</view>
<view class="dec">
{{`${type=='DEVICE'?'设备' : '模具'}`}}名称:<span>{{item.name}}</span>
</view>
<view class="dec">
所属厂区:<span>{{item.factoryAreaName}}</span>
</view>
<view class="dec">
班次:<span>{{item.classesName}}</span>
</view>
<view class="dec">
故障类型:<span>{{item.faultTypeName}}</span>
</view>
</view>
</view>
</view>
<view class="footer">
<view class="btns">
<button class="sure" @click="sure"> 确定</button>
</view>
<view style="height: constant(safe-area-inset-bottom); height: env(safe-area-inset-bottom);"></view>
</view>
<view style="height: constant(safe-area-inset-bottom); height: env(safe-area-inset-bottom);"></view>
</view>
</template>
<script setup lang="ts">
import {
onLoad,
} from '@dcloudio/uni-app'
import {
ref,
getCurrentInstance
} from 'vue'
import * as repairOrderApi from "@/api/repairOrder.js"
const { proxy } = getCurrentInstance()
const repairOrderList = ref([])
const type = ref('')
//
function getList() {
proxy.$modal.loading('加载中')
repairOrderApi.repairOrderList({
type: type.value,
result: 'TEMPORARILY'
}).then((res) => {
proxy.$modal.closeLoading()
res.data.forEach(item=>{
item.checked = false
})
repairOrderList.value = res.data
})
}
function chooseItem(item){
let arr = repairOrderList.value.filter(cur=>cur.id != item.id)
arr.forEach(item=>{
item.checked = false
})
item.checked = !item.checked
}
function sure(){
let data =repairOrderList.value.filter(cur=>cur.checked)[0]
uni.$emit('chooseOrder',data)
proxy.$tab.navigateBack()
}
onLoad((option) => {
if (option.type) type.value = option.type;
getList()
})
</script>
<style lang="scss" scoped>
.container{
background: #f5f5f5;
min-height: 100vh;
}
.list {
background: #f5f5f5;
margin-top: 20rpx;
padding-bottom: 120rpx;
.item {
padding: 30rpx 30rpx 0px 30rpx;
margin-top: 20rpx;
background: white;
display: flex;
align-items: flex-start;
.right{
flex: 1;
}
.title {
display: flex;
align-items: center;
padding-bottom: 20rpx;
.title-txt {
color: #409eff;
font-weight: bold;
font-size: 36rpx;
width: 0px;
flex: 1;
}
.time {
color: #919191;
}
}
.dec {
padding-bottom: 20rpx;
span {
color: #999999;
}
}
.last {
padding-bottom: 30rpx;
}
.bottom {
display: flex;
justify-content: space-between;
align-items: center;
border-top: 1px solid #E4E4E4;
padding: 20rpx 0px;
}
}
}
.list {
background: #f5f5f5;
margin-top: 20rpx;
.item {
padding: 30rpx 30rpx 0px 30rpx;
margin-top: 20rpx;
background: white;
.title {
display: flex;
align-items: center;
padding-bottom: 20rpx;
.title-txt {
color: #409eff;
font-weight: bold;
font-size: 36rpx;
width: 0px;
flex: 1;
}
.time {
color: #919191;
}
}
.dec {
padding-bottom: 20rpx;
span {
color: #999999;
}
}
.last {
padding-bottom: 30rpx;
}
.bottom {
display: flex;
justify-content: space-between;
align-items: center;
border-top: 1px solid #E4E4E4;
padding: 20rpx 0px;
position: relative;
.button {
position: absolute;
right: 0rpx;
}
}
}
}
.footer {
position: fixed;
bottom: 0px;
left: 0px;
width: 100%;
}
.btns {
display: flex;
button {
flex: 1;
}
.sure {
background: #409eff;
color: white;
border-radius: 0px;
&::after {
border: 1px solid #409eff;
border-radius: 0px;
}
}
.reset {
background: #F5F5F5;
border-radius: 0px;
&::after {
border-radius: 0px;
}
}
}
</style>

466
src/pages/repairOrder/addForm.vue

@ -0,0 +1,466 @@
<template>
<!-- 添加维修工单 -->
<view class="add-form-container">
<u-form :model="form" ref="formRef" label-width="160rpx">
<u-form-item label="故障描述" prop="describes" required>
<u-input v-model="form.describes" placeholder="请输入故障描述" :disabled="form&&form.id?true:false" />
</u-form-item>
<u-form-item label="类型" prop="type" required>
<view class="select" @click="openSingleColumn('type',form.type,appDeviceMoldType)">
<view class="input" v-if='form.type'>
{{selectFormat(form.type,appDeviceMoldType)}}
</view>
<view class="placeholder" v-else>
{{`请选择类型`}}
</view>
<u-icon name="arrow-right" color="#aaaaaa" size="28" v-if="!form.id"></u-icon>
</view>
</u-form-item>
<!-- <u-form-item :label="`${type=='DEVICE'||type == 'TECH'?'设备' : '模具'}名称`" prop="deviceNumber" required>
<view class="select" @click="openSingleColumn('deviceNumber',form.deviceNumber,deviceList)">
<view class="input" v-if='form.deviceName'>
{{form.deviceName}}
</view>
<view class="placeholder" v-else>
{{`请输入${type=='DEVICE'||type == 'TECH'?'设备' : '模具'}名称`}}
</view>
<u-icon name="arrow-right" color="#aaaaaa" size="28" v-if="!form.id"></u-icon>
</view>
</u-form-item> -->
<u-form-item :label="`${type=='DEVICE'||type == 'TECH'?'设备' : '模具'}编码`" prop="deviceNumber" required>
<u-input v-model="form.deviceNumber" :placeholder="`请输入${type=='DEVICE'||type == 'TECH'?'设备' : '模具'}编码`"
@blur="blur()" />
<view class="right-button" @click="chickRightButton">
扫描
</view>
</u-form-item>
<u-form-item :label="`${type=='DEVICE'||type == 'TECH'?'设备' : '模具'}名称`" prop="deviceNumber" required
class="disabled">
<u-input v-model="form.deviceName" :placeholder="`根据${type=='DEVICE'||type == 'TECH'?'设备' : '模具'}编码获得`"
disabled />
</u-form-item>
<u-form-item :label="`厂区编码`" prop="factoryAreaNumber" required class="disabled">
<u-input v-model="form.factoryAreaNumber"
:placeholder="`根据${type=='DEVICE'||type == 'TECH'?'设备' : '模具'}编码获得`" disabled />
</u-form-item>
<u-form-item :label="`厂区名称`" prop="factoryAreaName" required class="disabled">
<u-input v-model="form.factoryAreaName"
:placeholder="`根据${type=='DEVICE'||type == 'TECH'?'设备' : '模具'}编码获得`" disabled />
</u-form-item>
<u-form-item label="班次" prop="classes" required>
<view class="select" @click="openSingleColumn('classes',form.classes,maintenanceShift)">
<view class="input" v-if='(form.classes||form.classes==0)&&maintenanceShift.length>0'>
{{selectFormat(form.classes,maintenanceShift)}}
</view>
<view class="placeholder" v-else>
{{`请选择班次`}}
</view>
<u-icon name="arrow-right" color="#aaaaaa" size="28"></u-icon>
</view>
</u-form-item>
<u-form-item label="故障类型" prop="classes" required>
<view class="select" @click="openSingleColumn('faultType',form.faultType,faultType)">
<view class="input" v-if='form.faultType'>
{{selectFormat(form.faultType,faultType)}}
</view>
<view class="placeholder" v-else>
{{`请选择故障类型`}}
</view>
<u-icon name="arrow-right" color="#aaaaaa" size="28"></u-icon>
</view>
</u-form-item>
</u-form>
<view class="footer">
<view class="btns">
<button class="reset" @click="reset">重置</button>
<button class="sure" @click="submit" :loading='loading' :disabled='loading'>确定</button>
</view>
<view style="height: constant(safe-area-inset-bottom); height: env(safe-area-inset-bottom);"></view>
</view>
<u-select v-model="singleColumnShow" mode="single-column" :default-value='singleColumnDefaultValue'
:list="singleColumnList" @confirm="chooseSingleColumn"></u-select>
</view>
</template>
<script setup lang="ts">
import {
onLoad
} from '@dcloudio/uni-app'
import {
ref,
getCurrentInstance
} from 'vue'
import * as deviceApi from "@/api/device.js"
import * as moldApi from "@/api/mold.js"
import * as dictApi from "@/api/dict.js"
import * as repairOrderApi from "@/api/repairOrder.js"
const { proxy } = getCurrentInstance()
const loading = ref(false)
const appDeviceMoldType = ref([])
const type = ref('')
const form = ref({
id: '',
describes: "",
deviceNumber: '',
deviceName: '',
factoryAreaName: '',
factoryAreaNumber: '',
classes: '',
type: '',
faultType: ''
})
const deviceList = ref([])
const singleColumnShow = ref(false)
const singleColumnDefaultValue = ref([])
const singleColumnList = ref([])
const field = ref('')
const maintenanceShift = ref([])
const faultType = ref([])
const choosesingleColumnItem = ref()
//
function chickRightButton(field) {
if (!form.value.type) {
proxy.$modal.showToast('请先选择类型')
return;
}
uni.scanCode({
success: function (res) {
form.value.deviceNumber = res.result
getDetailsByNumber()
}
});
}
function blur() {
if (form.value.deviceNumber) {
getDetailsByNumber()
} else {
form.value.deviceName = ''
form.value.factoryAreaName = ''
form.value.factoryAreaNumber = ''
}
}
// /
function getDetailsByNumber() {
if (type.value == 'DEVICE' || type.value == 'TECH') {
deviceApi.getDeviceDetailsByNumber({
number: form.value.deviceNumber,
type: type.value
}).then((res) => {
if (!res.data) {
form.value.deviceName = ''
form.value.factoryAreaName = ''
form.value.factoryAreaNumber = ''
return;
}
form.value.deviceName = res.data.name
form.value.factoryAreaName = res.data.factoryAreaName
form.value.factoryAreaNumber = res.data.factoryAreaNumber
}).catch(() => {
form.value.deviceName = ''
form.value.factoryAreaName = ''
form.value.factoryAreaNumber = ''
})
} else if (type.value == 'MOLD') {
moldApi.getMoldDetailsByNumber({
number: form.value.deviceNumber
}).then(res => {
if (!res.data) {
form.value.deviceName = ''
form.value.factoryAreaName = ''
form.value.factoryAreaNumber = ''
return;
}
form.value.deviceName = res.data.name
form.value.factoryAreaName = res.data.factoryAreaName
form.value.factoryAreaNumber = res.data.factoryAreaNumber
}).catch(() => {
form.value.deviceName = ''
form.value.factoryAreaName = ''
form.value.factoryAreaNumber = ''
})
}
}
//
function submit() {
//
if (!form.value.describes) {
proxy.$modal.showToast('请输入故障描述')
return;
}
if (!form.value.deviceNumber) {
proxy.$modal.showToast(`请选择${type.value == 'DEVICE' || type.value == 'TECH' ? '设备' : '模具'}名称`)
return;
}
if (!form.value.factoryAreaName) {
proxy.$modal.showToast('请输入区域')
return;
}
if (!form.value.classes) {
proxy.$modal.showToast('请选择班次')
return;
}
const data = {
id: form.value && form.value.id ? form.value.id : '',
describes: form.value.describes,
type: form.value.type,
deviceNumber: form.value.deviceNumber,
factoryAreaNumber: form.value.factoryAreaNumber,
classes: form.value.classes,
faultType: form.value.faultType
}
if (form.value.id) {
proxy.$modal.confirm('是否修改维修工单').then(() => {
proxy.$modal.loading('加载中')
loading.value = true
repairOrderApi.repairOrderUpdate(data).then((res) => {
proxy.$modal.closeLoading()
if (res.data) {
proxy.$modal.showToast('修改成功')
setTimeout(() => {
proxy.$tab.navigateBack()
loading.value = false
}, 1500)
} else {
proxy.$modal.showToast('添加失败')
loading.value = false
}
}).catch(() => {
proxy.$modal.closeLoading()
loading.value = false
})
})
} else {
proxy.$modal.confirm('是否添加维修工单').then(() => {
proxy.$modal.loading('加载中')
loading.value = true
repairOrderApi.repairOrderCreate(data).then((res) => {
proxy.$modal.closeLoading()
if (res.data) {
proxy.$modal.showToast('添加成功')
setTimeout(() => {
proxy.$tab.navigateBack()
loading.value = false
}, 1500)
} else {
proxy.$modal.showToast('添加失败')
loading.value = false
}
}).catch(() => {
proxy.$modal.closeLoading()
loading.value = false
})
})
}
}
//
function reset() {
if (form.value.id) {
form.value.classes = undefined;
form.value.faultType = undefined
} else {
form.value = {}
}
}
//
function selectFormat(val, array) {
if (array.length > 0) {
let str = array.filter(item => item.value == val)[0].label
return str
} else {
return ''
}
}
//
function openSingleColumn(fieldName, val, list) {
if ((fieldName == 'deviceNumber' || fieldName == 'type') && form.value.id) return;
singleColumnList.value = list
field.value = fieldName
if (val) {
singleColumnDefaultValue.value = [list.findIndex(item => item.value == val)]
} else {
singleColumnDefaultValue.value = []
}
singleColumnShow.value = true
}
//
function chooseSingleColumn(e) {
form.value[field.value] = e[0].value
if (field.value == 'deviceNumber') {
choosesingleColumnItem.value = singleColumnList.value.filter(item => item.number == e[0].value)
form.value.factoryAreaName = choosesingleColumnItem.value[0].factoryAreaName
form.value.factoryAreaNumber = choosesingleColumnItem.value[0].factoryAreaNumber
form.value.deviceName = choosesingleColumnItem.value[0].name
}
singleColumnShow.value = false
}
// /
async function getDeviceList() {
if (type.value == 'DEVICE') {
await deviceApi.deviceList().then(res => {
res.data.map(item => {
item.value = item.number
item.label = item.name
})
deviceList.value = res.data
}).catch(() => { })
} else if (type.value == 'MOLD') {
await moldApi.moldList().then(res => {
res.data.map(item => {
item.value = item.number
item.label = item.name
})
deviceList.value = res.data
}).catch(() => { })
}
}
onLoad(async option => {
if (option.type) type.value = option.type;
if (option.data) {
let data = JSON.parse(decodeURIComponent(option.data))
form.value = {
id: data.id,
describes: data.describes,
deviceNumber: data.deviceNumber,
deviceName: data.name,
factoryAreaName: data.factoryAreaName,
factoryAreaNumber: data.factoryAreaNumber,
classes: data.classes || data.classes == 0 ? data.classes : undefined,
faultType: data.faultType,
type: data.type
}
};
await getDeviceList()
maintenanceShift.value = await dictApi.getDict('maintenance_shift')
appDeviceMoldType.value = await dictApi.getDict('app_device_mold_type')
if (type.value == 'MOLD') {
appDeviceMoldType.value = appDeviceMoldType.value.filter((item => item.value == "MOLD"))
} else {
appDeviceMoldType.value = appDeviceMoldType.value.filter((item => item.value != "MOLD"))
}
form.value.type = appDeviceMoldType.value[0].value
faultType.value = await dictApi.getDict('fault_type')
})
</script>
<style lang="scss" scoped>
.add-form-container {
min-height: calc(100vh - 140rpx);
background: white;
padding: 0px 0rpx 140rpx;
}
.u-form-item {
padding: 20rpx 30rpx;
}
.disabled {
background: #f5f5f5;
}
.list {
padding-bottom: 20rpx;
.item {
margin-top: 20rpx;
background: white;
padding: 30rpx;
display: flex;
align-items: center;
image {
width: 160rpx;
height: 160rpx;
margin-right: 20rpx;
}
.title {
font-size: 32rpx;
font-weight: bold;
}
.dec1 {
font-size: 28rpx;
margin-top: 16rpx;
color: #acacac;
}
.dec2 {
font-size: 28rpx;
margin-top: 6rpx;
color: #acacac;
}
}
}
.footer {
position: fixed;
bottom: 0px;
left: 0px;
width: 100%;
}
.btns {
display: flex;
button {
flex: 1;
}
.sure {
background: #409eff;
color: white;
border-radius: 0px;
&::after {
border: 1px solid #409eff;
border-radius: 0px;
}
}
.reset {
background: #F5F5F5;
border-radius: 0px;
&::after {
border-radius: 0px;
}
}
}
.right-button {
background: #409eff;
color: white;
padding: 0rpx 30rpx;
border-radius: 16rpx;
text-align: center;
font-size: 28rpx;
}
.select {
display: flex;
align-items: center;
height: 72rpx;
width: 100%;
.input {
flex: 1;
font-size: 28rpx;
color: #000000;
}
.placeholder {
flex: 1;
font-size: 28rpx;
color: rgb(192, 196, 204);
}
}
</style>

502
src/pages/repairOrder/addServiceRecord.vue

@ -0,0 +1,502 @@
<template>
<!-- 添加维修工单 -->
<view class="add-form-container">
<u-form :model="form" ref="formRef" label-width="160rpx">
<u-form-item label="故障描述" prop="describes" required>
<u-input v-model="form.describes" placeholder="请输入故障描述" />
</u-form-item>
<u-form-item label="故障真因" prop="describes" required>
<u-input v-model="form.describes1" placeholder="请输入故障真因" />
</u-form-item>
<u-form-item label="解决措施" prop="describes" required>
<u-input type='textarea' v-model="form.workOut" placeholder="请输入解决措施" />
</u-form-item>
<u-form-item label="维修人员" prop="describes" required>
<view class="select" @click="openSelecUser">
<view class="input" v-if='form.maintenances'>
{{selectFormatCheck(form.maintenances,selecUserList)}}
</view>
<view class="placeholder" v-else>
请选择维修人员
</view>
<u-icon name="arrow-right" color="#aaaaaa" size="28"></u-icon>
</view>
</u-form-item>
</u-form>
<view class="list">
<view class="title">
<span></span>备件
</view>
<view class="item " v-for="(item,index) in form.itemNumbers" :key="index">
<view class="item-box">
<view class="spare-title">
<view class="title-txt">
{{item.name}}
</view>
</view>
<u-row gutter="16">
<u-col :span="12">
<view class="dec">
<view class="">
数量:{{item.qty}}
</view>
</view>
</u-col>
</u-row>
</view>
<u-icon name="minus-circle" color="#aaaaaa" size="60" @click="delSpareParts(index)"></u-icon>
</view>
<view class="add-btn">
<u-button type="primary" @click="open"><u-icon name="plus-circle" color="#ffffff"
size="36"></u-icon>添加备件</u-button>
</view>
</view>
<view class="footer">
<view class="btns">
<button class="reset" @click="reset">重置</button>
<button class="sure" @click="submit" :loading='loading' :disabled='loading'>确定</button>
</view>
<view style="height: constant(safe-area-inset-bottom); height: env(safe-area-inset-bottom);"></view>
</view>
<!-- 添加备件 -->
<u-popup v-model="isPopupShow" mode="center" border-radius="14">
<view class="popup-title">添加备件</view>
<view class="popup">
<u-form :model="form1" ref="form1Ref" label-width="160rpx">
<u-form-item :label="`备件`" prop="number" required>
<view class="select" @click="openSingleColumn('number',form1.number,sparePartsList)">
<view class="input" v-if='form1.number'>
{{form1.name}}
</view>
<view class="placeholder" v-else>
请选择备件
</view>
<u-icon name="arrow-right" color="#aaaaaa" size="28"></u-icon>
</view>
</u-form-item>
<u-form-item label="数量" prop="qty" required>
<u-input v-model="form1.qty" type="number" placeholder="请输入数量" />
</u-form-item>
</u-form>
</view>
<view class="popup-footer">
<view @click="isPopupShow = false">取消</view>
<view class="sure" @click="addSpare">确认</view>
</view>
</u-popup>
<!-- 选择维修人员 -->
<u-popup v-model="isShowSelecUser" mode="center" border-radius="14">
<view class="popup-title">选择维修人员</view>
<view class="popup">
<u-checkbox-group @change="checkboxGroupChange">
<u-checkbox v-model="item.checked" v-for="(item, index) in selecUserList" :key="index"
:name="item.id">{{item.name}}</u-checkbox>
</u-checkbox-group>
</view>
<view class="popup-footer">
<view @click="isShowSelecUser = false">取消</view>
<view class="sure" @click="chooseUser">确认</view>
</view>
</u-popup>
<u-select v-model="singleColumnShow" mode="single-column" :default-value='singleColumnDefaultValue'
:list="singleColumnList" @confirm="chooseSingleColumn" @cancle='singleColumnShow = false'></u-select>
</view>
</template>
<script setup lang="ts">
import {
onLoad
} from '@dcloudio/uni-app'
import {
ref,
getCurrentInstance
} from 'vue'
import * as repairOrderApi from "@/api/repairOrder.js"
import * as sparePartsApi from "@/api/spareParts.js"
import * as deptApi from "@/api/dept.js"
const { proxy } = getCurrentInstance()
const loading = ref(false)
const type = ref('')
const isPopupShow = ref(false)
const sparePartsList = ref([])
const singleColumnShow = ref(false)
const singleColumnDefaultValue = ref([])
const singleColumnList = ref([])
const field = ref('')
const selecUserList = ref([])
const isShowSelecUser = ref(false)
const form = ref({
number: '',
describes: '',
describes1: '',
workOut: '',
maintenances: '',
itemNumbers: [],
})
const form1 = ref({
number: "",
name:"",
qty: 0
})
const factoryAreaNumber = ref('')
const chooseUserList = ref([])
//
function submit() {
//
if (!form.value.describes) {
proxy.$modal.showToast('请输入故障描述')
return;
}
if (!form.value.describes1) {
proxy.$modal.showToast(`请输入故障真因`)
return;
}
if (!form.value.workOut) {
proxy.$modal.showToast('请输入解决措施')
return;
}
if (!form.value.maintenances) {
proxy.$modal.showToast('请选择维修人员')
return;
}
if (form.value.id) {
proxy.$modal.confirm('是否修改维修内容').then(() => {
proxy.$modal.loading('加载中')
loading.value = true
repairOrderApi.repairOrderDetailUpdate(form.value).then((res) => {
proxy.$modal.closeLoading()
if (res.data) {
proxy.$modal.showToast('修改成功')
setTimeout(() => {
proxy.$tab.navigateBack()
loading.value = false
}, 1500)
} else {
proxy.$modal.showToast('添加失败')
loading.value = false
}
}).catch(() => {
proxy.$modal.closeLoading()
loading.value = false
})
})
} else {
proxy.$modal.confirm('是否添加维修内容').then(() => {
proxy.$modal.loading('加载中')
loading.value = true
repairOrderApi.repairOrderDetailCreate(form.value).then((res) => {
proxy.$modal.closeLoading()
if (res.data) {
proxy.$modal.showToast('添加成功')
setTimeout(() => {
proxy.$tab.navigateBack()
loading.value = false
}, 1500)
} else {
proxy.$modal.showToast('添加失败')
loading.value = false
}
}).catch(() => {
proxy.$modal.closeLoading()
loading.value = false
})
})
}
}
//
function reset() {
form.value = {
number: '',
describes: '',
describes1: '',
workOut: '',
maintenances: '',
itemNumbers: [],
}
}
//
async function getSelecUser() {
let data = {
classType: type.value,
factoryAreaNumber: factoryAreaNumber.value
}
let arr = []
if (form.value.maintenances) {
arr = form.value.maintenances.split(',')
}
await deptApi.getSelecUser(data).then(res => {
res.data.forEach(item => {
item.checked = false
arr.forEach(cur => {
if (item.id == cur) {
item.checked = true
}
})
})
selecUserList.value = res.data
}).catch(() => { })
}
//
function openSelecUser() {
isShowSelecUser.value = true
}
function checkboxGroupChange(e) {
chooseUserList.value = e
}
//
function selectFormatCheck(val, array) {
const arr = val.split(',').map(Number)
let str = array.filter(item => arr.includes(item.id)).map(item => item.name).join(',')
return str
}
//
function chooseUser() {
form.value.maintenances = chooseUserList.value.join(',')
isShowSelecUser.value = false
}
// function selectFormat(val, array) {
// let str = array.filter(item => item.value == val)[0].label
// return str
// }
//
function openSingleColumn(fieldName, val, list) {
if (fieldName == 'deviceNumber' && form.value.id) return;
singleColumnList.value = list
field.value = fieldName
if (val) {
singleColumnDefaultValue.value = [list.findIndex(item => item.value == val)]
} else {
singleColumnDefaultValue.value = []
}
singleColumnShow.value = true
}
//
function chooseSingleColumn(e) {
form1.value[field.value] = e[0].value
if(field.value=='number'){
form1.value.name = e[0].label
}
singleColumnShow.value = false
}
//
async function getSparePartsList() {
await sparePartsApi.getSparePartsList().then(res => {
res.data.map(item => {
item.value = item.number
item.label = item.name
})
sparePartsList.value = res.data
}).catch(() => { })
}
//
function open() {
form1.value = {
number: "",
name:'',
qty: 0
}
isPopupShow.value = true
}
//
function addSpare() {
if (!form1.value.number) {
proxy.$modal.showToast('请选择备件')
return;
}
if (!form1.value.qty || form1.value.qty == 0) {
proxy.$modal.showToast('请输入数量')
return;
}
if (form.value.itemNumbers && form.value.itemNumbers.length > 0) {
let arr = form.value.itemNumbers.filter(item => item.number == form1.value.number)
if (arr && arr.length > 0) {
proxy.$modal.showToast('该备件已添加')
return;
}
}
form.value.itemNumbers.push(form1.value)
isPopupShow.value = false
}
//
function delSpareParts(index) {
form.value.itemNumbers.splice(index, 1)
}
onLoad(async (option) => {
if (option.type) type.value = option.type;
if (option.factoryAreaNumber) factoryAreaNumber.value = option.factoryAreaNumber;
if (option.number) form.value.number = option.number;
if (option.data && JSON.parse(decodeURIComponent(option.data)) && JSON.parse(decodeURIComponent(option
.data)).id) {
form.value = JSON.parse(decodeURIComponent(option.data))
form.value.itemNumbers = form.value.items
};
await getSelecUser()
await getSparePartsList()
})
</script>
<style lang="scss" scoped>
.add-form-container {
min-height: calc(100vh - 140rpx);
background: white;
padding: 0px 30rpx 140rpx;
}
.footer {
position: fixed;
bottom: 0px;
left: 0px;
width: 100%;
z-index: 22;
}
.btns {
display: flex;
button {
flex: 1;
}
.sure {
background: #409eff;
color: white;
border-radius: 0px;
&::after {
border: 1px solid #409eff;
border-radius: 0px;
}
}
.reset {
background: #F5F5F5;
border-radius: 0px;
&::after {
border-radius: 0px;
}
}
}
.right-button {
background: #409eff;
color: white;
padding: 0rpx 30rpx;
border-radius: 16rpx;
text-align: center;
font-size: 28rpx;
}
.select {
display: flex;
align-items: center;
height: 72rpx;
width: 100%;
.input {
flex: 1;
font-size: 28rpx;
color: #000000;
}
.placeholder {
flex: 1;
font-size: 28rpx;
color: rgb(192, 196, 204);
}
}
.title {
padding: 32rpx 0px;
position: relative;
span {
position: absolute;
left: -16rpx;
color: #fa3534;
padding-top: 6rpx;
}
}
.list {
.item {
display: flex;
margin-bottom: 20rpx;
.item-box {
background: #F5F5F5;
border-radius: 12rpx;
flex: 1;
width: 0rpx;
}
.spare-title {
padding: 20rpx 30rpx;
border-bottom: 1px solid #e4e4e4;
.title-txt {
color: #409eff;
font-size: 30rpx;
font-weight: bold;
}
}
.dec {
color: #9c9c9c;
padding: 20rpx 30rpx 20rpx;
}
}
}
.add-btn {
display: flex;
justify-content: flex-start;
align-items: center;
}
.popup-title {
text-align: center;
font-size: 32rpx;
font-weight: bold;
color: #409eff;
padding: 30rpx 30rpx 0px
}
.popup {
width: 600rpx;
padding: 30rpx 60rpx 30rpx;
}
.popup-footer {
display: flex;
border-top: 1px solid #e4e4e4;
view {
line-height: 100rpx;
flex: 1;
text-align: center;
&.sure {
color: #409eff;
}
}
}
::v-deep .u-checkbox-group {
display: grid !important;
}
</style>

762
src/pages/repairOrder/detail.vue

@ -0,0 +1,762 @@
<template>
<!-- 详情 -->
<view class="detail-container">
<view class="info">
<view class="title">
<view>维修工单</view>
<view @click="transfer"
v-if="data.status == 'PECEIVED' && (!serviceList || serviceList && serviceList.length == 0)">转办
</view>
</view>
<view class="dec">
<view class="dec-item">
<view>工单单号</view>
<view>{{data.number}}</view>
</view>
<view class="dec-item">
<view>报修描述</view>
<view>{{data.describes}}</view>
</view>
<u-form :model="data" ref="form1" label-width="160rpx"
style="border-top: 1px solid rgba(220,220,220,0.5);border-bottom: 1px solid rgba(220,220,220,0.5);margin-bottom: 20rpx;"
v-if="data.status == 'PECEIVED'&& store.post.code == 'worker'">
<u-form-item label="班次" prop="classes" required>
<view class="select" @click="openSingleColumn('classes',data.classes,maintenanceShift)">
<view class="input" v-if='data.classes||data.classes==0'>
{{data.classesName}}
</view>
<view class="placeholder" v-else>
{{`请选择班次`}}
</view>
<u-icon name="arrow-right" color="#aaaaaa" size="28"></u-icon>
</view>
</u-form-item>
<u-form-item label="故障类型" prop="classes" required>
<view class="select" @click="openSingleColumn('faultType',data.faultType,faultType)">
<view class="input" v-if='data.faultType'>
{{data.faultTypeName}}
</view>
<view class="placeholder" v-else>
{{`请选择故障类型`}}
</view>
<u-icon name="arrow-right" color="#aaaaaa" size="28"></u-icon>
</view>
</u-form-item>
</u-form>
<view class="dec-item" v-if="data.status != 'PECEIVED'|| store.post.code != 'worker'">
<view>班次</view>
<view>{{data.classesName}}</view>
</view>
<view class="dec-item" v-if="data.status != 'PECEIVED'||store.post.code != 'worker'">
<view>故障类型</view>
<view>{{data.faultTypeName}}</view>
</view>
<view class="dec-item" v-if="data.createTime">
<view>创建时间</view>
<view>{{$time.formatDate(data.createTime)}}</view>
</view>
<view class="dec-item" v-if="data.creator">
<view>创建人员</view>
<view>{{data.creator}}</view>
</view>
<view class="dec-item" v-if="data.receivingTime">
<view>接单时间</view>
<view>{{$time.formatDate(data.receivingTime)}}</view>
</view>
<view class="dec-item" v-if="data.maintenanceName">
<view>接单人员</view>
<view>{{data.maintenanceName}}</view>
</view>
<view class="dec-item" v-if="data.completionTime">
<view>完成时间</view>
<view>{{$time.formatDate(data.completionTime)}}</view>
</view>
<view class="dec-item" v-if="data.verifyTime">
<view>验证时间</view>
<view>{{$time.formatDate(data.verifyTime)}}</view>
</view>
<view class="dec-item" v-if="data.verifyer">
<view>验证人员</view>
<view>{{data.verifyer}}</view>
</view>
</view>
</view>
<div class="line"></div>
<view class="info" style="padding-bottom: 130rpx;">
<view class="tab">
<u-tabs :list="list" :is-scroll="false" bar-height="2" bar-width="250" v-model="current"
@change="change"></u-tabs>
</view>
<view>
<view class="title">
<view>{{changeItem.name}}</view>
</view>
<view class="dec" v-if="changeItem.value == 1">
<view class="dec-item">
<view>设备编号</view>
<view>{{data.deviceNumber}}</view>
</view>
<view class="dec-item">
<view>设备名称</view>
<view>{{data.name}}</view>
</view>
<view class="dec-item">
<view>所属厂区</view>
<view>{{data.factoryAreaName}}</view>
</view>
<view class="dec-item">
<view>设备类型</view>
<view>{{data.type == 'DEVICE'?'设备':data.type == 'TECH'?'工艺':'模具'}}</view>
</view>
</view>
<view class="dec" v-if="changeItem.value == 2">
<view class="dec-item">
<view>报修单号</view>
<view>{{data1.number}}</view>
</view>
<view class="dec-item">
<view>报修描述</view>
<view>{{data1.describes}}</view>
</view>
<view class="dec-item">
<view>报修人</view>
<view>{{data1.declarName}}</view>
</view>
<view class="dec-item">
<view>报修时间</view>
<view>{{$time.formatDate(data.createTime)}}</view>
</view>
<!-- <view>图片</view> -->
<view class="images">
<image :src="cur" mode="" v-for="(cur,key) in data1.filePathList" :key='key'
@click="previewImage(key,data1.filePathList)"></image>
</view>
</view>
<view class="list" v-if="changeItem.value == 3">
<view class="item " v-for="(item,index) in serviceList" :key="index"
@click="addSubForm('updata',item)">
<view class="item-box">
<view class="spare-title">
<view class="title-txt">
{{item.describes}}
</view>
<u-icon name="trash" color="#aaaaaa" size="40"
v-if="(data.status == 'PENDING' || data.status == 'PECEIVED')&& store.post.code == 'worker'"
@click.native.stop="delService(item)"></u-icon>
</view>
<view class="dec2">
<view>故障真因</view>
<view>{{item.describes1}}</view>
</view>
<view class="dec2">
<view>解决措施</view>
<view>{{item.workOut}}</view>
</view>
<view class="dec2">
<view>维修人员</view>
<view>{{item.maintenancesName}}</view>
</view>
<view class="" v-show="item.items&&item.items.length>0">
<view class="dec2">
备件
</view>
<view class="items" v-for="(cur,key) in item.items" :key="key">
<view class="items-name">
{{cur.name}}
</view>
<view class="items-dec">
备件编号{{cur.number}}
</view>
<view class="items-dec">
数量{{cur.qty}}
</view>
</view>
</view>
</view>
<!-- <u-icon name="minus-circle" color="#aaaaaa" size="60" ></u-icon> -->
</view>
<view class="add-btn"
v-if="(data.status == 'PENDING' || data.status == 'PECEIVED')&& store.post.code == 'worker'">
<u-button type="primary" @click="addSubForm('creat')"><u-icon name="plus-circle" color="#ffffff"
size="36"></u-icon>添加维修内容</u-button>
</view>
</view>
</view>
</view>
<view class="footer">
<view class="btns" v-if="data.status == 'PENDING'&& store.post.code == 'worker'">
<u-button type="primary" @click="orderClick(1)" :loading='loading' :disabled='loading'>接单</u-button>
</view>
<view class="btns" v-if="data.status == 'PECEIVED'&& store.post.code == 'worker'">
<u-button shape="shape" type="warning" style="min-width: 120rpx;" :loading='loading1' @click="editForm"
:disabled='loading1'>修改工单</u-button>
<u-button type="primary" @click="orderClickSuccess()" :loading='loading'
:disabled='loading'>完成</u-button>
</view>
<view class="btns" v-if="data.status == 'COMPLETED'&& store.post.code == 'engineer'">
<u-button type="primary" @click="orderClick(3)" :loading='loading' :disabled='loading'>验证完结</u-button>
</view>
<view style="height: constant(safe-area-inset-bottom); height: env(safe-area-inset-bottom);"></view>
</view>
<!-- 完成类型 -->
<u-popup v-model="isShowSuccess" mode="center" border-radius="14">
<view class="popup-title">完成类型</view>
<view class="popup">
<u-radio-group v-model="result" @change="radioGroupChange">
<u-radio v-for="(item, index) in orderCompleteResult" :key="index" :name="item.value">
{{item.label}}
</u-radio>
</u-radio-group>
</view>
<view class="popup-footer">
<view @click="isShowSuccess = false">取消</view>
<view class="sure" @click="sure">确认</view>
</view>
</u-popup>
<view style="height: constant(safe-area-inset-bottom); height: env(safe-area-inset-bottom);"></view>
<u-select v-model="singleColumnShow" mode="single-column" :default-value='singleColumnDefaultValue'
:list="singleColumnList" @confirm="chooseSingleColumn"></u-select>
</view>
</template>
<script setup lang="ts">
import {
onLoad,
onShow
} from '@dcloudio/uni-app'
import {
ref,
getCurrentInstance
} from 'vue'
import * as dictApi from "@/api/dict.js"
import * as repairOrderApi from "@/api/repairOrder.js"
import { useCountStore } from '@/store'
const { proxy } = getCurrentInstance()
// store
const store = useCountStore()
const list = ref([{
name: '设备信息',
value: 1
}, {
name: '报修信息',
value: 2
}, {
name: '维修内容',
value: 3
}])
const current = ref(0)
const changeItem = ref({
name: '设备信息',
value: 1
})
const data = ref()
const loading = ref(false)
const loading1 = ref(false)
const type = ref('')
const serviceList = ref([])
const isShowSuccess = ref(false)
const orderCompleteResult = ref([]) //
const result = ref('TEMPORARILY')
const data1 = ref('')
const singleColumnShow = ref(false)
const singleColumnDefaultValue = ref([])
const singleColumnList = ref([])
const field = ref('')
const maintenanceShift = ref([]) //
const faultType = ref([]) //
function change(index) {
current.value = index
changeItem.value = list.value[current.value]
}
//
function addSubForm(clickType, item) {
if (data.value.status == 'PENDING') {
proxy.$modal.showToast('请先接单')
return
}
if (clickType == 'updata') {
proxy.$tab.navigateTo(
`/pages/repairOrder/addServiceRecord?type=${type.value}&factoryAreaNumber=${data.value.factoryAreaNumber}&number=${data.value.number}&data=${encodeURIComponent(JSON.stringify(item))}`
)
} else {
proxy.$tab.navigateTo(
`/pages/repairOrder/addServiceRecord?type=${type.value}&factoryAreaNumber=${data.value.factoryAreaNumber}&number=${data.value.number}`
)
}
}
//
function orderClickSuccess() {
//
if (data.value.status == 'PECEIVED') {
if (store.id != data.value.maintenance) {
proxy.$modal.showToast('当前人员与接单人员不一致')
return;
}
if (!serviceList.value || serviceList.value && serviceList.value.length == 0) {
proxy.$modal.showToast('请添加维修内容')
return;
}
if (!data.value.classesName || !data.value.faultTypeName) {
proxy.$modal.showToast('请完善班次和故障类型')
return;
}
}
isShowSuccess.value = true
}
function radioGroupChange(e) {
result.value = e
}
function sure() {
isShowSuccess.value = false
orderClick(2)
}
// APP
function orderClick(type) {
//
// if (this.data.status == 'PENDING') {
// if (this.$store.state.user.dept.parentId != this.data.factoryAreaNumber) {
// this.$modal.showToast('')
// return;
// }
// if (this.$store.state.user.dept.classType != this.data.type) {
// this.$modal.showToast('')
// return;
// }
// }
const dataOne = {
number: data.value.number,
status: data.value.status,
id: data.value.id,
result: type == 2 ? result.value : '',
requestNumber: data.value.requestNumber,
}
//
const dataTwo = {
id: data.value && data.value.id ? data.value.id : '',
describes: data.value.describes,
type: data.value.type,
deviceNumber: data.value.deviceNumber,
factoryAreaNumber: data.value.factoryAreaNumber,
classes: data.value.classes,
faultType: data.value.faultType
}
let tips = data.value.status == 'PENDING' ? '是否接单?' : data.value.status == 'PECEIVED' ? '是否完成?' : data
.value.status == 'COMPLETED' ? '是否验证完结?' : ''
proxy.$modal.confirm(tips).then(async () => {
proxy.$modal.loading('加载中')
loading.value = true
//
if (data.value.status == 'PECEIVED') {
await repairOrderApi.repairOrderUpdate(dataTwo).then((res) => { }).catch(() => {
proxy.$modal.closeLoading()
loading.value = false
})
}
await repairOrderApi.orderClick(dataOne).then((res) => {
if (res.data) {
proxy.$modal.showToast('操作成功')
setTimeout(() => {
proxy.$tab.navigateBack()
loading.value = false
}, 1500)
} else {
proxy.$modal.showToast('操作失败')
loading.value = false
}
}).catch(() => {
proxy.$modal.closeLoading()
loading.value = false
})
})
}
//
function getDeviceRepairDetailsByNumber() {
repairOrderApi.getDeviceRepairDetailsByNumber({
type: data.value.type,
requestNumber: data.value.requestNumber
}).then((res) => {
if (res.data) {
data1.value = res.data
}
}).catch(() => { })
}
//
function getRepairOrderDetaiList() {
repairOrderApi.repairOrderDetailList({
number: data.value.number
}).then((res) => {
if (res.data) {
serviceList.value = res.data
}
}).catch(() => { })
}
//
function delService(item) {
proxy.$modal.confirm('确定删除维修内容吗?').then(() => {
proxy.$modal.loading('加载中')
repairOrderApi.repairOrderDetailDelete(item.id).then((res) => {
proxy.$modal.closeLoading()
getRepairOrderDetaiList()
}).catch(() => { })
})
}
function transfer() {
proxy.$tab.navigateTo(`/pages/repairOrder/transfer?type=${data.value.type}&id=${data.value.id}&deviceNumber=${data.value.deviceNumber}`)
}
function previewImage(current, array) {
uni.previewImage({
urls: array,
current: current,
longPressActions: {
itemList: ['发送给朋友', '保存图片', '收藏'],
success: function (data) {
console.log('选中了第' + (data.tapIndex + 1) + '个按钮,第' + (data.index + 1) + '张图片');
},
fail: function (err) {
console.log(err.errMsg);
}
}
});
}
//
function openSingleColumn(fieldName, val, list) {
singleColumnList.value = list
field.value = fieldName
if (val) {
singleColumnDefaultValue.value = [list.findIndex(item => item.value == val)]
} else {
singleColumnDefaultValue.value = []
}
singleColumnShow.value = true
}
//
function chooseSingleColumn(e) {
data.value[field.value] = e[0].value
console.log(field.value)
if (field.value == 'classes') {
data.value.classesName = e[0].label
console.log(data.value.classesName)
}
if (field.value == 'faultType') {
data.value.faultTypeName = e[0].label
}
singleColumnShow.value = false
}
//
function editForm() {
const paramesData = {
id: data.value && data.value.id ? data.value.id : '',
describes: data.value.describes,
type: data.value.type,
deviceNumber: data.value.deviceNumber,
factoryAreaNumber: data.value.factoryAreaNumber,
classes: data.value.classes,
faultType: data.value.faultType
}
proxy.$modal.confirm('是否修改维修工单').then(() => {
proxy.$modal.loading('加载中')
loading1.value = true
repairOrderApi.repairOrderUpdate(paramesData).then((res) => {
proxy.$modal.closeLoading()
if (res.data) {
proxy.$modal.showToast('修改成功')
// setTimeout(() => {
// this.$tab.navigateBack()
loading1.value = false
// }, 1500)
} else {
proxy.$modal.showToast('修改失败')
loading1.value = false
}
}).catch(() => {
proxy.$modal.closeLoading()
loading.value = false
})
})
}
onLoad(async (option) => {
if (option.type) type.value = option.type;
if (option.data) {
data.value = JSON.parse(decodeURIComponent(option.data))
}
changeItem.value = list.value[current.value]
orderCompleteResult.value = await dictApi.getDict('order_complete_result')
})
onShow(async () => {
if (data.value.requestNumber) {
getDeviceRepairDetailsByNumber()
list.value = [{
name: '设备信息',
value: 1
}, {
name: '报修信息',
value: 2
}, {
name: '维修内容',
value: 3
}]
} else {
list.value = [{
name: '设备信息',
value: 1
}, {
name: '维修内容',
value: 3
}]
}
getRepairOrderDetaiList()
maintenanceShift.value = await dictApi.getDict('maintenance_shift')
faultType.value = await dictApi.getDict('fault_type')
})
</script>
<style lang="scss" scoped>
.detail-container {
min-height: 100vh;
background: white;
}
.line {
background: #f5f5f5;
height: 20rpx;
}
.info {
background: white;
}
.tab {
border-bottom: 1px solid #e4e4e4;
}
.title {
display: flex;
align-items: center;
padding: 20rpx 30rpx;
border-bottom: 1px solid #e4e4e4;
view {
&:nth-child(1) {
flex: 1;
border-left: 10rpx solid #409eff;
padding-left: 20rpx;
font-weight: bold;
}
}
}
.dec {
padding: 30rpx;
.dec-item {
padding-bottom: 30rpx;
display: flex;
view {
&:nth-child(1) {
width: 160rpx;
}
&:nth-child(2) {
color: #888888;
flex: 1;
width: 0px;
word-wrap: break-word;
}
}
}
}
.dec2 {
padding: 10rpx 30rpx;
display: flex;
view {
&:nth-child(1) {
width: 160rpx;
}
&:nth-child(2) {
color: #888888;
flex: 1;
width: 0px;
word-wrap: break-word;
}
}
}
.items {
margin: 20rpx 30rpx;
border-radius: 12rpx;
background: #F5F5F5;
padding-bottom: 20rpx;
.items-name {
padding: 20rpx;
border-bottom: 1px solid #dedede;
}
.items-dec {
padding: 0px 20rpx;
margin-top: 20rpx;
}
}
.popup-title {
text-align: center;
font-size: 32rpx;
font-weight: bold;
color: #409eff;
padding: 30rpx
}
.popup {
width: 600rpx;
padding: 0rpx 60rpx 0rpx;
}
.popup-footer {
display: flex;
border-top: 1px solid #e4e4e4;
view {
line-height: 100rpx;
flex: 1;
text-align: center;
&.sure {
color: #409eff;
}
}
}
.footer {
position: fixed;
bottom: 0px;
left: 0px;
width: 100%;
background: white;
z-index: 22;
}
.btns {
display: flex;
padding: 20rpx;
box-shadow: 0px -2rpx 20rpx rgba(0, 0, 0, 0.1);
button {
flex: 1;
margin: 0px 10rpx;
}
.sure {
background: #409eff;
color: white;
border-radius: 8rpx;
&::after {
border: 1px solid #409eff;
border-radius: 0px;
}
}
}
.list {
padding: 20rpx;
.item {
display: flex;
margin-bottom: 20rpx;
.item-box {
border-radius: 12rpx;
border: 1px solid #dedede;
border-radius: 12rpx;
flex: 1;
width: 0rpx;
}
.spare-title {
padding: 20rpx 30rpx;
border-bottom: 1px solid #e4e4e4;
display: flex;
.title-txt {
color: #409eff;
font-size: 30rpx;
font-weight: bold;
flex: 1;
}
}
.dec {
color: #9c9c9c;
padding: 0rpx 30rpx 20rpx;
}
}
}
.add-btn {
display: flex;
justify-content: flex-start;
align-items: center;
}
::v-deep .u-radio-group {
display: grid !important;
padding-bottom: 20rpx;
}
.images {
display: flex;
width: 100%;
image {
width: 30%;
margin-right: 20rpx;
height: 200rpx;
border-radius: 10rpx;
}
}
.select {
display: flex;
align-items: center;
height: 72rpx;
width: 100%;
.input {
flex: 1;
font-size: 28rpx;
color: #000000;
}
.placeholder {
flex: 1;
font-size: 28rpx;
color: rgb(192, 196, 204);
}
}
</style>

235
src/pages/repairOrder/index.vue

@ -0,0 +1,235 @@
<template>
<!-- 维修工单 -->
<view class="container">
<u-navbar back-icon-color='#fff' :background="{ background: '#409eff'}" back-text="" title-color='#fff'
title="维修工单">
<template v-slot:right>
<u-icon name="plus" color="#fff" size="36" style="padding-right: 30rpx;" @click="addForm" v-if=" store.post.code == 'worker'"></u-icon>
</template>
</u-navbar>
<view class="list">
<view class="item" v-for="(item,index) in list" :key="index" >
<view class="" @click="itemClick(item,index)">
<view class="title">
<view class="title-txt">
{{item.describes}}
</view>
<u-tag text="待接单" v-if="item.status == 'PENDING'" bg-color='rgba(255,255,255,0)' color='#fe8463' border-color='#fe8463' type="primary" shape='circle'/>
<u-tag text="已撤回" v-else-if="item.status=='REJECTED'" bg-color='rgba(255,255,255,0)' color='#d7d7d7' border-color='#d7d7d7 ' type="warning" shape='circle'/>
<u-tag text="已转办" v-else-if="item.status=='TRANSFERRED'" bg-color='rgba(255,255,255,0)' color='#e01f54' border-color='#e01f54' type="success" shape='circle'/>
<u-tag text="已接单" v-else-if="item.status=='PECEIVED'" bg-color='rgba(255,255,255,0)' color='#005eaa' border-color='#005eaa ' type="error" shape='circle'/>
<u-tag text="已验证" v-else-if="item.status=='VERIFIED'" bg-color='rgba(255,255,255,0)' color='#2EC7C9' border-color='#2EC7C9' type="info" shape='circle'/>
<u-tag text="已完成" v-else-if="item.status=='COMPLETED'" bg-color='rgba(255,255,255,0)' color='#2ba471' border-color='#2ba471' type="info" shape='circle'/>
</view>
<view class="dec">
工单单号:<span>{{item.number}}</span>
</view>
<view class="dec">
类型:<span>{{item.type=='DEVICE'?'设备':item.type=='TECH'?'工艺':'模具'}}</span>
</view>
<view class="dec">
{{`${params.type=='DEVICE'?'设备' : '模具'}`}}编号:<span>{{item.deviceNumber}}</span>
</view>
<view class="dec">
{{`${params.type=='DEVICE'?'设备' : '模具'}`}}名称:<span>{{item.name}}</span>
</view>
<view class="dec">
所属厂区:<span>{{item.factoryAreaName}}</span>
</view>
<view class="dec">
班次:<span>{{item.classesName}}</span>
</view>
<view class="dec">
故障类型:<span>{{item.faultTypeName}}</span>
</view>
</view>
<view class="bottom">
<view class="time" style="flex: 1;">
{{`${$time.formatDate(item.createTime)}`}}
</view>
</view>
</view>
</view>
<view style="height: 94rpx;padding-top: 30rpx;">
<u-loadmore :status="status" v-if="status != 'loadmore'" />
</view>
<view style="height: constant(safe-area-inset-bottom); height: env(safe-area-inset-bottom);"></view>
</view>
</template>
<script setup lang="ts">
import {
onLoad,
onShow,
onReachBottom
} from '@dcloudio/uni-app'
import {
ref,
getCurrentInstance
} from 'vue'
import * as repairOrderApi from "@/api/repairOrder.js"
import { useCountStore } from '@/store'
const { proxy } = getCurrentInstance()
// store
const store = useCountStore()
const params = ref({
pageNo: 1,
pageSize: 10,
type: '',
})
const status = ref('loadmore') //
const list = ref([])
function itemClick(item, index) {
proxy.$tab.navigateTo(`/pages/repairOrder/detail?type=${params.value.type}&data=${encodeURIComponent(JSON.stringify(item))}`)
}
function addForm(item) {
proxy.$tab.navigateTo(`/pages/repairOrder/addForm?type=${params.value.type}&data=${encodeURIComponent(JSON.stringify(item))}`)
}
async function getList() {
if (status.value == 'nomore') return;
status.value = 'loading';
proxy.$modal.loading('加载中')
await repairOrderApi.repairOrderPage(params.value).then((res) => {
proxy.$modal.closeLoading()
if (res.data.list.length > 0) {
list.value = list.value.concat(res.data.list);
params.value.pageNo++;
status.value = 'loadmore'
} else {
status.value = 'nomore'
}
}).catch(() => {
proxy.$modal.closeLoading()
})
}
onLoad((option) => {
if (option.type) params.value.type = option.type;
})
onShow(() => {
params.value.pageNo = 1
list.value = []
status.value = 'loadmore'
getList()
})
onReachBottom(() => {
getList()
})
</script>
<style lang="scss" scoped>
.container{
background: #f5f5f5;
min-height: 100vh;
}
.list {
background: #f5f5f5;
margin-top: 20rpx;
.item {
padding: 30rpx 30rpx 0px 30rpx;
margin-top: 20rpx;
background: white;
.title {
display: flex;
align-items: center;
padding-bottom: 20rpx;
.title-txt {
color: #409eff;
font-weight: bold;
font-size: 36rpx;
width: 0px;
flex: 1;
}
.time {
color: #919191;
}
}
.dec {
padding-bottom: 20rpx;
span {
color: #999999;
}
}
.last {
padding-bottom: 30rpx;
}
.bottom {
display: flex;
justify-content: space-between;
align-items: center;
border-top: 1px solid #E4E4E4;
padding: 20rpx 0px;
}
}
}
.list {
background: #f5f5f5;
margin-top: 20rpx;
.item {
padding: 30rpx 30rpx 0px 30rpx;
margin-top: 20rpx;
background: white;
.title {
display: flex;
align-items: center;
padding-bottom: 20rpx;
.title-txt {
color: #409eff;
font-weight: bold;
font-size: 36rpx;
width: 0px;
flex: 1;
}
.time {
color: #919191;
}
}
.dec {
padding-bottom: 20rpx;
span {
color: #999999;
}
}
.last {
padding-bottom: 30rpx;
}
.bottom {
display: flex;
justify-content: space-between;
align-items: center;
border-top: 1px solid #E4E4E4;
padding: 20rpx 0px;
position: relative;
.button {
position: absolute;
right: 0rpx;
}
}
}
}
</style>

229
src/pages/repairOrder/myOrder.vue

@ -0,0 +1,229 @@
<template>
<!-- 维修工单 -->
<view class="container">
<u-navbar back-icon-color='#fff' :background="{ background: '#409eff'}" back-text="" title-color='#fff'
title="维修工单">
</u-navbar>
<view class="list">
<view class="item" v-for="(item,index) in list" :key="index" >
<view class="">
<view class="title">
<view class="title-txt">
{{item.describes}}
</view>
<u-tag text="待接单" v-if="item.status == 'PENDING'" bg-color='rgba(255,255,255,0)' color='#fe8463' border-color='#fe8463' type="primary" shape='circle'/>
<u-tag text="已撤回" v-else-if="item.status=='REJECTED'" bg-color='rgba(255,255,255,0)' color='#d7d7d7' border-color='#d7d7d7 ' type="warning" shape='circle'/>
<u-tag text="已转办" v-else-if="item.status=='TRANSFERRED'" bg-color='rgba(255,255,255,0)' color='#e01f54' border-color='#e01f54' type="success" shape='circle'/>
<u-tag text="已接单" v-else-if="item.status=='PECEIVED'" bg-color='rgba(255,255,255,0)' color='#005eaa' border-color='#005eaa ' type="error" shape='circle'/>
<u-tag text="已验证" v-else-if="item.status=='VERIFIED'" bg-color='rgba(255,255,255,0)' color='#2EC7C9' border-color='#2EC7C9' type="info" shape='circle'/>
<u-tag text="已完成" v-else-if="item.status=='COMPLETED'" bg-color='rgba(255,255,255,0)' color='#2ba471' border-color='#2ba471' type="info" shape='circle'/>
</view>
<view class="dec">
报修单号:<span>{{item.number}}</span>
</view>
<view class="dec">
{{`${item.type=='DEVICE'?'设备' : '模具'}`}}编号:<span>{{item.deviceNumber}}</span>
</view>
<view class="dec">
{{`${item.type=='DEVICE'?'设备' : '模具'}`}}名称:<span>{{item.name}}</span>
</view>
<view class="dec">
所属厂区:<span>{{item.factoryAreaName}}</span>
</view>
<view class="dec">
班次:<span>{{item.classesName}}</span>
</view>
<view class="dec">
故障类型:<span>{{item.faultTypeName}}</span>
</view>
<view class="dec">
完成时间:<span>{{$time.formatDate(item.completionTime)}}</span>
</view>
</view>
<view class="bottom">
<view class="time" style="flex: 1;">
{{`${$time.formatDate(item.createTime)}`}}
</view>
<!-- <view class="status">
<u-button shape="circle" type="primary" size="mini" style="min-width: 120rpx;" @click="addForm(item)">编辑</u-button>
</view> -->
</view>
</view>
</view>
<view style="height: 94rpx;padding-top: 30rpx;">
<u-loadmore :status="status" v-if="status != 'loadmore'" />
</view>
<view style="height: constant(safe-area-inset-bottom); height: env(safe-area-inset-bottom);"></view>
</view>
</template>
<script setup lang="ts">
import {
onLoad,
onShow,
onReachBottom
} from '@dcloudio/uni-app'
import {
ref,
getCurrentInstance
} from 'vue'
import * as repairOrderApi from "@/api/repairOrder.js"
import { useCountStore } from '@/store'
const { proxy } = getCurrentInstance()
// store
const store = useCountStore()
const params = ref({
pageNo: 1,
pageSize: 10,
flag: 1
})
const status = ref('loadmore') //
const list = ref([])
async function getList() {
if (status.value == 'nomore') return;
status.value = 'loading';
proxy.$modal.loading('加载中')
await repairOrderApi.repairOrderPage(params.value).then((res) => {
proxy.$modal.closeLoading()
if (res.data.list.length > 0) {
list.value = list.value.concat(res.data.list);
params.value.pageNo++;
status.value = 'loadmore'
} else {
status.value = 'nomore'
}
}).catch(() => {
proxy.$modal.closeLoading()
})
}
onLoad((option) => {
if (option.type) params.value.type = option.type;
})
onShow(() => {
params.value.pageNo = 1
list.value = []
status.value = 'loadmore'
getList()
})
onReachBottom(() => {
getList()
})
</script>
<style lang="scss" scoped>
.container{
background: #f5f5f5;
min-height: 100vh;
}
.list {
background: #f5f5f5;
margin-top: 20rpx;
.item {
padding: 30rpx 30rpx 0px 30rpx;
margin-top: 20rpx;
background: white;
.title {
display: flex;
align-items: center;
padding-bottom: 20rpx;
.title-txt {
color: #409eff;
font-weight: bold;
font-size: 36rpx;
width: 0px;
flex: 1;
}
.time {
color: #919191;
}
}
.dec {
padding-bottom: 20rpx;
span {
color: #999999;
}
}
.last {
padding-bottom: 30rpx;
}
.bottom {
display: flex;
justify-content: space-between;
align-items: center;
border-top: 1px solid #E4E4E4;
padding: 20rpx 0px;
}
}
}
.list {
background: #f5f5f5;
margin-top: 20rpx;
.item {
padding: 30rpx 30rpx 0px 30rpx;
margin-top: 20rpx;
background: white;
.title {
display: flex;
align-items: center;
padding-bottom: 20rpx;
.title-txt {
color: #409eff;
font-weight: bold;
font-size: 36rpx;
width: 0px;
flex: 1;
}
.time {
color: #919191;
}
}
.dec {
padding-bottom: 20rpx;
span {
color: #999999;
}
}
.last {
padding-bottom: 30rpx;
}
.bottom {
display: flex;
justify-content: space-between;
align-items: center;
border-top: 1px solid #E4E4E4;
padding: 20rpx 0px;
position: relative;
.button {
position: absolute;
right: 0rpx;
}
}
}
}
</style>

565
src/pages/repairOrder/transfer.vue

@ -0,0 +1,565 @@
<template>
<!-- 添加维修工单 -->
<view class="add-form-container">
<u-form :model="form" ref="formRef" label-width="160rpx">
<u-form-item label="转办类型" prop="status" required>
<view class="select" @click="openSingleColumn('status',form.status,tansferType)">
<view class="input" v-if='form.status || form.status == 0'>
{{form.statusTxt}}
</view>
<view class="placeholder" v-else>
{{`请选择转办类型`}}
</view>
<u-icon name="arrow-right" color="#aaaaaa" size="28"></u-icon>
</view>
</u-form-item>
<u-form-item label="类型" prop="receiverType" required>
<view class="select" @click="openSingleColumn('receiverType',form.receiverType,deviceMoldType)">
<view class="input" v-if='form.receiverType'>
{{form.receiverTypeTxt}}
</view>
<view class="placeholder" v-else>
{{`请选择类型`}}
</view>
<u-icon name="arrow-right" color="#aaaaaa" size="28"></u-icon>
</view>
</u-form-item>
<u-form-item label="厂区名称" prop="factoryAreaNumber" required v-if="form.status==1">
<view class="select"
@click="openSingleColumn('factoryAreaNumber',form.factoryAreaNumber,factoryAreaList)">
<view class="input" v-if='form.factoryAreaNumber'>
{{form.factoryAreaName}}
</view>
<view class="placeholder" v-else>
{{`请选择厂区名称`}}
</view>
<u-icon name="arrow-right" color="#aaaaaa" size="28"></u-icon>
</view>
</u-form-item>
<u-form-item :label="`${type=='DEVICE'||type == 'TECH'?'设备' : '模具'}编码`" prop="deviceNumber" required
v-if="form.status==0">
<u-input v-model="form.deviceNumber" :placeholder="`请输入${type=='DEVICE'||type == 'TECH'?'设备' : '模具'}编码`"
@blur="blur()" />
<view class="right-button" @click="chickRightButton">
扫描
</view>
</u-form-item>
<u-form-item :label="`${type=='DEVICE'||type == 'TECH'?'设备' : '模具'}名称`" prop="deviceNumber" required
class="disabled" v-if="form.status==0">
<u-input v-model="form.deviceName" :placeholder="`根据${type=='DEVICE'||type == 'TECH'?'设备' : '模具'}编码获得`"
disabled />
</u-form-item>
<u-form-item label="维修人员" prop="describes" required>
<view class="select" @click="openSelecUser('receiverUserId')">
<view class="input" v-if='form.receiverUserId'>
{{selectFormatRadin(form.receiverUserId,selecUserList)}}
</view>
<view class="placeholder" v-else>
请选择维修人员
</view>
<u-icon name="arrow-right" color="#aaaaaa" size="28"></u-icon>
</view>
</u-form-item>
</u-form>
<view class="footer">
<view class="btns">
<button class="reset" @click="reset">重置</button>
<button class="sure" @click="submit" :loading='loading' :disabled='loading'>确定</button>
</view>
<view style="height: constant(safe-area-inset-bottom); height: env(safe-area-inset-bottom);"></view>
</view>
<!-- 选择维修人员 -->
<u-popup v-model="isShowSelecUser" mode="center" border-radius="14">
<view class="popup-title">选择维修人员</view>
<view class="popup">
<u-radio-group v-model="form.receiverUserId"
@change="radioGroupChange('receiverUserId',form.receiverUserId,selecUserList)">
<u-radio v-for="(item, index) in selecUserList" :key="index" :name="item.id">
{{item.name}}
</u-radio>
</u-radio-group>
</view>
<view class="popup-footer">
<view @click="isShowSelecUser = false">取消</view>
<view class="sure" @click="chooseUser">确认</view>
</view>
</u-popup>
<u-select v-model="singleColumnShow" mode="single-column" :default-value='singleColumnDefaultValue'
:list="singleColumnList" @confirm="chooseSingleColumn" @cancle='singleColumnShow = false'></u-select>
</view>
</template>
<script setup lang="ts">
import {
onLoad
} from '@dcloudio/uni-app'
import {
ref,
getCurrentInstance
} from 'vue'
import * as deviceApi from "@/api/device.js"
import * as moldApi from "@/api/mold.js"
import * as dictApi from "@/api/dict.js"
import * as repairOrderApi from "@/api/repairOrder.js"
import * as deptApi from "@/api/dept.js"
const { proxy } = getCurrentInstance()
const loading = ref(false)
const type = ref('')
const deviceMoldType = ref([])
const deviceMoldType1 = ref([])
const form = ref({
id: '',
receiverType: "",
receiverTypeTxt: '',
deviceNumber: '',
deviceName: '',
receiverUserId: '',
status: 0,
statusTxt: '设备',
factoryAreaNumber: '',
factoryAreaName: ''
})
const deviceList = ref([])
const singleColumnShow = ref(false)
const singleColumnDefaultValue = ref([])
const singleColumnList = ref([])
const field = ref('')
//
const selecUserList = ref([])//
const isShowSelecUser = ref(false)
//
const tansferType = ref([{
value: 0,
label: '设备'
}, {
value: 1,
label: '人员'
}])
const deviceNumber = ref('')//
const factoryAreaList = ref([])
const choosesingleColumnItem = ref([])
const chooseUserInfo = ref({})
//
function submit() {
//
if (!form.value.receiverType) {
proxy.$modal.showToast('请选择类型')
return;
}
if (form.value.status == 0) {
if (!form.value.deviceNumber) {
proxy.$modal.showToast(`请选择${type.value == 'DEVICE' || type.value == 'TECH' ? '设备' : '模具'}编码`)
return;
}
}
if (!form.value.factoryAreaNumber) {
proxy.$modal.showToast('请选择厂区')
return;
}
if (!form.value.receiverUserId) {
proxy.$modal.showToast('请选择维修人员')
return;
}
const paramsData = {
id: form.value && form.value.id ? form.value.id : '',
receiverType: form.value.receiverType,
deviceNumber: form.value.status == 0 ? form.value.deviceNumber : deviceNumber.value,
receiverUserId: form.value.receiverUserId,
factoryAreaNumber: form.value.factoryAreaNumber,
status: form.value.status,
}
proxy.$modal.confirm('是否转办维修工单').then(() => {
proxy.$modal.loading('加载中')
loading.value = true
repairOrderApi.transfer(paramsData).then((res) => {
proxy.$modal.closeLoading()
if (res.data) {
proxy.$modal.showToast('转办成功')
setTimeout(() => {
proxy.$tab.navigateBack(2)
loading.value = false
}, 1500)
} else {
proxy.$modal.showToast('转办失败')
loading.value = false
}
}).catch(() => {
proxy.$modal.closeLoading()
loading.value = false
})
})
}
//
function reset() {
if (form.value.id) {
form.value.receiverType = "";
form.value.deviceNumber = '';
form.value.deviceName = '';
form.value.receiverUserId = '';
} else {
form.value = {
id: '',
receiverType: "",
deviceNumber: '',
deviceName: '',
receiverUserId: '',
status: 0,
statusTxt: '',
factoryAreaNumber: ''
}
}
}
//
function chickRightButton(field) {
if (!form.value.receiverType) {
proxy.$modal.showToast('请先选择类型')
return;
}
uni.scanCode({
success: function (res) {
form.value.deviceNumber = res.result
getDetailsByNumber()
}
});
}
function blur() {
if (form.value.deviceNumber) {
getDetailsByNumber()
} else {
form.value.deviceName = ''
form.value.factoryAreaName = ''
form.value.factoryAreaNumber = ''
}
}
// /
function getDetailsByNumber() {
if (form.value.receiverType == 'DEVICE' || form.value.receiverType == 'TECH') {
deviceApi.getDeviceDetailsByNumber({
number: form.value.deviceNumber,
type: form.value.receiverType
}).then(async (res) => {
if (!res.data) {
form.value.deviceName = ''
form.value.factoryAreaName = ''
form.value.factoryAreaNumber = ''
selecUserList.value = []
return;
}
form.value.deviceName = res.data.name
form.value.factoryAreaName = res.data.factoryAreaName
form.value.factoryAreaNumber = res.data.factoryAreaNumber
await getSelecUser()
}).catch(() => {
form.value.deviceName = ''
form.value.factoryAreaName = ''
form.value.factoryAreaNumber = ''
selecUserList.value = []
})
} else if (form.value.receiverType == 'MOLD') {
moldApi.getMoldDetailsByNumber({
number: form.deviceNumber
}).then(async (res) => {
if (!res.data) {
form.value.deviceName = ''
form.value.factoryAreaName = ''
form.value.factoryAreaNumber = ''
selecUserList.value = []
return;
}
form.value.deviceName = res.data.name
form.value.factoryAreaName = res.data.factoryAreaName
form.value.factoryAreaNumber = res.data.factoryAreaNumber
await getSelecUser()
}).catch(() => {
form.value.deviceName = ''
form.value.factoryAreaName = ''
form.value.factoryAreaNumber = ''
selecUserList.value = []
})
}
}
//
function openSingleColumn(fieldName, val, list) {
singleColumnList.value = list
field.value = fieldName
if (val) {
singleColumnDefaultValue.value = [list.findIndex(item => item.value == val)]
} else {
singleColumnDefaultValue.value = []
}
singleColumnShow.value = true
}
//
function chooseSingleColumn(e) {
form.value[field.value] = e[0].value
if (field.value == 'receiverType') {
type.value = form.value[field.value]
form.value.deviceName = ''
form.value.deviceNumber = ''
form.value.receiverUserId = undefined
form.value.receiverTypeTxt = e[0].label
getDeviceList()
} else if (field.value == 'factoryAreaNumber') {
form.value.factoryAreaName = e[0].label
getSelecUser()
} else if (field.value == 'status') {
form.value.statusTxt = e[0].label
if (form.value.status == 0) {
deviceMoldType.value = deviceMoldType1.value.filter(item => item.value != type.value)
} else {
deviceMoldType.value = deviceMoldType1.value.filter(item => item.value == type.value)
}
console.log(deviceMoldType.value)
form.value.receiverType = deviceMoldType.value[0].value
form.value.receiverTypeTxt = deviceMoldType.value[0].label
}
singleColumnShow.value = false
}
// /
async function getDeviceList() {
if (type.value == 'DEVICE' || type.value == 'TECH') {
await deviceApi.deviceList().then(res => {
res.data.map(item => {
item.value = item.number
item.label = item.name
})
deviceList.value = res.data
})
} else if (type.value == 'MOLD') {
await moldApi.moldList().then(res => {
res.data.map(item => {
item.value = item.number
item.label = item.name
})
deviceList.value = res.data
})
}
}
//
async function getSelecUser() {
let data = {
classType: type.value,
factoryAreaNumber: form.value.factoryAreaNumber,
}
let arr = []
if (form.value.maintenances) {
arr = form.value.maintenances.split(',')
}
await deptApi.getSelecUser(data).then(res => {
res.data.forEach(item => {
item.checked = false
arr.forEach(cur => {
if (item.id == cur) {
item.checked = true
}
})
})
selecUserList.value = res.data
})
}
//
function openSelecUser(fieldName) {
field.value = fieldName
isShowSelecUser.value = true
}
function radioGroupChange(field, e, list) {
chooseUserInfo.value = e
}
//
function selectFormatRadin(val, array) {
let str = array.filter(item => item.id == val)[0].name
return str
}
//
function chooseUser() {
form.value[field.value] = chooseUserInfo.value
isShowSelecUser.value = false
}
//
function getFactoryAreaList() {
deptApi.getFactoryAreaList().then((res) => {
if (res.data && res.data.length > 0) {
res.data.map(item => {
item.value = item.id
item.label = item.name
})
factoryAreaList.value = res.data
} else {
factoryAreaList.value = []
}
}).catch(() => { })
}
onLoad(async (option) => {
if (option.type) type.value = option.type;
if (option.id) form.value.id = option.id;
if (option.deviceNumber) deviceNumber.value = option.deviceNumber;
deviceMoldType1.value = await dictApi.getDict('app_device_mold_type')
if (form.value.status == 0) {
deviceMoldType.value = deviceMoldType1.value.filter(item => item.value != type.value)
} else {
deviceMoldType.value = deviceMoldType1.value.filter(item => item.value == type.value)
}
form.value.receiverType = deviceMoldType.value[0].value
form.value.receiverTypeTxt = deviceMoldType.value[0].label
getFactoryAreaList()
})
</script>
<style lang="scss" scoped>
.add-form-container {
min-height: calc(100vh - 140rpx);
background: white;
padding: 0px 0rpx 140rpx;
}
.u-form-item {
padding: 20rpx 30rpx;
}
.disabled {
background: #f5f5f5;
}
.list {
padding-bottom: 20rpx;
.item {
margin-top: 20rpx;
background: white;
padding: 30rpx;
display: flex;
align-items: center;
image {
width: 160rpx;
height: 160rpx;
margin-right: 20rpx;
}
.title {
font-size: 32rpx;
font-weight: bold;
}
.dec1 {
font-size: 28rpx;
margin-top: 16rpx;
color: #acacac;
}
.dec2 {
font-size: 28rpx;
margin-top: 6rpx;
color: #acacac;
}
}
}
.footer {
position: fixed;
bottom: 0px;
left: 0px;
width: 100%;
}
.btns {
display: flex;
button {
flex: 1;
}
.sure {
background: #409eff;
color: white;
border-radius: 0px;
&::after {
border: 1px solid #409eff;
border-radius: 0px;
}
}
.reset {
background: #F5F5F5;
border-radius: 0px;
&::after {
border-radius: 0px;
}
}
}
.right-button {
background: #409eff;
color: white;
padding: 0rpx 30rpx;
border-radius: 16rpx;
text-align: center;
font-size: 28rpx;
}
.select {
display: flex;
align-items: center;
height: 72rpx;
width: 100%;
.input {
flex: 1;
font-size: 28rpx;
color: #000000;
}
.placeholder {
flex: 1;
font-size: 28rpx;
color: rgb(192, 196, 204);
}
}
.popup-title {
text-align: center;
font-size: 32rpx;
font-weight: bold;
color: #409eff;
padding: 30rpx 30rpx 0px
}
.popup {
width: 600rpx;
padding: 30rpx 60rpx 30rpx;
}
.popup-footer {
display: flex;
border-top: 1px solid #e4e4e4;
view {
line-height: 100rpx;
flex: 1;
text-align: center;
&.sure {
color: #409eff;
}
}
}
::v-deep .u-radio-group {
display: grid !important;
}
</style>

225
src/pages/spareParts/index.vue

@ -0,0 +1,225 @@
<template>
<!-- 设备 -->
<view class="work-container">
<view class="cartNull" v-show="!token">
还没有登录<navigator open-type="navigate" url="/pages/login">先登录</navigator>
</view>
<view class="" v-show='token'>
<Search :searchData='searchData' @search='search' @screen='screen' :isShowScreen='false' />
<view class="list">
<view class="item" v-for="(item,index) in list" :key='index'>
<u-image :src="item.images" width='160' height="160">
<template v-slot:error>
<view class="image-error">
<u-icon name="photo" color="#c7c7c7" size="38"></u-icon>
<view style="font-size: 24rpx;">暂无图片</view>
</view>
</template>
</u-image>
<view class="text">
<view class="title">
{{item.name}}
</view>
<view class="dec1">
备件编码{{item.number}}
</view>
<view class="dec2">
总库存{{item.qty}}
</view>
</view>
</view>
</view>
<view style="height: 94rpx;padding-top: 30rpx;">
<u-loadmore :status="status" v-if="status != 'loadmore'" />
</view>
</view>
<view style="height: constant(safe-area-inset-bottom); height: env(safe-area-inset-bottom);"></view>
</view>
</template>
<script setup lang="ts">
import {
onShow,
onReachBottom
} from '@dcloudio/uni-app'
import {
ref,
getCurrentInstance
} from 'vue'
import {
getAccessToken
} from '@/utils/auth'
import * as sparePartsApi from "@/api/spareParts.js"
import Search from '../../components/search/index.vue'
const { proxy } = getCurrentInstance()
const params = ref({
pageNo: 1,
pageSize: 10,
type: '',
name: ''
})
const status = ref('loadmore') //
const list = ref([])
const token = ref('')
const searchData = ref({
placeholder:'请输入模具名称'
})
//
function search(keyWord) {
params.value.name = keyWord
params.value.pageNo = 1
list.value = []
status.value = 'loadmore'
getList()
}
function screen() {
proxy.$tab.navigateTo(`/pages/device/screen`)
}
function getList() {
if (status.value == 'nomore') return;
status.value = 'loading';
proxy.$modal.loading('加载中')
sparePartsApi.getSparePartsPage(params.value).then((res) => {
proxy.$modal.closeLoading()
console.log(res)
if (res.data.list.length > 0) {
list.value = list.value.concat(res.data.list);
params.value.pageNo++;
status.value = 'loadmore'
} else {
status.value = 'nomore'
}
}).catch(() => { })
}
onShow(() => {
if (getAccessToken()) {
token.value = getAccessToken()
params.value.pageNo = 1
list.value = []
status.value = 'loadmore'
getList()
}
})
onReachBottom(() => {
getList()
})
// export default {
// components: {
// Search
// },
// data() {
// return {
// searchData: {
// placeholder: ''
// },
// params: {
// pageNo: 1,
// pageSize: 10,
// type: '',
// name: ''
// },
// status: 'loadmore', //
// list: [],
// token: ''
// }
// },
// methods: {
// //
// //
// search(keyWord) {
// this.params.name = keyWord
// this.params.pageNo = 1
// this.list = []
// this.status = 'loadmore'
// this.getList()
// },
// //
// screen() {
// this.$tab.navigateTo(`/pages/spareParts/screen`)
// },
// //
// getList() {
// if (this.status == 'nomore') return;
// this.status = 'loading';
// this.$modal.loading('')
// sparePartsApi.getSparePartsPage(this.params).then((res) => {
// this.$modal.closeLoading()
// if (res.data.list.length > 0) {
// this.list = this.list.concat(res.data.list);
// this.params.pageNo++;
// this.status = 'loadmore'
// } else {
// this.status = 'nomore'
// }
// }).catch(()=>{})
// },
// },
// onShow() {
// if (getAccessToken()) {
// this.token = getAccessToken()
// this.params.pageNo = 1
// this.list = []
// this.status = 'loadmore'
// this.getList()
// }
// },
// onReachBottom() {
// this.getList()
// }
// }
</script>
<style lang="scss" scoped>
.work-container{
min-height: 100vh;
background: #f5f5f5;
}
.list {
padding-bottom: 20rpx;
.item {
margin-top: 20rpx;
background: white;
padding: 30rpx;
display: flex;
align-items: center;
.text {
margin-left: 20rpx;
.title {
font-size: 32rpx;
font-weight: bold;
}
.dec1 {
font-size: 28rpx;
margin-top: 16rpx;
color: #acacac;
}
.dec2 {
font-size: 28rpx;
margin-top: 6rpx;
color: #acacac;
}
}
}
}
.image-error {
text-align: center;
}
.cartNull {
text-align: center;
padding: 500rpx 40rpx 0;
font-size: 28rpx;
color: #888;
}
.cartNull navigator {
color: #2979ff;
}
</style>

497
src/pages/sparePartsApplication/addForm.vue

@ -0,0 +1,497 @@
<template>
<!-- 添加维修工单 -->
<view class="add-form-container">
<u-form :model="form" ref="formRef" label-width="160rpx">
<u-form-item label="申请主题" prop="name" required>
<u-input v-model="form.name" placeholder="请输入申请主题" />
</u-form-item>
</u-form>
<view class="list">
<view class="title">
<span>*</span>申请备件
</view>
<view class="item " v-for="(item,index) in form.subList" :key="index">
<view class="item-box">
<view class="spare-title">
<view class="title-txt">
{{item.name}}
</view>
</view>
<u-row gutter="16">
<u-col :span="24">
<view class="dec" v-if="item.type">
类型:{{`${item.type=='DEVICE'?'设备' :item.type=='MOLD'?'模具' : ''}`}}
</view>
</u-col>
<u-col :span="24">
<view class="dec" v-if="item.deviceName">
{{`${item.type=='DEVICE'?'设备' : '模具'}`}}:{{item.deviceName}}
</view>
</u-col>
<u-col :span="24">
<view class="dec">
是否以旧换新:{{item.isRadeIn=='TRUE'?'是' :'否'}}
</view>
</u-col>
<u-col :span="24">
<view class="dec">
库存:{{item.currentQty}}
</view>
</u-col>
<u-col :span="24">
<view class="dec">
数量:{{item.qty}}
</view>
</u-col>
</u-row>
</view>
<u-icon name="minus-circle" color="#aaaaaa" size="60" @click="delSpareParts(index)"></u-icon>
</view>
<view class="add-btn">
<u-button type="primary" @click="open"><u-icon name="plus-circle" color="#ffffff"
size="36"></u-icon>添加备件</u-button>
</view>
</view>
<view class="footer">
<view class="btns">
<button class="reset" @click="reset">重置</button>
<button class="sure" @click="submit" :loading='loading' :disabled='loading'>确定</button>
</view>
<view style="height: constant(safe-area-inset-bottom); height: env(safe-area-inset-bottom);"></view>
</view>
<!-- 添加备件 -->
<u-popup v-model="isPopupShow" mode="center" border-radius="14">
<view class="popup-title">添加备件</view>
<view class="popup">
<u-form :model="form1" ref="form1Ref" label-width="200rpx">
<u-form-item :label="`备件`" prop="number" required>
<view class="select" @click="openSingleColumn('itemNumber',form1.itemNumber,sparePartsList)">
<view class="input" v-if='form1.itemNumber'>
{{form1.name}}
</view>
<view class="placeholder" v-else>
请选择备件
</view>
<u-icon name="arrow-right" color="#aaaaaa" size="28"></u-icon>
</view>
</u-form-item>
<u-form-item label="类型" prop="type">
<view class="select" @click="openSingleColumn('type',form1.type,deviceMoldType)">
<view class="input" v-if='form1.type'>
{{form1.typeName}}
</view>
<view class="placeholder" v-else>
{{`请选择类型`}}
</view>
<u-icon name="arrow-right" color="#aaaaaa" size="28"></u-icon>
</view>
</u-form-item>
<u-form-item :label="`${form1.type=='DEVICE'?'设备' : '模具'}`" prop="deviceNumber">
<view class="select" @click="openSingleColumn('deviceNumber',form1.deviceNumber,deviceList)">
<view class="input" v-if='form1.deviceNumber'>
{{form1.deviceName}}
</view>
<view class="placeholder" v-else>
{{`请选择${form1.type=='DEVICE'?'设备' : '模具'}`}}
</view>
<u-icon name="arrow-right" color="#aaaaaa" size="28"></u-icon>
</view>
</u-form-item>
<u-form-item label="是否以旧换新" prop="isRadeIn" required class="disabled">
<u-radio-group v-model="form1.isRadeIn" :key="updataKey" disabled>
<u-radio :name="'TRUE'"></u-radio>
<u-radio :name="'FALSE'"></u-radio>
</u-radio-group>
</u-form-item>
<u-form-item label="库存" prop="currentQty" required class="disabled">
<u-input v-model="form1.currentQty" type="number" disabled placeholder="请输入库存" />
</u-form-item>
<u-form-item label="数量" prop="qty" required>
<u-input v-model="form1.qty" type="number" placeholder="请输入数量" />
</u-form-item>
</u-form>
</view>
<view class="popup-footer">
<view @click="isPopupShow = false">取消</view>
<view class="sure" @click="addSpare">确认</view>
</view>
</u-popup>
<u-select v-model="singleColumnShow" mode="single-column" :default-value='singleColumnDefaultValue'
:list="singleColumnList" @confirm="chooseSingleColumn" @cancle='singleColumnShow = false'></u-select>
</view>
</template>
<script setup lang="ts">
import {
onLoad,
} from '@dcloudio/uni-app'
import {
ref,
getCurrentInstance
} from 'vue'
import * as sparePartsApplicationApi from "@/api/sparePartsApplication.js"
import * as sparePartsApi from "@/api/spareParts.js"
import * as deviceApi from "@/api/device.js"
import * as dictApi from "@/api/dict.js"
import * as moldApi from "@/api/mold.js"
const { proxy } = getCurrentInstance()
const loading = ref(false)
const type = ref('')
//
const isPopupShow = ref(false)
const sparePartsList = ref([])
const singleColumnShow = ref(false)
const singleColumnDefaultValue = ref([])
const singleColumnList = ref([])
const field = ref('')
const deviceList = ref([])//
const choosesingleColumnItem = ref([])
const form = ref({
name: '',
subList: []
})
const form1 = ref({
itemNumber: undefined,
type: '',
deviceNumber: undefined,
isRadeIn: '',
currentQty: '',
qty: ''
})
const deviceMoldType = ref([])//
const updataKey = ref(0)
//
function submit() {
//
if (!form.value.name) {
proxy.$modal.showToast('请输入主题')
return;
}
if (form.value.subList.length === 0) {
proxy.$modal.showToast('请选择备件')
return;
}
proxy.$modal.confirm('是否添加备件申请').then(() => {
proxy.$modal.loading('加载中')
loading.value = true
sparePartsApplicationApi.sparePartsApplicationCreate(form.value).then((res) => {
proxy.$modal.closeLoading()
if (res.data) {
proxy.$modal.showToast('添加成功')
setTimeout(() => {
proxy.$tab.navigateBack()
loading.value = false
}, 1500)
} else {
proxy.$modal.showToast('添加失败')
loading.value = false
}
}).catch(() => {
proxy.$modal.closeLoading()
loading.value = false
})
})
}
//
function reset() {
form.value = {
name: '',
subList: []
}
}
//
function openSingleColumn(fieldName, val, list) {
singleColumnList.value = list
field.value = fieldName
if (val) {
singleColumnDefaultValue.value = [list.findIndex(item => item.value == val)]
} else {
singleColumnDefaultValue.value = []
}
singleColumnShow.value = true
}
//
function chooseSingleColumn(e) {
form1.value[field.value] = e[0].value
if (field.value == 'itemNumber') {
form1.value.name = e[0].label
choosesingleColumnItem.value = singleColumnList.value.filter(item => item.number == e[0].value)
form1.value.isRadeIn = choosesingleColumnItem.value[0].isRadeIn
form1.value.currentQty = choosesingleColumnItem.value[0].qty
updataKey.value++
}
if (field.value == 'type') {
form1.value.typeName = e[0].label
form1.value.deviceNumber = ''
form1.value.deviceName = ''
}
if (field.value == 'deviceNumber') {
form1.value.deviceName = e[0].label
}
getApplyDeviceList()
singleColumnShow.value = false
}
//
async function getApplySparePartsList() {
await sparePartsApi.getApplySparePartsList().then(res => {
res.data.map(item => {
item.value = item.number
item.label = item.name
})
sparePartsList.value = res.data
}).catch(() => { })
}
//
async function getApplyDeviceList() {
if (form1.value.type == 'DEVICE') {
await deviceApi.getApplyDeviceList().then(res => {
res.data.map(item => {
item.value = item.number
item.label = item.name
})
deviceList.value = res.data
}).catch(() => { })
} else if (form1.value.type == 'MOLD') {
moldApi.getApplyMoldList().then((res) => {
res.data.map(item => {
item.value = item.number
item.label = item.name
})
deviceList.value = res.data
}).catch(() => { })
}
}
//
function open() {
form1.value = {
itemNumber: undefined,
type: '',
deviceNumber: undefined,
isRadeIn: '',
currentQty: "",
qty: '',
}
isPopupShow.value = true
}
//
function addSpare() {
if (!form1.value.itemNumber) {
proxy.$modal.showToast('请选择备件')
return;
}
// if (!this.form1.deviceNumber) {
// this.$modal.showToast('')
// return;
// }
if (!form1.value.qty || form1.value.qty == 0) {
proxy.$modal.showToast('请输入数量')
return;
}
if (form1.value.qty > form1.value.currentQty) {
proxy.$modal.showToast('数量不可以大于库存')
return;
}
// if (form1.value.itemNumber) {
// form1.value.name = this.selectFormat(this.form1.itemNumber, this.sparePartsList)
// }
// if (this.form1.deviceNumber) {
// this.form1.deviceName = this.selectFormat(this.form1.deviceNumber, this.deviceList)
// }
if (form.valuesubList && form.value.subList.length > 0) {
let arr = form.value.subList.filter(item => item.itemNumber == form1.value.itemNumber)
if (arr && arr.length > 0) {
proxy.$modal.showToast('该备件已添加')
return;
}
}
form.value.subList.push(form1.value)
isPopupShow.value = false
}
//
function delSpareParts(index) {
form.value.subList.splice(index, 1)
}
onLoad(async (option) => {
if (option.type)type.value = option.type;
if (option.number) form.value.maintenanceNumber = option.number;
if (option.data && JSON.parse(decodeURIComponent(option.data)) && JSON.parse(decodeURIComponent(option
.data)).id) {
form.value = JSON.parse(decodeURIComponent(option.data))
form.value.subList = form.value.subList
};
deviceMoldType.value = await dictApi.getDict('device_mold_type')
await getApplySparePartsList()
})
</script>
<style lang="scss" scoped>
.add-form-container {
min-height: calc(100vh - 140rpx);
background: white;
padding: 0px 0rpx 140rpx;
}
.u-form-item {
padding: 20rpx 30rpx;
}
.disabled {
background: #f5f5f5;
}
.footer {
position: fixed;
bottom: 0px;
left: 0px;
width: 100%;
z-index: 22;
}
.btns {
display: flex;
button {
flex: 1;
}
.sure {
background: #409eff;
color: white;
border-radius: 0px;
&::after {
border: 1px solid #409eff;
border-radius: 0px;
}
}
.reset {
background: #F5F5F5;
border-radius: 0px;
&::after {
border-radius: 0px;
}
}
}
.right-button {
background: #409eff;
color: white;
padding: 0rpx 30rpx;
border-radius: 16rpx;
text-align: center;
font-size: 28rpx;
}
.select {
display: flex;
align-items: center;
height: 72rpx;
width: 100%;
.input {
flex: 1;
font-size: 28rpx;
color: #000000;
}
.placeholder {
flex: 1;
font-size: 28rpx;
color: rgb(192, 196, 204);
}
}
.title {
padding: 32rpx 0rpx;
position: relative;
span {
position: absolute;
left: -16rpx;
color: #fa3534;
top: 19px;
}
}
.list {
padding: 0rpx 30rpx;
.item {
display: flex;
margin-bottom: 20rpx;
.item-box {
background: #F5F5F5;
border-radius: 12rpx;
flex: 1;
width: 0rpx;
}
.spare-title {
padding: 20rpx 30rpx;
border-bottom: 1px solid #e4e4e4;
.title-txt {
color: #409eff;
font-size: 30rpx;
font-weight: bold;
}
}
.dec {
color: #9c9c9c;
padding: 20rpx 30rpx 20rpx;
}
}
}
.add-btn {
display: flex;
justify-content: flex-start;
align-items: center;
}
.popup-title {
text-align: center;
font-size: 32rpx;
font-weight: bold;
color: #409eff;
padding: 30rpx 30rpx 0px
}
.popup {
width: 600rpx;
padding: 30rpx 0rpx 30rpx;
}
.popup-footer {
display: flex;
border-top: 1px solid #e4e4e4;
view {
line-height: 100rpx;
flex: 1;
text-align: center;
&.sure {
color: #409eff;
}
}
}
::v-deep .u-checkbox-group {
display: grid !important;
}
</style>

307
src/pages/sparePartsApplication/detail.vue

@ -0,0 +1,307 @@
<template>
<!-- 详情 -->
<view class="detail-container">
<view class="info">
<view class="title">
<view>备件申领工单</view>
</view>
<view class="dec">
<view class="dec-item">
<view>申请主题</view>
<view>{{data.name}}</view>
</view>
<view class="dec-item">
<view>申请单号</view>
<view>{{data.number}}</view>
</view>
<view class="dec-item">
<view>申请备件</view>
</view>
<view class="items" v-for="(cur,key) in data.subList" :key="key" style="margin-bottom: 20rpx;">
<view class="items-name">
备件名称{{cur.itemName}}
</view>
<view class="items-dec" v-if="cur.type">
类型{{cur.type == 'type'?'设备' :'模具'}}
</view>
<view class="items-dec" v-if="cur.name">
{{cur.type == 'type'?'设备' :'模具'}}名称{{cur.name}}
</view>
<view class="items-dec">
是否以旧换新{{cur.isRadeIn == 'TRUE'?'是' :'否'}}
</view>
<view class="items-dec">
数量{{cur.qty}}
</view>
</view>
</view>
</view>
<view class="footer" v-if="from == 3">
<view class="btns">
<button class="reset" @click="reject">驳回</button>
<button class="sure" @click="agree" :loading='loading' :disabled='loading'>通过</button>
</view>
<view style="height: constant(safe-area-inset-bottom); height: env(safe-area-inset-bottom);"></view>
</view>
<view style="height: constant(safe-area-inset-bottom); height: env(safe-area-inset-bottom);"></view>
</view>
</template>
<script setup lang="ts">
import {
onLoad,
onShow
} from '@dcloudio/uni-app'
import {
ref,
getCurrentInstance
} from 'vue'
import * as sparePartsApplicationApi from "@/api/sparePartsApplication.js"
import * as sparePartsApplicationApproveApi from "@/api/sparePartsApplicationApprove.js"
const { proxy } = getCurrentInstance()
const number = ref('')
const data = ref({})
const loading = ref(false)
const from = ref()//13
const type = ref()
function getSparePartsApplicationDetail() {
sparePartsApplicationApi.sparePartsApplicationDetail(number.value).then((res) => {
data.value = res.data
}).catch(() => { })
}
//
function agree() {
proxy.$modal.confirm('确定通过申请吗').then(() => {
proxy.$modal.loading('加载中')
loading.value = true
sparePartsApplicationApproveApi.sparePartsApplicationAgree(data.value.id).then((res) => {
proxy.$modal.closeLoading()
if (res.data) {
proxy.$modal.showToast('审核成功')
setTimeout(() => {
proxy.$tab.navigateBack()
loading.value = false
}, 1500)
} else {
proxy.$modal.showToast('审核失败')
loading.value = false
}
}).catch(() => {
proxy.$modal.closeLoading()
loading.value = false
})
})
}
//
function reject(item) {
proxy.$modal.confirm('确定驳回申请吗?').then(() => {
proxy.$modal.loading('加载中')
loading.value = true
sparePartsApplicationApproveApi.sparePartsApplicationReject(item.id).then(async (res) => {
if (res.data) {
proxy.$modal.showToast('已驳回')
setTimeout(() => {
proxy.$tab.navigateBack()
loading.value = false
}, 1500)
} else {
proxy.$modal.showToast('审核失败')
loading.value = false
}
}).catch(() => {
proxy.$modal.closeLoading()
loading.value = false
})
})
}
onLoad((option) => {
if (option.type) type.value = option.type;
if (option.from) from.value = option.from;
if (option.number) {
number.value = option.number
}
})
onShow(() => {
getSparePartsApplicationDetail()
})
</script>
<style lang="scss" scoped>
.detail-container {
min-height: 100vh;
background: white;
}
.line {
background: #f5f5f5;
height: 20rpx;
}
.info {
background: white;
}
.tab {
border-bottom: 1px solid #e4e4e4;
}
.title {
display: flex;
align-items: center;
padding: 20rpx 30rpx;
border-bottom: 1px solid #e4e4e4;
view {
&:nth-child(1) {
flex: 1;
border-left: 10rpx solid #409eff;
padding-left: 20rpx;
font-weight: bold;
}
}
}
.dec {
padding: 30rpx;
.dec-item {
padding-bottom: 30rpx;
display: flex;
view {
&:nth-child(1) {
width: 160rpx;
}
&:nth-child(2) {
color: #888888;
flex: 1;
width: 0px;
word-wrap: break-word;
}
}
}
}
.dec2 {
padding: 10rpx 30rpx;
display: flex;
view {
&:nth-child(1) {
width: 180rpx;
}
&:nth-child(2) {
color: #888888;
flex: 1;
width: 0px;
word-wrap: break-word;
}
}
}
.items {
border-radius: 12rpx;
background: #F5F5F5;
padding-bottom: 20rpx;
.items-name {
padding: 20rpx;
border-bottom: 1px solid #dedede;
}
.items-dec {
padding: 0px 20rpx;
margin-top: 20rpx;
}
}
.list {
padding: 20rpx;
.item {
display: flex;
margin-bottom: 20rpx;
.item-box {
border-radius: 12rpx;
border: 1px solid #dedede;
border-radius: 12rpx;
flex: 1;
width: 0rpx;
}
.spare-title {
padding: 20rpx 30rpx;
border-bottom: 1px solid #e4e4e4;
display: flex;
.title-txt {
color: #409eff;
font-size: 30rpx;
font-weight: bold;
flex: 1;
}
}
.dec {
color: #9c9c9c;
padding: 0rpx 30rpx 20rpx;
}
}
}
.add-btn {
display: flex;
justify-content: flex-start;
align-items: center;
}
.footer {
position: fixed;
bottom: 0px;
left: 0px;
width: 100%;
z-index: 22;
}
.btns {
display: flex;
button {
flex: 1;
}
.sure {
background: #409eff;
color: white;
border-radius: 0px;
&::after {
border: 1px solid #409eff;
border-radius: 0px;
}
}
.reset {
background: #F5F5F5;
border-radius: 0px;
&::after {
border-radius: 0px;
}
}
}
</style>

182
src/pages/sparePartsApplication/index.vue

@ -0,0 +1,182 @@
<template>
<!-- 备件领用申请 -->
<view class="container">
<u-navbar back-icon-color='#fff' :background="{ background: '#409eff'}" back-text="" title-color='#fff'
title="备件领用申请">
<template v-slot:right>
<u-icon name="plus" color="#fff" size="36" style="padding-right: 30rpx;" @click="addForm"></u-icon>
</template>
</u-navbar>
<!-- <Search @search='search' @screen='screen' /> -->
<view class="list">
<view class="item" v-for="(item,index) in list" :key="index" @click="openDetail(item)">
<view class="title">
<view class="title-txt">
{{item.name}}
</view>
<view class="time">
{{`${$time.formatDate(item.createTime)}`}}
</view>
</view>
<view class="dec">
申请单号:<span>{{item.number}}</span>
</view>
<view class="dec">
:<span>{{item.applyName}}</span>
</view>
<view class="bottom">
<view class="status">
<u-tag text="待审批" v-if="item.status==0" bg-color='rgba(255,255,255,0)' color='#fe8463'
border-color='#fe8463' type="primary" shape='circle' />
<u-tag text="审批通过" v-else-if="item.status==1" bg-color='rgba(255,255,255,0)' color='#2EC7C9'
border-color='#2EC7C9' type="info" shape='circle' />
<u-tag text="审批驳回" v-else-if="item.status==2" bg-color='rgba(255,255,255,0)' color='#e01f54'
border-color='#e01f54' type="success" shape='circle' />
<u-tag text="出库中" v-else-if="item.status==3" bg-color='rgba(255,255,255,0)' color='#005eaa'
border-color='#005eaa ' type="error" shape='circle' />
<u-tag text="完成" v-else-if="item.status==4" bg-color='rgba(255,255,255,0)' color='#2ba471'
border-color='#2ba471' type="info" shape='circle' />
<u-tag text="撤单" v-else-if="item.status==5" bg-color='rgba(255,255,255,0)' color='#d7d7d7'
border-color='#d7d7d7 ' type="warning" shape='circle' />
</view>
<view class="button">
<u-button shape="circle" type="primary" size="mini" style="min-width: 120rpx;"
v-if="item.status==0" @click="cancle(item)">撤回</u-button>
</view>
</view>
</view>
</view>
<view style="height: constant(safe-area-inset-bottom); height: env(safe-area-inset-bottom);"></view>
</view>
</template>
<script setup lang="ts">
import {
onLoad,
onShow,
onReachBottom
} from '@dcloudio/uni-app'
import {
ref,
getCurrentInstance
} from 'vue'
import * as sparePartsApplicationApi from "@/api/sparePartsApplication.js"
const { proxy } = getCurrentInstance()
const params = ref({
pageNo: 1,
pageSize: 10,
type: '',
})
const status = ref('loadmore') //
const list = ref([])
function openDetail(item, index) {
proxy.$tab.navigateTo(`/pages/sparePartsApplication/detail?number=${item.number}`)
}
function addForm(item) {
proxy.$tab.navigateTo(`/pages/sparePartsApplication/addForm`)
}
async function getList() {
if (status.value == 'nomore') return;
status.value = 'loading';
proxy.$modal.loading('加载中')
await sparePartsApplicationApi.sparePartsApplicationPage(params.value).then((res) => {
proxy.$modal.closeLoading()
if (res.data.list.length > 0) {
list.value = list.value.concat(res.data.list);
params.value.pageNo++;
status.value = 'loadmore'
} else {
status.value = 'nomore'
}
}).catch(() => {
proxy.$modal.closeLoading()
})
}
//
function cancle(item) {
proxy.$modal.confirm('确定撤回申请吗?').then(() => {
proxy.$modal.loading('加载中')
sparePartsApplicationApi.sparePartsApplicationCancle(item.id).then(async (res) => {
proxy.$modal.closeLoading()
params.value.pageNo = 1
list.value = []
status.value = 'loadmore'
await getList()
proxy.$modal.showToast('撤回成功')
}).catch(()=>{})
})
}
onLoad((option) => {
if (option.type) params.value.type = option.type;
})
onShow(() => {
params.value.pageNo = 1
list.value = []
status.value = 'loadmore'
getList()
})
onReachBottom(() => {
getList()
})
</script>
<style lang="scss" scoped>
.container{
background: #f5f5f5;
min-height: 100vh;
}
.list {
background: #f5f5f5;
margin-top: 20rpx;
.item {
padding: 30rpx 30rpx 0px 30rpx;
margin-top: 20rpx;
background: white;
position: relative;
.title {
display: flex;
align-items: center;
padding-bottom: 20rpx;
.title-txt {
color: #409eff;
font-weight: bold;
font-size: 36rpx;
width: 0px;
flex: 1;
}
.time {
color: #919191;
}
}
.dec {
padding-bottom: 20rpx;
span {
color: #999999;
}
}
.last {
padding-bottom: 30rpx;
}
.bottom {
display: flex;
justify-content: space-between;
align-items: center;
border-top: 1px solid #E4E4E4;
padding: 20rpx 0px;
height: 90rpx;
}
}
}
</style>

169
src/pages/sparePartsApplication/mySparePartsApplication.vue

@ -0,0 +1,169 @@
<template>
<!-- 备件领用申请 -->
<view class="container">
<view class="list">
<view class="item" v-for="(item,index) in list" :key="index" @click="openDetail(item)">
<view class="title">
<view class="title-txt">
{{item.name}}
</view>
<view class="time">
{{`${$time.formatDate(item.createTime)}`}}
</view>
</view>
<view class="dec">
申请单号:<span>{{item.number}}</span>
</view>
<view class="dec">
:<span>{{item.applyName}}</span>
</view>
<view class="dec" v-if="item.status!=0">
审批时间:<span>{{`${$time.formatDate(item.approveTime)}`}}</span>
</view>
<view class="dec" v-if="item.status!=0">
:<span>{{item.approveName}}</span>
</view>
<view class="bottom">
<view class="status">
<u-tag text="待审批" v-if="item.status==0" bg-color='rgba(255,255,255,0)' color='#fe8463'
border-color='#fe8463' type="primary" shape='circle' />
<u-tag text="审批通过" v-else-if="item.status==1" bg-color='rgba(255,255,255,0)' color='#2EC7C9'
border-color='#2EC7C9' type="info" shape='circle' />
<u-tag text="审批驳回" v-else-if="item.status==2" bg-color='rgba(255,255,255,0)' color='#e01f54'
border-color='#e01f54' type="success" shape='circle' />
<u-tag text="出库中" v-else-if="item.status==3" bg-color='rgba(255,255,255,0)' color='#005eaa'
border-color='#005eaa ' type="error" shape='circle' />
<u-tag text="完成" v-else-if="item.status==4" bg-color='rgba(255,255,255,0)' color='#2ba471'
border-color='#2ba471' type="info" shape='circle' />
<u-tag text="撤单" v-else-if="item.status==5" bg-color='rgba(255,255,255,0)' color='#d7d7d7'
border-color='#d7d7d7 ' type="warning" shape='circle' />
</view>
</view>
</view>
<view style="height: 94rpx;padding-top: 30rpx;">
<u-loadmore :status="status" v-if="status != 'loadmore'" />
</view>
</view>
<view style="height: constant(safe-area-inset-bottom); height: env(safe-area-inset-bottom);"></view>
</view>
</template>
<script setup lang="ts">
import {
onLoad,
onShow,
onReachBottom
} from '@dcloudio/uni-app'
import {
ref,
getCurrentInstance
} from 'vue'
import * as sparePartsApplicationApi from "@/api/sparePartsApplication.js"
const { proxy } = getCurrentInstance()
const params = ref({
pageNo: 1,
pageSize: 10,
flag:null
})
const status = ref('loadmore') //
const list = ref([])
function openDetail(item, index) {
proxy.$tab.navigateTo(`/pages/sparePartsApplication/detail?number=${item.number}`)
}
async function getList() {
if (status.value == 'nomore') return;
status.value = 'loading';
proxy.$modal.loading('加载中')
await sparePartsApplicationApi.sparePartsApplicationPage(params.value).then((res) => {
proxy.$modal.closeLoading()
if (res.data.list.length > 0) {
list.value = list.value.concat(res.data.list);
params.value.pageNo++;
status.value = 'loadmore'
} else {
status.value = 'nomore'
}
}).catch(() => {
proxy.$modal.closeLoading()
})
}
onLoad((option) => {
if (option.flag) params.value.flag = option.flag;
if(params.value.flag == 2){
uni.setNavigationBarTitle({
title:'领用申请审批'
})
}
})
onShow(() => {
params.value.pageNo = 1
list.value = []
status.value = 'loadmore'
getList()
})
onReachBottom(() => {
getList()
})
</script>
<style lang="scss" scoped>
.container{
background: #f5f5f5;
min-height: 100vh;
}
.list {
background: #f5f5f5;
margin-top: 20rpx;
.item {
padding: 30rpx 30rpx 0px 30rpx;
margin-top: 20rpx;
background: white;
position: relative;
.title {
display: flex;
align-items: center;
padding-bottom: 20rpx;
.title-txt {
color: #409eff;
font-weight: bold;
font-size: 36rpx;
width: 0px;
flex: 1;
}
.time {
color: #919191;
}
}
.dec {
padding-bottom: 20rpx;
span {
color: #999999;
}
}
.last {
padding-bottom: 30rpx;
}
.bottom {
display: flex;
justify-content: space-between;
align-items: center;
border-top: 1px solid #E4E4E4;
padding: 20rpx 0px;
height: 90rpx;
}
}
}
</style>

198
src/pages/sparePartsApplicationApprove/index.vue

@ -0,0 +1,198 @@
<template>
<!-- 备件领用申请审批 -->
<view class="container">
<u-navbar back-icon-color='#fff' :background="{ background: '#409eff'}" back-text="" title-color='#fff'
title="领用申请审批">
</u-navbar>
<!-- <Search @search='search' @screen='screen' /> -->
<view class="list">
<view class="item" v-for="(item,index) in list" :key="index" @click="openDetail(item)">
<view class="title">
<view class="title-txt">
{{item.name}}
</view>
<view class="time">
{{`${$time.formatDate(item.createTime)}`}}
</view>
</view>
<view class="dec">
申请单号:<span>{{item.number}}</span>
</view>
<view class="dec">
:<span>{{item.applyName}}</span>
</view>
<view class="bottom">
<view class="status">
<u-tag text="待审批" v-if="item.status==0" bg-color='rgba(255,255,255,0)' color='#fe8463'
border-color='#fe8463' type="primary" shape='circle' />
<u-tag text="审批通过" v-else-if="item.status==1" bg-color='rgba(255,255,255,0)' color='#2EC7C9'
border-color='#2EC7C9' type="info" shape='circle' />
<u-tag text="审批驳回" v-else-if="item.status==2" bg-color='rgba(255,255,255,0)' color='#e01f54'
border-color='#e01f54' type="success" shape='circle' />
<u-tag text="出库中" v-else-if="item.status==3" bg-color='rgba(255,255,255,0)' color='#005eaa'
border-color='#005eaa ' type="error" shape='circle' />
<u-tag text="完成" v-else-if="item.status==4" bg-color='rgba(255,255,255,0)' color='#2ba471'
border-color='#2ba471' type="info" shape='circle' />
<u-tag text="撤单" v-else-if="item.status==5" bg-color='rgba(255,255,255,0)' color='#d7d7d7'
border-color='#d7d7d7 ' type="warning" shape='circle' />
</view>
<view class="button">
<u-button shape="circle" size="mini" style="min-width: 120rpx;"
v-if="item.status==0" @click="reject(item)">驳回</u-button>
<u-button shape="circle" type="primary" size="mini" style="min-width: 120rpx;margin-left: 20rpx;"
v-if="item.status==0" @click="agree(item)">通过</u-button>
</view>
</view>
</view>
</view>
<view style="height: constant(safe-area-inset-bottom); height: env(safe-area-inset-bottom);"></view>
</view>
</template>
<script setup lang="ts">
import {
onLoad,
onShow,
onReachBottom
} from '@dcloudio/uni-app'
import {
ref,
getCurrentInstance
} from 'vue'
import * as sparePartsApplicationApproveApi from "@/api/sparePartsApplicationApprove.js"
const { proxy } = getCurrentInstance()
const params = ref({
pageNo: 1,
pageSize: 10,
type: '',
})
const status = ref('loadmore') //
const list = ref([])
const from = ref('')
function openDetail(item, index) {
console.log(from.value)
proxy.$tab.navigateTo(`/pages/sparePartsApplication/detail?number=${item.number}&from=${from.value}`)
}
function addForm(item) {
proxy.$tab.navigateTo(`/pages/sparePartsApplication/addForm`)
}
async function getList() {
if (status.value == 'nomore') return;
status.value = 'loading';
proxy.$modal.loading('加载中')
await sparePartsApplicationApproveApi.sparePartsApplicationApprovePage(params.value).then((res) => {
proxy.$modal.closeLoading()
if (res.data.list.length > 0) {
list.value = list.value.concat(res.data.list);
params.value.pageNo++;
status.value = 'loadmore'
} else {
status.value = 'nomore'
}
}).catch(() => {
proxy.$modal.closeLoading()
})
}
//
function agree(item) {
proxy.$modal.confirm('确定通过申请吗?').then(() => {
proxy.$modal.loading('加载中')
sparePartsApplicationApproveApi.sparePartsApplicationAgree(item.id).then(async (res) => {
proxy.$modal.closeLoading()
params.value.pageNo = 1
list.value = []
status.value = 'loadmore'
await getList()
proxy.$modal.showToast('审核成功')
})
}).catch(()=>{})
}
//
function reject(item) {
proxy.$modal.confirm('确定驳回申请吗?').then(() => {
proxy.$modal.loading('加载中')
sparePartsApplicationApproveApi.sparePartsApplicationReject(item.id).then(async (res) => {
proxy.$modal.closeLoading()
params.value.pageNo = 1
list.value = []
status.value = 'loadmore'
await getList()
proxy.$modal.showToast('已驳回')
}).catch(()=>{})
})
}
onLoad((option) => {
if (option.type) params.value.type = option.type;
if (option.from)from.value = option.from;
})
onShow(() => {
params.value.pageNo = 1
list.value = []
status.value = 'loadmore'
getList()
})
onReachBottom(() => {
getList()
})
</script>
<style lang="scss" scoped>
.list {
background: #f5f5f5;
margin-top: 20rpx;
.item {
padding: 30rpx 30rpx 0px 30rpx;
margin-top: 20rpx;
background: white;
position: relative;
.title {
display: flex;
align-items: center;
padding-bottom: 20rpx;
.title-txt {
color: #409eff;
font-weight: bold;
font-size: 36rpx;
width: 0px;
flex: 1;
}
.time {
color: #919191;
}
}
.dec {
padding-bottom: 20rpx;
span {
color: #999999;
}
}
.last {
padding-bottom: 30rpx;
}
.bottom {
display: flex;
justify-content: space-between;
align-items: center;
border-top: 1px solid #E4E4E4;
padding: 20rpx 0px;
height: 90rpx;
}
}
}
</style>

169
src/pages/sparePartsApplicationApprove/mySparePartsApplicationApprove.vue

@ -0,0 +1,169 @@
<template>
<!-- 备件领用申请 -->
<view class="container">
<view class="list">
<view class="item" v-for="(item,index) in list" :key="index" @click="openDetail(item)">
<view class="title">
<view class="title-txt">
{{item.name}}
</view>
<view class="time">
{{`${$time.formatDate(item.createTime)}`}}
</view>
</view>
<view class="dec">
申请单号:<span>{{item.number}}</span>
</view>
<view class="dec">
:<span>{{item.applyName}}</span>
</view>
<view class="dec" v-if="item.status!=0">
审批时间:<span>{{`${$time.formatDate(item.approveTime)}`}}</span>
</view>
<view class="dec" v-if="item.status!=0">
:<span>{{item.approveName}}</span>
</view>
<view class="bottom">
<view class="status">
<u-tag text="待审批" v-if="item.status==0" bg-color='rgba(255,255,255,0)' color='#fe8463'
border-color='#fe8463' type="primary" shape='circle' />
<u-tag text="审批通过" v-else-if="item.status==1" bg-color='rgba(255,255,255,0)' color='#2EC7C9'
border-color='#2EC7C9' type="info" shape='circle' />
<u-tag text="审批驳回" v-else-if="item.status==2" bg-color='rgba(255,255,255,0)' color='#e01f54'
border-color='#e01f54' type="success" shape='circle' />
<u-tag text="出库中" v-else-if="item.status==3" bg-color='rgba(255,255,255,0)' color='#005eaa'
border-color='#005eaa ' type="error" shape='circle' />
<u-tag text="完成" v-else-if="item.status==4" bg-color='rgba(255,255,255,0)' color='#2ba471'
border-color='#2ba471' type="info" shape='circle' />
<u-tag text="撤单" v-else-if="item.status==5" bg-color='rgba(255,255,255,0)' color='#d7d7d7'
border-color='#d7d7d7 ' type="warning" shape='circle' />
</view>
</view>
</view>
<view style="height: 94rpx;padding-top: 30rpx;">
<u-loadmore :status="status" v-if="status != 'loadmore'" />
</view>
</view>
<view style="height: constant(safe-area-inset-bottom); height: env(safe-area-inset-bottom);"></view>
</view>
</template>
<script setup lang="ts">
import {
onLoad,
onShow,
onReachBottom
} from '@dcloudio/uni-app'
import {
ref,
getCurrentInstance
} from 'vue'
import * as sparePartsApplicationApproveApi from "@/api/sparePartsApplicationApprove.js"
const { proxy } = getCurrentInstance()
const params = ref({
pageNo: 1,
pageSize: 10,
flag:''
})
const status = ref('loadmore') //
const list = ref([])
function openDetail(item) {
proxy.$tab.navigateTo(`/pages/sparePartsApplication/detail?number=${item.number}&from=1`)
}
async function getList() {
if (status.value == 'nomore') return;
status.value = 'loading';
proxy.$modal.loading('加载中')
await sparePartsApplicationApproveApi.sparePartsApplicationApprovePage(params.value).then((res) => {
proxy.$modal.closeLoading()
if (res.data.list.length > 0) {
list.value = list.value.concat(res.data.list);
params.value.pageNo++;
status.value = 'loadmore'
} else {
status.value = 'nomore'
}
}).catch(() => {
proxy.$modal.closeLoading()
})
}
onLoad((option) => {
if (option.flag) params.value.flag = option.flag;
if(params.value.flag == 2){
uni.setNavigationBarTitle({
title:'领用申请审批'
})
}
})
onShow(() => {
params.value.pageNo = 1
list.value = []
status.value = 'loadmore'
getList()
})
onReachBottom(() => {
getList()
})
</script>
<style lang="scss" scoped>
.container{
background: #f5f5f5;
min-height: 100vh;
}
.list {
background: #f5f5f5;
margin-top: 20rpx;
.item {
padding: 30rpx 30rpx 0px 30rpx;
margin-top: 20rpx;
background: white;
position: relative;
.title {
display: flex;
align-items: center;
padding-bottom: 20rpx;
.title-txt {
color: #409eff;
font-weight: bold;
font-size: 36rpx;
width: 0px;
flex: 1;
}
.time {
color: #919191;
}
}
.dec {
padding-bottom: 20rpx;
span {
color: #999999;
}
}
.last {
padding-bottom: 30rpx;
}
.bottom {
display: flex;
justify-content: space-between;
align-items: center;
border-top: 1px solid #E4E4E4;
padding: 20rpx 0px;
height: 90rpx;
}
}
}
</style>

478
src/pages/sparePartsServiceWorkOrderList/addForm.vue

@ -0,0 +1,478 @@
<template>
<!-- 添加维修工单 -->
<view class="add-form-container">
<!-- <u-form :model="form" ref="form1" label-width="160rpx">
<u-form-item label="申请主题" prop="name" required>
<u-input v-model="form.name" placeholder="请输入申请主题" />
</u-form-item>
</u-form> -->
<view class="list">
<view class="title">
<span>*</span>申请备件
</view>
<view class="item " v-for="(item,index) in form.itemNumbers" :key="index">
<view class="item-box">
<view class="spare-title">
<view class="title-txt">
{{item.name}}
</view>
</view>
<u-row gutter="16">
<u-col :span="24">
<view class="dec">
库位:{{item.locationNumber}}
</view>
</u-col>
<u-col :span="24">
<view class="dec">
数量:{{item.qty}}
</view>
</u-col>
<u-col :span="24">
<view class="dec">
维修结果:{{item.result == 'YES'?'完成':'未完成'}}
</view>
</u-col>
<u-col :span="24">
<view class="dec">
维修原因:{{item.reasons}}
</view>
</u-col>
</u-row>
</view>
<u-icon name="minus-circle" color="#aaaaaa" size="60" @click="delSpareParts(index)"></u-icon>
</view>
<view class="add-btn">
<u-button type="primary" @click="open"><u-icon name="plus-circle" color="#ffffff"
size="36"></u-icon>添加备件</u-button>
</view>
</view>
<view class="footer">
<view class="btns">
<button class="reset" @click="reset">重置</button>
<button class="sure" @click="submit" :loading='loading' :disabled='loading'>确定</button>
</view>
<view style="height: constant(safe-area-inset-bottom); height: env(safe-area-inset-bottom);"></view>
</view>
<!-- 添加备件 -->
<u-popup v-model="isPopupShow" mode="center" border-radius="14">
<view class="popup-title">添加备件</view>
<view class="popup">
<u-form :model="form1" ref="formRef" label-width="200rpx">
<u-form-item :label="`备件`" prop="itemNumber" required>
<view class="select" @click="openSingleColumn('itemNumber',form1.itemNumber,sparePartsList)">
<view class="input" v-if='form1.itemNumber'>
{{form1.name}}
</view>
<view class="placeholder" v-else>
请选择备件
</view>
<u-icon name="arrow-right" color="#aaaaaa" size="28"></u-icon>
</view>
</u-form-item>
<u-form-item label="库位" prop="locationNumber" required v-if="isShow">
<u-input v-model="form1.locationNumber" placeholder="请选择库位" @blur="blur()" />
<view class="right-button" @click="chickRightButton">
扫描
</view>
</u-form-item>
<u-form-item label="数量" prop="qty" required>
<u-input v-model="form1.qty" type="number" placeholder="请输入数量" />
</u-form-item>
<u-form-item label="维修结果" prop="reasons" required>
<u-radio-group v-model="form1.result">
<u-radio :name="item.value" v-for="(item,index) in result"
:key="index">{{item.label}}</u-radio>
</u-radio-group>
</u-form-item>
<u-form-item label="维修原因" prop="reasons" required>
<u-input v-model="form1.reasons" placeholder="请输入维修原因" />
</u-form-item>
</u-form>
</view>
<view class="popup-footer">
<view @click="isPopupShow = false">取消</view>
<view class="sure" @click="addSpare">确认</view>
</view>
</u-popup>
<u-select v-model="singleColumnShow" mode="single-column" :default-value='singleColumnDefaultValue'
:list="singleColumnList" @confirm="chooseSingleColumn" @cancle='singleColumnShow = false'></u-select>
</view>
</template>
<script setup lang="ts">
import {
onLoad,
} from '@dcloudio/uni-app'
import {
ref,
getCurrentInstance
} from 'vue'
import * as sparePartsApi from "@/api/spareParts.js"
import * as sparePartsServiceWorkOrderListApi from "@/api/sparePartsServiceWorkOrderList.js"
import * as dictApi from "@/api/dict.js"
import * as locationApi from "@/api/location.js"
const { proxy } = getCurrentInstance()
const loading = ref(false)
const type = ref('')
//
const isPopupShow = ref(false)
const sparePartsList = ref([])
const singleColumnShow = ref(false)
const singleColumnDefaultValue = ref([])
const singleColumnList = ref([])
const field = ref('')
const form = ref({
itemNumbers: []
})
const form1 = ref({
itemNumber: "",
qty: '',
result: 'YES',
reasons: '',
locationNumber: '',
areaNumber: ''
})
const result = ref([])
const isShow = ref(false)
const choosesingleColumnItem = ref()
const isInAccount = ref()
const itemNumber = ref()
//
function submit() {
//
if (form.value.itemNumbers == 0) {
proxy.$modal.showToast('请选择备件')
return;
}
proxy.$modal.confirm('是否添加备件维修工单').then(() => {
proxy.$modal.loading('加载中')
loading.value = true
sparePartsServiceWorkOrderListApi.sparePartsServiceWorkOrderListCreate(form.value).then((
res) => {
proxy.$modal.closeLoading()
if (res.data) {
proxy.$modal.showToast('添加成功')
setTimeout(() => {
proxy.$tab.navigateBack()
loading.value = false
}, 1500)
} else {
proxy.$modal.showToast('添加失败')
loading.value = false
}
}).catch(() => {
proxy.$modal.closeLoading()
loading.value = false
})
})
}
//
function reset() {
form.value = {
itemNumbers: []
}
}
//
function openSingleColumn(fieldName, val, list) {
if (fieldName == 'deviceNumber' && form.value.id) return;
singleColumnList.value = list
field.value = fieldName
if (val) {
singleColumnDefaultValue.value = [list.findIndex(item => item.value == val)]
} else {
singleColumnDefaultValue.value = []
}
singleColumnShow.value = true
}
//
function chooseSingleColumn(e) {
form1.value[field.value] = e[0].value
if (field.value == 'itemNumber') {
choosesingleColumnItem.value = singleColumnList.value.filter(item => item.number == e[0].value)
form1.value.name = e[0].label
form1.value.locationNumber = choosesingleColumnItem.value[0].locationNumber
form1.value.areaNumber = choosesingleColumnItem.value[0].areaNumber
if (!choosesingleColumnItem.value[0].locationNumber) {
isShow.value = true
} else {
isShow.value = false
}
}
singleColumnShow.value = false
}
//
async function getServiceSparePartsList() {
await sparePartsApi.getServiceSparePartsList().then(res => {
res.data.map(item => {
item.value = item.number
item.label = item.name
})
sparePartsList.value = res.data
}).catch(() => { })
}
//
function chickRightButton(field) {
uni.scanCode({
success: function (res) {
form1.value.locationNumber = res.result
getLocation()
}
});
}
function getLocation() {
locationApi.getLocation(form1.value.locationNumber).then(res => {
if (!res.data) {
proxy.$modal.showToast('找不到该库位')
return;
}
form1.value.areaNumber = res.data.areaNumber;
isInAccount.value = res.data.isInAccount
itemNumber.value = res.data.itemNumber
}).catch(() => { })
}
function blur() {
if (form1.value.locationNumber) {
getLocation()
}
}
//
function open() {
form1.value = {
itemNumber: "",
qty: '',
result: 'YES',
reasons: '',
locationNumber: '',
areaNumber: ''
}
isPopupShow.value = true
}
//
function addSpare() {
//
if (!form1.value.itemNumber) {
proxy.$modal.showToast('请选择备件')
return;
}
if (!form1.value.locationNumber) {
proxy.$modal.showToast('请扫描库位')
return;
}
if (isInAccount.value == 'TRUE') {
proxy.$modal.showToast('该库位属于帐内库,请选择帐外库')
return;
}
if (itemNumber.value) {
proxy.$modal.showToast('该库位已绑定过备件')
return;
}
if (!form1.value.qty) {
proxy.$modal.showToast(`请输入数量`)
return;
}
if (!form1.value.result) {
proxy.$modal.showToast('请选择维修结果')
return;
}
if (!form1.value.reasons) {
proxy.$modal.showToast('请输入维修原因')
return;
}
if (form.valueitemNumbers && form.value.itemNumbers.length > 0) {
let arr = form.value.itemNumbers.filter(item => item.itemNumber == form1.value.itemNumber)
if (arr && arr.length > 0) {
proxy.$modal.showToast('该备件已添加')
return;
}
}
if (form.value.itemNumbers && form.value.itemNumbers.length > 0) {
let arr1 = form.value.itemNumbers.filter(item => item.locationNumber == form1.value.locationNumber)
if (arr1 && arr1.length > 0) {
proxy.$modal.showToast('该库位已经绑定备件')
return;
}
}
form.value.itemNumbers.push(form1.value)
isPopupShow.value = false
}
//
function delSpareParts(index) {
form.value.itemNumbers.splice(index, 1)
}
onLoad(async (option) => {
if (option.type) type.value = option.type;
result.value = await dictApi.getDict('result')
await getServiceSparePartsList()
})
</script>
<style lang="scss" scoped>
.add-form-container {
min-height: calc(100vh - 140rpx);
background: white;
padding: 0px 0rpx 140rpx;
}
.u-form-item {
padding: 20rpx 30rpx;
}
.disabled {
background: #f5f5f5;
}
.footer {
position: fixed;
bottom: 0px;
left: 0px;
width: 100%;
z-index: 22;
}
.btns {
display: flex;
button {
flex: 1;
}
.sure {
background: #409eff;
color: white;
border-radius: 0px;
&::after {
border: 1px solid #409eff;
border-radius: 0px;
}
}
.reset {
background: #F5F5F5;
border-radius: 0px;
&::after {
border-radius: 0px;
}
}
}
.right-button {
background: #409eff;
color: white;
padding: 0rpx 30rpx;
border-radius: 16rpx;
text-align: center;
font-size: 28rpx;
}
.select {
display: flex;
align-items: center;
height: 72rpx;
width: 100%;
.input {
flex: 1;
font-size: 28rpx;
color: #000000;
}
.placeholder {
flex: 1;
font-size: 28rpx;
color: rgb(192, 196, 204);
}
}
.title {
padding: 32rpx 0rpx;
position: relative;
span {
position: absolute;
left: -16rpx;
color: #fa3534;
top: 19px;
}
}
.list {
padding: 0rpx 30rpx;
.item {
display: flex;
margin-bottom: 20rpx;
.item-box {
background: #F5F5F5;
border-radius: 12rpx;
flex: 1;
width: 0rpx;
}
.spare-title {
padding: 20rpx 30rpx;
border-bottom: 1px solid #e4e4e4;
.title-txt {
color: #409eff;
font-size: 30rpx;
font-weight: bold;
}
}
.dec {
color: #9c9c9c;
padding: 20rpx 30rpx 20rpx;
}
}
}
.add-btn {
display: flex;
justify-content: flex-start;
align-items: center;
}
.popup-title {
text-align: center;
font-size: 32rpx;
font-weight: bold;
color: #409eff;
padding: 30rpx 30rpx 0px
}
.popup {
width: 600rpx;
padding: 30rpx 0rpx 30rpx;
}
.popup-footer {
display: flex;
border-top: 1px solid #e4e4e4;
view {
line-height: 100rpx;
flex: 1;
text-align: center;
&.sure {
color: #409eff;
}
}
}
::v-deep .u-checkbox-group {
display: grid !important;
}
</style>

175
src/pages/sparePartsServiceWorkOrderList/mySparePartsService.vue

@ -0,0 +1,175 @@
<template>
<!-- 备件领用申请 -->
<view class="container">
<view class="list">
<view class="item" v-for="(item,index) in list" :key="index">
<view class="title">
<view class="title-txt">
{{item.itemName}}
</view>
<view class="time">
{{`${$time.formatDate(item.createTime)}`}}
</view>
</view>
<view class="dec">
<view>申请单号</view><view>{{item.number}}</view>
</view>
<view class="dec">
<view>备件单号</view><view>{{item.itemNumber}}</view>
</view>
<view class="dec">
<view>数量</view><view>{{item.qty}}</view>
</view>
<view class="dec">
<view>维修结果</view><view>{{item.result == 'YES'?'完成':'未完成'}}</view>
</view>
<view class="dec">
<view>维修原因</view><view>{{item.reasons}}</view>
</view>
<!-- <view class="bottom">
<view class="status">
<u-tag text="待审批" v-if="item.status==0" bg-color='rgba(255,255,255,0)' color='#fe8463'
border-color='#fe8463' type="primary" shape='circle' />
<u-tag text="审批通过" v-else-if="item.status==1" bg-color='rgba(255,255,255,0)' color='#2EC7C9'
border-color='#2EC7C9' type="info" shape='circle' />
<u-tag text="审批驳回" v-else-if="item.status==2" bg-color='rgba(255,255,255,0)' color='#e01f54'
border-color='#e01f54' type="success" shape='circle' />
<u-tag text="出库中" v-else-if="item.status==3" bg-color='rgba(255,255,255,0)' color='#005eaa'
border-color='#005eaa ' type="error" shape='circle' />
<u-tag text="完成" v-else-if="item.status==4" bg-color='rgba(255,255,255,0)' color='#2ba471'
border-color='#2ba471' type="info" shape='circle' />
<u-tag text="撤单" v-else-if="item.status==5" bg-color='rgba(255,255,255,0)' color='#d7d7d7'
border-color='#d7d7d7 ' type="warning" shape='circle' />
</view>
<view class="button">
<u-button shape="circle" type="primary" size="mini" style="min-width: 120rpx;"
v-if="item.status==0" @click="cancle(item)">撤回</u-button>
</view>
</view> -->
</view>
<view style="height: 94rpx;padding-top: 30rpx;">
<u-loadmore :status="status" v-if="status != 'loadmore'" />
</view>
</view>
<view style="height: constant(safe-area-inset-bottom); height: env(safe-area-inset-bottom);"></view>
</view>
</template>
<script setup lang="ts">
import {
onLoad,
onShow,
onReachBottom
} from '@dcloudio/uni-app'
import {
ref,
getCurrentInstance
} from 'vue'
import * as sparePartsServiceWorkOrderListApi from "@/api/sparePartsServiceWorkOrderList.js"
const { proxy } = getCurrentInstance()
const params = ref({
pageNo: 1,
pageSize: 10,
flag:null
})
const status = ref('loadmore') //
const list = ref([])
async function getList() {
if (status.value == 'nomore') return;
status.value = 'loading';
proxy.$modal.loading('加载中')
await sparePartsServiceWorkOrderListApi.sparePartsServiceWorkOrderListPage(params.value).then((res) => {
proxy.$modal.closeLoading()
if (res.data.list.length > 0) {
list.value = list.value.concat(res.data.list);
params.value.pageNo++;
status.value = 'loadmore'
} else {
status.value = 'nomore'
}
}).catch(() => {
proxy.$modal.closeLoading()
})
}
onShow(() => {
params.value.pageNo = 1
list.value = []
status.value = 'loadmore'
getList()
})
onReachBottom(() => {
getList()
})
</script>
<style lang="scss" scoped>
.container{
background: #f5f5f5;
min-height: 100vh;
}
.list {
background: #f5f5f5;
margin-top: 20rpx;
.item {
padding: 30rpx 30rpx 0px 30rpx;
margin-top: 20rpx;
background: white;
position: relative;
.title {
display: flex;
align-items: center;
padding-bottom: 20rpx;
.title-txt {
color: #409eff;
font-weight: bold;
font-size: 36rpx;
width: 0px;
flex: 1;
}
.time {
color: #919191;
}
}
.dec {
padding-bottom: 20rpx;
display: flex;
align-items: center;
view {
&:nth-child(1){
width: 160rpx;;
}
&:nth-child(2){
color: #999999;
flex: 1;
width: 0px;
word-wrap: break-word;
}
}
}
.last {
padding-bottom: 30rpx;
}
.bottom {
display: flex;
justify-content: space-between;
align-items: center;
border-top: 1px solid #E4E4E4;
padding: 20rpx 0px;
height: 90rpx;
}
}
}
</style>

354
src/pages/spotCheckOrder/addForm.vue

@ -0,0 +1,354 @@
<template>
<!-- 添加设备报修 -->
<view class="add-form-container">
<u-form :model="form" ref="formRef" label-width="160rpx">
<u-form-item label="点检描述" prop="describes" required>
<u-input v-model="form.describes" placeholder="请输入点检描述" />
</u-form-item>
<u-form-item :label="`${type=='DEVICE'?'设备' : '模具'}编码`" prop="deviceNumber" required>
<u-input v-model="form.deviceNumber"
:placeholder="`请输入${type=='DEVICE'?'设备' : '模具'}编码`" @blur="blur"/>
<view class="right-button" @click="chickRightButton">
扫描
</view>
</u-form-item>
<u-form-item :label="`${type=='DEVICE'?'设备' : '模具'}名称`" prop="deviceName" required class="disabled">
<u-input v-model="form.deviceName" :placeholder="`请输入${type=='DEVICE'?'设备' : '模具'}名称`" disabled />
</u-form-item>
<u-form-item label="维修人" prop="name" required class="disabled">
<u-input v-model=" store.name" placeholder="请输入维修人" disabled />
</u-form-item>
<u-form-item label="班次" prop="classes" required>
<view class="select" @click="openSingleColumn('classes',form.classes,maintenanceShift)">
<view class="input" v-if='form.classes'>
{{form.classesName}}
</view>
<view class="placeholder" v-else>
{{`请选择班次`}}
</view>
<u-icon name="arrow-right" color="#aaaaaa" size="28"></u-icon>
</view>
</u-form-item>
</u-form>
<view class="list">
<!-- <view class="title">
<span></span>备件
</view> -->
<view class="item " v-for="(item,index) in subList" :key="index">
<view class="item-box">
<view class="spare-title">
<view class="title-txt">
{{item.name}}
</view>
</view>
<u-row gutter="16">
<u-col :span="12">
<view class="dec">
<view class="">
设备部位名称:
</view>
<view>{{item.equipmentParts}}</view>
</view>
<view class="dec">
<view style="margin-right: 20rpx;">是否符合:</view><u-switch v-model="item.isConform"></u-switch>
</view>
</u-col>
</u-row>
</view>
</view>
</view>
<view class="footer">
<view class="btns">
<button class="reset" @click="reset">重置</button>
<button class="sure" @click="submit" :loading='loading' :disabled='loading'>确定</button>
</view>
<view style="height: constant(safe-area-inset-bottom); height: env(safe-area-inset-bottom);"></view>
</view>
<u-select v-model="singleColumnShow" mode="single-column" :default-value='singleColumnDefaultValue'
:list="singleColumnList" @confirm="chooseSingleColumn" @cancle='singleColumnShow = false'></u-select>
</view>
</template>
<script setup lang="ts">
import {
onLoad
} from '@dcloudio/uni-app'
import {
ref,
getCurrentInstance
} from 'vue'
import * as deviceApi from "@/api/device.js"
import * as spotCheckOrderApi from "@/api/spotCheckOrder.js"
import * as dictApi from "@/api/dict.js"
import { useCountStore } from '@/store'
const { proxy } = getCurrentInstance()
// store
const store = useCountStore()
const loading = ref(false)
const type = ref('')
const form = ref({
describes: "",
deviceNumber: '',
deviceName: '',
maintenances:'',
classes: '',
classesName:''
})
const singleColumnShow = ref(false)
const singleColumnDefaultValue = ref([])
const singleColumnList = ref([])
const field = ref('')
const maintenanceShift = ref([])
const subList = ref([])
//
function chickRightButton(field) {
uni.scanCode({
success: function(res) {
form.value.deviceNumber = res.result
getDetailsByNumber()
getSubList()
}
});
}
function blur() {
if (form.value.deviceNumber) {
getDetailsByNumber()
getSubList()
}
}
// /
function getDetailsByNumber() {
const data = {
number:form.value.deviceNumber,
flag:2
}
deviceApi.getDeviceDetailsByNumber(data).then((res) => {
if (res.data) {
form.value.deviceName = res.data.name
} else {
proxy.$modal.showToast(`找不到该${type.value=='DEVICE'?'设备' : '模具'}`)
}
}).catch(()=>{})
}
//
function getSubList() {
const data = {
number: form.value.deviceNumber
}
deviceApi.getSubList(data).then((res) => {
if (res.data) {
subList.value = res.data
} else {
proxy.$modal.showToast(`找不到该${type.value=='DEVICE'?'设备' : '模具'}`)
}
}).catch(()=>{})
}
//
function submit() {
//
if (!form.value.describes) {
proxy.$modal.showToast('请输入点检描述')
return;
}
if (!form.value.deviceNumber) {
proxy.$modal.showToast(`请输入${type.value=='DEVICE'?'设备' : '模具'}编码`)
return;
}
if (!form.value.classes) {
proxy.$modal.showToast('请选择班次')
return;
}
if (subList.value.length==0) {
proxy.$modal.showToast('该设备无检修项目')
return;
}
const data = {
describes:form.value.describes,
deviceNumber:form.value.deviceNumber,
maintenances: form.value.maintenances,
classes:form.value.classes,
subList:subList.value,
type: type.value
}
proxy.$modal.confirm('是否添加点检工单').then(() => {
proxy.$modal.loading('加载中')
loading.value = true
spotCheckOrderApi.spotCheckOrderCreate(data).then((res) => {
proxy.$modal.closeLoading()
if (res.data) {
proxy.$modal.showToast('添加成功')
setTimeout(() => {
proxy.$tab.navigateBack()
loading.value = false
}, 1500)
} else {
proxy.$modal.showToast('添加失败')
loading.value = false
}
}).catch(() => {
proxy.$modal.closeLoading()
loading.value = false
})
})
}
//
function reset() {
form.value = {
describes: "",
deviceNumber: '',
deviceName: '',
maintenances:'',
classes: ''
}
}
function selectFormat(val, array) {
let str = array.filter(item => item.value == val)[0].label
return str
}
//
function openSingleColumn(fieldName, val, list) {
singleColumnList.value = list
field.value = fieldName
if (val) {
singleColumnDefaultValue.value = [list.findIndex(item => item.value == val)]
} else {
singleColumnDefaultValue.value = []
}
singleColumnShow.value = true
}
//
function chooseSingleColumn(e) {
form.value[field.value] = e[0].value
if(field.value == 'classes'){
form.value.classesName = e[0].label
}
singleColumnShow.value = false
}
onLoad(async (option) => {
if (option.type) type.value = option.type;
maintenanceShift.value = await dictApi.getDict('maintenance_shift')
form.value.maintenances = uni.getStorageSync('user').nickname
})
</script>
<style lang="scss" scoped>
.add-form-container {
min-height: calc(100vh - 140rpx);
background: white;
padding: 0px 0rpx 140rpx;
}
.u-form-item {
padding: 20rpx 30rpx;
}
.disabled {
background: #f5f5f5;
}
.list {
padding: 30rpx 30rpx;
.item {
display: flex;
margin-bottom: 20rpx;
.item-box {
background: #F5F5F5;
border-radius: 12rpx;
flex: 1;
width: 0rpx;
}
.spare-title {
padding: 20rpx 30rpx;
border-bottom: 1px solid #e4e4e4;
.title-txt {
color: #409eff;
font-size: 30rpx;
font-weight: bold;
}
}
.dec {
color: #9c9c9c;
padding: 20rpx 30rpx 20rpx;
display: flex;
align-items: center;
}
}
}
.select {
display: flex;
align-items: center;
height: 72rpx;
width: 100%;
.input {
flex: 1;
font-size: 28rpx;
color: #000000;
}
.placeholder {
flex: 1;
font-size: 28rpx;
color: rgb(192, 196, 204);
}
}
.footer {
position: fixed;
bottom: 0px;
left: 0px;
width: 100%;
}
.btns {
display: flex;
button {
flex: 1;
}
.sure {
background: #409eff;
color: white;
border-radius: 0px;
&::after {
border: 1px solid #409eff;
border-radius: 0px;
}
}
.reset {
background: #F5F5F5;
border-radius: 0px;
&::after {
border-radius: 0px;
}
}
}
.right-button {
background: #409eff;
color: white;
padding: 0rpx 30rpx;
border-radius: 16rpx;
text-align: center;
font-size: 28rpx;
}
</style>

216
src/pages/spotCheckOrder/myOrder.vue

@ -0,0 +1,216 @@
<template>
<!-- 点检工单 -->
<view class="container">
<u-navbar back-icon-color='#fff' :background="{ background: '#409eff'}" back-text="" title-color='#fff'
title="点检工单">
</u-navbar>
<view class="list">
<view class="item" v-for="(item,index) in list" :key="index" >
<view class="">
<view class="title">
<view class="title-txt">
{{item.describes}}
</view>
<u-tag text="待接单" v-if="item.status == 'PENDING'" bg-color='rgba(255,255,255,0)' color='#fe8463' border-color='#fe8463' type="primary" shape='circle'/>
<u-tag text="已撤回" v-else-if="item.status=='REJECTED'" bg-color='rgba(255,255,255,0)' color='#d7d7d7' border-color='#d7d7d7 ' type="warning" shape='circle'/>
<u-tag text="已转办" v-else-if="item.status=='TRANSFERRED'" bg-color='rgba(255,255,255,0)' color='#e01f54' border-color='#e01f54' type="success" shape='circle'/>
<u-tag text="已接单" v-else-if="item.status=='PECEIVED'" bg-color='rgba(255,255,255,0)' color='#005eaa' border-color='#005eaa ' type="error" shape='circle'/>
<u-tag text="已验证" v-else-if="item.status=='VERIFIED'" bg-color='rgba(255,255,255,0)' color='#2EC7C9' border-color='#2EC7C9' type="info" shape='circle'/>
<u-tag text="已完成" v-else-if="item.status=='COMPLETED'" bg-color='rgba(255,255,255,0)' color='#2ba471' border-color='#2ba471' type="info" shape='circle'/>
</view>
<view class="dec">
点检单号:<span>{{item.number}}</span>
</view>
<view class="dec">
{{`${item.type=='DEVICE'?'设备' : '模具'}`}}编号:<span>{{item.deviceNumber}}</span>
</view>
<view class="dec">
{{`${item.type=='DEVICE'?'设备' : '模具'}`}}名称:<span>{{item.name}}</span>
</view>
<view class="dec">
班次:<span>{{item.classesName}}</span>
</view>
</view>
<view class="bottom">
<view class="time" style="flex: 1;">
{{`${$time.formatDate(item.createTime)}`}}
</view>
</view>
</view>
</view>
<view style="height: 94rpx;padding-top: 30rpx;">
<u-loadmore :status="status" v-if="status != 'loadmore'" />
</view>
<view style="height: constant(safe-area-inset-bottom); height: env(safe-area-inset-bottom);"></view>
</view>
</template>
<script setup lang="ts">
import {
onLoad,
onShow,
onReachBottom
} from '@dcloudio/uni-app'
import {
ref,
getCurrentInstance
} from 'vue'
import * as spotCheckOrderApi from "@/api/spotCheckOrder.js"
import { useCountStore } from '@/store'
const { proxy } = getCurrentInstance()
// store
const store = useCountStore()
const params = ref({
pageNo: 1,
pageSize: 10,
flag:1
})
const status = ref('loadmore') //
const list = ref([])
async function getList() {
if (status.value == 'nomore') return;
status.value = 'loading';
proxy.$modal.loading('加载中')
await spotCheckOrderApi.spotCheckOrderPage(params.value).then((res) => {
proxy.$modal.closeLoading()
if (res.data.list.length > 0) {
list.value = list.value.concat(res.data.list);
params.value.pageNo++;
status.value = 'loadmore'
} else {
status.value = 'nomore'
}
}).catch(() => {
proxy.$modal.closeLoading()
})
}
onLoad((option) => {
if (option.type) params.value.type = option.type;
})
onShow(() => {
params.value.pageNo = 1
list.value = []
status.value = 'loadmore'
getList()
})
onReachBottom(() => {
getList()
})
</script>
<style lang="scss" scoped>
.container{
background: #f5f5f5;
min-height: 100vh;
}
.list {
background: #f5f5f5;
margin-top: 20rpx;
.item {
padding: 30rpx 30rpx 0px 30rpx;
margin-top: 20rpx;
background: white;
.title {
display: flex;
align-items: center;
padding-bottom: 20rpx;
.title-txt {
color: #409eff;
font-weight: bold;
font-size: 36rpx;
width: 0px;
flex: 1;
}
.time {
color: #919191;
}
}
.dec {
padding-bottom: 20rpx;
span {
color: #999999;
}
}
.last {
padding-bottom: 30rpx;
}
.bottom {
display: flex;
justify-content: space-between;
align-items: center;
border-top: 1px solid #E4E4E4;
padding: 20rpx 0px;
}
}
}
.list {
background: #f5f5f5;
margin-top: 20rpx;
.item {
padding: 30rpx 30rpx 0px 30rpx;
margin-top: 20rpx;
background: white;
.title {
display: flex;
align-items: center;
padding-bottom: 20rpx;
.title-txt {
color: #409eff;
font-weight: bold;
font-size: 36rpx;
width: 0px;
flex: 1;
}
.time {
color: #919191;
}
}
.dec {
padding-bottom: 20rpx;
span {
color: #999999;
}
}
.last {
padding-bottom: 30rpx;
}
.bottom {
display: flex;
justify-content: space-between;
align-items: center;
border-top: 1px solid #E4E4E4;
padding: 20rpx 0px;
position: relative;
.button {
position: absolute;
right: 0rpx;
}
}
}
}
</style>

627
src/pages/upkeepOrder/addServiceRecord.vue

@ -0,0 +1,627 @@
<template>
<!-- 添加维修工单 -->
<view class="add-form-container">
<u-form :model="form" ref="form1" label-width="160rpx">
<u-form-item label="保养内容" prop="contents" required class="disabled">
<u-input v-model="form.contents" placeholder="请输入保养内容" maxlength="50" disabled/>
</u-form-item>
<!-- <u-form-item label="保养部位" prop="equipmentParts" required>
<u-input v-model="form.equipmentParts" placeholder="请输入保养部位" maxlength="50" disabled/>
</u-form-item> -->
<u-form-item label="预估人数" prop="peoples" class="disabled">
<u-input v-model="form.peoples" type="number" placeholder="请输入预估人数" maxlength="50"/>
</u-form-item>
<u-form-item label="预估分钟" prop="estimatedMinutes" class="disabled">
<u-input v-model="form.estimatedMinutes" type="number" placeholder="请输入预估分钟" maxlength="50"/>
</u-form-item>
<u-form-item label="实际分钟" prop="actualMinutes" required>
<u-input v-model="form.actualMinutes" type="number" placeholder="请输入实际分钟" maxlength="50"/>
</u-form-item>
<u-form-item label="责任人" prop="chargePeoples" required>
<view class="select" @click="openSelecUser">
<view class="input" v-if='form.chargePeoples'>
{{selectFormatCheck(form.chargePeoples,selecUserList)}}
</view>
<view class="placeholder" v-else>
请选择维修人员
</view>
<u-icon name="arrow-right" color="#aaaaaa" size="28"></u-icon>
</view>
</u-form-item>
<u-form-item label="完成情况" prop="status" required>
<view class="select" @click="openSingleColumn('status',form.status,jxDetailsStatus,'form')">
<view class="input" v-if='form.status'>
{{selectFormat(form.status,jxDetailsStatus)}}
</view>
<view class="placeholder" v-else>
{{`请选择完成情况`}}
</view>
<u-icon name="arrow-right" color="#aaaaaa" size="28" v-if="!form.id"></u-icon>
</view>
</u-form-item>
<u-form-item label="完成时间" prop="completionTime" required v-if='form.status === 0||form.status === "0"'>
<view class="select" @click="openDatetime('completionTime',formatDate,params,formatValue)">
<view class="input" v-if='formatDate'>
{{formatDate}}
</view>
<view class="placeholder" v-else>
{{`请选择完成时间`}}
</view>
<u-icon name="arrow-right" color="#aaaaaa" size="28"></u-icon>
</view>
</u-form-item>
<u-form-item label="工程师确认" prop="engineer">
<u-input v-model="form.engineer" placeholder="请输入工程师确认" maxlength="50"/>
</u-form-item>
<u-form-item label="未完成原因" prop="uncompleted" required v-if='form.status === 1||form.status === "1"'>
<u-input type='textarea' v-model="form.uncompleted" placeholder="请输入未完成原因" maxlength="200"/>
</u-form-item>
</u-form>
<view class="list">
<view class="title">
<span>*</span>备件
</view>
<view class="item " v-for="(item,index) in form.itemNumbers" :key="index">
<view class="item-box">
<view class="spare-title">
<view class="title-txt">
{{item.name}}
</view>
</view>
<u-row gutter="16">
<u-col :span="12">
<view class="dec">
<view class="">
数量:{{item.qty}}
</view>
</view>
</u-col>
</u-row>
</view>
<u-icon name="minus-circle" color="#aaaaaa" size="60" @click="delSpareParts(index)"></u-icon>
</view>
<view class="add-btn">
<u-button type="primary" @click="open"><u-icon name="plus-circle" color="#ffffff"
size="36"></u-icon>添加备件</u-button>
</view>
</view>
<view class="footer">
<view class="btns">
<button class="reset" @click="reset">重置</button>
<button class="sure" @click="submit" :loading='loading' :disabled='loading'>确定</button>
</view>
<view style="height: constant(safe-area-inset-bottom); height: env(safe-area-inset-bottom);"></view>
</view>
<!-- 添加备件 -->
<u-popup v-model="isPopupShow" mode="center" border-radius="14">
<view class="popup-title">添加备件</view>
<view class="popup">
<u-form :model="form1" ref="form1" label-width="160rpx">
<u-form-item :label="`备件`" prop="number" required>
<view class="select" @click="openSingleColumn('number',form1.number,sparePartsList,'form1')">
<view class="input" v-if='form1.number'>
{{selectFormat(form1.number,sparePartsList)}}
</view>
<view class="placeholder" v-else>
请选择备件
</view>
<u-icon name="arrow-right" color="#aaaaaa" size="28"></u-icon>
</view>
</u-form-item>
<u-form-item label="数量" prop="qty" required>
<u-input v-model="form1.qty" type="number" placeholder="请输入数量" />
</u-form-item>
</u-form>
</view>
<view class="popup-footer">
<view @click="isPopupShow = false">取消</view>
<view class="sure" @click="addSpare">确认</view>
</view>
</u-popup>
<!-- 选择维修人员 -->
<u-popup v-model="isShowSelecUser" mode="center" border-radius="14">
<view class="popup-title">选择维修人员</view>
<view class="popup">
<u-checkbox-group @change="checkboxGroupChange">
<u-checkbox v-model="item.checked" v-for="(item, index) in selecUserList" :key="index"
:name="item.id">{{item.name}}</u-checkbox>
</u-checkbox-group>
</view>
<view class="popup-footer">
<view @click="isShowSelecUser = false">取消</view>
<view class="sure" @click="chooseUser">确认</view>
</view>
</u-popup>
<u-select v-model="singleColumnShow" mode="single-column" :default-value='singleColumnDefaultValue'
:list="singleColumnList" @confirm="chooseSingleColumn" @cancle='singleColumnShow = false'></u-select>
<u-picker mode="time" v-model="datetimeShow" :default-time='datetimeDefaultValue' :params="params" @confirm='chooseDatetime' @cancle='datetimeShow = false'></u-picker>
</view>
</template>
<script setup lang="ts">
import {
onLoad
} from '@dcloudio/uni-app'
import {
ref,
getCurrentInstance
} from 'vue'
import * as upkeepOrderApi from "@/api/upkeepOrder.js"
import * as sparePartsApi from "@/api/spareParts.js"
import * as deptApi from "@/api/dept.js"
import * as dictApi from "@/api/dict.js"
const { proxy} = getCurrentInstance()
const loading = ref(false)
const type = ref('')
//
const isPopupShow = ref(false)
const sparePartsList = ref([])
const singleColumnShow = ref(false)
const singleColumnDefaultValue = ref([])
const singleColumnList = ref([])
const field = ref('')
const selecUserList = ref([])//
const isShowSelecUser = ref(false)
const jxDetailsStatus = ref([])//
const formatDate = ref('')//
const form = ref({
number: '',
name:'',
peoples: null,
estimatedMinutes: '',
actualMinutes: '',
chargePeoples: '',
status: null,
completionTime: '',
engineer: '',
uncompleted: '',
itemNumbers:[]
})
const form1 = ref({
number: "",
name: "",
qty: 0
})
//
const datetimeShow = ref(false)
const params = ref({
year: true,
month: true,
day: true,
hour: true,
minute: true,
second: true,
timestamp: true,
})
const datetimeDefaultValue = ref('')
const formatValue = ref('YYYY-MM-DD hh:mm:ss')
const factoryAreaNumber = ref('')
const chooseUserList = ref([])
//
function submit() {
//
if (form.value.peoples > 100) {
proxy.$modal.showToast('预估人数不得超出100')
return;
}
if (!form.value.actualMinutes) {
proxy.$modal.showToast('请输入实际分钟')
return;
}
if (!form.value.chargePeoples) {
proxy.$modal.showToast('请选择负责人')
return;
}
if (!form.value.status) {
proxy.$modal.showToast('请选择完成情况')
return;
}
if (form.value.status == 0) {
if (!form.value.completionTime) {
proxy.$modal.showToast('请选择完成时间')
return;
}
}
if (form.value.status == 1) {
if (!form.value.uncompleted) {
proxy.$modal.showToast('请输入未完成原因')
return;
}
}
if (form.value.id) {
proxy.$modal.confirm('是否修改检修内容').then(() => {
proxy.$modal.loading('加载中')
loading.value = true
upkeepOrderApi.upkeepOrderDetailUpdate(form.value).then((res) => {
proxy.$modal.closeLoading()
if (res.data) {
proxy.$modal.showToast('修改成功')
setTimeout(() => {
proxy.$tab.navigateBack()
loading.value = false
}, 1500)
} else {
proxy.$modal.showToast('添加失败')
loading.value = false
}
}).catch(() => {
proxy.$modal.closeLoading()
loading.value = false
})
})
} else {
proxy.$modal.confirm('是否添加检修内容').then(() => {
proxy.$modal.loading('加载中')
loading.value = true
upkeepOrderApi.upkeepOrderDetailCreate(form.value).then((res) => {
proxy.$modal.closeLoading()
if (res.data) {
proxy.$modal.showToast('添加成功')
setTimeout(() => {
proxy.$tab.navigateBack()
loading.value = false
}, 1500)
} else {
proxy.$modal.showToast('添加失败')
loading.value = false
}
}).catch(() => {
proxy.$modal.closeLoading()
loading.value = false
})
})
}
}
//
function reset() {
form.value = {
number: '',
name: '',
peoples: null,
estimatedMinutes: '',
actualMinutes: '',
chargePeoples: '',
status:null,
completionTime: '',
engineer: '',
uncompleted: '',
itemNumbers: []
}
}
//
async function getSelecUser() {
let paramsData = {
classType: type.value,
factoryAreaNumber: factoryAreaNumber.value,
flag: 0
}
let arr = []
if (form.value.chargePeoples) {
arr = form.value.chargePeoples.split(',')
}
await deptApi.getSelecUser(paramsData).then(res => {
res.data.forEach(item => {
item.checked = false
arr.forEach(cur => {
if (item.id == cur) {
item.checked = true
}
})
})
selecUserList.value = res.data
}).catch(() => { })
}
//
function openSelecUser() {
isShowSelecUser.value = true
}
function checkboxGroupChange(e) {
chooseUserList.value = e
}
//
function selectFormatCheck(val, array) {
const arr = val.split(',').map(Number)
let str = array.filter(item => arr.includes(item.id)).map(item => item.name).join(',')
return str
}
//
function chooseUser() {
form.value.chargePeoples = chooseUserList.value.join(',')
isShowSelecUser.value = false
}
const whichForm = ref()
//
function openSingleColumn(fieldName, val, list, from) {
if (fieldName == 'deviceNumber' && form.value.id) return;
whichForm.value = from
singleColumnList.value = list
field.value = fieldName
if (val) {
singleColumnDefaultValue.value = [list.findIndex(item => item.value == val)]
} else {
singleColumnDefaultValue.value = []
}
singleColumnShow.value = true
}
//
function chooseSingleColumn(e) {
if(whichForm.value == 'form'){
form.value[field.value] = e[0].value
if(field.value=='status'){
form.value.statusTxt = e[0].label
}
}else if(whichForm.value == 'form1'){
form1.value[field.value] = e[0].value
if(field.value=='number'){
form1.value.name = e[0].label
}
}
singleColumnShow.value = false
}
//
async function getSparePartsList() {
await sparePartsApi.getSparePartsList().then(res => {
res.data.map(item => {
item.value = item.number
item.label = item.name
})
sparePartsList.value = res.data
}).catch(() => { })
}
//
function open() {
form1.value = {
number: "",
name:'',
qty: 0
}
isPopupShow.value = true
}
//
function addSpare() {
if (!form1.value.number) {
proxy.$modal.showToast('请选择备件')
return;
}
if (!form1.value.qty || form1.value.qty == 0) {
proxy.$modal.showToast('请输入数量')
return;
}
if (form.value.itemNumbers && form.value.itemNumbers.length > 0) {
let arr = form.value.itemNumbers.filter(item => item.number == form1.value.number)
if (arr && arr.length > 0) {
proxy.$modal.showToast('该备件已添加')
return;
}
}
form.value.itemNumbers.push(form1.value)
isPopupShow.value = false
}
//
function delSpareParts(index) {
form.value.itemNumbers.splice(index, 1)
}
function openDatetime(fieldName, val, params, format) {
params.value = params
formatValue.value = format
field.value = fieldName
form.value[field.value] = val ? val : ''
datetimeDefaultValue.value = val ? val : proxy.$time.formatDate()
datetimeShow.value = true
}
//
function chooseDatetime(e) {
let array1 = []
let array2 = []
if (formatValue.value.indexOf('YYYY') > -1) {
array1.push(e.year)
}
if (formatValue.value.indexOf('MM') > -1) {
array1.push(e.month)
}
if (formatValue.value.indexOf('DD') > -1) {
array1.push(e.day)
}
if (formatValue.value.indexOf('hh') > -1) {
array2.push(e.hour)
}
if (formatValue.value.indexOf('mm') > -1) {
array2.push(e.minute)
}
if (formatValue.value.indexOf('ss') > -1) {
array2.push(e.second)
}
let str = array1.join('-') + ' ' + array2.join(':')
formatDate.value = str
form.value[field.value] = e.timestamp
}
onLoad(async(option) => {
if (option.type) type.value = option.type;
if (option.factoryAreaNumber) factoryAreaNumber.value = option.factoryAreaNumber;
if (option.number) form.value.number = option.number;
if (option.data && JSON.parse(decodeURIComponent(option.data)) && JSON.parse(decodeURIComponent(option
.data)).id) {
form.value = JSON.parse(decodeURIComponent(option.data))
form.value.itemNumbers = form.value.items
formatDate.value = form.value.completionTime ? proxy.$time.formatDate(form.value.completionTime * 1000) : ''
};
jxDetailsStatus.value = await dictApi.getDict('jx_details_status')
await getSelecUser()
await getSparePartsList()
})
</script>
<style lang="scss" scoped>
.add-form-container {
min-height: calc(100vh - 140rpx);
background: white;
padding: 0px 0rpx 140rpx;
}
.u-form-item{
padding: 20rpx 30rpx;
}
.disabled{
background: #f5f5f5;
}
.footer {
position: fixed;
bottom: 0px;
left: 0px;
width: 100%;
z-index: 22;
}
.btns {
display: flex;
button {
flex: 1;
}
.sure {
background: #409eff;
color: white;
border-radius: 0px;
&::after {
border: 1px solid #409eff;
border-radius: 0px;
}
}
.reset {
background: #F5F5F5;
border-radius: 0px;
&::after {
border-radius: 0px;
}
}
}
.right-button {
background: #409eff;
color: white;
padding: 0rpx 30rpx;
border-radius: 16rpx;
text-align: center;
font-size: 28rpx;
}
.select {
display: flex;
align-items: center;
height: 72rpx;
width: 100%;
.input {
flex: 1;
font-size: 28rpx;
color: #000000;
}
.placeholder {
flex: 1;
font-size: 28rpx;
color: rgb(192, 196, 204);
}
}
.title {
padding: 32rpx 0px;
position: relative;
span {
position: absolute;
left: -16rpx;
color: #fa3534;
padding-top: 6rpx;
}
}
.list {
padding: 0px 30rpx;
.item {
display: flex;
margin-bottom: 20rpx;
.item-box {
background: #F5F5F5;
border-radius: 12rpx;
flex: 1;
width: 0rpx;
}
.spare-title {
padding: 20rpx 30rpx;
border-bottom: 1px solid #e4e4e4;
.title-txt {
color: #409eff;
font-size: 30rpx;
font-weight: bold;
}
}
.dec {
color: #9c9c9c;
padding: 20rpx 30rpx 20rpx;
}
}
}
.add-btn {
display: flex;
justify-content: flex-start;
align-items: center;
}
.popup-title {
text-align: center;
font-size: 32rpx;
font-weight: bold;
color: #409eff;
padding: 30rpx 30rpx 0px
}
.popup {
width: 600rpx;
padding: 30rpx 60rpx 30rpx;
}
.popup-footer {
display: flex;
border-top: 1px solid #e4e4e4;
view {
line-height: 100rpx;
flex: 1;
text-align: center;
&.sure {
color: #409eff;
}
}
}
::v-deep .u-checkbox-group {
display: grid !important;
}
</style>

484
src/pages/upkeepOrder/detail.vue

@ -0,0 +1,484 @@
<template>
<!-- 详情 -->
<view class="detail-container">
<view class="info">
<view class="title">
<view>保养工单</view>
</view>
<view class="dec">
<view class="dec-item">
<view>工单单号</view>
<view>{{data.number}}</view>
</view>
<view class="dec-item">
<view>保养计划单号</view>
<view>{{data.planNumber}}</view>
</view>
<view class="dec-item">
<view>故障类型</view>
<view>{{data.faultTypeName}}</view>
</view>
<view class="dec-item" v-if="data.createTime">
<view>创建时间</view>
<view>{{$time.formatDate(data.createTime)}}</view>
</view>
<view class="dec-item" v-if="data.creator">
<view>创建人员</view>
<view>{{data.creator}}</view>
</view>
<view class="dec-item" v-if="data.receivingTime">
<view>接单时间</view>
<view>{{$time.formatDate(data.receivingTime)}}</view>
</view>
<view class="dec-item" v-if="data.maintenanceName">
<view>维修人员</view>
<view>{{data.maintenanceName}}</view>
</view>
<view class="dec-item" v-if="data.completionTime">
<view>完成时间</view>
<view>{{$time.formatDate(data.completionTime)}}</view>
</view>
</view>
</view>
<div class="line"></div>
<view class="info" style="padding-bottom: 130rpx;">
<view class="tab">
<u-tabs :list="list" :is-scroll="false" bar-height="2" bar-width="250" v-model="current"
@change="change"></u-tabs>
</view>
<view>
<view class="title">
<view>{{changeItem.name}}</view>
</view>
<view class="dec" v-if="current == 0">
<view class="dec-item">
<view>设备编号</view>
<view>{{data.number}}</view>
</view>
<view class="dec-item">
<view>设备名称</view>
<view>{{data.name}}</view>
</view>
<view class="dec-item">
<view>所属厂区</view>
<view>{{data.factoryAreaName}}</view>
</view>
<view class="dec-item">
<view>设备类型</view>
<view>{{data.type == 'DEVICE'?'设备':data.type == 'TECH'?'工艺':'模具'}}</view>
</view>
</view>
<view class="list" v-if="current == 1">
<view class="item " v-for="(item,index) in serviceList" :key="index"
@click="addSubForm('updata',item)">
<view class="item-box">
<view class="spare-title">
<view class="title-txt">
{{item.contents}}
</view>
</view>
<!-- <view class="dec2">
<view>保养部位</view>
<view>{{item.equipmentParts}}</view>
</view> -->
<view class="dec2">
<view>预估人数</view>
<view v-if="item.peoples||item.peoples==0">{{item.peoples}}</view>
</view>
<view class="dec2">
<view>预估分钟</view>
<view v-if='item.estimatedMinutes'>{{item.estimatedMinutes}}分钟</view>
</view>
<view class="dec2">
<view>实际分钟</view>
<view v-if='item.actualMinutes'>{{item.actualMinutes}}分钟</view>
</view>
<view class="dec2">
<view>责任人</view>
<view>{{item.chargePeoplesName}}</view>
</view>
<view class="dec2" >
<view>完成情况</view>
<view>{{item.status===0 || item.status === '0'? '完成':item.status===1 ||item.status === '1'?'未完成':''}}</view>
</view>
<view class="dec2" v-if='item.status === 0 || item.status === "0"'>
<view>完成时间</view>
<view>{{$time.formatDate(item.completionTime*1000)}}</view>
</view>
<view class="dec2">
<view>工程师确认</view>
<view>{{item.engineer}}</view>
</view>
<view class="dec2" v-if="item.status === 1 || item.status === '1'">
<view>未完成原因</view>
<view>{{item.uncompleted}}</view>
</view>
<view class="dec2">
备件
</view>
<view class="items" v-for="(cur,key) in item.items" :key="key">
<view class="items-name">
{{cur.name}}
</view>
<view class="items-dec">
备件编号{{cur.number}}
</view>
<view class="items-dec">
数量{{cur.qty}}
</view>
</view>
</view>
<!-- <u-icon name="minus-circle" color="#aaaaaa" size="60" ></u-icon> -->
</view>
</view>
</view>
</view>
<view class="footer">
<view class="btns">
<u-button type="primary" v-if="data.status == 'PENDING'" @click="orderClick(1)" :loading='loading'
:disabled='loading'>接单</u-button>
<u-button type="primary" v-if="data.status == 'PECEIVED'" @click="orderClick(2)" :loading='loading'
:disabled='loading'>完成</u-button>
</view>
<view style="height: constant(safe-area-inset-bottom); height: env(safe-area-inset-bottom);"></view>
</view>
</view>
</template>
<script setup lang="ts">
import {
onLoad,
onShow
} from '@dcloudio/uni-app'
import {
ref,
getCurrentInstance
} from 'vue'
import * as moldApi from "@/api/mold.js"
import * as upkeepOrderApi from "@/api/upkeepOrder.js"
const list = ref([{
name: '设备信息'
}, {
name: '检修内容'
}])
const current = ref(0)
const changeItem = ref({
name: '设备信息',
value: 1
})
const data = ref()
const loading = ref(false)
const type = ref('')
const serviceList = ref([])
const isTrue = ref(false)
function change(index) {
current.value = index
changeItem.value = list.value[current.value]
}
//
function addSubForm(clickType, item) {
if (data.value.status == 'PENDING') {
proxy.$modal.showToast('请先接单')
return
}
if (clickType == 'updata') {
proxy.$tab.navigateTo(
`/pages/upkeepOrder/addServiceRecord?type=${type.value}&factoryAreaNumber=${data.value.factoryAreaNumber}&number=${data.value.number}&data=${encodeURIComponent(JSON.stringify(item))}`
)
} else {
proxy.$tab.navigateTo(
`/pages/upkeepOrder/addServiceRecord?type=${type.value}&factoryAreaNumber=${data.value.factoryAreaNumber}&number=${data.value.number}`
)
}
}
function orderClick(type) {
if(!serviceList.value || serviceList.value&&serviceList.value.length == 0){
proxy.$modal.showToast('没有保养内容')
return;
}
if(type == 2){
isTrue.value = serviceList.value.some(item=>item.items.length == 0)
if(isTrue.value){
proxy.$modal.showToast('保养项目没有全部完成')
return;
}
}
const paramsData = {
id: data.value.id
}
let tips = data.value.status == 'PENDING' ? '是否接单?' : data.value.status == 'PECEIVED' ? '是否完成?' : ''
proxy.$modal.confirm(tips).then(() => {
proxy.$modal.loading('加载中')
loading.value = true
if(type == 1){
upkeepOrderApi.orderClick(paramsData).then((res) => {
if (res.data) {
proxy.$modal.showToast('操作成功')
setTimeout(() => {
proxy.$tab.navigateBack()
loading.value = false
}, 1500)
} else {
proxy.$modal.showToast('操作失败')
loading.value = false
}
}).catch(() => {
proxy.$modal.closeLoading()
loading.value = false
})
}else if(type == 2){
upkeepOrderApi.orderClickFinish(paramsData).then((res) => {
if (res.data) {
proxy.$modal.showToast('操作成功')
setTimeout(() => {
proxy.$tab.navigateBack()
loading.value = false
}, 1500)
} else {
proxy.$modal.showToast('操作失败')
loading.value = false
}
}).catch(() => {
proxy.$modal.closeLoading()
loading.value = false
})
}
})
}
//
function getUpkeepOrderDetailList() {
upkeepOrderApi.upkeepOrderDetailList({
number: data.value.number
}).then((res) => {
if (res.data) {
serviceList.value = res.data
}
}).catch(() => { })
}
//
function delService(item) {
proxy.$modal.confirm('确定删除维修内容吗?').then(() => {
proxy.$modal.loading('加载中')
upkeepOrderApi.upkeepOrderDetailDelete(item.id).then((res) => {
proxy.$modal.closeLoading()
getUpkeepOrderDetailList()
}).catch(() => { })
})
}
onLoad(async (option) => {
if (option.type) type.value = option.type;
if (option.data) {
data.value = JSON.parse(decodeURIComponent(option.data))
}
changeItem.value = list.value[current.value]
})
onShow(() => {
getUpkeepOrderDetailList()
})
</script>
<style lang="scss" scoped>
.detail-container{
min-height: 100vh;
background: white;
}
.line{
background: #f5f5f5;
height: 20rpx;
}
.info {
background: white;
}
.tab {
border-bottom: 1px solid #e4e4e4;
}
.title {
display: flex;
align-items: center;
padding: 20rpx 30rpx;
border-bottom: 1px solid #e4e4e4;
view {
&:nth-child(1) {
flex: 1;
border-left: 10rpx solid #409eff;
padding-left: 20rpx;
font-weight: bold;
}
}
}
.dec {
padding: 30rpx;
.dec-item {
padding-bottom: 30rpx;
display: flex;
view {
&:nth-child(1) {
width: 200rpx;
}
&:nth-child(2) {
color: #888888;
flex: 1;
width: 0px;
word-wrap: break-word;
}
}
}
}
.dec2 {
padding: 10rpx 30rpx;
display: flex;
view {
&:nth-child(1) {
width: 180rpx;
}
&:nth-child(2) {
color: #888888;
flex: 1;
width: 0px;
word-wrap: break-word;
}
}
}
.items {
margin: 20rpx 30rpx;
border-radius: 12rpx;
background: #F5F5F5;
padding-bottom: 20rpx;
.items-name {
padding: 20rpx;
border-bottom: 1px solid #dedede;
}
.items-dec {
padding: 0px 20rpx;
margin-top: 20rpx;
}
}
.popup-title {
text-align: center;
font-size: 32rpx;
font-weight: bold;
color: #409eff;
padding: 30rpx
}
.popup {
width: 600rpx;
padding: 0rpx 60rpx 0rpx;
}
.popup-footer {
display: flex;
border-top: 1px solid #e4e4e4;
view {
line-height: 100rpx;
flex: 1;
text-align: center;
&.sure {
color: #409eff;
}
}
}
.footer {
position: fixed;
bottom: 0px;
left: 0px;
width: 100%;
background: white;
z-index: 22;
}
.btns {
display: flex;
padding: 20rpx;
box-shadow: 0px -2rpx 20rpx rgba(0, 0, 0, 0.1);
button {
flex: 1;
margin: 0px 10rpx;
}
.sure {
background: #409eff;
color: white;
border-radius: 8rpx;
&::after {
border: 1px solid #409eff;
border-radius: 0px;
}
}
}
.list {
padding: 20rpx;
.item {
display: flex;
margin-bottom: 20rpx;
.item-box {
border-radius: 12rpx;
border: 1px solid #dedede;
border-radius: 12rpx;
flex: 1;
width: 0rpx;
}
.spare-title {
padding: 20rpx 30rpx;
border-bottom: 1px solid #e4e4e4;
display: flex;
.title-txt {
color: #409eff;
font-size: 30rpx;
font-weight: bold;
flex: 1;
}
}
.dec {
color: #9c9c9c;
padding: 0rpx 30rpx 20rpx;
}
}
}
.add-btn {
display: flex;
justify-content: flex-start;
align-items: center;
}
</style>

224
src/pages/upkeepOrder/index.vue

@ -0,0 +1,224 @@
<template>
<!-- 保养工单 -->
<view class="container">
<u-navbar back-icon-color='#fff' :background="{ background: '#409eff'}" back-text="" title-color='#fff'
title="保养工单">
</u-navbar>
<view class="list">
<view class="item" v-for="(item,index) in list" :key="index" >
<view class="" @click="itemClick(item,index)">
<view class="title">
<view class="title-txt">
{{item.describes}}
</view>
<u-tag text="待接单" v-if="item.status == 'PENDING'" bg-color='rgba(255,255,255,0)' color='#fe8463' border-color='#fe8463' type="primary" shape='circle'/>
<u-tag text="已撤回" v-else-if="item.status=='REJECTED'" bg-color='rgba(255,255,255,0)' color='#d7d7d7' border-color='#d7d7d7 ' type="warning" shape='circle'/>
<u-tag text="已转办" v-else-if="item.status=='TRANSFERRED'" bg-color='rgba(255,255,255,0)' color='#e01f54' border-color='#e01f54' type="success" shape='circle'/>
<u-tag text="已接单" v-else-if="item.status=='PECEIVED'" bg-color='rgba(255,255,255,0)' color='#005eaa' border-color='#005eaa ' type="error" shape='circle'/>
<u-tag text="已验证" v-else-if="item.status=='VERIFIED'" bg-color='rgba(255,255,255,0)' color='#2EC7C9' border-color='#2EC7C9' type="info" shape='circle'/>
<u-tag text="已完成" v-else-if="item.status=='COMPLETED'" bg-color='rgba(255,255,255,0)' color='#2ba471' border-color='#2ba471' type="info" shape='circle'/>
</view>
<view class="dec">
保养单号:<span>{{item.number}}</span>
</view>
<view class="dec">
保养计划单号:<span>{{item.planNumber}}</span>
</view>
<view class="dec">
{{`${params.type=='DEVICE'?'设备' : '模具'}`}}编号:<span>{{item.deviceNumber}}</span>
</view>
<view class="dec">
{{`${params.type=='DEVICE'?'设备' : '模具'}`}}名称:<span>{{item.name}}</span>
</view>
<view class="dec">
所属厂区:<span>{{item.factoryAreaName}}</span>
</view>
<view class="dec">
故障类型:<span>{{item.faultTypeName}}</span>
</view>
</view>
<view class="bottom">
<view class="time" style="flex: 1;">
{{`${$time.formatDate(item.createTime)}`}}
</view>
</view>
</view>
</view>
<view style="height: 94rpx;padding-top: 30rpx;">
<u-loadmore :status="status" v-if="status != 'loadmore'" />
</view>
<view style="height: constant(safe-area-inset-bottom); height: env(safe-area-inset-bottom);"></view>
</view>
</template>
<script setup lang="ts">
import {
onLoad,
onShow,
onReachBottom
} from '@dcloudio/uni-app'
import {
ref,
getCurrentInstance
} from 'vue'
import * as upkeepOrderApi from "@/api/upkeepOrder.js"
const { proxy } = getCurrentInstance()
const params = ref({
pageNo: 1,
pageSize: 10,
type: '',
})
const status = ref('loadmore') //
const list = ref([])
function itemClick(item, index) {
proxy.$tab.navigateTo(`/pages/upkeepOrder/detail?type=${params.value.type}&data=${encodeURIComponent(JSON.stringify(item))}`)
}
function addForm(item) {
proxy.$tab.navigateTo(`/pages/upkeepOrder/addForm?type=${params.value.type}&data=${encodeURIComponent(JSON.stringify(item))}`)
}
async function getList() {
if (status.value == 'nomore') return;
status.value = 'loading';
proxy.$modal.loading('加载中')
await upkeepOrderApi.upkeepOrderPage(params.value).then((res) => {
proxy.$modal.closeLoading()
if (res.data.list.length > 0) {
list.value = list.value.concat(res.data.list);
params.value.pageNo++;
status.value = 'loadmore'
} else {
status.value = 'nomore'
}
}).catch(() => {
proxy.$modal.closeLoading()
})
}
onLoad((option) => {
if (option.type) params.value.type = option.type;
})
onShow(() => {
params.value.pageNo = 1
list.value = []
status.value = 'loadmore'
getList()
})
onReachBottom(() => {
getList()
})
</script>
<style lang="scss" scoped>
.container{
background: #f5f5f5;
min-height: 100vh;
}
.list {
background: #f5f5f5;
margin-top: 20rpx;
.item {
padding: 30rpx 30rpx 0px 30rpx;
margin-top: 20rpx;
background: white;
.title {
display: flex;
align-items: center;
padding-bottom: 20rpx;
.title-txt {
color: #409eff;
font-weight: bold;
font-size: 36rpx;
width: 0px;
flex: 1;
}
.time {
color: #919191;
}
}
.dec {
padding-bottom: 20rpx;
span {
color: #999999;
}
}
.last {
padding-bottom: 30rpx;
}
.bottom {
display: flex;
justify-content: space-between;
align-items: center;
border-top: 1px solid #E4E4E4;
padding: 20rpx 0px;
}
}
}
.list {
background: #f5f5f5;
margin-top: 20rpx;
.item {
padding: 30rpx 30rpx 0px 30rpx;
margin-top: 20rpx;
background: white;
.title {
display: flex;
align-items: center;
padding-bottom: 20rpx;
.title-txt {
color: #409eff;
font-weight: bold;
font-size: 36rpx;
width: 0px;
flex: 1;
}
.time {
color: #919191;
}
}
.dec {
padding-bottom: 20rpx;
span {
color: #999999;
}
}
.last {
padding-bottom: 30rpx;
}
.bottom {
display: flex;
justify-content: space-between;
align-items: center;
border-top: 1px solid #E4E4E4;
padding: 20rpx 0px;
position: relative;
.button {
position: absolute;
right: 0rpx;
}
}
}
}
</style>

228
src/pages/upkeepOrder/myOrder.vue

@ -0,0 +1,228 @@
<template>
<!-- 保养工单 -->
<view class="container">
<u-navbar back-icon-color='#fff' :background="{ background: '#409eff'}" back-text="" title-color='#fff'
title="保养工单">
</u-navbar>
<view class="list">
<view class="item" v-for="(item,index) in list" :key="index">
<view class="">
<view class="title">
<view class="title-txt">
{{item.describes}}
</view>
<u-tag text="待接单" v-if="item.status == 'PENDING'" bg-color='rgba(255,255,255,0)' color='#fe8463'
border-color='#fe8463' type="primary" shape='circle' />
<u-tag text="已撤回" v-else-if="item.status=='REJECTED'" bg-color='rgba(255,255,255,0)'
color='#d7d7d7' border-color='#d7d7d7 ' type="warning" shape='circle' />
<u-tag text="已转办" v-else-if="item.status=='TRANSFERRED'" bg-color='rgba(255,255,255,0)'
color='#e01f54' border-color='#e01f54' type="success" shape='circle' />
<u-tag text="已接单" v-else-if="item.status=='PECEIVED'" bg-color='rgba(255,255,255,0)'
color='#005eaa' border-color='#005eaa ' type="error" shape='circle' />
<u-tag text="已验证" v-else-if="item.status=='VERIFIED'" bg-color='rgba(255,255,255,0)'
color='#2EC7C9' border-color='#2EC7C9' type="info" shape='circle' />
<u-tag text="已完成" v-else-if="item.status=='COMPLETED'" bg-color='rgba(255,255,255,0)'
color='#2ba471' border-color='#2ba471' type="info" shape='circle' />
</view>
<view class="dec">
保养单号:<span>{{item.number}}</span>
</view>
<view class="dec">
保养计划单号:<span>{{item.planNumber}}</span>
</view>
<view class="dec">
{{`${item.type=='DEVICE'?'设备' : '模具'}`}}编号:<span>{{item.deviceNumber}}</span>
</view>
<view class="dec">
{{`${item.type=='DEVICE'?'设备' : '模具'}`}}名称:<span>{{item.name}}</span>
</view>
<view class="dec">
所属厂区:<span>{{item.factoryAreaName}}</span>
</view>
<view class="dec">
故障类型:<span>{{item.faultTypeName}}</span>
</view>
<view class="dec">
完成时间:<span>{{$time.formatDate(item.completionTime)}}</span>
</view>
</view>
<view class="bottom">
<view class="time" style="flex: 1;">
{{`${$time.formatDate(item.createTime)}`}}
</view>
</view>
</view>
</view>
<view style="height: 94rpx;padding-top: 30rpx;">
<u-loadmore :status="status" v-if="status != 'loadmore'" />
</view>
<view style="height: constant(safe-area-inset-bottom); height: env(safe-area-inset-bottom);"></view>
</view>
</template>
<script setup lang="ts">
import {
onLoad,
onShow,
onReachBottom
} from '@dcloudio/uni-app'
import {
ref,
getCurrentInstance
} from 'vue'
import * as upkeepOrderApi from "@/api/upkeepOrder.js"
const { proxy } = getCurrentInstance()
const params = ref({
pageNo: 1,
pageSize: 10,
flag: 1
})
const status = ref('loadmore') //
const list = ref([])
async function getList() {
if (status.value == 'nomore') return;
status.value = 'loading';
proxy.$modal.loading('加载中')
await upkeepOrderApi.upkeepOrderPage(params.value).then((res) => {
proxy.$modal.closeLoading()
if (res.data.list.length > 0) {
list.value = list.value.concat(res.data.list);
params.value.pageNo++;
status.value = 'loadmore'
} else {
status.value = 'nomore'
}
}).catch(() => {
proxy.$modal.closeLoading()
})
}
onLoad((option) => {
if (option.type) params.value.type = option.type;
})
onShow(() => {
params.value.pageNo = 1
list.value = []
status.value = 'loadmore'
getList()
})
onReachBottom(() => {
getList()
})
</script>
<style lang="scss" scoped>
.container {
background: #f5f5f5;
min-height: 100vh;
}
.list {
background: #f5f5f5;
margin-top: 20rpx;
.item {
padding: 30rpx 30rpx 0px 30rpx;
margin-top: 20rpx;
background: white;
.title {
display: flex;
align-items: center;
padding-bottom: 20rpx;
.title-txt {
color: #409eff;
font-weight: bold;
font-size: 36rpx;
width: 0px;
flex: 1;
}
.time {
color: #919191;
}
}
.dec {
padding-bottom: 20rpx;
span {
color: #999999;
}
}
.last {
padding-bottom: 30rpx;
}
.bottom {
display: flex;
justify-content: space-between;
align-items: center;
border-top: 1px solid #E4E4E4;
padding: 20rpx 0px;
}
}
}
.list {
background: #f5f5f5;
margin-top: 20rpx;
.item {
padding: 30rpx 30rpx 0px 30rpx;
margin-top: 20rpx;
background: white;
.title {
display: flex;
align-items: center;
padding-bottom: 20rpx;
.title-txt {
color: #409eff;
font-weight: bold;
font-size: 36rpx;
width: 0px;
flex: 1;
}
.time {
color: #919191;
}
}
.dec {
padding-bottom: 20rpx;
span {
color: #999999;
}
}
.last {
padding-bottom: 30rpx;
}
.bottom {
display: flex;
justify-content: space-between;
align-items: center;
border-top: 1px solid #E4E4E4;
padding: 20rpx 0px;
position: relative;
.button {
position: absolute;
right: 0rpx;
}
}
}
}
</style>

60
src/plugins/auth.js

@ -0,0 +1,60 @@
import store from '@/store'
function authPermission(permission) {
const all_permission = "*:*:*"
const permissions = store.getters && store.getters.permissions
if (permission && permission.length > 0) {
return permissions.some(v => {
return all_permission === v || v === permission
})
} else {
return false
}
}
function authRole(role) {
const super_admin = "admin"
const roles = store.getters && store.getters.roles
if (role && role.length > 0) {
return roles.some(v => {
return super_admin === v || v === role
})
} else {
return false
}
}
export default {
// 验证用户是否具备某权限
hasPermi(permission) {
return authPermission(permission)
},
// 验证用户是否含有指定权限,只需包含其中一个
hasPermiOr(permissions) {
return permissions.some(item => {
return authPermission(item)
})
},
// 验证用户是否含有指定权限,必须全部拥有
hasPermiAnd(permissions) {
return permissions.every(item => {
return authPermission(item)
})
},
// 验证用户是否具备某角色
hasRole(role) {
return authRole(role)
},
// 验证用户是否含有指定角色,只需包含其中一个
hasRoleOr(roles) {
return roles.some(item => {
return authRole(item)
})
},
// 验证用户是否含有指定角色,必须全部拥有
hasRoleAnd(roles) {
return roles.every(item => {
return authRole(item)
})
}
}

17
src/plugins/index.js

@ -0,0 +1,17 @@
import tab from './tab'
// import auth from './auth'
import modal from './modal'
import time from './time'
export default {
install(app) {
// 页签操作
app.config.globalProperties.$tab = tab
// 认证对象
// Vue.prototype.$auth = auth
// 模态框对象
app.config.globalProperties.$modal = modal
// 时间对象
app.config.globalProperties.$time = time
}
}

73
src/plugins/modal.js

@ -0,0 +1,73 @@
export default {
// 消息提示
msg(content) {
uni.showToast({
title: content,
icon: 'none'
})
},
// 错误消息
msgError(content) {
uni.showToast({
title: content,
icon: 'error'
})
},
// 成功消息
msgSuccess(content) {
uni.showToast({
title: content,
icon: 'success'
})
},
// 隐藏消息
hideMsg(content) {
uni.hideToast()
},
// 弹出提示
alert(content) {
uni.showModal({
title: '提示',
content: content,
showCancel: false
})
},
// 确认窗体
confirm(content,confirmText,cancelText) {
return new Promise((resolve, reject) => {
uni.showModal({
title: '系统提示',
content: content,
cancelText: cancelText||'取消',
confirmText: confirmText || '确定',
success: function(res) {
if (res.confirm) {
resolve(res.confirm)
}
}
})
})
},
// 提示信息
showToast(option) {
if (typeof option === "object") {
uni.showToast(option)
} else {
uni.showToast({
title: option,
icon: "none",
duration: 2500
})
}
},
// 打开遮罩层
loading(content) {
uni.showLoading({
title: content,
})
},
// 关闭遮罩层
closeLoading() {
uni.hideLoading()
}
}

32
src/plugins/tab.js

@ -0,0 +1,32 @@
export default {
// 关闭所有页面,打开到应用内的某个页面
reLaunch(url) {
return uni.reLaunch({
url: url
})
},
// 跳转到tabBar页面,并关闭其他所有非tabBar页面
switchTab(url) {
return uni.switchTab({
url: url
})
},
// 关闭当前页面,跳转到应用内的某个页面
redirectTo(url) {
return uni.redirectTo({
url: url
})
},
// 保留当前页面,跳转到应用内的某个页面
navigateTo(url) {
return uni.navigateTo({
url: url
})
},
// 关闭当前页面,返回上一页面或多级页面
navigateBack(level) {
return uni.navigateBack({
delta:level
})
}
}

19
src/plugins/time.js

@ -0,0 +1,19 @@
export default {
formatDate(timestamp){
// 获取当前时间戳(单位:毫秒)
// var timestamp = Date.now(); // 或者传入特定的时间戳值
timestamp = timestamp ? timestamp :Date.now()
// 创建Date对象并设置时间戳
var dateObj = new Date(timestamp);
// 提取年份、月份、日期等信息
var year = dateObj.getFullYear();
var month = (dateObj.getMonth() + 1).toString().padStart(2, '0'); // 注意月份从0开始计数,所以需要加1
var day = dateObj.getDate().toString().padStart(2, '0');
var hour = dateObj.getHours().toString().padStart(2, '0');
var minutes = dateObj.getMinutes().toString().padStart(2, '0');
var seconds = dateObj.getSeconds().toString().padStart(2, '0');
return `${year}-${month}-${day} ${hour}:${minutes}:${seconds}`
}
}

BIN
src/static/icon/screen.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

BIN
src/static/images/banner/icon1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

BIN
src/static/images/banner/icon2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

BIN
src/static/images/banner/icon3.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
src/static/images/banner/icon4.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
src/static/images/banner/icon5.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
src/static/images/banner/icon6.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
src/static/images/banner/icon7.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

12
src/static/images/banner/login_banner.svg

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" width="47px" height="66px" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient gradientUnits="userSpaceOnUse" x1="5.63807152481269" y1="62.1175381975164" x2="43.4328694937704" y2="1.76792360964131" id="LinearGradient40">
<stop id="Stop41" stop-color="#09005d" offset="0" />
<stop id="Stop42" stop-color="#1a0f91" offset="1" />
</linearGradient>
</defs>
<g transform="matrix(1 0 0 1 -97 -106 )">
<path d="M 36.7877623440973 1.59223308620249 C 37.7932710870804 0.0521044544140052 39.8698652301974 -0.408494762569467 41.450991297062 0.55588484798968 L 45.378304430887 2.95244014885682 C 46.9594304977516 3.91681975941597 47.4694711644821 5.96072878478014 46.5222527834112 7.54403859316083 L 11.8977778076482 65.9393830713469 L 0.95376235865917 59.2534975623212 C 0.0648343395002736 58.7137328549186 -0.197472289103991 57.5550379496946 0.37814503477759 56.6914144178506 L 36.7877623440973 1.59223308620249 Z " fill-rule="nonzero" fill="url(#LinearGradient40)" stroke="none" transform="matrix(1 0 0 1 97 106 )" />
</g>
</svg>

BIN
src/static/images/banner/logo-banner.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

6
src/static/images/banner/u2335.svg

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" width="37px" height="37px" xmlns="http://www.w3.org/2000/svg">
<g transform="matrix(1 0 0 1 -200 -131 )">
<path d="M 1.8705291643251 26.4306710705829 C 0.0206628251877919 22.5581882283421 -0.41841050822613 18.2538299761859 0.58210085807772 14.1438156584916 C 0.733257251548091 13.5319921611116 0.91320533901281 12.9273665872301 1.12194512047189 12.3299389368472 C 1.1867264319592 12.1427929258839 1.25870566694509 11.9556469149206 1.33068490193098 11.7685009039573 C 1.69058107686042 10.8471666961379 2.12245648677576 9.95462418231291 2.6191132081784 9.11246713297802 C 2.62631113167697 9.09807128598083 2.63350905517557 9.09087336248225 2.64070697867417 9.07647751548507 C 2.66230074916992 9.04048789799212 2.67669659616711 9.01169620399777 2.69829036666286 8.97570658650483 C 2.73427998415581 8.91092527501753 2.77746752514735 8.84614396353023 2.81345714264029 8.78856057554152 C 2.91422807162054 8.62300833507397 3.10857200608242 8.55102910008808 3.28852009354714 8.59421664107961 C 3.33170763453868 8.6014145645782 3.37489517553022 8.62300833507396 3.41808271652174 8.64460210556974 C 3.62682249798082 8.77416472854433 3.68440588596954 9.04048789799212 3.56204118649352 9.2492276794512 C 2.90703014812193 10.3073224337438 2.36718588572777 11.4445943465208 1.9497063228096 12.6250538002894 C -0.130493568282595 18.4985593751379 1.1147471969733 24.7535548954117 4.69211517577197 29.3314342405142 C 6.67874206138249 31.8794991590147 9.39235922035051 33.9093135856167 12.6602164887099 35.060981345391 C 13.236050368597 35.2625232033514 13.8118842484841 35.4352733673176 14.3949160518698 35.5792318372894 C 18.3105864351022 36.5365556626017 22.4062049057992 36.1190760996835 26.0987396605753 34.3555848425293 C 30.3383166012442 32.3329683394258 33.5341946346176 28.7843920546214 35.0961440338114 24.3576691029893 C 38.3280116846779 15.2163062597814 33.5269967111191 5.15360920875412 24.3856338679112 1.9217415578877 C 23.8241958350213 1.72019969992721 23.2483619551341 1.55464745945966 22.672528075247 1.41068898948788 C 20.1748486212367 0.798865492107825 17.5692003147475 0.748480027617699 15.0427291667428 1.25953259601752 C 14.9779478552555 1.27392844301469 14.9131665437682 1.27392844301469 14.8555831557795 1.25233467251892 C 14.6972288388105 1.21634505502598 14.5676662158359 1.08678243205138 14.531676598343 0.914032268085244 C 14.4812911338529 0.676500792631811 14.6396454508218 0.446167240676965 14.8771769262753 0.395781776186839 C 17.526012773756 -0.144062486207328 20.2612237032198 -0.0864790982186222 22.8884657802047 0.554136093155797 C 23.4930913540862 0.698094563127572 24.090519004469 0.8780426505923 24.6879466548519 1.08678243205138 C 34.2827786784709 4.47700439988675 39.3213251274832 15.0507540193138 35.9311031596477 24.6383881194342 C 34.2899766019695 29.2882466995226 30.9285463281285 33.0095731482931 26.4802296060006 35.1329605803768 C 22.6077467637597 36.9828269195142 18.3105864351022 37.4219002529281 14.1933741939093 36.4213888866243 C 13.5815506965292 36.2702324931539 12.9769251226478 36.0902844056892 12.3722995487663 35.8815446242301 C 7.7224409686779 34.2404180665518 3.99391659640884 30.8789877927108 1.8705291643251 26.4306710705829 Z " fill-rule="nonzero" fill="#ffffff" stroke="none" transform="matrix(1 0 0 1 200 131 )" />
</g>
</svg>

6
src/static/images/banner/u2450.svg

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" width="26px" height="30px" xmlns="http://www.w3.org/2000/svg">
<g transform="matrix(1 0 0 1 -47 -440 )">
<path d="M 0 5.43375 C 0 4.39821609406726 0.831471178885669 3.55875 1.85714285714286 3.55875 L 4.667 3.55875 L 4.667 9 L 20.6142857142857 9 L 20.6142857142857 3.55875 L 24.1428571428571 3.55875 C 25.1685288211143 3.55875 26 4.39821609406726 26 5.43375 L 26 28.125 C 26 29.1605339059327 25.1685288211143 30 24.1428571428571 30 L 1.85714285714286 30 C 0.831471178885669 30 0 29.1605339059327 0 28.125 L 0 5.43375 Z M 6.68571428571429 7.213125 L 6.68571428571429 2.638125 L 8.54657142857143 2.638125 C 8.54657142857143 1.18125 9.71657142857143 0 11.1614285714286 0 L 14.1328571428571 0 C 15.5758571428571 0 16.7458571428571 1.18125 16.7458571428571 2.638125 L 18.5714285714286 2.638125 L 18.5714285714286 7.213125 L 6.68571428571429 7.213125 Z M 10.8958571428571 3.178125 C 10.8958571428571 4.231875 11.726 5.085 12.753 5.085 C 13.7781428571429 5.085 14.6101428571429 4.231875 14.6101428571429 3.178125 C 14.6101428571429 2.124375 13.7781428571429 1.27125 12.753 1.27125 C 11.726 1.27125 10.8958571428571 2.124375 10.8958571428571 3.178125 Z M 21.7898571428571 12 L 4.21014285714286 12 L 4.21014285714286 14 L 21.7898571428571 14 L 21.7898571428571 12 Z M 4.21014285714286 15.76125 L 4.21014285714286 15.763125 L 4.21014285714286 17.5425 L 8.17142857142857 17.5425 L 8.17142857142857 15.76125 L 4.21014285714286 15.76125 Z M 4.21014285714286 19.83 L 4.21014285714286 19.831875 L 4.21014285714286 21.609375 L 8.17142857142857 21.609375 L 8.17142857142857 19.83 L 4.21014285714286 19.83 Z M 4.21014285714286 23.896875 L 4.21014285714286 23.89875 L 4.21014285714286 25.678125 L 9.16128571428571 25.678125 L 9.16128571428571 23.896875 L 4.21014285714286 23.896875 Z M 19.1007142857143 22.936875 C 18.6304250353497 23.601697854168 18.054348350795 24.1833137376127 17.3958571428571 24.658125 C 17.3499258944188 24.6907879240536 17.3226001725233 24.743965009545 17.3226001725233 24.800686363582 C 17.3226001725233 24.8471234159694 17.3409461471698 24.8916424010547 17.3735714285714 24.924375 L 19.955 27.530625 C 20.0943364195914 27.6714577822726 20.2834102728407 27.7505899923118 20.4805714285714 27.7505899923118 C 20.6777325843022 27.7505899923118 20.8668064375515 27.6714577822726 21.0061428571429 27.530625 L 21.9495714285714 26.578125 C 22.0890629462509 26.4374488071433 22.1674415161946 26.2465569360743 22.1674415161946 26.0475 C 22.1674415161946 25.8484430639257 22.0890629462509 25.6575511928567 21.9495714285714 25.516875 L 19.3718571428571 22.914375 C 19.3384169107129 22.8805790204336 19.2930418828892 22.8615897586197 19.2457262895471 22.8615897586197 C 19.1881881961978 22.8615897586197 19.1341869943616 22.8896253240047 19.1007142857143 22.936875 Z M 14.759255467994 24.5140374791424 C 15.8204396264006 24.5140374791424 16.8379731597654 24.0875460419895 17.5871428571429 23.32875 C 18.3393810181837 22.5713714085468 18.7621586915612 21.5428888032805 18.7621586915612 20.4703129946648 C 18.7621586915612 19.4014123902587 18.3422653206105 18.3761442986165 17.5945714285714 17.619375 C 16.4639051022835 16.4793931723658 14.7689506313882 16.1297666636769 13.286 16.730625 C 13.2322852506052 16.7522006308877 13.1970325664254 16.804665558827 13.1970325664254 16.8630310876505 C 13.1970325664254 16.9004978712548 13.2116477538362 16.9364572975827 13.2377142857143 16.963125 L 14.4857142857143 18.223125 C 14.702965366557 18.4427381600805 14.702965366557 18.7985118399195 14.4857142857143 19.018125 L 13.2637142857143 20.251875 C 13.1592443813362 20.3572532390508 13.017609951532 20.4164460384021 12.8699345449049 20.4164460384021 C 12.7186473849234 20.4164460384021 12.5738649451232 20.3543311831856 12.4688571428571 20.244375 L 11.2524285714286 18.97125 C 11.228278977567 18.9459814310735 11.1949935626667 18.9317087237978 11.160214266276 18.9317087237978 C 11.1072954788903 18.9317087237978 11.0598197467671 18.9645509214797 11.0407142857143 19.014375 C 10.8594350431001 19.4823089185733 10.7663983251369 19.9803341788901 10.7663983251369 20.4827874791424 C 10.7663983251369 22.7091853768978 12.5540613597411 24.5140374791424 14.759255467994 24.5140374791424 Z M 21.0771333988002 25.9865625 C 21.0771333988002 26.1605123044669 21.0088694902987 26.3273761781034 20.8872857142857 26.450625 C 20.7650596956061 26.5745248598445 20.5989889589728 26.6441731430195 20.4257857142857 26.6441731430195 C 20.0660563212907 26.6441731430195 19.7744380297712 26.3497508294661 19.7744380297712 25.9865625 C 19.7744380297712 25.8126126955331 19.8427019382728 25.6457488218966 19.9642857142857 25.5225 C 20.0865117329653 25.3986001401555 20.2525824695986 25.3289518569805 20.4257857142857 25.3289518569805 C 20.7855151072807 25.3289518569805 21.0771333988002 25.6233741705339 21.0771333988002 25.9865625 Z " fill-rule="nonzero" fill="#9bca63" stroke="none" transform="matrix(1 0 0 1 47 440 )" />
</g>
</svg>

6
src/static/images/banner/u253_selected.svg

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" width="20px" height="18px" xmlns="http://www.w3.org/2000/svg">
<g transform="matrix(1 0 0 1 -30 -16 )">
<path d="M 19.7374790983607 8.04830870454546 C 19.9665962704918 7.76331261818182 19.9137230737705 7.351651575 19.6317327254098 7.12646946818182 L 11.2566194672131 0.571559031818182 C 10.5410689754098 0.00508528636363643 9.42015733606558 0.00508528636363643 8.70460684426229 0.571559031818182 L 0.392941434426229 7.12998793636364 C 0.107426209016393 7.35517004318182 0.0616027868852459 7.76683108636364 0.28367018442623 8.048308725 C 0.505737581967213 8.32978636363636 0.921673340163934 8.37904493863636 1.20366368852459 8.1573813 L 1.47155450819672 7.94627306590909 L 1.47155450819672 15.8733869727273 C 1.47155450819672 16.9957790386364 2.63828956967213 17.8366934863636 3.68165383196721 17.8366934863636 L 16.7942048770492 17.8366934863636 C 17.8234696311475 17.8366934863636 18.5178708606557 17.0485561022727 18.5178708606557 15.8733869727273 L 18.5178708606557 7.92516225681818 L 18.8139607172131 8.1573813 C 18.9338066188525 8.25238000227273 19.0748017827869 8.29812010909091 19.2193218442623 8.29812010909091 C 19.413190204918 8.29812010909091 19.6070585655738 8.21367681136364 19.7374790983607 8.04830870454546 Z M 11.9651202254098 15.1591374818182 L 11.9651202254098 16.5243040159091 L 10.6538651229508 16.5243040159091 L 9.3426100204918 16.5243040159091 L 8.03135491803279 16.5243040159091 L 8.03135491803279 15.1591374818182 L 8.03135491803279 12.8615762863636 C 8.03135491803279 12.1015866681818 8.64820879098361 11.28178305 9.99823758196722 11.28178305 C 11.3517912295082 11.28178305 11.9651202459016 12.1015866681818 11.9651202459016 12.8615762863636 L 11.9651202254098 15.1591374818182 Z " fill-rule="nonzero" fill="#0052d9" stroke="none" transform="matrix(1 0 0 1 30 16 )" />
</g>
</svg>

BIN
src/static/images/bg.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 KiB

BIN
src/static/images/default.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

1
src/static/images/icon1.svg

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="86" height="86" viewBox="0 0 86 86"><g><g><ellipse cx="43" cy="43" rx="43" ry="43" fill="#DAF9F4" fill-opacity="1"/></g><g><g><g><path d="M24.384619999999998,20L61.6154,20C63.5333,20,65,21.48571,65,23.42857L65,64.5714C65,66.51429999999999,63.5333,68,61.6154,68L24.384619999999998,68C22.46667,68,21,66.51429999999999,21,64.5714L21,23.42857C21,21.48571,22.46667,20,24.384619999999998,20Z" fill="#09D3B6" fill-opacity="1"/></g><g><path d="M37.85714,16.469839999999998C38.08571,14.01143,40.371430000000004,12,43,12C45.6286,12,47.8,14.01143,48.1429,16.469839999999998L52.7143,16.469839999999998C53.9714,16.469839999999998,55,17.47556,55,18.70476L55,22.0571C55,23.2863,53.9714,24.292099999999998,52.7143,24.292099999999998L33.28571,24.292099999999998C32.02857,24.292099999999998,31,23.2863,31,22.0571L31,18.70476C31,17.47556,32.02857,16.469839999999998,33.28571,16.469839999999998L37.85714,16.469839999999998Z" fill="#A5ECE2" fill-opacity="1"/></g><g><rect x="28" y="30" width="30" height="3" rx="1.5" fill="#A5ECE2" fill-opacity="1"/></g><g><rect x="28" y="39" width="30" height="3" rx="1.5" fill="#A5ECE2" fill-opacity="1"/></g><g><rect x="28" y="48" width="12" height="3" rx="1.5" fill="#A5ECE2" fill-opacity="1"/></g><g><rect x="28" y="57" width="12" height="3" rx="1.5" fill="#A5ECE2" fill-opacity="1"/></g></g><g><path d="M55.0518,55.0411C54.9959,55.1612,54.9345,55.28009,54.8672,55.39658L53.3279,58.085499999999996C55.0584,57.417699999999996,56.4,57.7078,57.3516,58.9561C57.4707,59.1125,57.4106,59.340199999999996,57.2301,59.4161L49.82228,62.5283C47.93876,63.438199999999995,45.6871,63.004999999999995,44.26822,61.4596C42.84935,59.9142,42.594156,57.6171,43.638749,55.79348L46.61558,50.593469999999996L48.69979,46.952854C49.03085,46.383296,49.75577,46.190005,50.32276,46.520105C50.88976,46.850204,51.08619,47.5799,50.76255,48.15378L51.65578,46.593775C51.986869999999996,46.0242674,52.71176,45.831011,53.2787,46.161094C53.8457,46.491177,54.0421,47.22083,53.7185,47.7947L54.314,46.754699C54.6451,46.185189,55.37,45.99193163,55.937,46.322016C56.5039,46.652101,56.7004,47.38175,56.3768,47.95563L55.7813,48.99563C56.1124,48.42603,56.8373,48.2327,57.4043,48.56281C57.9713,48.89293,58.1678,49.62267,57.8441,50.19656L55.1644,54.876580000000004C55.131,54.93542,55.0929,54.99066,55.0512,55.0411L55.0518,55.0411Z" fill="#A5ECE2" fill-opacity="1"/></g></g></g></svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

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

Loading…
Cancel
Save