@ -0,0 +1,6 @@
|
||||
.history/ |
||||
.idea |
||||
.vscode |
||||
|
||||
/node_modules/ |
||||
/unpackage/ |
||||
@ -0,0 +1,82 @@
|
||||
<script> |
||||
import { |
||||
mapMutations |
||||
} from 'vuex' |
||||
import { |
||||
version |
||||
} from './package.json' |
||||
|
||||
|
||||
import store from '@/store' |
||||
|
||||
import { getToken, setToken } from '@/common/auth' |
||||
import { login } from '@/api/auth' |
||||
|
||||
export default { |
||||
onLaunch: async function() { |
||||
const url = 'http://127.0.0.1:8080/app/'; |
||||
//--------------------------------------------------------------- |
||||
// #ifdef H5 |
||||
if (!store.state.requestUrl) { |
||||
store.commit('setRequestUrl', url + 'forward') |
||||
} |
||||
if (!getToken() || !store.state.hasLogin) { |
||||
const userData = await login({ empNo: '012893' }); |
||||
setToken(userData.token); |
||||
store.commit('setUser', userData.user) |
||||
} |
||||
// #endif |
||||
}, |
||||
onShow: function() { |
||||
console.log('App Show') |
||||
}, |
||||
onHide: function() { |
||||
console.log('App Hide') |
||||
}, |
||||
globalData: { |
||||
test: '' |
||||
}, |
||||
methods: { |
||||
...mapMutations(['setUniverifyErrorMsg', 'setUniverifyLogin']) |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss"> |
||||
@import '@/uni_modules/uni-scss/index.scss'; |
||||
/* #ifndef APP-PLUS-NVUE */ |
||||
/* uni.css - 通用组件、模板样式库,可以当作一套ui库应用 */ |
||||
@import './common/uni.scss'; |
||||
@import '@/static/customicons.css'; |
||||
/* H5 兼容 pc 所需 */ |
||||
/* #ifdef H5 */ |
||||
@media screen and (min-width: 768px) { |
||||
body { |
||||
overflow-y: scroll; |
||||
} |
||||
} |
||||
|
||||
uni-page-body { |
||||
min-height: 100% !important; |
||||
height: auto !important; |
||||
} |
||||
|
||||
.uni-top-window uni-tabbar .uni-tabbar { |
||||
background-color: #fff !important; |
||||
} |
||||
|
||||
.uni-app--showleftwindow .hideOnPc { |
||||
display: none !important; |
||||
} |
||||
|
||||
/* #endif */ |
||||
|
||||
/* 以下样式用于 hello uni-app 演示所需 */ |
||||
page { |
||||
height: 100%; |
||||
font-size: 28rpx; |
||||
/* line-height: 1.8; */ |
||||
} |
||||
|
||||
/* #endif*/ |
||||
</style> |
||||
@ -0,0 +1,129 @@
|
||||
# hello-uniapp |
||||
|
||||
`uni-app`框架示例,一套代码,同时发行到iOS、Android、H5、小程序等多个平台,请使用手机在下方扫码快速体验`uni-app`的强大功能。[官方文档](https://uniapp.dcloud.net.cn/) |
||||
|
||||
## 快速上手 |
||||
hello-uniapp 示例工程可以通过两种方式创建, 一种是 HBuilderX, 配套 IDE,集成开发;另一种是 CLI 创建;推荐前者。 |
||||
### 通过 HBuilderX 可视化界面创建(推荐) |
||||
|
||||
可视化的方式比较简单,HBuilderX内置相关环境,开箱即用,无需配置nodejs。 |
||||
|
||||
开始之前,开发者需先下载安装如下工具: |
||||
|
||||
- HBuilderX:[官方IDE下载地址](https://www.dcloud.io/hbuilderx.html) |
||||
|
||||
HBuilderX是通用的前端开发工具,但为`uni-app`做了特别强化,请下载App开发版。 |
||||
|
||||
由于截图在 github 不便浏览,参见官方文档 [HBuilderX 可视化界面创建](https://uniapp.dcloud.net.cn/quickstart?id=_1-%e9%80%9a%e8%bf%87-hbuilderx-%e5%8f%af%e8%a7%86%e5%8c%96%e7%95%8c%e9%9d%a2) |
||||
|
||||
### 通过 vue-cli 创建 |
||||
|
||||
``` |
||||
npm install -g @vue/cli |
||||
``` |
||||
|
||||
#### 创建uni-app |
||||
|
||||
**使用正式版**(对应HBuilderX最新正式版) |
||||
|
||||
``` |
||||
vue create -p dcloudio/uni-preset-vue my-project |
||||
``` |
||||
|
||||
**使用alpha版**(对应HBuilderX最新alpha版) |
||||
|
||||
``` |
||||
vue create -p dcloudio/uni-preset-vue#alpha my-alpha-project |
||||
``` |
||||
|
||||
此时,会提示选择项目模板,选择 `hello uni-app` 项目模板,如下所示: |
||||
|
||||
<div> |
||||
<img src="https://img.cdn.aliyun.dcloud.net.cn/guide/uniapp/h5-cli-01.png" width="300"> |
||||
</div> |
||||
|
||||
创建好后,进入项目目录 |
||||
``` |
||||
cd my-project |
||||
``` |
||||
|
||||
执行该命令运行到 h5 端 |
||||
``` |
||||
npm run dev:h5 |
||||
``` |
||||
|
||||
欢迎提 issues,推荐到[官方社区](https://ask.dcloud.net.cn/explore/)提问。 |
||||
|
||||
## 扫码体验 |
||||
|
||||
<div class="quick"> |
||||
<p>一套代码编到10个平台,这不是梦想。眼见为实,扫描10个二维码,亲自体验最全面的跨平台效果!</p> |
||||
<div style="display: flex;"> |
||||
<a href="//m3w.cn/uniapp" target="_blank" class="clear-style barcode-view"> |
||||
<div class="barcode-img-box"> |
||||
<img src="https://web-assets.dcloud.net.cn/unidoc/zh/uni-android.png" width="160" /> |
||||
</div> |
||||
<b>Android版</b> |
||||
</a> |
||||
<a href="https://itunes.apple.com/cn/app/hello-uni-app/id1417078253?mt=8" target="_blank" class="clear-style barcode-view"> |
||||
<div class="barcode-img-box"> |
||||
<img src="https://web-assets.dcloud.net.cn/unidoc/zh/uni-h5.png" width="160" /> |
||||
</div> |
||||
<b>iOS版</b> |
||||
</a> |
||||
<a href="https://hellouniapp.dcloud.net.cn/" target="_blank" class="clear-style barcode-view"> |
||||
<div class="barcode-img-box"> |
||||
<img src="https://img.cdn.aliyun.dcloud.net.cn/guide/uniapp/uni-h5-hosting-qr.png" width="160" /> |
||||
</div> |
||||
<b>H5版</b> |
||||
</a> |
||||
<a href="//m3w.cn/uniapp" target="_blank" class="clear-style barcode-view"> |
||||
<div class="barcode-img-box"><img src="//img.cdn.aliyun.dcloud.net.cn/guide/uniapp/gh_33446d7f7a26_430.jpg" width="160" /></div> |
||||
<b>微信小程序版</b> |
||||
</a> |
||||
<a href="//m3w.cn/uniapp" target="_blank" class="clear-style barcode-view"> |
||||
<div class="barcode-img-box"><img src="https://web-assets.dcloud.net.cn/unidoc/zh/alipay1.png" width="160" /></div> |
||||
<b>支付宝小程序版</b> |
||||
</a> |
||||
</div> |
||||
<div class="flex-img-group-view" style="margin-top: 20px;"> |
||||
<a href="//m3w.cn/uniapp" target="_blank" class="clear-style barcode-view"> |
||||
<div class="barcode-img-box"><img src="https://web-assets.dcloud.net.cn/unidoc/zh/baidu-uniapp.png" width="160" /></div> |
||||
<b>百度小程序版</b> |
||||
</a> |
||||
<a href="//m3w.cn/uniapp" target="_blank" class="clear-style barcode-view"> |
||||
<div class="barcode-img-box"> |
||||
<img src="https://img.cdn.aliyun.dcloud.net.cn/guide/uniapp/mp-toutiao.png" width="160" /> |
||||
</div> |
||||
<b>字节跳动小程序版</b> |
||||
</a> |
||||
<a href="//m3w.cn/uniapp" target="_blank" class="clear-style barcode-view"> |
||||
<div class="barcode-img-box"> |
||||
<img src="https://img.cdn.aliyun.dcloud.net.cn/guide/uniapp/hello-uni-qq.png" width="160" /> |
||||
</div> |
||||
<b>QQ小程序版</b> |
||||
</a> |
||||
<a href="//m3w.cn/uniapp" target="_blank" class="clear-style barcode-view"> |
||||
<div class="barcode-img-box"> |
||||
<img src="https://img.cdn.aliyun.dcloud.net.cn/guide/uniapp/hello-uni-qa-union.png" width="160" /> |
||||
</div> |
||||
<b>快应用</b> |
||||
</a> |
||||
<a href="https://so.mp.360.cn/mp.html?appid=qh4j181qqtru354st6" target="_blank" class="clear-style barcode-view"> |
||||
<div class="barcode-img-box"> |
||||
<img src="https://img.cdn.aliyun.dcloud.net.cn/guide/uniapp/hello-uni-mp-360-qr.png" width="160" /> |
||||
</div> |
||||
<b>360小程序</b> |
||||
</a> |
||||
</div> |
||||
<p> |
||||
<em>注:某些平台不能提交简单demo,故补充了一些其他功能;hello uni-app示例代码可从[github](https://github.com/dcloudio/hello-uniapp)获取</em></br> |
||||
<em>快应用仅支持 vivo 、oppo、华为</em></br> |
||||
<em>360小程序仅 windows平台支持,需要在360浏览器中打开</em></br> |
||||
</p> |
||||
</div> |
||||
|
||||
`uni-app`官网文档详见[https://uniapp.dcloud.io](https://uniapp.dcloud.io) |
||||
|
||||
更多uni-app的模板、示例详见[插件市场](https://ext.dcloud.net.cn/) |
||||
|
||||
@ -0,0 +1,5 @@
|
||||
import request from './request' |
||||
|
||||
export function login(query) { |
||||
return request.post({ url: '/app/login', query }) |
||||
} |
||||
@ -0,0 +1,5 @@
|
||||
import request from './request' |
||||
|
||||
export function listBook(query) { |
||||
return request.get({ url: '/book', query }) |
||||
} |
||||
@ -0,0 +1,17 @@
|
||||
import request from './request' |
||||
|
||||
export function listComfort(query) { |
||||
return request.get({ url: '/comfort', query }) |
||||
} |
||||
|
||||
export function getComfort(id) { |
||||
return request.get({ url: '/comfort/' + id }) |
||||
} |
||||
|
||||
export function addComfort(body) { |
||||
return request.post({ url: '/comfort', body }) |
||||
} |
||||
|
||||
export function listRightPersonByDepartId(departId) { |
||||
return request.get({ url: '/rightPerson/depart/' + departId }) |
||||
} |
||||
@ -0,0 +1,9 @@
|
||||
import request from './request' |
||||
|
||||
export function departTree() { |
||||
return request.get({ url: '/depart/tree' }) |
||||
} |
||||
|
||||
export function secondList() { |
||||
return request.get({ url: '/depart/second' }) |
||||
} |
||||
@ -0,0 +1,7 @@
|
||||
import request from './request' |
||||
|
||||
export function listDictDataAll(dictType) { |
||||
return request.get({ |
||||
url: `/dict/data/${dictType}` |
||||
}); |
||||
} |
||||
@ -0,0 +1,5 @@
|
||||
import request from './request' |
||||
|
||||
export function addFeedback(body) { |
||||
return request.post({ url: '/feedback', body }) |
||||
} |
||||
@ -0,0 +1,9 @@
|
||||
import request from './request' |
||||
|
||||
export function uploadFileBase64(body) { |
||||
return request.post({ url: '/file/upload/base64', body }) |
||||
} |
||||
|
||||
export function getFileBase64(filepath) { |
||||
return request.get({ url: '/file/base64?filepath=' + filepath }) |
||||
} |
||||
@ -0,0 +1,17 @@
|
||||
import request from './request' |
||||
|
||||
export function listInspection(query) { |
||||
return request.get({ url: `/task/inspection`, query }) |
||||
} |
||||
|
||||
export function listInspectionProblem(taskId, query) { |
||||
return request.get({ url: `/task/inspection/${taskId}/problem`, query }) |
||||
} |
||||
|
||||
export function signInspection(taskId) { |
||||
return request.post({ url: `/task/inspection/${taskId}/sign` }) |
||||
} |
||||
|
||||
export function getInspection(taskId) { |
||||
return request.get({ url: `/task/inspection/${taskId}` }) |
||||
} |
||||
@ -0,0 +1,13 @@
|
||||
import request from './request' |
||||
|
||||
export function listNegative(query) { |
||||
return request.get({ url: `/negative`, query }) |
||||
} |
||||
|
||||
export function getNegative(id, workId) { |
||||
return request.get({ url: `/negative/${id}?workId=${workId || ''}` }) |
||||
} |
||||
|
||||
export function executeNegative(id, body) { |
||||
return request.post({ url: `/negative/${id}/execute`, body}) |
||||
} |
||||
@ -0,0 +1,9 @@
|
||||
import request from './request' |
||||
|
||||
export function listPhoto() { |
||||
return request.get({ url: '/photo' }) |
||||
} |
||||
|
||||
export function addPhoto(body) { |
||||
return request.post({ url: '/photo', body }) |
||||
} |
||||
@ -0,0 +1,5 @@
|
||||
import request from './request' |
||||
|
||||
export function listPolice(query) { |
||||
return request.get({ url: '/police', query }) |
||||
} |
||||
@ -0,0 +1,5 @@
|
||||
import request from './request' |
||||
|
||||
export function problemTypeTree() { |
||||
return request.get({ url: '/dict/content/tree' }) |
||||
} |
||||
@ -0,0 +1,131 @@
|
||||
import { getToken, clearToken } from '@/common/auth' |
||||
import store from '@/store' |
||||
|
||||
function get(options) { |
||||
options.method = 'GET'; |
||||
return ajax(options.url, options) |
||||
} |
||||
|
||||
function post(options) { |
||||
options.method = 'POST'; |
||||
return ajax(options.url, options) |
||||
} |
||||
|
||||
function put(options) { |
||||
options.method = 'PUT'; |
||||
return ajax(options.url, options) |
||||
} |
||||
|
||||
function del(options) { |
||||
options.method = 'DELETE'; |
||||
return ajax(options.url, options) |
||||
} |
||||
|
||||
function ajax(url, options) { |
||||
let body; |
||||
if (options?.params && Object.keys(options.params).length > 0) { |
||||
if (options.method === 'GET') { |
||||
options.query = options.params; |
||||
} else { |
||||
body = JSON.stringify(options.params); |
||||
} |
||||
} |
||||
if (options?.query) { |
||||
const queryParams = [] |
||||
for (const key in options.query) { |
||||
queryParams.push(key + '=' + options.query[key]) |
||||
} |
||||
url += (url.indexOf('?') > -1 ? '' : '?') + queryParams.join('&') |
||||
} |
||||
if (options?.body) { |
||||
if (options.body === 'string') { |
||||
body = options.body; |
||||
} else { |
||||
if (Object.keys(options.body).length > 0) { |
||||
body = JSON.stringify(options.body); |
||||
} |
||||
} |
||||
} |
||||
|
||||
return new Promise((resolve, reject) => { |
||||
const requestUrl = store.state.requestUrl; |
||||
if (!requestUrl) { |
||||
uni.showToast({ |
||||
title: '未找到资源', |
||||
icon: 'none', |
||||
duration: 5000 |
||||
}) |
||||
reject('未找到资源') |
||||
return |
||||
} |
||||
uni.request({ |
||||
url: requestUrl, |
||||
method: 'POST', |
||||
data: { |
||||
url, |
||||
method: options.method, |
||||
token: getToken(), |
||||
body |
||||
}, |
||||
header: { |
||||
"Content-Type": "application/json", |
||||
messageId: generateUUID(), |
||||
appCredential: store.state.appCredential, |
||||
userCredential: store.state.userCredential |
||||
}, |
||||
success: function(response) { |
||||
if (response.statusCode !== 200) { |
||||
uni.showToast({ |
||||
title: 'response信息:' + JSON.stringify(response), |
||||
icon: 'none', |
||||
duration: 5000 |
||||
}); |
||||
return |
||||
} |
||||
const res = response.data; |
||||
if (res.code === 200) { |
||||
resolve(res.data) |
||||
} else { |
||||
let message = res.message; |
||||
if (res.code === 401) { |
||||
message = '未授权登录' |
||||
} |
||||
uni.showToast({ |
||||
title: message || '系统异常', |
||||
icon: 'none', |
||||
duration: 5000 |
||||
}); |
||||
reject(res) |
||||
} |
||||
|
||||
}, |
||||
fail: function(err) { |
||||
uni.showToast({ |
||||
title: err, |
||||
icon: 'none', |
||||
duration: 5000 |
||||
}) |
||||
resolve() |
||||
} |
||||
}) |
||||
}) |
||||
} |
||||
|
||||
function generateUUID() { |
||||
var d = new Date().getTime(); |
||||
var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { |
||||
var r = (d + Math.random() * 16) % 16 | 0; |
||||
d = Math.floor(d / 16); |
||||
return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16); |
||||
}); |
||||
return uuid; |
||||
} |
||||
|
||||
const request = { |
||||
get, |
||||
post, |
||||
put, |
||||
del |
||||
} |
||||
|
||||
export default request; |
||||
@ -0,0 +1,13 @@
|
||||
import request from './request' |
||||
|
||||
export function getTaskSelfexamination(taskId) { |
||||
return request.get({ url: '/task/selfexamination/' + taskId }) |
||||
} |
||||
|
||||
export function signTaskSelfexamination(taskId) { |
||||
return request.post({ url: `/task/selfexamination/${taskId}/sign` }) |
||||
} |
||||
|
||||
export function listTaskSelfexamination(query) { |
||||
return request.get({ url: `/task/selfexamination`, query }) |
||||
} |
||||
@ -0,0 +1,13 @@
|
||||
import request from './request' |
||||
|
||||
export function listTask(query) { |
||||
return request.get({ url: '/task', query }) |
||||
} |
||||
|
||||
export function getTaskCount() { |
||||
return request.get({ url: '/task/count' }) |
||||
} |
||||
|
||||
export function submitTask(taskId) { |
||||
return request.post({ url: `/task/${taskId}/submit` }) |
||||
} |
||||
@ -0,0 +1,13 @@
|
||||
import request from './request' |
||||
|
||||
export function getProblem(id) { |
||||
return request.get({ url: '/task/problem/' + id }) |
||||
} |
||||
|
||||
export function listProblem(query) { |
||||
return request.get({ url: '/task/problem', query }) |
||||
} |
||||
|
||||
export function addProblem(body) { |
||||
return request.post({ url: '/task/problem', body }) |
||||
} |
||||
@ -0,0 +1,13 @@
|
||||
import request from './request' |
||||
|
||||
export function listTestingAlcoholPeople(taskId, query) { |
||||
return request.get({ url: `/task/testingAlcohol/${taskId}/people`, query }) |
||||
} |
||||
|
||||
export function updateTestingAlcoholPeople(taskId, body) { |
||||
return request.put({ url: `/task/testingAlcohol/${taskId}/people`, body }) |
||||
} |
||||
|
||||
export function countTestingAlcoholPeople(taskId) { |
||||
return request.get({ url: `/task/testingAlcohol/${taskId}/people/count` }) |
||||
} |
||||
@ -0,0 +1,13 @@
|
||||
|
||||
const TOKEN_KEY = "token"; |
||||
|
||||
export function setToken(token) { |
||||
uni.setStorageSync(TOKEN_KEY, token); |
||||
} |
||||
export function getToken() { |
||||
return uni.getStorageSync(TOKEN_KEY); |
||||
} |
||||
|
||||
export function clearToken() { |
||||
uni.removeStorageSync(TOKEN_KEY); |
||||
} |
||||
@ -0,0 +1,12 @@
|
||||
import { |
||||
listDictDataAll |
||||
} from '@/api/dict' |
||||
import { ref } from 'vue' |
||||
|
||||
export const getDictOptions = (dictType) => { |
||||
const result = ref([]) |
||||
listDictDataAll(dictType).then(data => { |
||||
result.value = data |
||||
}) |
||||
return result; |
||||
} |
||||
@ -0,0 +1,97 @@
|
||||
/** |
||||
数据验证(表单验证) |
||||
来自 grace.hcoder.net
|
||||
作者 hcoder 深海 |
||||
*/ |
||||
export default { |
||||
error:'', |
||||
check : function (data, rule){ |
||||
for(var i = 0; i < rule.length; i++){ |
||||
if (!rule[i].checkType){return true;} |
||||
if (!rule[i].name) {return true;} |
||||
if (!rule[i].errorMsg) {return true;} |
||||
if (!data[rule[i].name]) {this.error = rule[i].errorMsg; return false;} |
||||
switch (rule[i].checkType){ |
||||
case 'string': |
||||
var reg = new RegExp('^.{' + rule[i].checkRule + '}$'); |
||||
if(!reg.test(data[rule[i].name])) {this.error = rule[i].errorMsg; return false;} |
||||
break; |
||||
case 'int': |
||||
var reg = new RegExp('^(-[1-9]|[1-9])[0-9]{' + rule[i].checkRule + '}$'); |
||||
if(!reg.test(data[rule[i].name])) {this.error = rule[i].errorMsg; return false;} |
||||
break; |
||||
break; |
||||
case 'between': |
||||
if (!this.isNumber(data[rule[i].name])){ |
||||
this.error = rule[i].errorMsg; |
||||
return false; |
||||
} |
||||
var minMax = rule[i].checkRule.split(','); |
||||
minMax[0] = Number(minMax[0]); |
||||
minMax[1] = Number(minMax[1]); |
||||
if (data[rule[i].name] > minMax[1] || data[rule[i].name] < minMax[0]) { |
||||
this.error = rule[i].errorMsg; |
||||
return false; |
||||
} |
||||
break; |
||||
case 'betweenD': |
||||
var reg = /^-?[1-9][0-9]?$/; |
||||
if (!reg.test(data[rule[i].name])) { this.error = rule[i].errorMsg; return false; } |
||||
var minMax = rule[i].checkRule.split(','); |
||||
minMax[0] = Number(minMax[0]); |
||||
minMax[1] = Number(minMax[1]); |
||||
if (data[rule[i].name] > minMax[1] || data[rule[i].name] < minMax[0]) { |
||||
this.error = rule[i].errorMsg; |
||||
return false; |
||||
} |
||||
break; |
||||
case 'betweenF':
|
||||
var reg = /^-?[0-9][0-9]?.+[0-9]+$/; |
||||
if (!reg.test(data[rule[i].name])){this.error = rule[i].errorMsg; return false;} |
||||
var minMax = rule[i].checkRule.split(','); |
||||
minMax[0] = Number(minMax[0]); |
||||
minMax[1] = Number(minMax[1]); |
||||
if (data[rule[i].name] > minMax[1] || data[rule[i].name] < minMax[0]) { |
||||
this.error = rule[i].errorMsg; |
||||
return false; |
||||
} |
||||
break; |
||||
case 'same': |
||||
if (data[rule[i].name] != rule[i].checkRule) { this.error = rule[i].errorMsg; return false;} |
||||
break; |
||||
case 'notsame': |
||||
if (data[rule[i].name] == rule[i].checkRule) { this.error = rule[i].errorMsg; return false; } |
||||
break; |
||||
case 'email': |
||||
var reg = /^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/; |
||||
if (!reg.test(data[rule[i].name])) { this.error = rule[i].errorMsg; return false; } |
||||
break; |
||||
case 'phoneno': |
||||
var reg = /^1[0-9]{10,10}$/; |
||||
if (!reg.test(data[rule[i].name])) { this.error = rule[i].errorMsg; return false; } |
||||
break; |
||||
case 'zipcode': |
||||
var reg = /^[0-9]{6}$/; |
||||
if (!reg.test(data[rule[i].name])) { this.error = rule[i].errorMsg; return false; } |
||||
break; |
||||
case 'reg': |
||||
var reg = new RegExp(rule[i].checkRule); |
||||
if (!reg.test(data[rule[i].name])) { this.error = rule[i].errorMsg; return false; } |
||||
break; |
||||
case 'in': |
||||
if(rule[i].checkRule.indexOf(data[rule[i].name]) == -1){ |
||||
this.error = rule[i].errorMsg; return false; |
||||
} |
||||
break; |
||||
case 'notnull': |
||||
if(data[rule[i].name] == null || data[rule[i].name].length < 1){this.error = rule[i].errorMsg; return false;} |
||||
break; |
||||
} |
||||
} |
||||
return true; |
||||
}, |
||||
isNumber : function (checkVal){ |
||||
var reg = /^-?[1-9][0-9]?.?[0-9]*$/; |
||||
return reg.test(checkVal); |
||||
} |
||||
} |
||||
@ -0,0 +1,352 @@
|
||||
/* |
||||
* HTML5 Parser By Sam Blowes |
||||
* |
||||
* Designed for HTML5 documents |
||||
* |
||||
* Original code by John Resig (ejohn.org) |
||||
* http://ejohn.org/blog/pure-javascript-html-parser/
|
||||
* Original code by Erik Arvidsson, Mozilla Public License |
||||
* http://erik.eae.net/simplehtmlparser/simplehtmlparser.js
|
||||
* |
||||
* ---------------------------------------------------------------------------- |
||||
* License |
||||
* ---------------------------------------------------------------------------- |
||||
* |
||||
* This code is triple licensed using Apache Software License 2.0, |
||||
* Mozilla Public License or GNU Public License |
||||
* |
||||
* ////////////////////////////////////////////////////////////////////////////
|
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not |
||||
* use this file except in compliance with the License. You may obtain a copy |
||||
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* ////////////////////////////////////////////////////////////////////////////
|
||||
* |
||||
* The contents of this file are subject to the Mozilla Public License |
||||
* Version 1.1 (the "License"); you may not use this file except in |
||||
* compliance with the License. You may obtain a copy of the License at |
||||
* http://www.mozilla.org/MPL/
|
||||
* |
||||
* Software distributed under the License is distributed on an "AS IS" |
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the |
||||
* License for the specific language governing rights and limitations |
||||
* under the License. |
||||
* |
||||
* The Original Code is Simple HTML Parser. |
||||
* |
||||
* The Initial Developer of the Original Code is Erik Arvidsson. |
||||
* Portions created by Erik Arvidssson are Copyright (C) 2004. All Rights |
||||
* Reserved. |
||||
* |
||||
* ////////////////////////////////////////////////////////////////////////////
|
||||
* |
||||
* This program is free software; you can redistribute it and/or |
||||
* modify it under the terms of the GNU General Public License |
||||
* as published by the Free Software Foundation; either version 2 |
||||
* of the License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||
* |
||||
* ---------------------------------------------------------------------------- |
||||
* Usage |
||||
* ---------------------------------------------------------------------------- |
||||
* |
||||
* // Use like so:
|
||||
* HTMLParser(htmlString, { |
||||
* start: function(tag, attrs, unary) {}, |
||||
* end: function(tag) {}, |
||||
* chars: function(text) {}, |
||||
* comment: function(text) {} |
||||
* }); |
||||
* |
||||
* // or to get an XML string:
|
||||
* HTMLtoXML(htmlString); |
||||
* |
||||
* // or to get an XML DOM Document
|
||||
* HTMLtoDOM(htmlString); |
||||
* |
||||
* // or to inject into an existing document/DOM node
|
||||
* HTMLtoDOM(htmlString, document); |
||||
* HTMLtoDOM(htmlString, document.body); |
||||
* |
||||
*/ |
||||
// Regular Expressions for parsing tags and attributes
|
||||
var startTag = /^<([-A-Za-z0-9_]+)((?:\s+[a-zA-Z_:][-a-zA-Z0-9_:.]*(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/; |
||||
var endTag = /^<\/([-A-Za-z0-9_]+)[^>]*>/; |
||||
var attr = /([a-zA-Z_:][-a-zA-Z0-9_:.]*)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g; // Empty Elements - HTML 5
|
||||
|
||||
var empty = makeMap('area,base,basefont,br,col,frame,hr,img,input,link,meta,param,embed,command,keygen,source,track,wbr'); // Block Elements - HTML 5
|
||||
// fixed by xxx 将 ins 标签从块级名单中移除
|
||||
|
||||
var block = makeMap('a,address,article,applet,aside,audio,blockquote,button,canvas,center,dd,del,dir,div,dl,dt,fieldset,figcaption,figure,footer,form,frameset,h1,h2,h3,h4,h5,h6,header,hgroup,hr,iframe,isindex,li,map,menu,noframes,noscript,object,ol,output,p,pre,section,script,table,tbody,td,tfoot,th,thead,tr,ul,video'); // Inline Elements - HTML 5
|
||||
|
||||
var inline = makeMap('abbr,acronym,applet,b,basefont,bdo,big,br,button,cite,code,del,dfn,em,font,i,iframe,img,input,ins,kbd,label,map,object,q,s,samp,script,select,small,span,strike,strong,sub,sup,textarea,tt,u,var'); // Elements that you can, intentionally, leave open
|
||||
// (and which close themselves)
|
||||
|
||||
var closeSelf = makeMap('colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr'); // Attributes that have their values filled in disabled="disabled"
|
||||
|
||||
var fillAttrs = makeMap('checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected'); // Special Elements (can contain anything)
|
||||
|
||||
var special = makeMap('script,style'); |
||||
function HTMLParser(html, handler) { |
||||
var index; |
||||
var chars; |
||||
var match; |
||||
var stack = []; |
||||
var last = html; |
||||
|
||||
stack.last = function () { |
||||
return this[this.length - 1]; |
||||
}; |
||||
|
||||
while (html) { |
||||
chars = true; // Make sure we're not in a script or style element
|
||||
|
||||
if (!stack.last() || !special[stack.last()]) { |
||||
// Comment
|
||||
if (html.indexOf('<!--') == 0) { |
||||
index = html.indexOf('-->'); |
||||
|
||||
if (index >= 0) { |
||||
if (handler.comment) { |
||||
handler.comment(html.substring(4, index)); |
||||
} |
||||
|
||||
html = html.substring(index + 3); |
||||
chars = false; |
||||
} // end tag
|
||||
|
||||
} else if (html.indexOf('</') == 0) { |
||||
match = html.match(endTag); |
||||
|
||||
if (match) { |
||||
html = html.substring(match[0].length); |
||||
match[0].replace(endTag, parseEndTag); |
||||
chars = false; |
||||
} // start tag
|
||||
|
||||
} else if (html.indexOf('<') == 0) { |
||||
match = html.match(startTag); |
||||
|
||||
if (match) { |
||||
html = html.substring(match[0].length); |
||||
match[0].replace(startTag, parseStartTag); |
||||
chars = false; |
||||
} |
||||
} |
||||
|
||||
if (chars) { |
||||
index = html.indexOf('<'); |
||||
var text = index < 0 ? html : html.substring(0, index); |
||||
html = index < 0 ? '' : html.substring(index); |
||||
|
||||
if (handler.chars) { |
||||
handler.chars(text); |
||||
} |
||||
} |
||||
} else { |
||||
html = html.replace(new RegExp('([\\s\\S]*?)<\/' + stack.last() + '[^>]*>'), function (all, text) { |
||||
text = text.replace(/<!--([\s\S]*?)-->|<!\[CDATA\[([\s\S]*?)]]>/g, '$1$2'); |
||||
|
||||
if (handler.chars) { |
||||
handler.chars(text); |
||||
} |
||||
|
||||
return ''; |
||||
}); |
||||
parseEndTag('', stack.last()); |
||||
} |
||||
|
||||
if (html == last) { |
||||
throw 'Parse Error: ' + html; |
||||
} |
||||
|
||||
last = html; |
||||
} // Clean up any remaining tags
|
||||
|
||||
|
||||
parseEndTag(); |
||||
|
||||
function parseStartTag(tag, tagName, rest, unary) { |
||||
tagName = tagName.toLowerCase(); |
||||
|
||||
if (block[tagName]) { |
||||
while (stack.last() && inline[stack.last()]) { |
||||
parseEndTag('', stack.last()); |
||||
} |
||||
} |
||||
|
||||
if (closeSelf[tagName] && stack.last() == tagName) { |
||||
parseEndTag('', tagName); |
||||
} |
||||
|
||||
unary = empty[tagName] || !!unary; |
||||
|
||||
if (!unary) { |
||||
stack.push(tagName); |
||||
} |
||||
|
||||
if (handler.start) { |
||||
var attrs = []; |
||||
rest.replace(attr, function (match, name) { |
||||
var value = arguments[2] ? arguments[2] : arguments[3] ? arguments[3] : arguments[4] ? arguments[4] : fillAttrs[name] ? name : ''; |
||||
attrs.push({ |
||||
name: name, |
||||
value: value, |
||||
escaped: value.replace(/(^|[^\\])"/g, '$1\\\"') // "
|
||||
|
||||
}); |
||||
}); |
||||
|
||||
if (handler.start) { |
||||
handler.start(tagName, attrs, unary); |
||||
} |
||||
} |
||||
} |
||||
|
||||
function parseEndTag(tag, tagName) { |
||||
// If no tag name is provided, clean shop
|
||||
if (!tagName) { |
||||
var pos = 0; |
||||
} // Find the closest opened tag of the same type
|
||||
else { |
||||
for (var pos = stack.length - 1; pos >= 0; pos--) { |
||||
if (stack[pos] == tagName) { |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
if (pos >= 0) { |
||||
// Close all the open elements, up the stack
|
||||
for (var i = stack.length - 1; i >= pos; i--) { |
||||
if (handler.end) { |
||||
handler.end(stack[i]); |
||||
} |
||||
} // Remove the open elements from the stack
|
||||
|
||||
|
||||
stack.length = pos; |
||||
} |
||||
} |
||||
} |
||||
|
||||
function makeMap(str) { |
||||
var obj = {}; |
||||
var items = str.split(','); |
||||
|
||||
for (var i = 0; i < items.length; i++) { |
||||
obj[items[i]] = true; |
||||
} |
||||
|
||||
return obj; |
||||
} |
||||
|
||||
function removeDOCTYPE(html) { |
||||
return html.replace(/<\?xml.*\?>\n/, '').replace(/<!doctype.*>\n/, '').replace(/<!DOCTYPE.*>\n/, ''); |
||||
} |
||||
|
||||
function parseAttrs(attrs) { |
||||
return attrs.reduce(function (pre, attr) { |
||||
var value = attr.value; |
||||
var name = attr.name; |
||||
|
||||
if (pre[name]) { |
||||
pre[name] = pre[name] + " " + value; |
||||
} else { |
||||
pre[name] = value; |
||||
} |
||||
|
||||
return pre; |
||||
}, {}); |
||||
} |
||||
|
||||
function parseHtml(html) { |
||||
html = removeDOCTYPE(html); |
||||
var stacks = []; |
||||
var results = { |
||||
node: 'root', |
||||
children: [] |
||||
}; |
||||
HTMLParser(html, { |
||||
start: function start(tag, attrs, unary) { |
||||
var node = { |
||||
name: tag |
||||
}; |
||||
|
||||
if (attrs.length !== 0) { |
||||
node.attrs = parseAttrs(attrs); |
||||
} |
||||
|
||||
if (unary) { |
||||
var parent = stacks[0] || results; |
||||
|
||||
if (!parent.children) { |
||||
parent.children = []; |
||||
} |
||||
|
||||
parent.children.push(node); |
||||
} else { |
||||
stacks.unshift(node); |
||||
} |
||||
}, |
||||
end: function end(tag) { |
||||
var node = stacks.shift(); |
||||
if (node.name !== tag) console.error('invalid state: mismatch end tag'); |
||||
|
||||
if (stacks.length === 0) { |
||||
results.children.push(node); |
||||
} else { |
||||
var parent = stacks[0]; |
||||
|
||||
if (!parent.children) { |
||||
parent.children = []; |
||||
} |
||||
|
||||
parent.children.push(node); |
||||
} |
||||
}, |
||||
chars: function chars(text) { |
||||
var node = { |
||||
type: 'text', |
||||
text: text |
||||
}; |
||||
|
||||
if (stacks.length === 0) { |
||||
results.children.push(node); |
||||
} else { |
||||
var parent = stacks[0]; |
||||
|
||||
if (!parent.children) { |
||||
parent.children = []; |
||||
} |
||||
|
||||
parent.children.push(node); |
||||
} |
||||
}, |
||||
comment: function comment(text) { |
||||
var node = { |
||||
node: 'comment', |
||||
text: text |
||||
}; |
||||
var parent = stacks[0]; |
||||
|
||||
if (!parent.children) { |
||||
parent.children = []; |
||||
} |
||||
|
||||
parent.children.push(node); |
||||
} |
||||
}); |
||||
return results.children; |
||||
} |
||||
|
||||
export default parseHtml; |
||||
@ -0,0 +1,209 @@
|
||||
/// null = 未请求,1 = 已允许,0 = 拒绝|受限, 2 = 系统未开启
|
||||
|
||||
var isIOS |
||||
|
||||
function album() { |
||||
var result = 0; |
||||
var PHPhotoLibrary = plus.ios.import("PHPhotoLibrary"); |
||||
var authStatus = PHPhotoLibrary.authorizationStatus(); |
||||
if (authStatus === 0) { |
||||
result = null; |
||||
} else if (authStatus == 3) { |
||||
result = 1; |
||||
} else { |
||||
result = 0; |
||||
} |
||||
plus.ios.deleteObject(PHPhotoLibrary); |
||||
return result; |
||||
} |
||||
|
||||
function camera() { |
||||
var result = 0; |
||||
var AVCaptureDevice = plus.ios.import("AVCaptureDevice"); |
||||
var authStatus = AVCaptureDevice.authorizationStatusForMediaType('vide'); |
||||
if (authStatus === 0) { |
||||
result = null; |
||||
} else if (authStatus == 3) { |
||||
result = 1; |
||||
} else { |
||||
result = 0; |
||||
} |
||||
plus.ios.deleteObject(AVCaptureDevice); |
||||
return result; |
||||
} |
||||
|
||||
function location() { |
||||
var result = 0; |
||||
var cllocationManger = plus.ios.import("CLLocationManager"); |
||||
var enable = cllocationManger.locationServicesEnabled(); |
||||
var status = cllocationManger.authorizationStatus(); |
||||
if (!enable) { |
||||
result = 2; |
||||
} else if (status === 0) { |
||||
result = null; |
||||
} else if (status === 3 || status === 4) { |
||||
result = 1; |
||||
} else { |
||||
result = 0; |
||||
} |
||||
plus.ios.deleteObject(cllocationManger); |
||||
return result; |
||||
} |
||||
|
||||
function push() { |
||||
var result = 0; |
||||
var UIApplication = plus.ios.import("UIApplication"); |
||||
var app = UIApplication.sharedApplication(); |
||||
var enabledTypes = 0; |
||||
if (app.currentUserNotificationSettings) { |
||||
var settings = app.currentUserNotificationSettings(); |
||||
enabledTypes = settings.plusGetAttribute("types"); |
||||
if (enabledTypes == 0) { |
||||
result = 0; |
||||
console.log("推送权限没有开启"); |
||||
} else { |
||||
result = 1; |
||||
console.log("已经开启推送功能!") |
||||
} |
||||
plus.ios.deleteObject(settings); |
||||
} else { |
||||
enabledTypes = app.enabledRemoteNotificationTypes(); |
||||
if (enabledTypes == 0) { |
||||
result = 3; |
||||
console.log("推送权限没有开启!"); |
||||
} else { |
||||
result = 4; |
||||
console.log("已经开启推送功能!") |
||||
} |
||||
} |
||||
plus.ios.deleteObject(app); |
||||
plus.ios.deleteObject(UIApplication); |
||||
return result; |
||||
} |
||||
|
||||
function contact() { |
||||
var result = 0; |
||||
var CNContactStore = plus.ios.import("CNContactStore"); |
||||
var cnAuthStatus = CNContactStore.authorizationStatusForEntityType(0); |
||||
if (cnAuthStatus === 0) { |
||||
result = null; |
||||
} else if (cnAuthStatus == 3) { |
||||
result = 1; |
||||
} else { |
||||
result = 0; |
||||
} |
||||
plus.ios.deleteObject(CNContactStore); |
||||
return result; |
||||
} |
||||
|
||||
function record() { |
||||
var result = null; |
||||
var avaudiosession = plus.ios.import("AVAudioSession"); |
||||
var avaudio = avaudiosession.sharedInstance(); |
||||
var status = avaudio.recordPermission(); |
||||
console.log("permissionStatus:" + status); |
||||
if (status === 1970168948) { |
||||
result = null; |
||||
} else if (status === 1735552628) { |
||||
result = 1; |
||||
} else { |
||||
result = 0; |
||||
} |
||||
plus.ios.deleteObject(avaudiosession); |
||||
return result; |
||||
} |
||||
|
||||
function calendar() { |
||||
var result = null; |
||||
var EKEventStore = plus.ios.import("EKEventStore"); |
||||
var ekAuthStatus = EKEventStore.authorizationStatusForEntityType(0); |
||||
if (ekAuthStatus == 3) { |
||||
result = 1; |
||||
console.log("日历权限已经开启"); |
||||
} else { |
||||
console.log("日历权限没有开启"); |
||||
} |
||||
plus.ios.deleteObject(EKEventStore); |
||||
return result; |
||||
} |
||||
|
||||
function memo() { |
||||
var result = null; |
||||
var EKEventStore = plus.ios.import("EKEventStore"); |
||||
var ekAuthStatus = EKEventStore.authorizationStatusForEntityType(1); |
||||
if (ekAuthStatus == 3) { |
||||
result = 1; |
||||
console.log("备忘录权限已经开启"); |
||||
} else { |
||||
console.log("备忘录权限没有开启"); |
||||
} |
||||
plus.ios.deleteObject(EKEventStore); |
||||
return result; |
||||
} |
||||
|
||||
function requestAndroid(permissionID) { |
||||
return new Promise((resolve, reject) => { |
||||
plus.android.requestPermissions( |
||||
[permissionID], |
||||
function(resultObj) { |
||||
var result = 0; |
||||
for (var i = 0; i < resultObj.granted.length; i++) { |
||||
var grantedPermission = resultObj.granted[i]; |
||||
console.log('已获取的权限:' + grantedPermission); |
||||
result = 1 |
||||
} |
||||
for (var i = 0; i < resultObj.deniedPresent.length; i++) { |
||||
var deniedPresentPermission = resultObj.deniedPresent[i]; |
||||
console.log('拒绝本次申请的权限:' + deniedPresentPermission); |
||||
result = 0 |
||||
} |
||||
for (var i = 0; i < resultObj.deniedAlways.length; i++) { |
||||
var deniedAlwaysPermission = resultObj.deniedAlways[i]; |
||||
console.log('永久拒绝申请的权限:' + deniedAlwaysPermission); |
||||
result = -1 |
||||
} |
||||
resolve(result); |
||||
}, |
||||
function(error) { |
||||
console.log('result error: ' + error.message) |
||||
resolve({ |
||||
code: error.code, |
||||
message: error.message |
||||
}); |
||||
} |
||||
); |
||||
}); |
||||
} |
||||
|
||||
function gotoAppPermissionSetting() { |
||||
if (permission.isIOS) { |
||||
var UIApplication = plus.ios.import("UIApplication"); |
||||
var application2 = UIApplication.sharedApplication(); |
||||
var NSURL2 = plus.ios.import("NSURL"); |
||||
var setting2 = NSURL2.URLWithString("app-settings:"); |
||||
application2.openURL(setting2); |
||||
plus.ios.deleteObject(setting2); |
||||
plus.ios.deleteObject(NSURL2); |
||||
plus.ios.deleteObject(application2); |
||||
} else { |
||||
var Intent = plus.android.importClass("android.content.Intent"); |
||||
var Settings = plus.android.importClass("android.provider.Settings"); |
||||
var Uri = plus.android.importClass("android.net.Uri"); |
||||
var mainActivity = plus.android.runtimeMainActivity(); |
||||
var intent = new Intent(); |
||||
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); |
||||
var uri = Uri.fromParts("package", mainActivity.getPackageName(), null); |
||||
intent.setData(uri); |
||||
mainActivity.startActivity(intent); |
||||
} |
||||
} |
||||
|
||||
const permission = { |
||||
get isIOS(){ |
||||
return typeof isIOS === 'boolean' ? isIOS : (isIOS = uni.getSystemInfoSync().platform === 'ios') |
||||
}, |
||||
requestAndroid: requestAndroid, |
||||
gotoAppSetting: gotoAppPermissionSetting |
||||
} |
||||
|
||||
export default permission |
||||
@ -0,0 +1,136 @@
|
||||
/* #ifndef APP-PLUS-NVUE */ |
||||
page { |
||||
min-height: 100%; |
||||
height: auto; |
||||
} |
||||
/* #endif */ |
||||
|
||||
/* 解决头条小程序字体图标不显示问题,因为头条运行时自动插入了span标签,且有全局字体 */ |
||||
/* #ifdef MP-TOUTIAO */ |
||||
/* text :not(view) { |
||||
font-family: uniicons; |
||||
} */ |
||||
/* #endif */ |
||||
|
||||
.uni-icon { |
||||
font-family: uniicons; |
||||
font-weight: normal; |
||||
} |
||||
|
||||
.uni-container { |
||||
padding: 15px; |
||||
background-color: #f8f8f8; |
||||
} |
||||
|
||||
.uni-header-logo { |
||||
/* #ifdef H5 */ |
||||
display: flex; |
||||
/* #endif */ |
||||
padding: 15px 15px; |
||||
flex-direction: column; |
||||
justify-content: center; |
||||
align-items: center; |
||||
margin-top: 10rpx; |
||||
} |
||||
|
||||
.uni-header-image { |
||||
width: 80px; |
||||
height: 80px; |
||||
} |
||||
|
||||
.uni-hello-text { |
||||
margin-bottom: 20px; |
||||
} |
||||
|
||||
.hello-text { |
||||
color: #7A7E83; |
||||
font-size: 14px; |
||||
line-height: 20px; |
||||
} |
||||
|
||||
.hello-link { |
||||
color: #7A7E83; |
||||
font-size: 14px; |
||||
line-height: 20px; |
||||
} |
||||
|
||||
.uni-panel { |
||||
margin-bottom: 12px; |
||||
} |
||||
|
||||
.uni-panel-h { |
||||
/* #ifdef H5 */ |
||||
display: flex; |
||||
/* #endif */ |
||||
background-color: #ffffff; |
||||
flex-direction: row !important; |
||||
/* justify-content: space-between !important; */ |
||||
align-items: center !important; |
||||
padding: 12px; |
||||
/* #ifdef H5 */ |
||||
cursor: pointer; |
||||
/* #endif */ |
||||
} |
||||
/* |
||||
.uni-panel-h:active { |
||||
background-color: #f8f8f8; |
||||
} |
||||
*/ |
||||
.uni-panel-h-on { |
||||
background-color: #f0f0f0; |
||||
} |
||||
|
||||
.uni-panel-text { |
||||
flex: 1; |
||||
color: #000000; |
||||
font-size: 14px; |
||||
font-weight: normal; |
||||
} |
||||
|
||||
.uni-panel-icon { |
||||
margin-left: 15px; |
||||
color: #999999; |
||||
font-size: 14px; |
||||
font-weight: normal; |
||||
transform: rotate(0deg); |
||||
transition-duration: 0s; |
||||
transition-property: transform; |
||||
} |
||||
|
||||
.uni-panel-icon-on { |
||||
transform: rotate(180deg); |
||||
} |
||||
|
||||
.uni-navigate-item { |
||||
/* #ifdef H5 */ |
||||
display: flex; |
||||
/* #endif */ |
||||
flex-direction: row; |
||||
align-items: center; |
||||
background-color: #FFFFFF; |
||||
border-top-style: solid; |
||||
border-top-color: #f0f0f0; |
||||
border-top-width: 1px; |
||||
padding: 12px; |
||||
/* #ifdef H5 */ |
||||
cursor: pointer; |
||||
/* #endif */ |
||||
} |
||||
|
||||
.uni-navigate-item:active { |
||||
background-color: #f8f8f8; |
||||
} |
||||
|
||||
.uni-navigate-text { |
||||
flex: 1; |
||||
color: #000000; |
||||
font-size: 14px; |
||||
font-weight: normal; |
||||
} |
||||
|
||||
.uni-navigate-icon { |
||||
margin-left: 15px; |
||||
color: #999999; |
||||
font-size: 14px; |
||||
font-weight: normal; |
||||
} |
||||
@ -0,0 +1,154 @@
|
||||
import moment from 'moment' |
||||
|
||||
export function formatTime(time) { |
||||
if (typeof time !== 'number' || time < 0) { |
||||
return time |
||||
} |
||||
|
||||
var hour = parseInt(time / 3600) |
||||
time = time % 3600 |
||||
var minute = parseInt(time / 60) |
||||
time = time % 60 |
||||
var second = time |
||||
|
||||
return ([hour, minute, second]).map(function(n) { |
||||
n = n.toString() |
||||
return n[1] ? n : '0' + n |
||||
}).join(':') |
||||
} |
||||
|
||||
export function formatLocation(longitude, latitude) { |
||||
if (typeof longitude === 'string' && typeof latitude === 'string') { |
||||
longitude = parseFloat(longitude) |
||||
latitude = parseFloat(latitude) |
||||
} |
||||
|
||||
longitude = longitude.toFixed(2) |
||||
latitude = latitude.toFixed(2) |
||||
|
||||
return { |
||||
longitude: longitude.toString().split('.'), |
||||
latitude: latitude.toString().split('.') |
||||
} |
||||
} |
||||
|
||||
export var dateUtils = { |
||||
UNITS: { |
||||
'年': 31557600000, |
||||
'月': 2629800000, |
||||
'天': 86400000, |
||||
'小时': 3600000, |
||||
'分钟': 60000, |
||||
'秒': 1000 |
||||
}, |
||||
humanize: function(milliseconds) { |
||||
var humanize = ''; |
||||
for (var key in this.UNITS) { |
||||
if (milliseconds >= this.UNITS[key]) { |
||||
humanize = Math.floor(milliseconds / this.UNITS[key]) + key + '前'; |
||||
break; |
||||
} |
||||
} |
||||
return humanize || '刚刚'; |
||||
}, |
||||
format: function(dateStr) { |
||||
var date = this.parse(dateStr) |
||||
var diff = Date.now() - date.getTime(); |
||||
if (diff < this.UNITS['天']) { |
||||
return this.humanize(diff); |
||||
} |
||||
var _format = function(number) { |
||||
return (number < 10 ? ('0' + number) : number); |
||||
}; |
||||
return date.getFullYear() + '/' + _format(date.getMonth() + 1) + '/' + _format(date.getDate()) + '-' + |
||||
_format(date.getHours()) + ':' + _format(date.getMinutes()); |
||||
}, |
||||
parse: function(str) { //将"yyyy-mm-dd HH:MM:ss"格式的字符串,转化为一个Date对象
|
||||
var a = str.split(/[^0-9]/); |
||||
return new Date(a[0], a[1] - 1, a[2], a[3], a[4], a[5]); |
||||
} |
||||
}; |
||||
|
||||
export function now(format) { |
||||
return moment().format(format) |
||||
} |
||||
|
||||
export function getDictLabel(dicts, value) { |
||||
if (!value) { |
||||
return '' |
||||
} |
||||
if (!dicts || !dicts.length) { |
||||
return '' |
||||
} |
||||
const obj = dicts.find(item => item.dictValue === value) |
||||
if (!obj) { |
||||
return '' |
||||
} |
||||
return obj.dictLabel; |
||||
} |
||||
|
||||
export function getDictLabelByArray(dicts, value) { |
||||
if (!value) { |
||||
return '' |
||||
} |
||||
if (!dicts || !dicts.length) { |
||||
return '' |
||||
} |
||||
const arr = dicts.filter(item => value.split(',').indexOf(item.dictValue) > -1) |
||||
if (arr.length === 0) { |
||||
return '' |
||||
} |
||||
return arr.map(item => item.dictLabel).join('、'); |
||||
} |
||||
|
||||
export const formatTimeText = (seconds) => { |
||||
if (!seconds) { |
||||
return '' |
||||
} |
||||
if (seconds < 0) { |
||||
return formatTimeText(-seconds); |
||||
} |
||||
// 秒
|
||||
if (seconds < 60) { |
||||
return seconds + '秒' |
||||
} |
||||
// 分钟
|
||||
if (seconds < 3600) { |
||||
return `${Math.floor(seconds / 60)}分${seconds % 60}秒` |
||||
} |
||||
// 小时
|
||||
if (seconds < 86400) { |
||||
const remainder = seconds % 3600; |
||||
return `${Math.floor(seconds / 3600)}时${parseInt(seconds % 3600 / 60)}分` |
||||
} |
||||
// 天
|
||||
const remainder = seconds % 86400; |
||||
return `${Math.floor(seconds / 86400)}天${parseInt(seconds % 86400 / 3600)}时` |
||||
} |
||||
|
||||
export const getFileType = (fileName) => { |
||||
if (!fileName || fileName.indexOf('.') === -1) { |
||||
return 'txt'; |
||||
} |
||||
const fileSuffix = fileName.substr(fileName.lastIndexOf('.') + 1).toLowerCase(); |
||||
const imgSuffix = ['png', 'jpg', 'jpeg', 'gif']; |
||||
if (imgSuffix.indexOf(fileSuffix) > -1) { |
||||
return 'img' |
||||
} |
||||
if (fileSuffix === 'doc' || fileSuffix === 'docx' ) { |
||||
return 'doc' |
||||
} |
||||
if (fileSuffix === 'xls' || fileSuffix === 'xlsx' ) { |
||||
return 'xls' |
||||
} |
||||
if (fileSuffix === 'pdf' ) { |
||||
return 'pdf' |
||||
} |
||||
if (fileSuffix === 'mp3') { |
||||
return 'mp3' |
||||
} |
||||
if (fileSuffix === 'mp4') { |
||||
return 'mp4' |
||||
} |
||||
return 'txt'; |
||||
} |
||||
@ -0,0 +1,31 @@
|
||||
<template> |
||||
<view class="empty-container"> |
||||
<image src="/static/empty.png"></image> |
||||
<view class="empty-description">{{ description }}</view> |
||||
</view> |
||||
</template> |
||||
|
||||
<script setup> |
||||
import { defineProps } from 'vue' |
||||
defineProps({ |
||||
description: { |
||||
type: String, |
||||
default: '无数据' |
||||
} |
||||
}) |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
.empty-container { |
||||
text-align: center; |
||||
padding: 40rpx 0; |
||||
image { |
||||
width: 200rpx; |
||||
height: 200rpx; |
||||
} |
||||
.empty-description { |
||||
color: #999; |
||||
font-size: 12px; |
||||
} |
||||
} |
||||
</style> |
||||
@ -0,0 +1,91 @@
|
||||
<template> |
||||
<view class="flex gap-8 wrap"> |
||||
<view v-for="(file, index) in files" class="col-8 file-item"> |
||||
<view class="file flex wrap flex-col items-center" v-if="getFileType(file.fileName) !== 'img'"> |
||||
<view class="mt-10"> |
||||
<image :src="`/static/icon/${ getFileType(file.fileName) }.png`" mode="widthFix" style="width: 78rpx"></image> |
||||
</view> |
||||
<view class="uni-text-nowrap filename">{{ file.fileName }}</view> |
||||
</view> |
||||
<net-image :filepath="file.filePath" v-else class="img" /> |
||||
</view> |
||||
</view> |
||||
|
||||
<!-- <view class="file-preview-wrapper" v-if="previewFlag" @tap="previewFlag = false" > |
||||
<view class="file-preview-container"> |
||||
<template v-if="activeFile.type.indexOf('image') > -1"> |
||||
<image :src="imgSrc" mode="widthFix"></image> |
||||
</template> |
||||
<template v-else-if="activeFile.type.indexOf('audio') > -1"> |
||||
<view class="audio-container flex column"> |
||||
<view class="audio-title mb-20">{{ activeFile.orgiinFilename }}</view> |
||||
<view @tap.stop="playFlag = !playFlag" class="flex center"> |
||||
<fui-icon name="suspend" color="#fff" :size="120" v-if="!playFlag"></fui-icon> |
||||
<fui-icon name="play" color="#fff" :size="120" v-else></fui-icon> |
||||
</view> |
||||
</view> |
||||
</template> |
||||
<template v-else-if="activeFile.type.indexOf('video') > -1"> |
||||
<video :src="videoSrc" controls @tap.stop style="width: 100vw; height: 60vh"></video> |
||||
</template> |
||||
<template v-else-if="activeFile.type.indexOf('word') > -1 || |
||||
activeFile.type.indexOf('excel') > -1 || activeFile.type.indexOf('spreadsheetml.sheet') > -1"> |
||||
<view class="docx-container"> |
||||
<view class="docx-content"> |
||||
<rich-text :nodes="htmlString"></rich-text> |
||||
</view> |
||||
</view> |
||||
</template> |
||||
<template v-else> |
||||
<view class="unsupported flex column"> |
||||
<view class="mb-20">{{ activeFile.orgiinFilename }}</view> |
||||
<view class="text-center tips mb-20">暂不支持该文件格式的预览</view> |
||||
</view> |
||||
</template> |
||||
</view> |
||||
<view class="file-dot-container flex gap" v-if="files.length > 1"> |
||||
<view v-for="(file, index) in files" class="dot" :active="files.indexOf(activeFile) === index"></view> |
||||
</view> |
||||
<view class="tools flex gap-6"> |
||||
<view class="tool-btn" @tap.stop="download"> |
||||
<fui-icon name="dropdown" color="#fff" :size="40"></fui-icon> |
||||
</view> |
||||
<template v-if="files.length > 1"> |
||||
<view class="tool-btn" @tap.stop="prev"> |
||||
<fui-icon name="arrowleft" color="#fff" :size="40"></fui-icon> |
||||
</view> |
||||
<view class="tool-btn" @tap.stop="next"> |
||||
<fui-icon name="arrowright" color="#fff" :size="40"></fui-icon> |
||||
</view> |
||||
</template> |
||||
</view> |
||||
</view> --> |
||||
</template> |
||||
|
||||
<script setup> |
||||
import { ref, defineProps, defineEmits, onMounted } from 'vue'; |
||||
import { getFileType } from '@/common/util'; |
||||
|
||||
defineProps({ |
||||
files: { |
||||
type: Array, |
||||
default: [] |
||||
} |
||||
}) |
||||
</script> |
||||
|
||||
<style lang="scss"> |
||||
.file-item { |
||||
width: 178rpx; |
||||
height: 178rpx; |
||||
background: #F3FAFF; |
||||
overflow: hidden; |
||||
.filename { |
||||
font-size: 12px; |
||||
} |
||||
.img { |
||||
width: 100%; |
||||
height: 100%; |
||||
} |
||||
} |
||||
</style> |
||||
@ -0,0 +1,60 @@
|
||||
<template> |
||||
<view class="radio-group-container"> |
||||
<view :class="modelValue === item[prop.value]? 'radio-group-item active' : 'radio-group-item'" v-for="item in data" @tap="change(item[prop.value])">{{ item[prop.text] }}</view> |
||||
</view> |
||||
</template> |
||||
|
||||
<script setup> |
||||
import { defineProps } from 'vue' |
||||
|
||||
const props = defineProps({ |
||||
data: { |
||||
type: Array, |
||||
default: [] |
||||
}, |
||||
modelValue: { |
||||
type: String |
||||
}, |
||||
prop: { |
||||
type: Object, |
||||
default: { |
||||
text: 'text', |
||||
value: 'value' |
||||
} |
||||
} |
||||
}) |
||||
|
||||
const emit = defineEmits(['update:modelValue', 'change']) |
||||
|
||||
function change(val) { |
||||
if (props.modelValue === val) { |
||||
emit('update:modelValue', '') |
||||
} else { |
||||
emit('update:modelValue', val) |
||||
} |
||||
emit('change') |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
.radio-group-container { |
||||
display: flex; |
||||
flex-wrap: wrap; |
||||
gap: 24rpx; |
||||
margin-bottom: 48rpx; |
||||
.radio-group-item { |
||||
height: 60rpx; |
||||
line-height: 60rpx; |
||||
width: 212rpx; |
||||
text-align: center; |
||||
background: #F6F6F6; |
||||
border-radius: 27rpx; |
||||
font-size: 15px; |
||||
border: 1px solid #F6F6F6; |
||||
&.active { |
||||
background: #E7F2FF; |
||||
border-color: var(--primary-color); |
||||
} |
||||
} |
||||
} |
||||
</style> |
||||
@ -0,0 +1,134 @@
|
||||
<template> |
||||
<view class="inspection-task-input" @tap="show = true"> |
||||
<view> |
||||
<view v-if="text">{{ text }}</view> |
||||
<view class="inspection-task-input_placeholder" v-else>请关联督察任务</view> |
||||
</view> |
||||
<view class="inspection-task-input_icon"> |
||||
<uni-icons type="down" v-if="!text"></uni-icons> |
||||
</view> |
||||
</view> |
||||
<view class="inspection-task-dialog" v-if="show"> |
||||
<view class="flex search"> |
||||
<view class="search-item flex justify-center" :search="searchFlag"> |
||||
<view class="flex gap-8 search-item-conent"> |
||||
<uni-easyinput prefixIcon="search" type="text" placeholder="搜索" :inputBorder="false" v-model="query.taskName" @focus="searchFlag = true" /> |
||||
</view> |
||||
</view> |
||||
<view class="search-item flex justify-center" v-if="!searchFlag"> |
||||
<view class="flex gap-8 search-item-conent"> |
||||
<uni-icons customPrefix="customicons" type="filter" size="20" color="#666" /> |
||||
<view>筛选</view> |
||||
</view> |
||||
</view> |
||||
<view v-else> |
||||
<view class="cancel-btn" @tap="cancleSearch">取消</view> |
||||
</view> |
||||
</view> |
||||
<view class="inspection-task-container"> |
||||
<view v-for="item in tasks" class="inspection-task-item" @tap="handleSelect(item)"> |
||||
<view class="row"> |
||||
<view class="col col-24"> |
||||
<view class="label">任务名称:</view> |
||||
<view class="content">{{ item.taskName }}</view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">参与人员:</view> |
||||
<view class="content">{{ item.persons }}</view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">督察单位:</view> |
||||
<view class="content">{{ item.supDepartName }}</view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">任务类型:</view> |
||||
<view class="content">{{ item.supervisionType }}</view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">任务内容:</view> |
||||
<view class="content">{{ item.taskContent }}</view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">督察时间:</view> |
||||
<view class="content">{{ item.beginTime }} ~ {{ item.endTime }}</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
<view class="footer col-24"> |
||||
<button type="primary" @click="handleAdd">创建督察任务</button> |
||||
</view> |
||||
</view> |
||||
</template> |
||||
|
||||
<script setup> |
||||
import { ref, defineProps, defineEmits, onMounted } from 'vue'; |
||||
import { listInspection } from '@/api/inspection' |
||||
|
||||
defineProps({ |
||||
modelValue: { |
||||
type: Object |
||||
} |
||||
}) |
||||
const emit = defineEmits(['update:modelValue']); |
||||
|
||||
const show = ref(false); |
||||
const query = ref({}); |
||||
const searchFlag = ref(false) |
||||
const tasks = ref([]); |
||||
const text = ref('') |
||||
|
||||
function cancleSearch() { |
||||
searchFlag.value = false |
||||
} |
||||
|
||||
onMounted(() => { |
||||
listInspection(query.value).then(data => { |
||||
tasks.value = data.records |
||||
}) |
||||
}) |
||||
|
||||
function handleSelect(item) { |
||||
text.value = item.taskName; |
||||
emit('update:modelValue', item.id); |
||||
show.value = false |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss"> |
||||
.inspection-task-input { |
||||
width: 100%; |
||||
display: flex; |
||||
justify-content: space-between; |
||||
padding-right: 10px; |
||||
.inspection-task-input_placeholder { |
||||
font-size: 12px; |
||||
color: grey; |
||||
padding-left: 6px; |
||||
} |
||||
.inspection-task-input_icon { |
||||
.uni-icons { |
||||
color: #666 !important; |
||||
} |
||||
} |
||||
} |
||||
.inspection-task-dialog { |
||||
background-color: #fff; |
||||
position: fixed; |
||||
top: 0; |
||||
/* #ifdef H5 */ |
||||
top: 44px; |
||||
/* #endif */ |
||||
left: 0; |
||||
right: 0; |
||||
bottom: 0; |
||||
z-index: 9999; |
||||
} |
||||
.inspection-task-container { |
||||
padding: 0 24rpx; |
||||
.inspection-task-item { |
||||
padding: 24rpx 0; |
||||
box-shadow: inset 0 -1px 0 0 #DDDDDD; |
||||
} |
||||
} |
||||
</style> |
||||
@ -0,0 +1,110 @@
|
||||
<template> |
||||
<view class="wrapper" v-if="show"> |
||||
<view class="modal-container"> |
||||
<view class="modal-body"> |
||||
<view class="model-title">{{ title }}</view> |
||||
<view> |
||||
<uni-forms ref="formRef" :modelValue="formData" :rules="rules"> |
||||
<uni-forms-item name="value"> |
||||
<uni-easyinput type="textarea" :placeholder="placeholderText" v-model="formData.value" /> |
||||
</uni-forms-item> |
||||
</uni-forms> |
||||
</view> |
||||
</view> |
||||
<view class="footer col-24 flex gap-8"> |
||||
<button class="col-12" @tap="close">取消</button> |
||||
<button :type="confirmType" @tap="confirm" class="col-12">{{ confirmText }}</button> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
</template> |
||||
|
||||
<script setup> |
||||
import { ref, defineProps, defineEmits, defineExpose } from 'vue' |
||||
|
||||
const props = defineProps({ |
||||
title: { |
||||
type: String, |
||||
default: '温馨提示' |
||||
}, |
||||
placeholderText: { |
||||
type: String, |
||||
default: '' |
||||
}, |
||||
confirmText: { |
||||
type: String, |
||||
default: '提交' |
||||
}, |
||||
confirmType: { |
||||
type: String, |
||||
default: 'primary' |
||||
} |
||||
}) |
||||
const emit = defineEmits(['confirm']) |
||||
|
||||
const formData = ref({}); |
||||
const rules = { |
||||
value: { |
||||
rules: [{ |
||||
required: true, |
||||
errorMessage: props.placeholderText, |
||||
}] |
||||
}, |
||||
} |
||||
const formRef = ref() |
||||
const show = ref(false) |
||||
|
||||
function confirm() { |
||||
formRef.value.validate().then(res => { |
||||
emit('confirm', formData.value.value) |
||||
close() |
||||
}) |
||||
} |
||||
|
||||
function open() { |
||||
show.value = true |
||||
} |
||||
|
||||
function close() { |
||||
show.value = false |
||||
} |
||||
|
||||
defineExpose({ |
||||
open, |
||||
close |
||||
}); |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
.wrapper { |
||||
position: fixed; |
||||
top: 0; |
||||
left: 0; |
||||
right: 0; |
||||
bottom: 0; |
||||
background-color: rgba(0, 0, 0, .6); |
||||
display: flex; |
||||
justify-content: center; |
||||
align-items: center; |
||||
z-index: 9999; |
||||
.modal-container { |
||||
background-color: #fff; |
||||
border-radius: 16rpx; |
||||
width: 80vw; |
||||
.modal-body { |
||||
padding: 24rpx 24rpx 0 24rpx; |
||||
.model-title { |
||||
font-size: 18px; |
||||
font-weight: bold; |
||||
line-height: 50rpx; |
||||
text-align: center; |
||||
margin-bottom: 12rpx; |
||||
} |
||||
} |
||||
.footer { |
||||
position: static; |
||||
padding-top: 0; |
||||
} |
||||
} |
||||
} |
||||
</style> |
||||
@ -0,0 +1,36 @@
|
||||
<template> |
||||
<button :type="type" :plain="plain" :class="`button ${type}`">{{ label }}</button> |
||||
</template> |
||||
|
||||
<script setup> |
||||
import { defineProps } from 'vue' |
||||
|
||||
defineProps({ |
||||
label: { |
||||
type: String, |
||||
default: '' |
||||
}, |
||||
type: { |
||||
type: String, |
||||
default: '' |
||||
}, |
||||
plain: { |
||||
type: Boolean, |
||||
default: true |
||||
} |
||||
}) |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
.button { |
||||
font-size: 26rpx; |
||||
border-radius: 4rpx; |
||||
padding-left: 24rpx; |
||||
padding-right: 24rpx; |
||||
&.danger { |
||||
background-color: var(--danger-color); |
||||
border-color: var(--danger-color); |
||||
color: #fff; |
||||
} |
||||
} |
||||
</style> |
||||
@ -0,0 +1,420 @@
|
||||
<template> |
||||
<view class="wrapper"> |
||||
<template v-if="!loading"> |
||||
<view class="header"> |
||||
<view class="flex"> |
||||
<view v-for="(item, index) in steps" class="step text-center" :active="index == activeIndex" :completed="index < activeIndex"> |
||||
<text>{{ index + 1 }}</text> |
||||
<text>{{ item }}</text> |
||||
</view> |
||||
</view> |
||||
<view class="timer" v-if="!remainingDuration || remainingDuration >= 0"> |
||||
<view class="flex between mb-8"> |
||||
<text>剩余处理时间</text> |
||||
<text>{{ formatTimeText(remainingDuration) }}</text> |
||||
</view> |
||||
<!-- <view class="progress"> |
||||
<view class="progress-action" :style="{width: `${percentage}%`}" :type="getType()"></view> |
||||
</view> --> |
||||
</view> |
||||
<view class="timer-danger flex between" v-else> |
||||
<text>超时</text> |
||||
<text>{{ formatTimeText(remainingDuration) }}</text> |
||||
</view> |
||||
</view> |
||||
<tabs :options="tabOptions" :labelFull="true" v-model="current" /> |
||||
<template v-if="current === 'info'"> |
||||
<view class="container"> |
||||
<view class="h1">问题信息</view> |
||||
<view class="row" style="--label-width: 170rpx"> |
||||
<view class="col col-24"> |
||||
<view class="label">源头编号:</view> |
||||
<view class="content">{{ negative.originId }}</view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">问题发现时间:</view> |
||||
<view class="content">{{ negative.discoveryTime }}</view> |
||||
</view> |
||||
<view class="col col-24" v-if="negative.happenTime"> |
||||
<view class="label">问题发生时间:</view> |
||||
<view class="content">{{ negative.happenTime }}</view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">问题来源:</view> |
||||
<view class="content">{{ negative.problemSources }}</view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">业务类别:</view> |
||||
<view class="content">{{ negative.businessTypeName }}</view> |
||||
</view> |
||||
<view class="col col-12" v-if="negative.responderName"> |
||||
<view class="label">投诉反映人:</view> |
||||
<view class="content">{{ negative.responderName }}</view> |
||||
</view> |
||||
<view class="col col-12" v-if="negative.responderName"> |
||||
<view class="label">联系电话:</view> |
||||
<view class="content">{{ negative.contactPhone }}</view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">涉嫌问题:</view> |
||||
<view class="content">{{ getDictLabelByArray(suspectProblems, negative.involveProblem) || '/' }}</view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">涉及单位:</view> |
||||
<view class="content">{{ negative.involveDepartName }}</view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label" style="text-align: left;">事情简要描述</view> |
||||
</view> |
||||
<view class="col col-24 c">{{ negative.thingDesc }}</view> |
||||
</view> |
||||
</view> |
||||
<view class="container" v-if="negative.checkStatusName"> |
||||
<view class="h1">核查办理</view> |
||||
<view class="row" style="--label-width: 170rpx"> |
||||
<view class="col col-12"> |
||||
<view class="label">核查情况:</view> |
||||
<view class="content">{{ negative.checkStatusName }}</view> |
||||
</view> |
||||
<view class="col col-12" v-if="negative.isRectifyName"> |
||||
<view class="label">是否已整改:</view> |
||||
<view class="content">{{ negative.isRectifyName }}</view> |
||||
</view> |
||||
<view class="col col-12" v-if="negative.happenTime"> |
||||
<view class="label">追责对象:</view> |
||||
<view class="content">{{ getDictLabel(accountabilityTarget, negative.accountabilityTarget) }}</view> |
||||
</view> |
||||
<view class="col col-12" v-if="negative.rectifyRestrictionDays"> |
||||
<view class="label">整改限制:</view> |
||||
<view class="content">{{ negative.rectifyRestrictionDays }}天</view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label" style="text-align: left;">问题核查情况</view> |
||||
</view> |
||||
<view class="col col-24 c">{{ negative.checkStatusDesc }}</view> |
||||
<view class="col col-24" v-if="negative.rectifyDesc"> |
||||
<view class="label" style="text-align: left;">问题整改情况</view> |
||||
</view> |
||||
<view class="col col-24 c" v-if="negative.rectifyDesc">{{ negative.rectifyDesc }}</view> |
||||
<view class="col col-24" v-if="negative.unrectifyReason"> |
||||
<view class="label" style="text-align: left;">问题未整改原因</view> |
||||
</view> |
||||
<view class="col col-24 c" v-if="negative.rectifyDesc">{{ negative.unrectifyReason }}</view> |
||||
</view> |
||||
</view> |
||||
<view class="container" v-if="negative.checkStatusName" v-for="(item, index) in negative.blames"> |
||||
<view class="h1">涉及人员{{ index + 1 }}</view> |
||||
<view class="row" style="--label-width: 170rpx"> |
||||
<view class="col col-12"> |
||||
<view class="label">姓名:</view> |
||||
<view class="content">{{ item.blameName }}</view> |
||||
</view> |
||||
<view class="col col-12"> |
||||
<view class="label">警号:</view> |
||||
<view class="content">{{ item.blameEmpNo }}</view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">身份证:</view> |
||||
<view class="content">{{ item.blameIdCode }}</view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">人员属性:</view> |
||||
<view class="content">{{ getDictLabel(personTypes, item.ivPersonTypeCode) }}</view> |
||||
</view> |
||||
<view class="col col-24" v-for="(problem, index) in item.problems"> |
||||
<view class="label">问题类型{{ index + 1 }}:</view> |
||||
<view class="content">{{ problem.oneLevelContent }} / {{ problem.twoLevelContent }} / {{ problem.threeLevelContent }}</view> |
||||
</view> |
||||
<template v-if="negative.checkStatus === '1' || negative.checkStatus === '2'"> |
||||
<view class="col col-12" v-if="item.responsibilityTypeName"> |
||||
<view class="label">责任类别:</view> |
||||
<view class="content">{{ item.responsibilityTypeName }}</view> |
||||
</view> |
||||
<view class="col col-12" > |
||||
<view class="label">主观方面:</view> |
||||
<view class="content">{{ item.subjectiveAspectName }}</view> |
||||
</view> |
||||
<view class="col col-12" v-if="item.protectRightsName"> |
||||
<view class="label">维权容错:</view> |
||||
<view class="content">{{ item.protectRightsName }}</view> |
||||
</view> |
||||
<view class="col col-12" v-if="item.superviseMeasuresName"> |
||||
<view class="label">督察措施:</view> |
||||
<view class="content">{{ item.superviseMeasuresName }}</view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">处置结果:</view> |
||||
<view class="content">{{ item.handleResultName }} {{ item.handleResultNameOther }}</view> |
||||
</view> |
||||
</template> |
||||
|
||||
</view> |
||||
<view class="h1">涉及领导</view> |
||||
<view class="row" style="--label-width: 180rpx"> |
||||
<view class="col col-12"> |
||||
<view class="label">领导姓名:</view> |
||||
<view class="content">{{ item.leadName }}</view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">身份证:</view> |
||||
<view class="content">{{ item.leadIdCode }}</view> |
||||
</view> |
||||
<template v-if="negative.checkStatus === '1' || negative.checkStatus === '2'"> |
||||
<view class="col col-12"> |
||||
<view class="label">责任类别:</view> |
||||
<view class="content">{{ item.responsibilityTypeName }}</view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">处置结果:</view> |
||||
<view class="content">{{ item.leadHandleResultName }} {{ item.leadHandleResultNameOther }}</view> |
||||
</view> |
||||
</template> |
||||
</view> |
||||
</view> |
||||
<view class="container" v-if="negative.files?.length"> |
||||
<view class="h1">办结佐证材料</view> |
||||
<file-list :files="negative.files" /> |
||||
</view> |
||||
|
||||
</template> |
||||
<template v-else> |
||||
<view class="container"> |
||||
<!-- <view class="action-history-header"> |
||||
<text>总耗时</text> |
||||
<text class="ml-8">{{ getTotalTime() }}</text> |
||||
</view> --> |
||||
<view class="body" > |
||||
<view v-for="(item, index) in actionHistory" class="action-history"> |
||||
<view class="action-history-info"> |
||||
<text class="time mr-12">{{ item.crtTime }}</text> |
||||
<text class="mr-4">{{ item.departName }}</text> |
||||
<text class="mr-12">{{ item.crtName }}</text> |
||||
<text class="primary uni-bold">{{ item.actionName }}</text> |
||||
</view> |
||||
<view class="flex-inline gap action-history-time"> |
||||
<text class="info mr-12" v-if="index > 0">用时</text> |
||||
<text class="primary" v-if="index > 0">{{ getTime(index) }}</text> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
</template> |
||||
</template> |
||||
<template v-else> |
||||
<view class="header"> |
||||
<view class="flex"> |
||||
<view v-for="(item, index) in steps" class="step text-center"> |
||||
<text>{{ index + 1 }}</text> |
||||
<text>{{ item }}</text> |
||||
</view> |
||||
</view> |
||||
<view class="timer"> |
||||
<view class="flex mb-8"> |
||||
<text>剩余处理时间 0</text> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
<tabs :options="tabOptions" :labelFull="true" v-model="current" /> |
||||
<view class="container"> |
||||
<view class="h1">问题信息</view> |
||||
<view class="row" style="--label-width: 170rpx"> |
||||
<view class="col col-24"> |
||||
<view class="label">源头编号:</view> |
||||
<view class="content"> |
||||
<skeleton width="50%" /> |
||||
</view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">问题发现时间:</view> |
||||
<view class="content"><skeleton width="50%" /></view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">问题来源:</view> |
||||
<view class="content"><skeleton width="50%" /></view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">业务类别:</view> |
||||
<view class="content"><skeleton width="50%" /></view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">涉嫌问题:</view> |
||||
<view class="content"><skeleton /></view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">涉及单位:</view> |
||||
<view class="content"><skeleton width="50%" /></view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label" style="text-align: left;">事情简要描述</view> |
||||
</view> |
||||
<skeleton width="100%" height="120rpx" /> |
||||
</view> |
||||
</view> |
||||
</template> |
||||
</view> |
||||
</template> |
||||
|
||||
<script setup> |
||||
import moment from 'moment' |
||||
import { ref, defineProps, watch } from 'vue' |
||||
import { formatTimeText, getDictLabel, getDictLabelByArray } from '@/common/util' |
||||
import { getDictOptions } from '@/common/dict' |
||||
|
||||
const personTypes = getDictOptions('personType'); |
||||
const suspectProblems = getDictOptions('suspectProblem'); |
||||
const accountabilityTarget = getDictOptions('accountabilityTarget'); |
||||
const steps = ['问题签收', '核查办理', '办结审批', '认定办结']; |
||||
const activeIndex = ref(1) |
||||
const tabOptions = [ |
||||
{ |
||||
text: '问题详情', |
||||
value: 'info' |
||||
}, |
||||
{ |
||||
text: '流转记录', |
||||
value: 'flow' |
||||
} |
||||
] |
||||
const current = ref('info') |
||||
|
||||
const props = defineProps({ |
||||
data: { |
||||
type: Object, |
||||
default: {} |
||||
}, |
||||
loading: { |
||||
type: Boolean, |
||||
default: false |
||||
} |
||||
}); |
||||
|
||||
const negative = ref({}) |
||||
const remainingDuration = ref(0) |
||||
const actionHistory = ref([]) |
||||
watch(() => props.data, (data) => { |
||||
negative.value = data.negative |
||||
remainingDuration.value = data.remainingDuration |
||||
actionHistory.value = data.actionHistory |
||||
}) |
||||
|
||||
function getTime(index) { |
||||
console.log(moment(actionHistory.value[index].crtTime, 'YYYY-MM-DD HH:mm:ss')) |
||||
return formatTimeText(moment(actionHistory.value[index].crtTime, 'YYYY-MM-DD HH:mm:ss').diff(moment(actionHistory.value[index - 1].crtTime, 'YYYY-MM-DD HH:mm:ss'), 'seconds')) |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
.header { |
||||
background-color: var(--primary-color); |
||||
} |
||||
.step { |
||||
--background-color: #004CB5; |
||||
width: 25%; |
||||
color: #ACB7FF; |
||||
height: 40rpx; |
||||
line-height: 38rpx; |
||||
border-top: 1rpx solid #4B60E4; |
||||
border-bottom: 1rpx solid #4B60E4; |
||||
box-sizing: border-box; |
||||
position: relative; |
||||
background-color: var(--background-color); |
||||
text-align: center; |
||||
font-size: 12px; |
||||
&:before { |
||||
display: block; |
||||
content: ''; |
||||
height: 25.87rpx; |
||||
width: 25.87rpx; |
||||
position: absolute; |
||||
top: 5.5rpx; |
||||
right: -13.43rpx; |
||||
border-top: 1rpx solid #4B60E4; |
||||
border-right: 1rpx solid #4B60E4; |
||||
transform: rotate(45deg); |
||||
z-index: 1; |
||||
background-color: var(--background-color);; |
||||
} |
||||
&:last-child::before { |
||||
display: none; |
||||
} |
||||
&[active=true] { |
||||
--background-color: #f40000; |
||||
border-color: #FF7474; |
||||
color: #fff; |
||||
&:before { |
||||
border-color: #FF7474; |
||||
} |
||||
} |
||||
&[completed=true] { |
||||
color: #fff; |
||||
} |
||||
} |
||||
.timer { |
||||
padding: 12px; |
||||
} |
||||
.timer-danger { |
||||
background: linear-gradient( 180deg, #FF5C37 0%, #E03021 100%); |
||||
color: #fff; |
||||
height: 45px; |
||||
line-height: 45px; |
||||
margin-top: 10px; |
||||
padding: 0 10px; |
||||
} |
||||
.h1 { |
||||
font-weight: 700; |
||||
margin-bottom: 24rpx; |
||||
} |
||||
.c { |
||||
background: #E7F2FF; |
||||
padding: 24rpx; |
||||
} |
||||
.container { |
||||
background-color: #fff; |
||||
margin-bottom: 12rpx; |
||||
} |
||||
.wrapper { |
||||
background-color: #f5f5f5; |
||||
} |
||||
|
||||
.action-history-header { |
||||
height: 52rpx; |
||||
line-height: 52rpx; |
||||
margin-bottom: 24rpx; |
||||
} |
||||
.action-history { |
||||
margin-bottom: 16rpx; |
||||
.action-history-info { |
||||
margin-bottom: 16rpx; |
||||
padding-left: 36rpx; |
||||
position: relative; |
||||
display: flex; |
||||
align-items: center; |
||||
&:before { |
||||
content: ''; |
||||
display: block; |
||||
position: absolute; |
||||
left: 0; |
||||
top: 50%; |
||||
transform: translate(-50%, -50%); |
||||
width: 20rpx; |
||||
height: 20rpx; |
||||
background-color: #bfbfbf; |
||||
border: 1px solid #f1fff1; |
||||
border-radius: 50%; |
||||
} |
||||
.time { |
||||
color: #999; |
||||
font-size: 12px; |
||||
} |
||||
} |
||||
.action-history-time { |
||||
height: 56rpx; |
||||
line-height: 56rpx; |
||||
padding-left: 32rpx; |
||||
padding-right: 40rpx; |
||||
background: #F5F6FF; |
||||
border-left: 2px solid #00D050; |
||||
border-radius: 0 24rpx 24rpx 0; |
||||
} |
||||
} |
||||
</style> |
||||
@ -0,0 +1,30 @@
|
||||
<template> |
||||
<image :src="src"></image> |
||||
</template> |
||||
|
||||
<script setup> |
||||
import { onMounted, ref, defineProps } from 'vue'; |
||||
import store from '@/store' |
||||
import { getFileBase64 } from '@/api/file' |
||||
|
||||
const props = defineProps({ |
||||
filepath: { |
||||
type: String |
||||
} |
||||
}); |
||||
|
||||
const src = ref(''); |
||||
console.log('filepath', props.filepath) |
||||
onMounted(() => { |
||||
getFileBase64(props.filepath).then(data => { |
||||
src.value = data; |
||||
}) |
||||
}) |
||||
|
||||
</script> |
||||
|
||||
<style scoped> |
||||
image { |
||||
background-color: #eee; |
||||
} |
||||
</style> |
||||
@ -0,0 +1,214 @@
|
||||
<template> |
||||
<view class="police-c"> |
||||
<view class="police-item-tag-box"> |
||||
<view v-for="item in activePolices" class="police-item-tag police-item-tag_small">{{ item.name.substring(item.name.length - 2) }}</view> |
||||
</view> |
||||
<button size="small" @tap="show = true" class="add-btn"> |
||||
<uni-icons type="plusempty" size="20"></uni-icons> |
||||
</button> |
||||
</view> |
||||
<view class="police-picker-container" v-if="show"> |
||||
<view class="header"> |
||||
<view class="hidden-btn" @tap="show = false"> |
||||
<uni-icons type="left" size="20"></uni-icons> |
||||
</view> |
||||
<uni-easyinput prefixIcon="search" type="text" placeholder="搜索" v-model="query.name" /> |
||||
</view> |
||||
<!-- <uni-data-picker :localdata="departs" :border="false" |
||||
:map="{text:'shortName', value: 'id'}" v-model="query.departId" /> --> |
||||
<view class="police-container"> |
||||
<view class="police-item" v-for="item in polices" @tap="handleChange(item)"> |
||||
<checkbox :checked="activePolices.findIndex(police => item.empNo === police.empNo) !== -1" @tap.stop="handleChange(item)" /> |
||||
<view class="police-item-tag">{{ item.name.substring(item.name.length - 2) }}</view> |
||||
<view>{{ item.name }}</view> |
||||
</view> |
||||
</view> |
||||
<view class="footer"> |
||||
<view class="footer-left"> |
||||
<view>已选择({{ activePolices.length }}):</view> |
||||
<view class="police-item-tag-container"> |
||||
<view class="police-item-tag-box"> |
||||
<view v-for="item in activePolices" class="police-item-tag police-item-tag_small">{{ item.name.substring(item.name.length - 2) }}</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
<button type="primary" @tap="show = false">确定</button> |
||||
</view> |
||||
</view> |
||||
</template> |
||||
|
||||
<script setup> |
||||
import { onMounted, ref, watch, defineProps, defineEmits } from 'vue'; |
||||
import { listPolice } from '@/api/police' |
||||
import { |
||||
departTree |
||||
} from '@/api/depart' |
||||
|
||||
const props = defineProps({ |
||||
modelValue: { |
||||
type: Array, |
||||
default: [] |
||||
}, |
||||
departId: { |
||||
type: String, |
||||
default: '' |
||||
} |
||||
}) |
||||
|
||||
const emit = defineEmits(['update:modelValue']) |
||||
|
||||
const show = ref(false); |
||||
const polices = ref([]); |
||||
const query = ref({ |
||||
current: 1, |
||||
size: 16, |
||||
departBranch: true, |
||||
}) |
||||
|
||||
watch(() => props.modelValue, (val) => { |
||||
if (val) { |
||||
polices.value = val |
||||
} else { |
||||
polices.value = [] |
||||
} |
||||
}) |
||||
|
||||
watch(() => props.departId, (val) => { |
||||
query.value.departId = val; |
||||
getPolice() |
||||
}) |
||||
|
||||
const activePolices = ref(props.modelValue || []); |
||||
|
||||
function handleChange(police) { |
||||
const index = activePolices.value.findIndex(item => item.empNo === police.empNo); |
||||
if (index === -1) { |
||||
activePolices.value.push({ |
||||
name: police.name, |
||||
empNo: police.empNo, |
||||
}) |
||||
emit('update:modelValue', activePolices.value) |
||||
} else { |
||||
activePolices.value.splice(index, 1) |
||||
emit('update:modelValue', activePolices.value) |
||||
} |
||||
} |
||||
|
||||
const departs = ref([]) |
||||
const departId = ref('') |
||||
onMounted(() => { |
||||
getPolice() |
||||
departTree().then(data => { |
||||
departs.value = data[0].children |
||||
}) |
||||
}) |
||||
|
||||
watch(() => query.value.name, () => { |
||||
getPolice() |
||||
}) |
||||
|
||||
function getPolice() { |
||||
listPolice(query.value).then(data => { |
||||
polices.value = data.records |
||||
}) |
||||
} |
||||
|
||||
|
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
.police-picker-container { |
||||
position: fixed; |
||||
top: 0; |
||||
left: 0; |
||||
right: 0; |
||||
bottom: 0; |
||||
background-color: #f5f5f5; |
||||
z-index: 9999; |
||||
.header { |
||||
display: flex; |
||||
padding: 24rpx; |
||||
padding-left: 0; |
||||
display: flex; |
||||
align-items: center; |
||||
gap: 0 12rpx; |
||||
background-color: #fff; |
||||
margin-bottom: 12rpx; |
||||
position: relative; |
||||
.hidden-btn { |
||||
height: 37px; |
||||
width: 37px; |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: center; |
||||
} |
||||
} |
||||
.police-item { |
||||
|
||||
background-color: #fff; |
||||
height: 88rpx; |
||||
line-height: 88rpx; |
||||
display: flex; |
||||
gap: 0 24rpx; |
||||
align-items: center; |
||||
padding-left: 24rpx; |
||||
|
||||
} |
||||
.footer { |
||||
display: flex; |
||||
justify-content: space-between; |
||||
align-items: center; |
||||
width: 100%; |
||||
background-color: #fff; |
||||
button { |
||||
margin: 0; |
||||
} |
||||
.footer-left { |
||||
display: flex; |
||||
align-items: center; |
||||
width: calc(100% - 64px); |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
.police-container { |
||||
max-height: 82vh; |
||||
overflow: auto; |
||||
} |
||||
|
||||
.police-item-tag { |
||||
background-color: var(--primary-color); |
||||
color: #fff; |
||||
height: 72rpx; |
||||
width: 72rpx; |
||||
line-height: 72rpx; |
||||
text-align: center; |
||||
border-radius: 10rpx; |
||||
&_small { |
||||
height: 52rpx; |
||||
width: 52rpx; |
||||
line-height: 52rpx; |
||||
font-size: 12px; |
||||
} |
||||
} |
||||
.add-btn { |
||||
height: 52rpx; |
||||
width: 52rpx; |
||||
line-height: 52rpx; |
||||
padding: 0; |
||||
} |
||||
.police-item-tag-container { |
||||
width: calc(100% - 200rpx); |
||||
overflow: hidden; |
||||
} |
||||
.police-item-tag-box { |
||||
display: flex; |
||||
gap: 0 12rpx; |
||||
width: max-content; |
||||
} |
||||
.police-c { |
||||
display: flex; |
||||
gap: 0 12rpx; |
||||
} |
||||
</style> |
||||
@ -0,0 +1,21 @@
|
||||
<template> |
||||
<uni-data-picker :localdata="localdata" placeholder="请选择问题类型" :border="false" :map="{text:'name', value: 'id'}" /> |
||||
</template> |
||||
|
||||
<script setup> |
||||
import { onMounted, ref} from 'vue' |
||||
import { problemTypeTree } from '@/api/problemType' |
||||
|
||||
const localdata = ref([]); |
||||
|
||||
onMounted(() => { |
||||
problemTypeTree().then(data => { |
||||
localdata.value = data; |
||||
}) |
||||
}) |
||||
|
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
|
||||
</style> |
||||
@ -0,0 +1,52 @@
|
||||
<template> |
||||
<view class="skeleton" :style="{width, height}"></view> |
||||
</template> |
||||
|
||||
<script setup> |
||||
import { defineProps } from 'vue' |
||||
|
||||
defineProps({ |
||||
width: { |
||||
type: String, |
||||
default: '' |
||||
}, |
||||
height: { |
||||
type: String, |
||||
default: '' |
||||
} |
||||
}) |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
.skeleton { |
||||
height: 100%; |
||||
background: #f0f0f0; |
||||
position: relative; |
||||
border-radius: 24rpx; |
||||
display: block; |
||||
} |
||||
.skeleton::after { |
||||
content: ""; |
||||
position: absolute; |
||||
top: 0; |
||||
left: 0; |
||||
width: 100%; |
||||
height: 100%; |
||||
background: linear-gradient( |
||||
90deg, |
||||
transparent, |
||||
rgba(255, 255, 255, 0.5), |
||||
transparent |
||||
); |
||||
animation: skeleton-shimmer 1.5s infinite; |
||||
} |
||||
|
||||
@keyframes skeleton-shimmer { |
||||
0% { |
||||
transform: translateX(-100%); |
||||
} |
||||
100% { |
||||
transform: translateX(100%); |
||||
} |
||||
} |
||||
</style> |
||||
@ -0,0 +1,87 @@
|
||||
<template> |
||||
<view class="tabs" ref="tab"> |
||||
<view v-for="item in options" :class="modelValue === item.value ? 'tabs-item active' : 'tabs-item'" @tap="changeTab(item.value)"> |
||||
<view class="tabs-item-label" :style="{width: labelFull ? '100%' : 'auto'}">{{ item.text }}</view> |
||||
</view> |
||||
<view class="tab-active-bar" :style="{width: `${width}px`, transform: `translateX(${left}px)`}"></view> |
||||
</view> |
||||
</template> |
||||
<script setup> |
||||
import { defineProps, defineEmits, nextTick, ref, onMounted } from 'vue' |
||||
defineProps({ |
||||
options: { |
||||
type: Array, |
||||
default: [] |
||||
}, |
||||
modelValue: { |
||||
type: String, |
||||
default: '' |
||||
}, |
||||
labelFull: { |
||||
type: Boolean, |
||||
default: false |
||||
} |
||||
}); |
||||
const emit = defineEmits(['update:modelValue']); |
||||
|
||||
const tab = ref() |
||||
const width = ref(0) |
||||
const left = ref(0) |
||||
|
||||
function changeTab(value) { |
||||
emit('update:modelValue', value); |
||||
nextTick(() => { |
||||
getActiveBarStyle() |
||||
}) |
||||
} |
||||
|
||||
onMounted(() => { |
||||
nextTick(() => { |
||||
getActiveBarStyle() |
||||
}) |
||||
}) |
||||
|
||||
function getActiveBarStyle() { |
||||
const query = uni.createSelectorQuery().in(this); |
||||
query |
||||
.select(".tabs-item.active>.tabs-item-label") |
||||
.boundingClientRect((data) => { |
||||
width.value = data.width; |
||||
left.value = data.left; |
||||
}) |
||||
.exec(); |
||||
|
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
.tabs { |
||||
display: flex; |
||||
box-shadow: inset 0 -1px 0 0 #eee; |
||||
position: relative; |
||||
.tabs-item { |
||||
width: 50%; |
||||
display: flex; |
||||
justify-content: center; |
||||
.tabs-item-label { |
||||
text-align: center; |
||||
height: 84rpx; |
||||
line-height: 84rpx; |
||||
color: #333; |
||||
} |
||||
&.active { |
||||
.tabs-item-label { |
||||
color: var(--primary-color); |
||||
} |
||||
} |
||||
} |
||||
.tab-active-bar { |
||||
height: 2px; |
||||
position: absolute; |
||||
bottom: 0; |
||||
transition: all .3s; |
||||
background-color: var(--primary-color); |
||||
} |
||||
} |
||||
|
||||
</style> |
||||
@ -0,0 +1,182 @@
|
||||
<template> |
||||
<view class="upload-container"> |
||||
<view v-for="(item, index) in files" class="upload-item"> |
||||
<net-image :filepath="item.filePath" /> |
||||
<button class="remove-btn" @tap="handleRemove(index)"> |
||||
<uni-icons type="closeempty" color="#fff" size="18" /> |
||||
</button> |
||||
</view> |
||||
<view class="upload-btn upload-item" @tap="chooseImage"> |
||||
<uni-icons type="plusempty" size="32" color="#162582" /> |
||||
</view> |
||||
</view> |
||||
</template> |
||||
|
||||
<script setup> |
||||
import { ref, defineProps, defineEmits } from 'vue' |
||||
import store from '@/store' |
||||
import { pathToBase64 } from 'image-tools' |
||||
import { |
||||
uploadFileBase64 |
||||
} from '@/api/file' |
||||
import permission from '@/common/permission' |
||||
|
||||
var sourceType = [ |
||||
['camera'], |
||||
['album'], |
||||
['camera', 'album'] |
||||
] |
||||
var sizeType = [ |
||||
['compressed'], |
||||
['original'], |
||||
['compressed', 'original'] |
||||
] |
||||
|
||||
const props = defineProps({ |
||||
modelValue: { |
||||
type: Array, |
||||
default: [] |
||||
} |
||||
}); |
||||
const emit = defineEmits(['update:modelValue']); |
||||
|
||||
const files = ref(props.modelValue || []) |
||||
|
||||
async function chooseImage() { |
||||
// #ifdef APP-PLUS |
||||
// TODO 选择相机或相册时 需要弹出actionsheet,目前无法获得是相机还是相册,在失败回调中处理 |
||||
// if (this.sourceTypeIndex !== 2) { |
||||
// let status = await this.checkPermission(); |
||||
// if (status !== 1) { |
||||
// return; |
||||
// } |
||||
// } |
||||
// #endif |
||||
uni.chooseImage({ |
||||
sourceType: ['camera'], |
||||
sizeType: ['original'], |
||||
count: 3, |
||||
success: (res) => { |
||||
uni.showLoading({ |
||||
title: '文件上传中, 请稍等' |
||||
}); |
||||
res.tempFiles.forEach(async (file) => { |
||||
const base64 = await pathToBase64(file.path); |
||||
const filename = file.path.substring(file.path.lastIndexOf('/') + 1) |
||||
const data = await uploadFileBase64({ |
||||
base64, |
||||
originalFilename: filename |
||||
}) |
||||
files.value.push({ |
||||
filePath: data.filePath, |
||||
fileName: filename |
||||
}); |
||||
emit('update:modelValue', files.value) |
||||
uni.hideLoading(); |
||||
}) |
||||
}, |
||||
fail: (err) => { |
||||
console.log("err: ", err); |
||||
// #ifdef APP-PLUS |
||||
if (err['code'] && err.code !== 0 && this.sourceTypeIndex === 2) { |
||||
this.checkPermission(err.code); |
||||
} |
||||
// #endif |
||||
// #ifdef MP |
||||
if (err.errMsg.indexOf('cancel') !== '-1') { |
||||
return; |
||||
} |
||||
uni.getSetting({ |
||||
success: (res) => { |
||||
let authStatus = false; |
||||
switch (this.sourceTypeIndex) { |
||||
case 0: |
||||
authStatus = res.authSetting['scope.camera']; |
||||
break; |
||||
case 1: |
||||
authStatus = res.authSetting['scope.album']; |
||||
break; |
||||
case 2: |
||||
authStatus = res.authSetting['scope.album'] && res |
||||
.authSetting['scope.camera']; |
||||
break; |
||||
default: |
||||
break; |
||||
} |
||||
if (!authStatus) { |
||||
uni.showModal({ |
||||
title: '授权失败', |
||||
content: 'Hello uni-app需要从您的相机或相册获取图片,请在设置界面打开相关权限', |
||||
success: (res) => { |
||||
if (res.confirm) { |
||||
uni.openSetting() |
||||
} |
||||
} |
||||
}) |
||||
} |
||||
} |
||||
}) |
||||
// #endif |
||||
} |
||||
}) |
||||
} |
||||
async function checkPermission(code) { |
||||
let type = code ? code - 1 : this.sourceTypeIndex; |
||||
let status = await permision.requestAndroid(type === 0 ? 'android.permission.CAMERA' : |
||||
'android.permission.READ_EXTERNAL_STORAGE'); |
||||
|
||||
if (status === null || status === 1) { |
||||
status = 1; |
||||
} else { |
||||
uni.showModal({ |
||||
content: "没有开启权限", |
||||
confirmText: "设置", |
||||
success: function(res) { |
||||
if (res.confirm) { |
||||
permision.gotoAppSetting(); |
||||
} |
||||
} |
||||
}) |
||||
} |
||||
return status; |
||||
} |
||||
|
||||
function handleRemove(index) { |
||||
files.value.splice(index, 1) |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
.upload-container { |
||||
display: flex; |
||||
gap: 38rpx; |
||||
flex-wrap: wrap; |
||||
.upload-item { |
||||
height: 178rpx; |
||||
width: 178rpx; |
||||
position: relative; |
||||
image { |
||||
width: 100%; |
||||
height: 100%; |
||||
} |
||||
.remove-btn { |
||||
height: 46rpx; |
||||
width: 46rpx; |
||||
line-height: 46rpx; |
||||
border-radius: 50%; |
||||
position: absolute; |
||||
top: -20rpx; |
||||
right: -20rpx; |
||||
padding: 0; |
||||
background-color: #fff; |
||||
background-color: $uni-color-error; |
||||
} |
||||
} |
||||
} |
||||
.upload-btn { |
||||
display: flex; |
||||
justify-content: center; |
||||
align-items: center; |
||||
border: 1px solid #162582; |
||||
} |
||||
</style> |
||||
@ -0,0 +1,88 @@
|
||||
<!DOCTYPE html> |
||||
<html> |
||||
<head> |
||||
<meta charset="utf-8" /> |
||||
<meta name="viewport" content="width=device-width, initial-scale=1"> |
||||
<title>本地网页</title> |
||||
<style type="text/css"> |
||||
.btn { |
||||
display: block; |
||||
margin: 20px auto; |
||||
padding: 5px; |
||||
background-color: #007aff; |
||||
border: 0; |
||||
color: #ffffff; |
||||
height: 40px; |
||||
width: 200px; |
||||
} |
||||
|
||||
.btn-red { |
||||
background-color: #dd524d; |
||||
} |
||||
|
||||
.btn-yellow { |
||||
background-color: #f0ad4e; |
||||
} |
||||
|
||||
.desc { |
||||
padding: 10px; |
||||
color: #999999; |
||||
} |
||||
</style> |
||||
</head> |
||||
<body> |
||||
<p class="desc">web-view 组件加载本地 html 示例,仅在 App 环境下生效。点击下列按钮,跳转至其它页面。</p> |
||||
<div class="btn-list"> |
||||
<button class="btn" type="button" data-action="navigateTo">navigateTo</button> |
||||
<button class="btn" type="button" data-action="redirectTo">redirectTo</button> |
||||
<button class="btn" type="button" data-action="navigateBack">navigateBack</button> |
||||
<button class="btn" type="button" data-action="reLaunch">reLaunch</button> |
||||
<button class="btn" type="button" data-action="switchTab">switchTab</button> |
||||
</div> |
||||
<p class="desc">网页向应用发送消息。注意:小程序端应用会在此页面后退时接收到消息。</p> |
||||
<div class="btn-list"> |
||||
<button class="btn btn-red" type="button" id="postMessage">postMessage</button> |
||||
</div> |
||||
<!-- uni 的 SDK --> |
||||
<script type="text/javascript" src="https://unpkg.com/@dcloudio/uni-webview-js@0.0.1/index.js"></script> |
||||
<script type="text/javascript"> |
||||
document.addEventListener('UniAppJSBridgeReady', function() { |
||||
document.querySelector('.btn-list').addEventListener('click', function(evt) { |
||||
var target = evt.target; |
||||
if (target.tagName === 'BUTTON') { |
||||
var action = target.getAttribute('data-action'); |
||||
switch (action) { |
||||
case 'switchTab': |
||||
uni.switchTab({ |
||||
url: '/pages/tabBar/API/API' |
||||
}); |
||||
break; |
||||
case 'reLaunch': |
||||
uni.reLaunch({ |
||||
url: '/pages/tabBar/API/API' |
||||
}); |
||||
break; |
||||
case 'navigateBack': |
||||
uni.navigateBack({ |
||||
delta: 1 |
||||
}); |
||||
break; |
||||
default: |
||||
uni[action]({ |
||||
url: '/pages/component/button/button' |
||||
}); |
||||
break; |
||||
} |
||||
} |
||||
}); |
||||
document.querySelector("#postMessage").addEventListener('click', function() { |
||||
uni.postMessage({ |
||||
data: { |
||||
action: 'message' |
||||
} |
||||
}); |
||||
}) |
||||
}); |
||||
</script> |
||||
</body> |
||||
</html> |
||||
@ -0,0 +1,22 @@
|
||||
<!DOCTYPE html> |
||||
<html lang="zh-CN"> |
||||
<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> |
||||
<script src="/static/image-resize-3.0.1.min.js"></script> |
||||
<script src="/static/quill-1.3.7.min.js"></script> |
||||
<!--preload-links--> |
||||
<!--app-context--> |
||||
</head> |
||||
<body> |
||||
<div id="app"><!--app-html--></div> |
||||
<script type="module" src="/main.js"></script> |
||||
</body> |
||||
</html> |
||||
@ -0,0 +1,11 @@
|
||||
module.exports = { |
||||
testTimeout: 20000, |
||||
reporters: [ |
||||
'default' |
||||
], |
||||
watchPathIgnorePatterns: ['/node_modules/', '/dist/', '/.git/'], |
||||
moduleFileExtensions: ['js', 'json'], |
||||
rootDir: __dirname, |
||||
testMatch: ["<rootDir>/pages/**/*test.[jt]s?(x)"], |
||||
testPathIgnorePatterns: ['/node_modules/'] |
||||
} |
||||
@ -0,0 +1,45 @@
|
||||
import App from './App' |
||||
import store from './store' |
||||
|
||||
// #ifndef VUE3
|
||||
import Vue from 'vue' |
||||
Vue.config.productionTip = false |
||||
Vue.prototype.$store = store |
||||
Vue.prototype.$adpid = "1111111111" |
||||
Vue.prototype.$backgroundAudioData = { |
||||
playing: false, |
||||
playTime: 0, |
||||
formatedPlayTime: '00:00:00' |
||||
} |
||||
App.mpType = 'app' |
||||
const app = new Vue({ |
||||
store, |
||||
...App |
||||
}) |
||||
app.$mount() |
||||
// #endif
|
||||
|
||||
// #ifdef VUE3
|
||||
import { |
||||
createSSRApp |
||||
} from 'vue' |
||||
import * as Pinia from 'pinia'; |
||||
import Vuex from "vuex"; |
||||
export function createApp() { |
||||
const app = createSSRApp(App) |
||||
app.use(store) |
||||
app.use(Pinia.createPinia()); |
||||
|
||||
app.config.globalProperties.$adpid = "1111111111" |
||||
app.config.globalProperties.$backgroundAudioData = { |
||||
playing: false, |
||||
playTime: 0, |
||||
formatedPlayTime: '00:00:00' |
||||
} |
||||
return { |
||||
app, |
||||
Vuex, // 如果 nvue 使用 vuex 的各种map工具方法时,必须 return Vuex
|
||||
Pinia // 此处必须将 Pinia 返回
|
||||
} |
||||
} |
||||
// #endif
|
||||
@ -0,0 +1,200 @@
|
||||
{ |
||||
"name" : "supervision-app", |
||||
"appid" : "__UNI__3A60B92", |
||||
"description" : "应用描述", |
||||
"versionName" : "1.0.0", |
||||
"versionCode" : "100", |
||||
"transformPx" : false, |
||||
"app-plus" : { |
||||
"usingComponents" : true, |
||||
"nvueCompiler" : "uni-app", |
||||
"nvueStyleCompiler" : "uni-app", |
||||
"compilerVersion" : 3, |
||||
"nvueLaunchMode" : "fast", |
||||
"splashscreen" : { |
||||
"alwaysShowBeforeRender" : true, |
||||
"waiting" : true, |
||||
"autoclose" : true, |
||||
"delay" : 0 |
||||
}, |
||||
"compatible" : { |
||||
//uni-app兼容模式 |
||||
"ignoreVersion" : true |
||||
}, |
||||
"modules" : { |
||||
"OAuth" : {}, |
||||
"Payment" : {}, |
||||
"Push" : {}, |
||||
"Share" : {}, |
||||
"Speech" : {}, |
||||
"VideoPlayer" : {}, |
||||
"LivePusher" : {} |
||||
}, |
||||
"distribute" : { |
||||
"android" : { |
||||
"permissions" : [ |
||||
"<uses-feature android:name=\"android.hardware.camera\"/>", |
||||
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>", |
||||
"<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>", |
||||
"<uses-permission android:name=\"android.permission.VIBRATE\"/>", |
||||
"<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"/>", |
||||
"<uses-permission android:name=\"android.permission.ACCESS_MOCK_LOCATION\"/>", |
||||
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>", |
||||
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>", |
||||
"<uses-permission android:name=\"android.permission.CALL_PHONE\"/>", |
||||
"<uses-permission android:name=\"android.permission.CAMERA\"/>", |
||||
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>", |
||||
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>", |
||||
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>", |
||||
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>", |
||||
"<uses-permission android:name=\"android.permission.GET_TASKS\"/>", |
||||
"<uses-permission android:name=\"android.permission.INTERNET\"/>", |
||||
"<uses-permission android:name=\"android.permission.MODIFY_AUDIO_SETTINGS\"/>", |
||||
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>", |
||||
"<uses-permission android:name=\"android.permission.READ_CONTACTS\"/>", |
||||
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>", |
||||
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>", |
||||
"<uses-permission android:name=\"android.permission.READ_SMS\"/>", |
||||
"<uses-permission android:name=\"android.permission.RECEIVE_BOOT_COMPLETED\"/>", |
||||
"<uses-permission android:name=\"android.permission.RECORD_AUDIO\"/>", |
||||
"<uses-permission android:name=\"android.permission.SEND_SMS\"/>", |
||||
"<uses-permission android:name=\"android.permission.SYSTEM_ALERT_WINDOW\"/>", |
||||
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>", |
||||
"<uses-permission android:name=\"android.permission.WRITE_CONTACTS\"/>", |
||||
"<uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\"/>", |
||||
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>", |
||||
"<uses-permission android:name=\"android.permission.WRITE_SMS\"/>", |
||||
"<uses-permission android:name=\"android.permission.RECEIVE_USER_PRESENT\"/>" |
||||
] |
||||
}, |
||||
"ios" : {}, |
||||
"sdkConfigs" : { |
||||
"speech" : { |
||||
"ifly" : {} |
||||
} |
||||
}, |
||||
"orientation" : [ "portrait-primary" ], |
||||
"splashscreen" : { |
||||
"androidStyle" : "default", |
||||
"iosStyle" : "common", |
||||
"android" : { |
||||
"hdpi" : "static/splash.9.png" |
||||
} |
||||
} |
||||
}, |
||||
"uniStatistics" : { |
||||
"enable" : true |
||||
} |
||||
}, |
||||
"quickapp" : {}, |
||||
"quickapp-native" : { |
||||
"icon" : "/static/logo.png", |
||||
"package" : "com.example.demo", |
||||
"features" : [ |
||||
{ |
||||
"name" : "system.clipboard" |
||||
} |
||||
] |
||||
}, |
||||
"quickapp-webview" : { |
||||
"icon" : "/static/logo.png", |
||||
"package" : "com.example.demo", |
||||
"minPlatformVersion" : 1070, |
||||
"versionName" : "1.0.0", |
||||
"versionCode" : 100 |
||||
}, |
||||
"mp-weixin" : { |
||||
"appid" : "", |
||||
"setting" : { |
||||
"urlCheck" : false |
||||
}, |
||||
"usingComponents" : true, |
||||
"permission" : { |
||||
"scope.userLocation" : { |
||||
"desc" : "演示定位能力" |
||||
} |
||||
}, |
||||
"uniStatistics" : { |
||||
"enable" : true |
||||
} |
||||
}, |
||||
"mp-alipay" : { |
||||
"usingComponents" : true, |
||||
"uniStatistics" : { |
||||
"enable" : true |
||||
} |
||||
}, |
||||
"mp-baidu" : { |
||||
"usingComponents" : true, |
||||
"uniStatistics" : { |
||||
"enable" : true |
||||
}, |
||||
"dynamicLib" : { |
||||
"editorLib" : { |
||||
"provider" : "swan-editor" |
||||
} |
||||
} |
||||
}, |
||||
"mp-toutiao" : { |
||||
"usingComponents" : true, |
||||
"uniStatistics" : { |
||||
"enable" : true |
||||
} |
||||
}, |
||||
"mp-jd" : { |
||||
"usingComponents" : true, |
||||
"uniStatistics" : { |
||||
"enable" : true |
||||
} |
||||
}, |
||||
"h5" : { |
||||
"template" : "template.h5.html", |
||||
"router" : { |
||||
"mode" : "history", |
||||
"base" : "" |
||||
}, |
||||
"sdkConfigs" : { |
||||
"maps" : { |
||||
"qqmap" : { |
||||
"key" : "TKUBZ-D24AF-GJ4JY-JDVM2-IBYKK-KEBCU" |
||||
} |
||||
} |
||||
}, |
||||
"async" : { |
||||
"timeout" : 20000 |
||||
}, |
||||
"uniStatistics" : { |
||||
"enable" : true |
||||
} |
||||
}, |
||||
"vueVersion" : "3", |
||||
"mp-kuaishou" : { |
||||
"uniStatistics" : { |
||||
"enable" : true |
||||
} |
||||
}, |
||||
"mp-lark" : { |
||||
"uniStatistics" : { |
||||
"enable" : true |
||||
} |
||||
}, |
||||
"mp-qq" : { |
||||
"uniStatistics" : { |
||||
"enable" : true |
||||
} |
||||
}, |
||||
"quickapp-webview-huawei" : { |
||||
"uniStatistics" : { |
||||
"enable" : true |
||||
} |
||||
}, |
||||
"quickapp-webview-union" : { |
||||
"uniStatistics" : { |
||||
"enable" : true |
||||
} |
||||
}, |
||||
"uniStatistics" : { |
||||
"version" : "2", |
||||
"enable" : true |
||||
} |
||||
} |
||||
@ -0,0 +1,81 @@
|
||||
{ |
||||
"id": "supervision-app", |
||||
"name": "supervision-app", |
||||
"displayName": "supervision-app", |
||||
"version": "3.4.8", |
||||
"description": "", |
||||
"scripts": { |
||||
"test": "echo \"Error: no test specified\" && exit 1" |
||||
}, |
||||
"repository": "https://github.com/dcloudio/hello-uniapp.git", |
||||
"keywords": [], |
||||
"author": "", |
||||
"license": "MIT", |
||||
"homepage": "https://github.com/dcloudio/hello-uniapp#readme", |
||||
"dependencies": { |
||||
"image-tools": "^1.4.0", |
||||
"moment": "^2.30.1" |
||||
}, |
||||
"dcloudext": { |
||||
"sale": { |
||||
"regular": { |
||||
"price": "0.00" |
||||
}, |
||||
"sourcecode": { |
||||
"price": "0.00" |
||||
} |
||||
}, |
||||
"contact": { |
||||
"qq": "" |
||||
}, |
||||
"declaration": { |
||||
"ads": "无", |
||||
"data": "无", |
||||
"permissions": "无" |
||||
}, |
||||
"npmurl": "", |
||||
"type": "uniapp-template-project" |
||||
}, |
||||
"uni_modules": { |
||||
"dependencies": [], |
||||
"encrypt": [], |
||||
"platforms": { |
||||
"cloud": { |
||||
"tcb": "y", |
||||
"aliyun": "y", |
||||
"alipay": "n" |
||||
}, |
||||
"client": { |
||||
"App": { |
||||
"app-vue": "y", |
||||
"app-nvue": "y", |
||||
"app-harmony": "u", |
||||
"app-uvue": "u" |
||||
}, |
||||
"H5-mobile": { |
||||
"Safari": "y", |
||||
"Android Browser": "y", |
||||
"微信浏览器(Android)": "y", |
||||
"QQ浏览器(Android)": "y" |
||||
}, |
||||
"H5-pc": { |
||||
"Chrome": "y", |
||||
"IE": "y", |
||||
"Edge": "y", |
||||
"Firefox": "y", |
||||
"Safari": "y" |
||||
}, |
||||
|
||||
"Vue": { |
||||
"vue2": "y", |
||||
"vue3": "y" |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
"uni-app": { |
||||
"scripts": { |
||||
|
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,215 @@
|
||||
{ |
||||
|
||||
"pages": [ |
||||
// pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages |
||||
{ |
||||
"path": "pages/index/index", |
||||
"style": { |
||||
"navigationBarTitleText": "移动督察", |
||||
"enablePullDownRefresh": true, |
||||
"app-plus": { |
||||
"pullToRefresh": { |
||||
"support": true, |
||||
"color": "#2979ff", //小圈圈的颜色 |
||||
"style": "circle" //小圈圈的样式 |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
{ |
||||
"path": "pages/common/camera", |
||||
"style": { |
||||
"navigationBarTitleText": "随手拍", |
||||
"app-plus": { |
||||
|
||||
} |
||||
} |
||||
}, |
||||
{ |
||||
"path": "pages/photo/index", |
||||
"style": { |
||||
"navigationBarTitleText": "问题照片" |
||||
} |
||||
}, |
||||
{ |
||||
"path": "pages/negative/index", |
||||
"style": { |
||||
"navigationBarTitleText": "问题清单" |
||||
} |
||||
}, |
||||
{ |
||||
"path": "pages/negative/info", |
||||
"style": { |
||||
"navigationBarTitleText": "" |
||||
} |
||||
}, |
||||
{ |
||||
"path": "pages/negative/action", |
||||
"style": { |
||||
"navigationBarTitleText": "" |
||||
} |
||||
}, |
||||
{ |
||||
"path": "pages/duty/index", |
||||
"style": { |
||||
"navigationBarTitleText": "值班报备" |
||||
} |
||||
}, |
||||
{ |
||||
"path": "pages/comfort/list", |
||||
"style": { |
||||
"navigationBarTitleText": "抚慰申请" |
||||
} |
||||
}, |
||||
{ |
||||
"path": "pages/comfort/action", |
||||
"style": { |
||||
"navigationBarTitleText": "抚慰申请" |
||||
} |
||||
}, |
||||
{ |
||||
"path": "pages/comfort/add", |
||||
"style": { |
||||
"navigationBarTitleText": "抚慰申请" |
||||
} |
||||
}, |
||||
{ |
||||
"path": "pages/books/index", |
||||
"style": { |
||||
"navigationBarTitleText": "知识库" |
||||
} |
||||
}, |
||||
{ |
||||
"path": "pages/center/manual", |
||||
"style": { |
||||
"navigationBarTitleText": "使用手册" |
||||
} |
||||
}, |
||||
{ |
||||
"path": "pages/center/about", |
||||
"style": { |
||||
"navigationBarTitleText": "关于APP" |
||||
} |
||||
}, |
||||
{ |
||||
"path": "pages/center/feedback", |
||||
"style": { |
||||
"navigationBarTitleText": "意见反馈" |
||||
} |
||||
} |
||||
], |
||||
"subPackages": [ |
||||
{ |
||||
"root": "pages/task", |
||||
"pages": [{ |
||||
"path": "index", |
||||
"style": { |
||||
"navigationBarTitleText": "我的任务" |
||||
} |
||||
}, |
||||
{ |
||||
"path": "testingAlcohol/people", |
||||
"style": { |
||||
"navigationBarTitleText": "工作日测酒" |
||||
} |
||||
}, |
||||
{ |
||||
"path": "testingAlcohol/info", |
||||
"style": { |
||||
"navigationBarTitleText": "工作日测酒" |
||||
} |
||||
}, |
||||
{ |
||||
"path": "testingAlcohol/add", |
||||
"style": { |
||||
"navigationBarTitleText": "测酒情况录入" |
||||
} |
||||
}, |
||||
{ |
||||
"path": "inspection/info", |
||||
"style": { |
||||
"navigationBarTitleText": "督察任务要求" |
||||
} |
||||
}, |
||||
{ |
||||
"path": "inspection/list", |
||||
"style": { |
||||
"navigationBarTitleText": "督察任务" |
||||
} |
||||
}, |
||||
|
||||
{ |
||||
"path": "selfexamination/index", |
||||
"style": { |
||||
"navigationBarTitleText": "所队自查任务" |
||||
} |
||||
}, |
||||
{ |
||||
"path": "selfexamination/add", |
||||
"style": { |
||||
"navigationBarTitleText": "所队自查任务" |
||||
} |
||||
}, |
||||
{ |
||||
"path": "selfexamination/list", |
||||
"style": { |
||||
"navigationBarTitleText": "所队自查任务" |
||||
} |
||||
}, |
||||
{ |
||||
"path": "selfexamination/info", |
||||
"style": { |
||||
"navigationBarTitleText": "所队自查任务" |
||||
} |
||||
}, |
||||
{ |
||||
"path": "problem/index", |
||||
"style": { |
||||
"navigationBarTitleText": "问题详情" |
||||
} |
||||
}, |
||||
{ |
||||
"path": "problem/list", |
||||
"style": { |
||||
"navigationBarTitleText": "问题详情" |
||||
} |
||||
}, |
||||
{ |
||||
"path": "problem/add", |
||||
"style": { |
||||
"navigationBarTitleText": "新增督察任务" |
||||
} |
||||
} |
||||
] |
||||
} |
||||
], |
||||
"globalStyle": { |
||||
"pageOrientation": "portrait", |
||||
"navigationBarTitleText": "移动督察", |
||||
"navigationBarTextStyle": "white", |
||||
"navigationBarBackgroundColor": "#0e79f2", |
||||
"h5": { |
||||
"maxWidth": 1190, |
||||
"navigationBarTextStyle": "white", |
||||
"navigationBarBackgroundColor": "#0e79f2" |
||||
} |
||||
}, |
||||
"easycom": { |
||||
"autoscan": true, |
||||
"custom": { |
||||
"tabs": "@/components/tabs.vue", |
||||
"upload": "@/components/upload.vue", |
||||
"police-picker": "@/components/police-picker.vue", |
||||
"problem-picker": "@/components/problem-picker.vue", |
||||
"inspection-task-data-picker": "@/components/inspection-task-data-picker.vue", |
||||
"net-image": "@/components/net-image.vue", |
||||
"empty": "@/components/empty.vue", |
||||
"skeleton": "@/components/skeleton.vue", |
||||
"file-list": "@/components/file-list.vue", |
||||
"filter-radio": "@/components/filter-radio.vue", |
||||
"negative": "@/components/negative.vue", |
||||
"n-button": "@/components/n-button.vue", |
||||
"modal": "@/components/modal.vue" |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,121 @@
|
||||
<template> |
||||
<view class="books-container" v-if="!searchFlag"> |
||||
<view class="flex justify-center"> |
||||
<image src="/static/image/police-badge.png" style="width: 238rpx" mode="widthFix"></image> |
||||
</view> |
||||
<view class="title">督察知识库</view> |
||||
<view class="flex search-box"> |
||||
<input class="search-input" v-model="query.fileName" placeholder="搜索词" /> |
||||
<button type="primary" class="search-btn" @tap="search">搜索</button> |
||||
</view> |
||||
</view> |
||||
<view v-else> |
||||
<view class="flex search"> |
||||
<view class="search-item flex justify-center" :search="searchFlag"> |
||||
<view class="search-item-conent"> |
||||
<uni-easyinput prefixIcon="search" type="text" placeholder="搜索" :inputBorder="false" v-model="query.fileName" /> |
||||
</view> |
||||
</view> |
||||
<view> |
||||
<view class="cancel-btn" @tap="cancleSearch">取消</view> |
||||
</view> |
||||
</view> |
||||
<view class="container"> |
||||
<view v-for="item in books" class="flex items-center gap-8 file-item"> |
||||
<view> |
||||
<image :src="`/static/icon/${ getFileType(item.fileName) }.png`" mode="widthFix" style="width: 120rpx"></image> |
||||
</view> |
||||
<view class="filename">{{ item.fileName }}</view> |
||||
</view> |
||||
<empty description="无知识数据" v-if="books.length === 0" /> |
||||
</view> |
||||
</view> |
||||
</template> |
||||
|
||||
<script> |
||||
import { getFileType } from '@/common/util'; |
||||
import { listBook } from '@/api/book' |
||||
export default { |
||||
data() { |
||||
return { |
||||
searchFlag: false, |
||||
books: [], |
||||
query: { |
||||
size: 20, |
||||
current: 1 |
||||
} |
||||
} |
||||
}, |
||||
watch: { |
||||
'query.fileName': function(val) { |
||||
if (this.searchFlag && val) { |
||||
this.search() |
||||
} |
||||
}, |
||||
}, |
||||
setup() { |
||||
return { |
||||
getFileType |
||||
} |
||||
}, |
||||
onLoad() { |
||||
|
||||
}, |
||||
methods: { |
||||
search() { |
||||
if (!this.query.fileName) { |
||||
return |
||||
} |
||||
this.searchFlag = true |
||||
listBook(this.query).then(data => { |
||||
this.books = data.records |
||||
}) |
||||
}, |
||||
cancleSearch() { |
||||
this.searchFlag = false |
||||
this.query.fileName = '' |
||||
} |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
.books-container { |
||||
padding: 36rpx; |
||||
padding-top: 6vh; |
||||
} |
||||
.title { |
||||
font-size: 24px; |
||||
font-weight: bold; |
||||
color: #444; |
||||
margin-top: 20rpx; |
||||
margin-bottom: 60rpx; |
||||
text-align: center; |
||||
} |
||||
.search-box { |
||||
border-radius: 8rpx; |
||||
border: 1rpx solid #B6D5FE; |
||||
padding: 12rpx; |
||||
gap: 16rpx; |
||||
.search-input { |
||||
height: 92rpx; |
||||
line-height: 92rpx; |
||||
background: rgba(0,0,0,0.04); |
||||
border-radius: 8rpx; |
||||
flex-grow: 1; |
||||
padding-left: 12rpx; |
||||
} |
||||
.search-btn { |
||||
height: 92rpx; |
||||
line-height: 92rpx; |
||||
margin: 0; |
||||
padding: 0 40rpx; |
||||
} |
||||
} |
||||
.file-item { |
||||
padding: 12rpx 0; |
||||
.filename { |
||||
color: #555; |
||||
} |
||||
} |
||||
</style> |
||||
@ -0,0 +1,31 @@
|
||||
<template> |
||||
<view class="container"> |
||||
<view class="flex justify-center"> |
||||
<image src="/static/image/logo-p.png" style="width: 238rpx" mode="widthFix"></image> |
||||
</view> |
||||
<view class="h1">移动督察</view> |
||||
<view class="version">版本 v6.2.1</view> |
||||
</view> |
||||
</template> |
||||
|
||||
<script> |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
.container { |
||||
padding-top: 10vh; |
||||
} |
||||
.h1 { |
||||
margin-top: 28rpx; |
||||
text-align: center; |
||||
font-size: 22px; |
||||
font-weight: bold; |
||||
color: #555; |
||||
} |
||||
.version { |
||||
margin-top: 12rpx; |
||||
text-align: center; |
||||
font-size: 16px; |
||||
color: #777; |
||||
} |
||||
</style> |
||||
@ -0,0 +1,65 @@
|
||||
<template> |
||||
<uni-forms ref="form" :modelValue="formData" :rules="rules" style="margin: 12px"> |
||||
<uni-forms-item label="意见反馈" name="content" label-position="top" required> |
||||
<uni-easyinput type="textarea" :input-border="false" placeholder="请输入具体意见反馈" v-model="formData.content" /> |
||||
</uni-forms-item> |
||||
</uni-forms> |
||||
<view class="footer col-24 flex gap-8"> |
||||
<button class="col-12" @tap="back">取消</button> |
||||
<button type="primary" @tap="submit" class="col-12">确定</button> |
||||
</view> |
||||
</template> |
||||
|
||||
<script> |
||||
import { |
||||
addFeedback |
||||
} from '@/api/feedback.js' |
||||
|
||||
let _this; |
||||
export default { |
||||
data() { |
||||
return { |
||||
formData: { |
||||
}, |
||||
rules: { |
||||
thingDesc: { |
||||
rules: [{ |
||||
required: true, |
||||
errorMessage: '请输入具体意见反馈', |
||||
}] |
||||
} |
||||
}, |
||||
} |
||||
}, |
||||
onLoad() { |
||||
_this = this; |
||||
}, |
||||
methods: { |
||||
submit() { |
||||
this.$refs.form.validate().then(res => { |
||||
addFeedback(this.formData).then(data => { |
||||
_this.formData = {} |
||||
uni.showToast({ |
||||
title: '操作成功', |
||||
icon: 'none', |
||||
duration: 3000 |
||||
}) |
||||
uni.navigateBack({ |
||||
|
||||
}); |
||||
}) |
||||
}).catch(err => { |
||||
console.log('表单错误信息:', err, this.formData); |
||||
}) |
||||
}, |
||||
back() { |
||||
uni.navigateBack({ |
||||
|
||||
}); |
||||
} |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style> |
||||
</style> |
||||
@ -0,0 +1,21 @@
|
||||
<template> |
||||
<view class="container"> |
||||
<uni-title type="h1" title="工作日测酒"></uni-title> |
||||
<view> |
||||
<image src="/static/image/1.png" style="height: 200vh" mode="heightFix"></image> |
||||
</view> |
||||
<uni-title type="h1" title="督察任务"></uni-title> |
||||
<view> |
||||
<image src="/static/image/2.png" style="height: 200vh" mode="heightFix"></image> |
||||
</view> |
||||
</view> |
||||
</template> |
||||
|
||||
<script> |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
.container { |
||||
width: auto; |
||||
} |
||||
</style> |
||||
@ -0,0 +1,176 @@
|
||||
<template> |
||||
<view class="wrapper"> |
||||
<view class="container"> |
||||
<view class="h1">办理信息</view> |
||||
<view class="row" style="--label-width: 160rpx"> |
||||
<view class="col col-24"> |
||||
<view class="label">申请时间:</view> |
||||
<view class="content">{{ comfort.apply?.applyDate }}</view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">是否本人:</view> |
||||
<view class="content">{{ comfort.apply?.isSelf === '1'? '是' : '否' }}</view> |
||||
</view> |
||||
<view class="col col-12" v-if="comfort.apply?.isSelf === '0'"> |
||||
<view class="label">代理人姓名:</view> |
||||
<view class="content">{{ comfort.apply?.agentName }}</view> |
||||
</view> |
||||
<view class="col col-12" v-if="comfort.apply?.isSelf === '0'"> |
||||
<view class="label">关系:</view> |
||||
<view class="content">{{ comfort.apply?.relation }}</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
<view class="container"> |
||||
<view class="h1">申请人信息</view> |
||||
<view class="row" style="--label-width: 160rpx"> |
||||
<view class="col col-12"> |
||||
<view class="label">申请人姓名:</view> |
||||
<view class="content">{{ comfort.apply?.applicantEmpName }}</view> |
||||
</view> |
||||
<view class="col col-12"> |
||||
<view class="label">性别:</view> |
||||
<view class="content">{{ comfort.apply?.sex }}</view> |
||||
</view> |
||||
<view class="col col-12"> |
||||
<view class="label">警号:</view> |
||||
<view class="content">{{ comfort.person?.empNo }}</view> |
||||
</view> |
||||
<view class="col col-12"> |
||||
<view class="label">联系电话:</view> |
||||
<view class="content">{{ comfort.person?.mobile }}</view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">单位:</view> |
||||
<view class="content">{{ comfort.apply?.departName }}</view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">身份证:</view> |
||||
<view class="content">{{ comfort.person?.idCode }}</view> |
||||
</view> |
||||
<view class="col col-12"> |
||||
<view class="label">出生年月:</view> |
||||
<view class="content">{{ comfort.person?.birthday }}</view> |
||||
</view> |
||||
|
||||
<view class="col col-12"> |
||||
<view class="label">职务:</view> |
||||
<view class="content">{{ comfort.person?.job || '/' }}</view> |
||||
</view> |
||||
|
||||
<view class="col col-12"> |
||||
<view class="label">警衔:</view> |
||||
<view class="content">{{ comfort.person?.policeRank || '/' }}</view> |
||||
</view> |
||||
<view class="col col-12"> |
||||
<view class="label">文化程度:</view> |
||||
<view class="content">{{ comfort.person?.levelEducation || '/' }}</view> |
||||
</view> |
||||
<view class="col col-12"> |
||||
<view class="label">政治面貌:</view> |
||||
<view class="content">{{ comfort.person?.politicCountenance || '/' }}</view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">开户行:</view> |
||||
<view class="content">{{ comfort.person?.bankCardAccount }}{{ comfort.person?.bankBranch }}</view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">银行账号:</view> |
||||
<view class="content">{{ comfort.person?.bankCardAccount }}</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
<view class="container"> |
||||
<view class="h1">案发情况</view> |
||||
<view class="row" style="--label-width: 160rpx"> |
||||
<view class="col col-24"> |
||||
<view class="label">事发时间:</view> |
||||
<view class="content">{{ comfort.apply?.happenTime }}</view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">事实与理由:</view> |
||||
<view class="content">{{ comfort.apply?.factReason }}</view> |
||||
</view> |
||||
<view class="col col-12"> |
||||
<view class="label">案发环节:</view> |
||||
<view class="content">{{ comfort.apply?.incidentLink }}</view> |
||||
</view> |
||||
<view class="col col-12"> |
||||
<view class="label">受伤程度:</view> |
||||
<view class="content">{{ comfort.apply?.injurySeverity }}</view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">侵权形式:</view> |
||||
<view class="content">{{ comfort.apply?.formsOfTort }}</view> |
||||
</view> |
||||
<view class="col col-12"> |
||||
<view class="label">侵权人姓名:</view> |
||||
<view class="content">{{ comfort.apply?.infringerName || '/' }}</view> |
||||
</view> |
||||
<view class="col col-12"> |
||||
<view class="label">处理方式:</view> |
||||
<view class="content">{{ comfort.apply?.infringerHandle }}</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
<view class="container"> |
||||
<view class="h1">附件</view> |
||||
<file-list :files="comfort.apply?.documentFile? JSON.parse(comfort.apply?.documentFile) : []" /> |
||||
<empty description="无附件" v-if="!comfort.apply?.documentFile" /> |
||||
</view> |
||||
</view> |
||||
</template> |
||||
|
||||
<script> |
||||
import { getDictOptions } from '@/common/dict' |
||||
import { getComfort } from '@/api/comfort' |
||||
|
||||
let _this; |
||||
export default { |
||||
data() { |
||||
return { |
||||
comfort: {} |
||||
} |
||||
}, |
||||
watch : { |
||||
|
||||
}, |
||||
setup() { |
||||
const formsOfTort = getDictOptions('formsOfTort') |
||||
const injurySeverity = getDictOptions('injurySeverity') |
||||
const incidentLink = getDictOptions('incidentLink') |
||||
const bank = getDictOptions('bank') |
||||
|
||||
return { |
||||
formsOfTort, |
||||
injurySeverity, |
||||
incidentLink, |
||||
bank |
||||
} |
||||
}, |
||||
onLoad() { |
||||
_this = this; |
||||
getComfort(this.$page.options.id).then(data => { |
||||
this.comfort = data |
||||
}) |
||||
}, |
||||
methods: { |
||||
|
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
.container { |
||||
background-color: #fff; |
||||
margin-bottom: 12rpx; |
||||
} |
||||
.wrapper { |
||||
background-color: #f5f5f5; |
||||
min-height: 100vh; |
||||
} |
||||
.h1 { |
||||
font-weight: 700; |
||||
margin-bottom: 24rpx; |
||||
} |
||||
</style> |
||||
@ -0,0 +1,513 @@
|
||||
<template> |
||||
<uni-forms ref="form" :modelValue="formData" :rules="rules" label-width="210rpx" class="wrapper"> |
||||
<view class="container"> |
||||
<view class="title">办理信息</view> |
||||
<uni-forms-item label="申请时间" name="applyDate" required> |
||||
<uni-datetime-picker type="date" v-model="formData.applyDate" :border="false" placeholder="请选择申请时间" /> |
||||
</uni-forms-item> |
||||
<uni-forms-item label="是否本人申请" name="isSelf" required> |
||||
<uni-data-checkbox v-model="formData.isSelf" :localdata="isSelf" @change="handleIsSelfChange" /> |
||||
</uni-forms-item> |
||||
<uni-forms-item label="代理人姓名" name="agentName" required v-if="formData.isSelf === '0'"> |
||||
<uni-easyinput :input-border="false" placeholder="代理人姓名" v-model="formData.agentName" /> |
||||
</uni-forms-item> |
||||
<uni-forms-item label="关系" name="relation" required v-if="formData.isSelf === '0'"> |
||||
<uni-data-checkbox v-model="formData.relation" :localdata="relation" /> |
||||
</uni-forms-item> |
||||
</view> |
||||
<view class="container"> |
||||
<view class="title">申请人信息</view> |
||||
<uni-forms-item label="申请人姓名" name="applicantEmpName" required> |
||||
<uni-easyinput :input-border="false" placeholder="申请人姓名" v-model="formData.applicantEmpName" /> |
||||
</uni-forms-item> |
||||
<uni-forms-item label="性别" name="sex" required> |
||||
<uni-data-checkbox v-model="formData.sex" :localdata="sex" /> |
||||
</uni-forms-item> |
||||
<uni-forms-item label="警号" name="empNo" required> |
||||
<uni-easyinput :input-border="false" placeholder="警号" v-model="formData.empNo" /> |
||||
|
||||
</uni-forms-item> |
||||
<uni-forms-item label="单位" name="departId" required> |
||||
<uni-data-picker :localdata="departs" placeholder="请选择单位" :border="false" |
||||
:map="{text:'shortName', value: 'id'}" v-model="formData.departId" /> |
||||
</uni-forms-item> |
||||
<uni-forms-item label="身份证" name="idCode" required> |
||||
<uni-easyinput :input-border="false" placeholder="身份证" v-model="formData.idCode" /> |
||||
|
||||
</uni-forms-item> |
||||
<uni-forms-item label="出生年月" name="birthday"> |
||||
<uni-datetime-picker type="date" v-model="formData.birthday" :border="false" placeholder="请选择出生年月" /> |
||||
|
||||
</uni-forms-item> |
||||
<uni-forms-item label="联系电话" name="mobile" required> |
||||
<uni-easyinput :input-border="false" placeholder="联系电话" v-model="formData.mobile" /> |
||||
</uni-forms-item> |
||||
<uni-forms-item label="职务" name="job" > |
||||
<uni-easyinput :input-border="false" placeholder="职务" v-model="formData.job" /> |
||||
</uni-forms-item> |
||||
<uni-forms-item label="警衔" name="policeRank" > |
||||
<uni-easyinput :input-border="false" placeholder="警衔" v-model="formData.policeRank" /> |
||||
</uni-forms-item> |
||||
<uni-forms-item label="文化程度" name="levelEducation"> |
||||
<uni-data-select |
||||
v-model="formData.levelEducation" |
||||
:localdata="levelEducation" |
||||
></uni-data-select> |
||||
</uni-forms-item> |
||||
<uni-forms-item label="政治面貌" name="politicCountenance" > |
||||
<uni-data-select |
||||
v-model="formData.politicCountenance" |
||||
:localdata="politicCountenance" |
||||
></uni-data-select> |
||||
</uni-forms-item> |
||||
|
||||
<uni-forms-item label="开户行" name="bankCard" required> |
||||
<uni-data-select |
||||
v-model="formData.bankCard" |
||||
:localdata="bank.map(item => { |
||||
return { |
||||
text: item.dictLabel, |
||||
value: item.dictValue |
||||
} |
||||
})" |
||||
|
||||
></uni-data-select> |
||||
</uni-forms-item> |
||||
<uni-forms-item label="所属支行" name="bankBranch" required> |
||||
<uni-easyinput :input-border="false" placeholder="所属支行" v-model="formData.bankBranch" /> |
||||
</uni-forms-item> |
||||
<uni-forms-item label="银行账号" name="bankCardAccount" required> |
||||
<uni-easyinput :input-border="false" placeholder="银行账号" v-model="formData.bankCardAccount" /> |
||||
</uni-forms-item> |
||||
</view> |
||||
<view class="container"> |
||||
<view class="title">案发情况</view> |
||||
<uni-forms-item label="事发时间" name="happenTime" required> |
||||
<uni-datetime-picker type="datetime" v-model="formData.happenTime" :border="false" placeholder="请选择事发时间" /> |
||||
</uni-forms-item> |
||||
<uni-forms-item label="事实与理由" name="factReason" required> |
||||
<uni-easyinput type="textarea" :input-border="false" placeholder="事实与理由" v-model="formData.factReason" /> |
||||
</uni-forms-item> |
||||
<uni-forms-item label="案发环节" name="incidentLink" required> |
||||
<uni-data-select |
||||
v-model="formData.incidentLink" |
||||
:localdata="incidentLink.map(item => { |
||||
return { |
||||
text: item.dictLabel, |
||||
value: item.dictValue |
||||
} |
||||
})" |
||||
@change="(val) => { |
||||
formData.incidentLinkName = getDictLabel(incidentLink, val) |
||||
}" |
||||
></uni-data-select> |
||||
</uni-forms-item> |
||||
<uni-forms-item label="受伤程度" name="injurySeverity" required> |
||||
<uni-data-select |
||||
v-model="formData.injurySeverity" |
||||
:localdata="injurySeverity.map(item => { |
||||
return { |
||||
text: item.dictLabel, |
||||
value: item.dictValue |
||||
} |
||||
})" |
||||
@change="(val) => { |
||||
formData.injurySeverityName = getDictLabel(injurySeverity, val) |
||||
}" |
||||
></uni-data-select> |
||||
</uni-forms-item> |
||||
<uni-forms-item label="侵权形式" name="formsOfTort" required> |
||||
<uni-data-picker :localdata="formsOfTort" placeholder="侵权形式" :border="false" :map="{text:'dictLabel', value: 'dictValue'}" v-model="formData.formsOfTort" |
||||
@change="(val) => { |
||||
formData.formsOfTortName = detail.value[0].text |
||||
}" |
||||
/> |
||||
</uni-forms-item> |
||||
<uni-forms-item label="侵权人姓名" name="infringerName"> |
||||
<uni-easyinput :input-border="false" placeholder="侵权人姓名" v-model="formData.infringerName" /> |
||||
</uni-forms-item> |
||||
<uni-forms-item label="处理方式" name="infringerHandle" required> |
||||
<uni-data-checkbox v-model="formData.infringerHandle" :localdata="infringerHandle" /> |
||||
|
||||
</uni-forms-item> |
||||
</view> |
||||
<view class="container"> |
||||
<view class="title">佐证材料</view> |
||||
<uni-forms-item label="附件" name="documentFile" label-position="top" required> |
||||
<upload v-model="formData.documentFile" /> |
||||
</uni-forms-item> |
||||
</view> |
||||
<view class="container"> |
||||
<view class="title">呈报审批</view> |
||||
<uni-forms-item label="主办单位" name="handleDepartId" required> |
||||
<uni-data-picker :localdata="secondDeparts" placeholder="请选择主办单位" :border="false" |
||||
:map="{text:'shortName', value: 'id'}" v-model="formData.handleDepartId" /> |
||||
</uni-forms-item> |
||||
<uni-forms-item label="审批人" name="approverEmpNo" required> |
||||
<view>{{ formData.approver }}</view> |
||||
</uni-forms-item> |
||||
</view> |
||||
</uni-forms> |
||||
<view class="footer col-24 flex gap-8"> |
||||
<button class="col-12" @tap="back">取消</button> |
||||
<button type="primary" @tap="submit" class="col-12">确定</button> |
||||
</view> |
||||
</template> |
||||
|
||||
<script> |
||||
import { getDictLabel } from '@/common/util' |
||||
import moment from 'moment' |
||||
import store from '@/store' |
||||
import { getDictOptions } from '@/common/dict' |
||||
import { |
||||
departTree, secondList |
||||
} from '@/api/depart' |
||||
|
||||
import { |
||||
addComfort, |
||||
listRightPersonByDepartId |
||||
} from '@/api/comfort' |
||||
|
||||
let _this; |
||||
export default { |
||||
data() { |
||||
return { |
||||
formData: { |
||||
applyDate: moment().format('YYYY-MM-DD'), |
||||
documentFile: [], |
||||
}, |
||||
departs: [], |
||||
secondDeparts: [], |
||||
rules: { |
||||
applyDate: { |
||||
rules: [{ |
||||
required: true, |
||||
errorMessage: '请选择申请时间', |
||||
}] |
||||
}, |
||||
isSelf: { |
||||
rules: [{ |
||||
required: true, |
||||
errorMessage: '请选择是否本人申请', |
||||
}] |
||||
}, |
||||
agentName: { |
||||
rules: [{ |
||||
required: true, |
||||
errorMessage: '请输入代理人姓名', |
||||
}] |
||||
}, |
||||
relation: { |
||||
rules: [{ |
||||
required: true, |
||||
errorMessage: '请选择代理人关系', |
||||
}] |
||||
}, |
||||
applicantEmpName: { |
||||
rules: [{ |
||||
required: true, |
||||
errorMessage: '请输入申请人姓名', |
||||
}] |
||||
}, |
||||
sex: { |
||||
rules: [{ |
||||
required: true, |
||||
errorMessage: '请选择性别', |
||||
}] |
||||
}, |
||||
empNo: { |
||||
rules: [{ |
||||
required: true, |
||||
errorMessage: '请输入警号', |
||||
}] |
||||
}, |
||||
departId: { |
||||
rules: [{ |
||||
required: true, |
||||
errorMessage: '请选择单位', |
||||
}] |
||||
}, |
||||
idCode: { |
||||
rules: [{ |
||||
required: true, |
||||
errorMessage: '请输入身份证', |
||||
}] |
||||
}, |
||||
mobile: { |
||||
rules: [{ |
||||
required: true, |
||||
errorMessage: '请输入联系方式', |
||||
}] |
||||
}, |
||||
bankCard: { |
||||
rules: [{ |
||||
required: true, |
||||
errorMessage: '请选择开户行', |
||||
}] |
||||
}, |
||||
bankBranch: { |
||||
rules: [{ |
||||
required: true, |
||||
errorMessage: '请输入所属支行', |
||||
}] |
||||
}, |
||||
bankCardAccount: { |
||||
rules: [{ |
||||
required: true, |
||||
errorMessage: '请输入银行账号', |
||||
}] |
||||
}, |
||||
happenTime: { |
||||
rules: [{ |
||||
required: true, |
||||
errorMessage: '请选择事发时间', |
||||
}] |
||||
}, |
||||
factReason: { |
||||
rules: [{ |
||||
required: true, |
||||
errorMessage: '请输入事实与理由', |
||||
}] |
||||
}, |
||||
incidentLink: { |
||||
rules: [{ |
||||
required: true, |
||||
errorMessage: '请选择案发环节', |
||||
}] |
||||
}, |
||||
injurySeverity: { |
||||
rules: [{ |
||||
required: true, |
||||
errorMessage: '请选择受伤程度', |
||||
}] |
||||
}, |
||||
formsOfTort: { |
||||
rules: [{ |
||||
required: true, |
||||
errorMessage: '请选择侵权形式', |
||||
}] |
||||
}, |
||||
infringerHandle: { |
||||
rules: [{ |
||||
required: true, |
||||
errorMessage: '请选择处理方式', |
||||
}] |
||||
}, |
||||
handleDepartId: { |
||||
rules: [{ |
||||
required: true, |
||||
errorMessage: '请选择主办单位', |
||||
}] |
||||
}, |
||||
approverEmpNo: { |
||||
rules: [{ |
||||
required: true, |
||||
errorMessage: '未配置审批人,当前主办单位的未配置维权专干(请联系系统管理员)', |
||||
}] |
||||
}, |
||||
// documentFile: { |
||||
// rules: [{ |
||||
// validateFunction: function(rule,value,data,callback){ |
||||
// if (!value || value.length === 0) { |
||||
// callback('请上传附件') |
||||
// } |
||||
// return true |
||||
// } |
||||
// }] |
||||
// }, |
||||
}, |
||||
isSelf: [ |
||||
{ |
||||
text: '是', |
||||
value: '1' |
||||
}, |
||||
{ |
||||
text: '否', |
||||
value: '0' |
||||
} |
||||
], |
||||
relation: [ |
||||
{ |
||||
text: '同事', |
||||
value: '1' |
||||
}, |
||||
{ |
||||
text: '亲属', |
||||
value: '2' |
||||
} |
||||
], |
||||
sex: [ |
||||
{ |
||||
text: '男', |
||||
value: '0' |
||||
}, |
||||
{ |
||||
text: '女', |
||||
value: '1' |
||||
} |
||||
], |
||||
levelEducation: [ |
||||
{ |
||||
text: '高中', |
||||
value: '高中' |
||||
}, |
||||
{ |
||||
text: '大专', |
||||
value: '大专' |
||||
}, |
||||
{ |
||||
text: '本科', |
||||
value: '本科' |
||||
}, |
||||
{ |
||||
text: '研究生及以上', |
||||
value: '研究生及以上' |
||||
} |
||||
], |
||||
politicCountenance: [ |
||||
{ |
||||
text: '群众', |
||||
value: '群众' |
||||
}, |
||||
{ |
||||
text: '团员', |
||||
value: '团员' |
||||
}, |
||||
{ |
||||
text: '预备党员', |
||||
value: '预备党员' |
||||
}, |
||||
{ |
||||
text: '党员', |
||||
value: '党员' |
||||
} |
||||
], |
||||
infringerHandle: [ |
||||
{ |
||||
text: '行政处罚', |
||||
value: '行政处罚' |
||||
}, |
||||
{ |
||||
text: '刑事处罚', |
||||
value: '刑事处罚' |
||||
}, |
||||
] |
||||
} |
||||
}, |
||||
watch : { |
||||
'formData.handleDepartId': function(val) { |
||||
listRightPersonByDepartId(val).then((data) => { |
||||
if (data.length) { |
||||
this.formData.approverEmpNo = data.map((item) => item.empNo); |
||||
this.formData.approver = data |
||||
.map((item) => item.empName) |
||||
.join("、"); |
||||
} else { |
||||
delete this.formData.approverEmpNo; |
||||
delete this.formData.approver; |
||||
} |
||||
}); |
||||
}, |
||||
}, |
||||
setup() { |
||||
const formsOfTort = getDictOptions('formsOfTort') |
||||
const injurySeverity = getDictOptions('injurySeverity') |
||||
const incidentLink = getDictOptions('incidentLink') |
||||
const bank = getDictOptions('bank') |
||||
|
||||
return { |
||||
formsOfTort, |
||||
injurySeverity, |
||||
incidentLink, |
||||
bank, |
||||
getDictLabel |
||||
} |
||||
}, |
||||
onLoad() { |
||||
_this = this; |
||||
departTree().then(data => { |
||||
this.departs = data[0].children |
||||
}) |
||||
secondList().then(data => { |
||||
this.secondDeparts = data |
||||
}) |
||||
}, |
||||
methods: { |
||||
submit() { |
||||
this.$refs.form.validate().then(res => { |
||||
this.formData.happenTime = moment(this.formData.happenTime, 'YYYY-MM-DD HH:mm:ss').format('YYYY-MM-DD HH:mm') |
||||
addComfort(this.formData).then(data => { |
||||
_this.formData = { |
||||
applyDate: moment().format('YYYY-MM-DD'), |
||||
documentFile: [], |
||||
} |
||||
uni.showToast({ |
||||
title: '操作成功', |
||||
icon: 'none', |
||||
duration: 3000 |
||||
}) |
||||
uni.navigateBack({ |
||||
|
||||
}); |
||||
|
||||
}) |
||||
}).catch(err => { |
||||
uni.showToast({ |
||||
title: '请检查表单必填项', |
||||
icon: 'none', |
||||
duration: 3000 |
||||
}) |
||||
}) |
||||
}, |
||||
back() { |
||||
uni.navigateBack({ |
||||
|
||||
}); |
||||
}, |
||||
handleIsSelfChange() { |
||||
console.log('handleIsSelfChange') |
||||
if (this.formData.isSelf === '1') { |
||||
this.formData.applicantEmpName = store.state.user.nickName |
||||
this.formData.empNo = store.state.user.empNo |
||||
this.formData.idCode = store.state.user.userName |
||||
this.formData.mobile = store.state.user.mobile |
||||
this.formData.departId = store.state.user.departId |
||||
if (store.state.user.userName.length === 18) { |
||||
this.formData.birthday = moment(store.state.user.userName.substr(6, 8), 'YYYYMMDD').format('YYYY-MM-DD') |
||||
this.formData.sex = getSex(store.state.user.userName) |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
function getSex(idCard) { |
||||
let res = /^(\d{6})(\d{4})(\d{2})(\d{2})(\d{3})([0-9]|X)$/; |
||||
if (idCard && res.test(idCard)) { |
||||
let genderCode = idCard.charAt(16); |
||||
if (parseInt(genderCode) % 2 == 0) { |
||||
return '1'; |
||||
} |
||||
return '0'; |
||||
} |
||||
return ''; |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
.wrapper { |
||||
background-color: #f5f5f5; |
||||
padding-bottom: 72px; |
||||
} |
||||
.container { |
||||
background-color: #fff; |
||||
margin-bottom: 24rpx; |
||||
} |
||||
.footer { |
||||
background-color: #fff; |
||||
border-top: 1px solid #eee; |
||||
} |
||||
.title { |
||||
margin-bottom: 16rpx; |
||||
} |
||||
</style> |
||||
@ -0,0 +1,209 @@
|
||||
<template> |
||||
<view class="flex search"> |
||||
<view class="search-item flex justify-center" :search="searchFlag"> |
||||
<view class="search-item-conent"> |
||||
<uni-easyinput prefixIcon="search" type="text" v-model="query.applicantEmpName" placeholder="搜索" :inputBorder="false" @focus="searchFlag = true" /> |
||||
|
||||
</view> |
||||
</view> |
||||
<view class="search-item flex justify-center" v-if="!searchFlag" @tap="showPopup"> |
||||
<view :class="filterFlag ? 'search-item-conent active': 'search-item-conent'"> |
||||
<uni-icons customPrefix="customicons" type="filter" size="20" color="#666" /> |
||||
<view>筛选</view> |
||||
</view> |
||||
</view> |
||||
<view v-else> |
||||
<view class="cancel-btn" @tap="searchFlag = false">取消</view> |
||||
</view> |
||||
</view> |
||||
<view class="negative-container"> |
||||
<view class="card negative-item" v-for="item in comforts" @tap="open(item)"> |
||||
<view class="row" style="--label-width: 160rpx"> |
||||
<view class="col col-12"> |
||||
<view class="label">申请人:</view> |
||||
<view class="content">{{ item.applicantEmpName }}</view> |
||||
</view> |
||||
<view class="col col-12"> |
||||
<view class="label">申请时间:</view> |
||||
<view class="content">{{ item.applyDate }}</view> |
||||
</view> |
||||
<view class="col col-12"> |
||||
<view class="label">受伤程度:</view> |
||||
<view class="content">{{ item.injurySeverityName }}</view> |
||||
</view> |
||||
<view class="col col-12"> |
||||
<view class="label">申请金额:</view> |
||||
<view class="content">{{ item.injurySeverity }}</view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">事实与理由:</view> |
||||
<view class="content">{{ item.factReason }}</view> |
||||
</view> |
||||
</view> |
||||
<view class="negative-bottom"> |
||||
<uni-tag :text="getDictLabel(comfortStatus, item.rpcStatus)" :type="getRpcStatusTagType(item.rpcStatus)" /> |
||||
</view> |
||||
</view> |
||||
<empty v-if="comforts.length === 0" /> |
||||
</view> |
||||
<view class="footer col-24"> |
||||
<button type="primary" @tap="openAdd">我要抚慰</button> |
||||
</view> |
||||
|
||||
<uni-popup ref="filterPopupRef" type="top"> |
||||
<view class="popup-container"> |
||||
<view class="popup-header"> |
||||
<view>全部筛选</view> |
||||
<uni-icons type="closeempty" class="close-btn" @tap="closePopup"></uni-icons> |
||||
</view> |
||||
<view class="popup-body"> |
||||
<view class="filter-container"> |
||||
<view class="filter-label mt-10">状态</view> |
||||
<filter-radio :data="comfortStatus" v-model="query.rpcStatus" :prop="{text: 'dictLabel', value: 'dictValue'}" @change="search" /> |
||||
|
||||
</view> |
||||
</view> |
||||
<view class="footer col-24 flex gap-8"> |
||||
<button class="col-12" @tap="reset">重置</button> |
||||
<button type="primary" @tap="handleSearch" class="col-12">完成</button> |
||||
</view> |
||||
</view> |
||||
</uni-popup> |
||||
</template> |
||||
<script> |
||||
import store from '@/store' |
||||
import { getDictOptions } from '@/common/dict' |
||||
import { listComfort } from '@/api/comfort' |
||||
import { |
||||
departTree |
||||
} from '@/api/depart' |
||||
import { getDictLabel } from '@/common/util' |
||||
|
||||
let oldList; |
||||
let _this; |
||||
|
||||
export default { |
||||
data() { |
||||
return { |
||||
comforts: [], |
||||
query: { |
||||
size: 20, |
||||
current: 1 |
||||
}, |
||||
departs: [], |
||||
searchFlag: false, |
||||
filterFlag: false, |
||||
} |
||||
}, |
||||
setup(props, context) { |
||||
const processingStatus = getDictOptions('processingStatus'); |
||||
const businessTypes = getDictOptions('businessType') |
||||
const comfortStatus = getDictOptions('comfortStatus') |
||||
return { |
||||
processingStatus, |
||||
businessTypes, |
||||
comfortStatus, |
||||
getDictLabel |
||||
} |
||||
}, |
||||
watch: { |
||||
searchFlag(val) { |
||||
if (val) { |
||||
oldList = this.comforts; |
||||
this.comforts = [] |
||||
} else { |
||||
this.comforts = oldList |
||||
} |
||||
}, |
||||
'query.thingDesc': function(val) { |
||||
if (_this.searchFlag) { |
||||
if (val) { |
||||
_this.getComforts() |
||||
} else { |
||||
this.comforts = [] |
||||
} |
||||
|
||||
} |
||||
} |
||||
}, |
||||
onLoad() { |
||||
_this = this; |
||||
this.getComforts(); |
||||
departTree().then(data => { |
||||
this.departs = data[0].children |
||||
}) |
||||
}, |
||||
methods: { |
||||
open(item) { |
||||
uni.navigateTo({ |
||||
url: '/pages/comfort/action?id=' + item.rpcId |
||||
}); |
||||
}, |
||||
openAdd() { |
||||
uni.navigateTo({ |
||||
url: '/pages/comfort/add' |
||||
}); |
||||
}, |
||||
getComforts() { |
||||
uni.showLoading({ |
||||
title: '数据加载中' |
||||
}); |
||||
listComfort(this.query).then(data => { |
||||
this.comforts = data.records |
||||
uni.hideLoading(); |
||||
}); |
||||
}, |
||||
showPopup() { |
||||
this.$refs.filterPopupRef.open() |
||||
}, |
||||
closePopup() { |
||||
this.$refs.filterPopupRef.close() |
||||
}, |
||||
search() { |
||||
if (this.query.rpcStatus) { |
||||
this.filterFlag = true |
||||
} else { |
||||
this.filterFlag = false |
||||
} |
||||
this.getComforts() |
||||
}, |
||||
handleSearch() { |
||||
this.search() |
||||
this.closePopup() |
||||
}, |
||||
reset() { |
||||
this.filterFlag = false |
||||
this.query = { |
||||
size: 20, |
||||
current: 1 |
||||
} |
||||
this.getComforts() |
||||
}, |
||||
getRpcStatusTagType(rpcStatus) { |
||||
if (rpcStatus === 'returned') { |
||||
return 'error' |
||||
} |
||||
if (rpcStatus === 'approval') { |
||||
return 'primary' |
||||
} |
||||
return '' |
||||
} |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
.negative-container { |
||||
max-height: calc(100vh - 98rpx); |
||||
overflow: auto; |
||||
box-sizing: border-box; |
||||
padding-bottom: 72px; |
||||
} |
||||
.negative-bottom { |
||||
display: flex; |
||||
justify-content: space-between; |
||||
.negative-tag { |
||||
color: #FF0000; |
||||
} |
||||
} |
||||
</style> |
||||
@ -0,0 +1,296 @@
|
||||
<template> |
||||
<view :style="{ width: windowWidth, height: windowHeight }"> |
||||
<live-pusher id="livePusher" ref="livePusher" class="livePusher" mode="FHD" beauty="0" whiteness="0" |
||||
min-bitrate="1000" audio-quality="16KHz" device-position="back" :auto-focus="true" |
||||
:muted="true" :enable-camera="true" :enable-mic="false" :zoom="false" |
||||
@statechange="statechange" |
||||
:style="{ width: windowWidth, height: windowHeight }"></live-pusher> |
||||
<view class="tools-t" v-if="files.length > 0"> |
||||
<view> |
||||
<button class="rollover-btn tools-btn" @tap="handleNext"> |
||||
<uni-icons type="checkmarkempty" size="32" color="#84FF6D" /> |
||||
</button> |
||||
</view> |
||||
</view> |
||||
<view class="tools-b"> |
||||
<view> |
||||
<view class="img-btn tools-btn" @tap="openPhoto"> |
||||
<template v-if="files.length > 0"> |
||||
<view class="img-number">{{ files.length }}</view> |
||||
<net-image :filepath="files[0].filePath" class="img-btn-img" /> |
||||
</template> |
||||
</view> |
||||
|
||||
</view> |
||||
<view> |
||||
<button class="photo-btn tools-btn" @tap="snapshot"> |
||||
<view class="photo-btn-c"></view> |
||||
</button> |
||||
</view> |
||||
<view> |
||||
<button class="rollover-btn tools-btn" @tap="flip"> |
||||
<uni-icons type="loop" size="24" color="#fff" /> |
||||
</button> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
</template> |
||||
|
||||
<script> |
||||
import { addPhoto } from '@/api/photo' |
||||
import { pathToBase64 } from 'image-tools' |
||||
import { |
||||
uploadFileBase64 |
||||
} from '@/api/file' |
||||
import store from '@/store' |
||||
|
||||
let _this = null; |
||||
export default { |
||||
data() { |
||||
return { |
||||
livePusher: null, |
||||
aspect: '2:3', |
||||
windowWidth: '', //屏幕可用宽度 |
||||
windowHeight: '', //屏幕可用高度 |
||||
camerastate: false, |
||||
files: [] |
||||
} |
||||
}, |
||||
async onLoad() { |
||||
|
||||
_this = this; |
||||
this.initCamera(); |
||||
// 解决 store 取不到值的问题 |
||||
store.commit('setRequestUrl', this.$store.state.requestUrl) |
||||
store.commit('setFileRequestUrl', this.$store.state.fileRequestUrl) |
||||
store.commit('setAppCredential', this.$store.state.appCredential) |
||||
store.commit('setUserCredential', this.$store.state.userCredential) |
||||
}, |
||||
async onReady() { |
||||
// #ifdef APP-PLUS |
||||
this.livePusher = uni.createLivePusherContext('livePusher', this); |
||||
this.startPreview(); //开启预览并设置摄像头 |
||||
this.poenCarme(); |
||||
// #endif |
||||
}, |
||||
methods: { |
||||
initCamera() { |
||||
uni.getSystemInfo({ |
||||
success: function(res) { |
||||
_this.windowWidth = res.windowWidth; |
||||
_this.windowHeight = res.windowHeight; |
||||
let zcs = _this.aliquot(_this.windowWidth,_this.windowHeight); |
||||
_this.aspect = (_this.windowWidth/zcs)+':'+(_this.windowHeight/zcs); |
||||
console.log('画面比例:'+_this.aspect); |
||||
} |
||||
}); |
||||
}, |
||||
//整除数计算 |
||||
aliquot(x, y) { |
||||
if (x % y == 0) return y; |
||||
return this.aliquot(y, x % y); |
||||
}, |
||||
//轮询打开 |
||||
poenCarme(){ |
||||
//#ifdef APP-PLUS |
||||
if (plus.os.name == 'Android') { |
||||
setInterval(function() { |
||||
console.log(_this.camerastate); |
||||
if (!_this.camerastate) _this.startPreview(); |
||||
}, 2500); |
||||
} |
||||
//#endif |
||||
}, |
||||
//开始预览 |
||||
startPreview() { |
||||
this.livePusher.startPreview({ |
||||
success: a => { |
||||
console.log('startPreview', a.errMsg) |
||||
if (a.errMsg == 'startPreview:ok' || a.errMsg == 'operateLivePusher:ok') { |
||||
_this.camerastate = true; //标记相机启动成功 |
||||
} |
||||
} |
||||
}); |
||||
}, |
||||
//抓拍 |
||||
snapshot() { |
||||
//震动 |
||||
uni.vibrateShort({ |
||||
success: function() { |
||||
console.log('震动 success'); |
||||
} |
||||
}); |
||||
//拍照 |
||||
this.livePusher.snapshot({ |
||||
success: (e) => { |
||||
console.log(e.message.tempImagePath) |
||||
const fileName = e.message.tempImagePath.substring(e.message.tempImagePath.lastIndexOf('/') + 1) |
||||
pathToBase64(e.message.tempImagePath).then(base64 => { |
||||
|
||||
console.log('base64', base64) |
||||
console.log('fileName', fileName) |
||||
// 上传文件 |
||||
uploadFileBase64({ |
||||
base64, |
||||
originalFilename: fileName |
||||
}).then(data => { |
||||
_this.files.push({ |
||||
filePath: data.filePath, |
||||
fileName |
||||
}) |
||||
addPhoto({ |
||||
filePath: data.filePath, |
||||
fileName |
||||
}).then(() => { |
||||
|
||||
}) |
||||
}) |
||||
}); |
||||
|
||||
_this.stopPreview(); |
||||
setTimeout(() => { |
||||
_this.startPreview() |
||||
}, 1000) |
||||
}, |
||||
fail(e) { |
||||
console.log('fail', e) |
||||
} |
||||
}); |
||||
}, |
||||
//停止预览 |
||||
stopPreview() { |
||||
this.livePusher.stopPreview({ |
||||
success: a => { |
||||
// _this.camerastate = false; //标记相机未启动 |
||||
} |
||||
}); |
||||
}, |
||||
//反转 |
||||
flip() { |
||||
this.livePusher.switchCamera(); |
||||
}, |
||||
//状态 |
||||
statechange(e) { |
||||
//状态改变 |
||||
console.log(e); |
||||
if (e.detail.code == 1007) { |
||||
_this.camerastate = true; |
||||
} else if (e.detail.code == -1301) { |
||||
_this.camerastate = false; |
||||
} |
||||
}, |
||||
openPhoto() { |
||||
uni.navigateTo({ |
||||
url: `/pages/photo/index` |
||||
}); |
||||
}, |
||||
handleNext() { |
||||
uni.showModal({ |
||||
content: `关联问题,将照片关联到对应问题信息,并结束拍照;`, |
||||
cancelText: '继续拍照', |
||||
confirmText: '关联问题', |
||||
success: function (res) { |
||||
if (res.confirm) { |
||||
uni.navigateTo({ |
||||
url: '/pages/task/problem/add?files=' + JSON.stringify(_this.files) |
||||
}); |
||||
} |
||||
} |
||||
}); |
||||
} |
||||
} |
||||
} |
||||
|
||||
</script> |
||||
|
||||
<style lang="scss"> |
||||
.livePusher { |
||||
height: 100vh; |
||||
width: 100vw; |
||||
} |
||||
|
||||
.tools-t { |
||||
position: fixed; |
||||
top: 32rpx; |
||||
right: 32rpx; |
||||
z-index: 9999; |
||||
display: flex; |
||||
flex-direction: row; |
||||
justify-content: flex-end; |
||||
|
||||
.tools-btn { |
||||
border-radius: 50%; |
||||
padding: 0; |
||||
margin: 0; |
||||
display: flex; |
||||
justify-content: center; |
||||
align-items: center; |
||||
background: rgba(0, 0, 0, 0.6); |
||||
height: 112rpx; |
||||
width: 112rpx; |
||||
border: none; |
||||
} |
||||
} |
||||
|
||||
.tools-b { |
||||
position: fixed; |
||||
bottom: 0; |
||||
left: 0; |
||||
right: 0; |
||||
z-index: 9999; |
||||
background-color: rgba(0, 0, 0, 1); |
||||
padding: 48rpx 80rpx; |
||||
display: flex; |
||||
flex-direction: row; |
||||
justify-content: space-between; |
||||
align-items: center; |
||||
|
||||
.tools-btn { |
||||
border-radius: 50%; |
||||
padding: 0; |
||||
display: flex; |
||||
justify-content: center; |
||||
align-items: center; |
||||
} |
||||
|
||||
.photo-btn { |
||||
height: 140rpx; |
||||
width: 140rpx; |
||||
|
||||
>.photo-btn-c { |
||||
height: 128rpx; |
||||
width: 128rpx; |
||||
border-radius: 50%; |
||||
border: 2px solid #000; |
||||
} |
||||
} |
||||
|
||||
.rollover-btn { |
||||
background-color: transparent; |
||||
border: 1px solid #fff; |
||||
height: 96rpx; |
||||
width: 96rpx; |
||||
} |
||||
.img-btn { |
||||
background-color: transparent; |
||||
border: 1px solid #fff; |
||||
height: 96rpx; |
||||
width: 96rpx; |
||||
position: relative; |
||||
|
||||
.img-btn-img { |
||||
height: 96rpx; |
||||
width: 96rpx; |
||||
border-radius: 50%; |
||||
display: block; |
||||
} |
||||
} |
||||
.img-number { |
||||
position: absolute; |
||||
top: -16rpx; |
||||
right: -16rpx; |
||||
z-index: 999; |
||||
color: #fff; |
||||
} |
||||
} |
||||
</style> |
||||
@ -0,0 +1,92 @@
|
||||
<template> |
||||
<view class="calendar-content"> |
||||
<view> |
||||
<uni-calendar :selected="info.selected" :showMonth="false" @change="change" |
||||
@monthSwitch="monthSwitch" /> |
||||
</view> |
||||
</view> |
||||
<view class="duty-container"> |
||||
<view class="duty-title">市局</view> |
||||
<view class="row"> |
||||
<view class="col col-12 duty-item"> |
||||
<view class="duty-item-label">值班领导</view> |
||||
<view class="duty-item-content">张三</view> |
||||
</view> |
||||
</view> |
||||
<view class="duty-title">分局</view> |
||||
<view class="row"> |
||||
<view class="col col-12 duty-item"> |
||||
<view class="duty-item-label">天心分局</view> |
||||
<view class="duty-item-content">李四</view> |
||||
</view> |
||||
<view class="col col-12 duty-item"> |
||||
<view class="duty-item-label">雨花分局</view> |
||||
<view class="duty-item-content">王五</view> |
||||
</view> |
||||
<view class="col col-12 duty-item"> |
||||
<view class="duty-item-label">芙蓉分局</view> |
||||
<view class="duty-item-content">游麻</view> |
||||
</view> |
||||
<view class="col col-12 duty-item"> |
||||
<view class="duty-item-label">长沙县局</view> |
||||
<view class="duty-item-content">张三</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
</template> |
||||
|
||||
<script> |
||||
export default { |
||||
components: {}, |
||||
data() { |
||||
return { |
||||
info: { |
||||
selected: [] |
||||
} |
||||
} |
||||
}, |
||||
onReady() { |
||||
|
||||
}, |
||||
methods: { |
||||
change(e) { |
||||
console.log('change 返回:', e) |
||||
|
||||
}, |
||||
monthSwitch(e) { |
||||
console.log('monthSwitchs 返回:', e) |
||||
} |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
.duty-container { |
||||
padding: 24rpx; |
||||
.col { |
||||
margin-bottom: 0; |
||||
} |
||||
} |
||||
.duty-title { |
||||
font-size: 17px; |
||||
margin-top: 24rpx; |
||||
margin-bottom: 12rpx; |
||||
} |
||||
.duty-item { |
||||
display: flex; |
||||
text-align: center; |
||||
.duty-item-label { |
||||
width: 50%; |
||||
height: 64rpx; |
||||
line-height: 64rpx; |
||||
background: #0F78F3; |
||||
color: #fff; |
||||
} |
||||
.duty-item-content { |
||||
width: 50%; |
||||
height: 64rpx; |
||||
line-height: 64rpx; |
||||
background: #E3F0FF; |
||||
} |
||||
} |
||||
</style> |
||||
@ -0,0 +1,442 @@
|
||||
<template> |
||||
<template v-if="currentPage === 'home'"> |
||||
<view> |
||||
<image src="/static/image/carousel.png" style="width: 100%" mode="widthFix"></image> |
||||
</view> |
||||
<view class="container"> |
||||
<view class="title">我的任务</view> |
||||
<view class="flex flex-wrap gap-32"> |
||||
<view class="app-item" @tap="openTask('todo')"> |
||||
<view class="item-icon item-number mb-6"> |
||||
<text>{{ task.todoCount }}</text> |
||||
</view> |
||||
<view class="item-name mb-6">待处理</view> |
||||
</view> |
||||
<view class="app-item" @tap="openTask('done')"> |
||||
<view class="item-icon item-number mb-6"> |
||||
<text>{{ task.doneCount }}</text> |
||||
</view> |
||||
<view class="item-name">已办结</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
<!-- <view class="container"> |
||||
<view class="title">问题处置</view> |
||||
<view class="flex flex-wrap gap-32"> |
||||
<view class="app-item" @tap="openTask('todo')"> |
||||
<view class="item-icon item-number mb-6"> |
||||
<text>{{ task.todoCount }}</text> |
||||
</view> |
||||
<view class="item-name mb-6">待处理</view> |
||||
</view> |
||||
</view> |
||||
</view> --> |
||||
<view class="container"> |
||||
<view class="title">督察应用</view> |
||||
<view class="flex flex-wrap app-container"> |
||||
<view class="app-item" @tap="openTaskProblem"> |
||||
<view class="item-icon mb-6"> |
||||
<image src="/static/icon/ic_camera.png"></image> |
||||
</view> |
||||
<view class="item-name">问题随拍</view> |
||||
</view> |
||||
<view class="app-item" @tap="openNegative"> |
||||
<view class="item-icon mb-6"> |
||||
<image src="/static/icon/ic_warning.png"></image> |
||||
</view> |
||||
<view class="item-name">问题清单</view> |
||||
</view> |
||||
<view class="app-item" @tap="openSelfexamination"> |
||||
<view class="item-icon mb-6"> |
||||
<image src="/static/icon/ic_selfexamination.png"></image> |
||||
</view> |
||||
<view class="item-name">所队自查</view> |
||||
</view> |
||||
|
||||
<view class="app-item" @tap="openDuty"> |
||||
<view class="item-icon mb-6"> |
||||
<image src="/static/icon/ic_card.png"></image> |
||||
</view> |
||||
<view class="item-name">值班报备</view> |
||||
</view> |
||||
<view class="app-item" @tap="openComfort"> |
||||
<view class="item-icon mb-6"> |
||||
<image src="/static/icon/ic_apply.png"></image> |
||||
</view> |
||||
<view class="item-name">抚慰申请</view> |
||||
</view> |
||||
<view class="app-item" @tap="openBooks"> |
||||
<view class="item-icon mb-6"> |
||||
<image src="/static/icon/ic_book.png"></image> |
||||
</view> |
||||
<view class="item-name">知识库</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
</template> |
||||
<template v-else> |
||||
<view class="wrapper"> |
||||
<view class="center-card flex gap-12"> |
||||
<view class="avatar"> |
||||
<net-image :filepath="store.state.user.avatarUrl" v-if="store.state.user.avatarUrl" /> |
||||
<image src="/static/police.png" v-else></image> |
||||
</view> |
||||
<view class="flex flex-col justify-between"> |
||||
<view> |
||||
<view class="name mb-6">{{ store.state.user.nickName }}</view> |
||||
<view class="second mb-6">{{ store.state.user.departName }}</view> |
||||
<view class="second">{{ }}</view> |
||||
</view> |
||||
<view class="info flex"> |
||||
<view>警号:</view> |
||||
<view class="mr-20">{{ store.state.user.empNo }}</view> |
||||
</view> |
||||
</view> |
||||
<view class="edit-btn"> |
||||
<image src="/static/edit.png" style="height: 37px" mode="heightFix"></image> |
||||
</view> |
||||
</view> |
||||
<view class="panel"> |
||||
<view class="panel-h" @tap="openManual"> |
||||
<image src="/static/icon/ic_c_book.png" style="height: 27px; width: 27px"></image> |
||||
<view class="panel-c"> |
||||
<text class="panel-text">使用手册</text> |
||||
<uni-icons type="right" size="20" color="#666" /> |
||||
</view> |
||||
|
||||
</view> |
||||
<view class="panel-h" @tap="openFeedback"> |
||||
<image src="/static/icon/ic_c_message.png" style="height: 27px; width: 27px"></image> |
||||
|
||||
<view class="panel-c"> |
||||
<text class="panel-text">意见反馈</text> |
||||
<uni-icons type="right" size="20" color="#666" /> |
||||
</view> |
||||
</view> |
||||
<view class="panel-h" @tap="openAbout"> |
||||
<image src="/static/icon/ic_c_app.png" style="height: 27px; width: 27px"></image> |
||||
|
||||
<view class="panel-c"> |
||||
<text class="panel-text">关于APP</text> |
||||
<uni-icons type="right" size="20" color="#666" /> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
</template> |
||||
<view class="tab-bar"> |
||||
<view v-for="item in tabBars" :class="currentPage === item.name ? 'tab-bar-item active': 'tab-bar-item'" @tap="currentPage = item.name"> |
||||
<uni-icons :type="item.icon" size="50rpx"></uni-icons> |
||||
<view>{{ item.text }}</view> |
||||
</view> |
||||
<view class="tab-bar-item_center" @tap="openCamera"> |
||||
<image src="/static/camer.png" class="tab-bar-item_center-icon" mode="widthFix"></image> |
||||
<view>随手拍</view> |
||||
</view> |
||||
</view> |
||||
</template> |
||||
|
||||
<script lang="uts"> |
||||
import permision from '@/common/permission' |
||||
import { getToken } from '@/common/auth' |
||||
import store from '@/store' |
||||
import { setToken } from '@/common/auth' |
||||
import { login } from '@/api/auth' |
||||
import { getTaskCount } from '@/api/task' |
||||
|
||||
let _this; |
||||
export default { |
||||
data() { |
||||
return { |
||||
task: { |
||||
todoCount: 0, |
||||
doneCount: 0 |
||||
}, |
||||
user: {}, |
||||
currentPage: 'home', |
||||
tabBars: [ |
||||
{ |
||||
text: '首页', |
||||
icon: 'home', |
||||
name: 'home' |
||||
}, |
||||
{ |
||||
text: '我的', |
||||
icon: 'person', |
||||
name: 'center' |
||||
} |
||||
] |
||||
} |
||||
}, |
||||
setup() { |
||||
return { |
||||
store |
||||
} |
||||
}, |
||||
async onShow() { |
||||
_this = this; |
||||
const url = 'http://172.20.10.3:8080/app/'; |
||||
const env = 'prod'; |
||||
// const url = 'http://192.168.3.22:8080/app/' |
||||
// #ifdef APP-PLUS |
||||
if (env === 'dev') { |
||||
if (!store.state.requestUrl) { |
||||
store.commit('setRequestUrl', url + 'forward') |
||||
} |
||||
if (!getToken() || !store.state.hasLogin) { |
||||
const userData = await login({ empNo: '012893' }); |
||||
setToken(userData.token); |
||||
store.commit('setUser', userData.user) |
||||
} |
||||
} else { |
||||
const event = plus.android.importClass('com.maker.supervise.Event') |
||||
if (!store.state.requestUrl) { |
||||
const requestUrl = event.getRequestUrl() |
||||
store.commit('setRequestUrl', requestUrl) |
||||
} |
||||
if (!store.state.appCredential) { |
||||
const appCredential = encodeURIComponent(event.getAppCredential()) |
||||
store.commit('setAppCredential', appCredential) |
||||
} |
||||
if (!store.state.userCredential) { |
||||
const userCredential = encodeURIComponent(event.getUserCredential()) |
||||
store.commit('setUserCredential', userCredential) |
||||
} |
||||
if (!getToken() || !store.state.hasLogin) { |
||||
const userData = await login({ empNo: event.getEmpNo() }); |
||||
setToken(userData.token); |
||||
store.commit('setUser', userData.user) |
||||
} |
||||
} |
||||
// #endif |
||||
|
||||
const data = await getTaskCount() |
||||
if (data) { |
||||
_this.task = data; |
||||
} |
||||
}, |
||||
methods: { |
||||
openDeveloping() { |
||||
uni.showModal({ |
||||
title: '温馨提示', |
||||
content: '功能开发中...', |
||||
success: function (res) { |
||||
if (res.confirm) { |
||||
console.log('用户点击确定'); |
||||
} else if (res.cancel) { |
||||
console.log('用户点击取消'); |
||||
} |
||||
} |
||||
}); |
||||
}, |
||||
openTask(taskStatus) { |
||||
uni.navigateTo({ |
||||
url: '/pages/task/index?taskStatus=' + taskStatus |
||||
}); |
||||
}, |
||||
async openCamera() { |
||||
// #ifdef APP-PLUS |
||||
let status = await permision.requestAndroid('android.permission.CAMERA'); |
||||
if (status === null || status === 1) { |
||||
uni.navigateTo({ |
||||
url: '/pages/common/camera' |
||||
}); |
||||
} else { |
||||
uni.showModal({ |
||||
content: "没有开启相机权限", |
||||
confirmText: "设置", |
||||
success: function(res) { |
||||
if (res.confirm) { |
||||
permision.gotoAppSetting(); |
||||
} |
||||
} |
||||
}) |
||||
} |
||||
// #endif |
||||
|
||||
// #ifdef H5 |
||||
uni.navigateTo({ |
||||
url: '/pages/common/camera' |
||||
}); |
||||
// #endif |
||||
}, |
||||
openNegative() { |
||||
uni.navigateTo({ |
||||
url: '/pages/negative/index' |
||||
}); |
||||
}, |
||||
openDuty() { |
||||
uni.navigateTo({ |
||||
url: '/pages/duty/index' |
||||
}); |
||||
}, |
||||
openComfort() { |
||||
uni.navigateTo({ |
||||
url: '/pages/comfort/list' |
||||
}); |
||||
}, |
||||
openBooks() { |
||||
uni.navigateTo({ |
||||
url: '/pages/books/index' |
||||
}); |
||||
}, |
||||
openSelfexamination() { |
||||
uni.navigateTo({ |
||||
url: '/pages/task/selfexamination/list' |
||||
}); |
||||
}, |
||||
openTaskProblem() { |
||||
uni.navigateTo({ |
||||
url: '/pages/task/problem/list' |
||||
}); |
||||
}, |
||||
openFeedback() { |
||||
uni.navigateTo({ |
||||
url: `/pages/center/feedback` |
||||
}); |
||||
}, |
||||
openManual() { |
||||
uni.navigateTo({ |
||||
url: `/pages/center/manual` |
||||
}); |
||||
}, |
||||
openAbout() { |
||||
uni.navigateTo({ |
||||
url: `/pages/center/about` |
||||
}); |
||||
}, |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
.container { |
||||
padding: 20rpx 30rpx; |
||||
.title { |
||||
font-size: 28rpx; |
||||
font-weight: 700; |
||||
margin-bottom: 24rpx; |
||||
} |
||||
} |
||||
.app-item { |
||||
width: 124rpx; |
||||
.item-icon { |
||||
width: 124rpx; |
||||
height: 124rpx; |
||||
line-height: 124rpx; |
||||
text-align: center; |
||||
background: #F3F3F3; |
||||
border-radius: 24rpx; |
||||
image { |
||||
width: 100%; |
||||
height: 100%; |
||||
} |
||||
} |
||||
.item-name { |
||||
font-size: 26rpx; |
||||
text-align: center; |
||||
} |
||||
.item-number { |
||||
font-size: 42rpx; |
||||
font-weight: 700; |
||||
} |
||||
} |
||||
.app-container { |
||||
gap: 24rpx 64rpx; |
||||
} |
||||
.tab-bar { |
||||
position: fixed; |
||||
left: 0; |
||||
right: 0; |
||||
bottom: 0; |
||||
height: 96rpx; |
||||
display: flex; |
||||
box-shadow: inset 0 1px 0 0 #E4E4E4; |
||||
.tab-bar-item { |
||||
width: 50%; |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: center; |
||||
flex-direction: column; |
||||
font-size: 12px; |
||||
color: #666; |
||||
.uni-icons { |
||||
color: #666 !important; |
||||
} |
||||
&.active { |
||||
color: var(--primary-color); |
||||
.uni-icons { |
||||
color: var(--primary-color) !important; |
||||
} |
||||
} |
||||
} |
||||
|
||||
.tab-bar-item_center { |
||||
position: absolute; |
||||
left: 50%; |
||||
top: -48rpx; |
||||
transform: translateX(-50%); |
||||
font-size: 12px; |
||||
color: #666; |
||||
text-align: center; |
||||
.tab-bar-item_center-icon { |
||||
width: 96rpx; |
||||
display: block; |
||||
} |
||||
} |
||||
} |
||||
|
||||
.center-card { |
||||
box-shadow: 0px 10rpx 26rpx 6rpx rgba(0, 0, 0, 0.08); |
||||
margin: 24rpx; |
||||
padding: 24rpx; |
||||
position: relative; |
||||
.name { |
||||
font-size: 28rpx; |
||||
line-height: 40rpx; |
||||
} |
||||
|
||||
.second { |
||||
font-size: 24rpx; |
||||
line-height: 34rpx; |
||||
color: #666; |
||||
} |
||||
|
||||
.info { |
||||
font-size: 24rpx; |
||||
} |
||||
|
||||
.edit-btn { |
||||
position: absolute; |
||||
bottom: 0; |
||||
right: 0; |
||||
image { |
||||
display: block; |
||||
} |
||||
} |
||||
} |
||||
.panel { |
||||
padding: 0 24rpx; |
||||
.panel-h { |
||||
display: flex; |
||||
align-items: center; |
||||
gap: 0 24rpx; |
||||
.panel-c { |
||||
height: 90rpx; |
||||
line-height: 90rpx; |
||||
box-shadow: inset 0 -1px 0 0 #eee; |
||||
width: calc(100% - 80rpx); |
||||
display: flex; |
||||
justify-content: space-between; |
||||
} |
||||
} |
||||
} |
||||
.avatar { |
||||
width: 136rpx; |
||||
height: 205rpx; |
||||
image { |
||||
width: 100%; |
||||
height: 100%; |
||||
} |
||||
} |
||||
</style> |
||||
@ -0,0 +1,198 @@
|
||||
<template> |
||||
<view class="negative-wrapper"> |
||||
<negative :data="data" :loading="loading" /> |
||||
|
||||
<view class="container" v-if="flowKey === 'first_distribute' || flowKey === 'second_distribute'"> |
||||
<uni-forms ref="distributeFormRef" :modelValue="actionData" :rules="distributeRules" label-width="200rpx" style="margin: 12px"> |
||||
<uni-forms-item label="主办层级" name="hostLevel" required> |
||||
<uni-data-checkbox v-model="actionData.hostLevel" :localdata="hostLevel" :map="{text: 'dictLabel', value: 'dictValue'}" /> |
||||
</uni-forms-item> |
||||
<uni-forms-item label="办理单位" name="departId" required> |
||||
<uni-data-picker :localdata="departs" placeholder="请选择办理单位" :border="false" |
||||
:map="{text:'shortName', value: 'id'}" v-model="actionData.departId" /> |
||||
</uni-forms-item> |
||||
</uni-forms> |
||||
</view> |
||||
</view> |
||||
<view class="footer col-24 flex flex-wrap justify-end"> |
||||
<n-button v-for="item in flowActions" :type="item.buttonType" class="button" :plain="item.plain" :label="item.buttonLabel" @tap="submit(item)" :disabled="loading" /> |
||||
</view> |
||||
|
||||
<modal ref="approveModelRef" @confirm="handleApproval" title="审批意见" placeholderText="请输入审批意见" confirmText="审批通过" /> |
||||
|
||||
<modal ref="returnModelRef" @confirm="handleApproval" title="退回意见" placeholderText="请输入退回意见" confirmType="warn" /> |
||||
|
||||
</template> |
||||
<script> |
||||
import { getDictOptions } from '@/common/dict' |
||||
import { getNegative, executeNegative } from '@/api/negative' |
||||
import { |
||||
departTree, |
||||
secondList |
||||
} from '@/api/depart' |
||||
|
||||
let _this; |
||||
export default { |
||||
inheritAttrs: false, |
||||
data() { |
||||
return { |
||||
data: {}, |
||||
flowActions: [], |
||||
loading: true, |
||||
actionData: {}, |
||||
activeFlowAction: {}, |
||||
departs: [], |
||||
distributeRules: { |
||||
hostLevel: { |
||||
rules: [{ |
||||
required: true, |
||||
errorMessage: '请选择主办层级', |
||||
}] |
||||
}, |
||||
departId: { |
||||
rules: [{ |
||||
required: true, |
||||
errorMessage: '请选择办理单位', |
||||
}] |
||||
}, |
||||
}, |
||||
flowKey: '', |
||||
confirmationCompletionFlag: false |
||||
} |
||||
}, |
||||
setup() { |
||||
const hostLevel = getDictOptions("hostLevel"); |
||||
return { |
||||
hostLevel |
||||
} |
||||
}, |
||||
onLoad() { |
||||
|
||||
_this = this; |
||||
uni.setNavigationBarTitle({ |
||||
title: `问题编号 ` + this.$page.options.id |
||||
}) |
||||
this.getData() |
||||
|
||||
}, |
||||
methods: { |
||||
getData() { |
||||
getNegative(this.$page.options.id, this.$page.options.workId).then(data => { |
||||
this.data = data |
||||
this.flowActions = data.flowActions |
||||
this.flowKey = data.flowNode.flowKey |
||||
this.confirmationCompletionFlag = data.confirmationCompletionFlag |
||||
this.loading = false |
||||
if (this.flowKey === 'first_distribute' || this.flowKey === 'second_distribute') { |
||||
if (this.flowKey === 'first_distribute') { |
||||
secondList().then(data => { |
||||
this.departs = data |
||||
}) |
||||
} else { |
||||
departTree().then(data => { |
||||
this.departs = data[0].children |
||||
}) |
||||
} |
||||
|
||||
} |
||||
}) |
||||
}, |
||||
async submit(item) { |
||||
console.log(item.actionKey) |
||||
const actions = ['save', 'apply_extension', 'apply_completion', 'apply_countersign', 'update_verify']; |
||||
if (actions.indexOf(item.actionKey) > -1) { |
||||
uni.showModal({ |
||||
title: '温馨提示', |
||||
content: '该功能暂不支持在APP上操作,如有需要请在电脑端操作', |
||||
success: function (res) { |
||||
if (res.confirm) { |
||||
console.log('用户点击确定'); |
||||
} else if (res.cancel) { |
||||
console.log('用户点击取消'); |
||||
} |
||||
} |
||||
}); |
||||
return |
||||
} |
||||
if (item.openDialog) { |
||||
const approveActionKeys = ['second_approve', 'first_approve'] |
||||
if (approveActionKeys.indexOf(item.actionKey) > -1) { |
||||
if ( |
||||
this.confirmationCompletionFlag |
||||
) { |
||||
item = { |
||||
actionName: "认定办结", |
||||
actionKey: "confirmationCompletion", |
||||
doClose: true |
||||
}; |
||||
} |
||||
this.$refs.approveModelRef.open() |
||||
this.activeFlowAction = item |
||||
return |
||||
} |
||||
const returnActionKeys = ['second_sign_return', 'three_sign_return', 'second_approve_return', 'first_approve_return'] |
||||
if (returnActionKeys.indexOf(item.actionKey) > -1) { |
||||
this.$refs.returnModelRef.open() |
||||
this.activeFlowAction = item |
||||
} |
||||
return |
||||
} |
||||
if (item.actionKey === 'second_distribute') { |
||||
await this.$refs.distributeFormRef.validate() |
||||
} |
||||
this.loading = true |
||||
executeNegative(this.$page.options.id, { |
||||
workId: this.$page.options.workId, |
||||
actionKey: item.actionKey, |
||||
nextFlowKey: item.nextFlowKey, |
||||
actionName: item.actionName, |
||||
data: this.actionData |
||||
}).then(data => { |
||||
console.log(data) |
||||
if (item.actionKey === 'second_sign') { |
||||
uni.showToast({ |
||||
title: '签收成功', |
||||
icon: 'success', |
||||
duration: 3000 |
||||
}) |
||||
} |
||||
if (item.doClose) { |
||||
uni.showToast({ |
||||
title: '操作成功', |
||||
icon: 'success', |
||||
duration: 3000 |
||||
}) |
||||
uni.navigateBack({ |
||||
|
||||
}); |
||||
} else { |
||||
this.getData() |
||||
} |
||||
|
||||
}) |
||||
}, |
||||
handleApproval(comments) { |
||||
this.activeFlowAction.openDialog = false |
||||
this.actionData.comments = comments |
||||
this.submit(this.activeFlowAction) |
||||
} |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
.footer { |
||||
background-color: #fff; |
||||
gap: 8rpx; |
||||
} |
||||
.negative-wrapper { |
||||
background-color: #f5f5f5; |
||||
min-height: 100vh; |
||||
box-sizing: border-box; |
||||
padding-bottom: 60px; |
||||
.container { |
||||
background-color: #fff; |
||||
margin-bottom: 12rpx; |
||||
} |
||||
} |
||||
</style> |
||||
@ -0,0 +1,226 @@
|
||||
<template> |
||||
<view class="flex search"> |
||||
<view class="search-item flex justify-center" :search="searchFlag"> |
||||
<view class="search-item-conent"> |
||||
<uni-easyinput prefixIcon="search" type="text" v-model="query.thingDesc" placeholder="搜索" :inputBorder="false" @focus="searchFlag = true" /> |
||||
|
||||
</view> |
||||
</view> |
||||
<view class="search-item flex justify-center" v-if="!searchFlag" @tap="showPopup"> |
||||
<view :class="filterFlag ? 'search-item-conent active': 'search-item-conent'"> |
||||
<uni-icons customPrefix="customicons" type="filter" size="20" color="#666" /> |
||||
<view>筛选</view> |
||||
</view> |
||||
</view> |
||||
<view v-else> |
||||
<view class="cancel-btn" @tap="searchFlag = false">取消</view> |
||||
</view> |
||||
</view> |
||||
<view class="negative-container"> |
||||
<view class="card negative-item" v-for="item in negatives" @tap="open(item)"> |
||||
<view class="negative-title"> |
||||
<view>{{ item.problemSources }}</view> |
||||
<view></view> |
||||
</view> |
||||
<view class="row"> |
||||
<view class="col col-12"> |
||||
<view class="label">录入时间:</view> |
||||
<view class="content">{{ item.crtTime }}</view> |
||||
</view> |
||||
<view class="col col-12"> |
||||
<view class="label">发现时间:</view> |
||||
<view class="content">{{ item.discoveryTime }}</view> |
||||
</view> |
||||
<view class="col col-12"> |
||||
<view class="label">业务类别:</view> |
||||
<view class="content">{{ item.businessTypeName }}</view> |
||||
</view> |
||||
<view class="col col-12"> |
||||
<view class="label">涉及单位:</view> |
||||
<view class="content">{{ item.involveDepartName }}</view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">问题内容:</view> |
||||
<view class="content">{{ item.thingDesc }}</view> |
||||
</view> |
||||
<view class="col col-24" v-if="item.checkStatusName"> |
||||
<view class="label">是否属实:</view> |
||||
<view class="content">{{ item.checkStatusName }}</view> |
||||
</view> |
||||
<view class="col col-24" v-if="item.currentProcessingObject"> |
||||
<view class="label">当前处理:</view> |
||||
<view class="content">{{ item.currentProcessingObject }}</view> |
||||
</view> |
||||
</view> |
||||
<view class="negative-bottom"> |
||||
<view v-if="item.processingStatus === 'signing'" style="color: var(--danger-color)">签收中</view> |
||||
<view v-if="item.processingStatus === 'processing'" style="color: #ff5722">办理中</view> |
||||
<view v-if="item.processingStatus === 'approval'" style="color: var(--primary-color)">审批中</view> |
||||
<view v-if="item.processingStatus === 'completed'" style="color: var(--success-color)">已办结</view> |
||||
</view> |
||||
</view> |
||||
<empty v-if="negatives.length === 0" /> |
||||
</view> |
||||
|
||||
<uni-popup ref="filterPopupRef" type="top"> |
||||
<view class="popup-container"> |
||||
<view class="popup-header"> |
||||
<view>全部筛选</view> |
||||
<uni-icons type="closeempty" class="close-btn" @tap="closePopup"></uni-icons> |
||||
</view> |
||||
<view class="popup-body"> |
||||
<view class="filter-container"> |
||||
<!-- <view class="filter-label">问题来源</view> |
||||
<problem-picker v-model="query.problemTypeCode" @change="search" /> --> |
||||
<view class="filter-label mt-10">业务类型</view> |
||||
<filter-radio :data="businessTypes" v-model="query.businessTypeCode" :prop="{text: 'dictLabel', value: 'dictValue'}" @change="search" /> |
||||
<view class="filter-label mt-10">办理状态</view> |
||||
<filter-radio :data="processingStatus" v-model="query.processingStatus" :prop="{text: 'dictLabel', value: 'dictValue'}" @change="search" /> |
||||
|
||||
<view class="filter-label mt-10">涉及单位</view> |
||||
<view class="mb-10"> |
||||
<uni-data-picker :localdata="departs" placeholder="请选择涉及单位" :border="false" |
||||
:map="{text:'shortName', value: 'id'}" v-model="query.involveDepartId" @change="search" /> |
||||
</view> |
||||
<view class="filter-label mt-10">办理单位</view> |
||||
<view class="mb-10"> |
||||
<uni-data-picker :localdata="departs" placeholder="请选择办理单位" :border="false" |
||||
:map="{text:'shortName', value: 'id'}" v-model="query.handleDepartId" @change="search" /> |
||||
</view> |
||||
|
||||
</view> |
||||
</view> |
||||
<view class="footer col-24 flex gap-8"> |
||||
<button class="col-12" @tap="reset">重置</button> |
||||
<button type="primary" @tap="handleSearch" class="col-12">完成</button> |
||||
</view> |
||||
</view> |
||||
</uni-popup> |
||||
</template> |
||||
<script> |
||||
import store from '@/store' |
||||
import { getDictOptions } from '@/common/dict' |
||||
import { listNegative } from '@/api/negative' |
||||
import { |
||||
departTree |
||||
} from '@/api/depart' |
||||
import { getDictLabel } from '@/common/util' |
||||
|
||||
|
||||
let oldList; |
||||
let _this; |
||||
|
||||
export default { |
||||
data() { |
||||
return { |
||||
negatives: [], |
||||
query: { |
||||
size: 100, |
||||
current: 1 |
||||
}, |
||||
departs: [], |
||||
searchFlag: false, |
||||
filterFlag: false, |
||||
} |
||||
}, |
||||
setup(props, context) { |
||||
const processingStatus = getDictOptions('processingStatus'); |
||||
const businessTypes = getDictOptions('businessType') |
||||
return { |
||||
processingStatus, |
||||
businessTypes, |
||||
getDictLabel |
||||
} |
||||
}, |
||||
watch: { |
||||
searchFlag(val) { |
||||
if (val) { |
||||
oldList = this.negatives; |
||||
this.negatives = [] |
||||
} else { |
||||
this.negatives = oldList |
||||
} |
||||
}, |
||||
'query.thingDesc': function(val) { |
||||
if (_this.searchFlag) { |
||||
if (val) { |
||||
_this.getNegatives() |
||||
} else { |
||||
this.negatives = [] |
||||
} |
||||
|
||||
} |
||||
} |
||||
}, |
||||
onLoad() { |
||||
_this = this; |
||||
this.getNegatives(); |
||||
departTree().then(data => { |
||||
this.departs = data[0].children |
||||
}) |
||||
}, |
||||
methods: { |
||||
open(item) { |
||||
uni.navigateTo({ |
||||
url: '/pages/negative/info?id=' + item.id |
||||
}); |
||||
}, |
||||
getNegatives() { |
||||
uni.showLoading({ |
||||
title: '数据加载中' |
||||
}); |
||||
listNegative(this.query).then(data => { |
||||
this.negatives = data.records |
||||
uni.hideLoading(); |
||||
}); |
||||
}, |
||||
showPopup() { |
||||
this.$refs.filterPopupRef.open() |
||||
}, |
||||
closePopup() { |
||||
this.$refs.filterPopupRef.close() |
||||
}, |
||||
search() { |
||||
if (this.query.problemTypeCode || this.query.businessTypeCode || this.query.involveDepartId || this.query.handleDepartId) { |
||||
this.filterFlag = true |
||||
} else { |
||||
this.filterFlag = false |
||||
} |
||||
this.getNegatives() |
||||
}, |
||||
handleSearch() { |
||||
this.search() |
||||
this.closePopup() |
||||
}, |
||||
reset() { |
||||
this.filterFlag = false |
||||
this.query = { |
||||
size: 100, |
||||
current: 1 |
||||
} |
||||
this.getNegatives() |
||||
} |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
.negative-container { |
||||
max-height: calc(100vh - 98rpx); |
||||
overflow: auto; |
||||
} |
||||
.negative-title { |
||||
display: flex; |
||||
justify-content: space-between; |
||||
margin-bottom: 12rpx; |
||||
font-weight: 500; |
||||
font-size: 16px; |
||||
} |
||||
.negative-bottom { |
||||
display: flex; |
||||
justify-content: space-between; |
||||
.negative-tag { |
||||
color: #FF0000; |
||||
} |
||||
} |
||||
</style> |
||||
@ -0,0 +1,41 @@
|
||||
<template> |
||||
<view class="negative-wrapper"> |
||||
<negative :data="data" :loading="loading" /> |
||||
</view> |
||||
</template> |
||||
|
||||
<script> |
||||
import { getNegative } from '@/api/negative' |
||||
|
||||
let _this; |
||||
export default { |
||||
data() { |
||||
return { |
||||
data: {}, |
||||
loading: true |
||||
} |
||||
}, |
||||
onLoad() { |
||||
_this = this; |
||||
uni.setNavigationBarTitle({ |
||||
title: `问题编号 ` + this.$page.options.id |
||||
}) |
||||
|
||||
getNegative(this.$page.options.id).then(data => { |
||||
this.data = data |
||||
this.loading = false |
||||
}) |
||||
}, |
||||
methods: { |
||||
|
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
.negative-wrapper { |
||||
background-color: #f5f5f5; |
||||
min-height: 100vh; |
||||
box-sizing: border-box; |
||||
} |
||||
</style> |
||||
@ -0,0 +1,60 @@
|
||||
<template> |
||||
<view v-for="item in photoGroups" class="container"> |
||||
<view class="photo-date">记录时间:{{ item.date }}</view> |
||||
<view class="photo-container"> |
||||
<view v-for="photo in item.photos" class="photo-item" @tap="handleCheckPhoto(photo)"> |
||||
<net-image :filepath="photo.filePath" /> |
||||
<radio :checked="activePhotos.findIndex(o => o.filePath === photo.filePath) > -1" @tap.stop="handleCheckPhoto(photo)" /> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
<empty v-if="photoGroups.length === 0" description="无照片" /> |
||||
<view class="footer col-24"> |
||||
<button type="primary" @click="openInspectionAdd">关联问题</button> |
||||
</view> |
||||
</template> |
||||
|
||||
<script> |
||||
import store from '@/store' |
||||
import { listPhoto } from '@/api/photo' |
||||
|
||||
export default { |
||||
data() { |
||||
return { |
||||
photoGroups: [], |
||||
activePhotos: [] |
||||
} |
||||
}, |
||||
onLoad() { |
||||
listPhoto().then(data => { |
||||
this.photoGroups = data; |
||||
}) |
||||
}, |
||||
methods: { |
||||
openInspectionAdd() { |
||||
uni.navigateTo({ |
||||
url: '/pages/task/problem/add?files=' + JSON.stringify(this.activePhotos) |
||||
}); |
||||
}, |
||||
handleCheckPhoto(photo) { |
||||
const index = this.activePhotos.findIndex(o => o.filePath === photo.filePath); |
||||
if (index === -1) { |
||||
this.activePhotos.push({ |
||||
filePath: photo.filePath, |
||||
fileName: photo.fileName |
||||
}) |
||||
} else { |
||||
this.activePhotos.splice(index, 1) |
||||
} |
||||
} |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
.photo-date { |
||||
margin-bottom: 24rpx; |
||||
font-size: 12px; |
||||
} |
||||
|
||||
</style> |
||||
@ -0,0 +1,392 @@
|
||||
<template> |
||||
<tabs :options="tabOptions" v-model="query.taskStatus" v-if="!searchFlag" /> |
||||
<view class="flex search"> |
||||
<view class="search-item flex justify-center" :search="searchFlag"> |
||||
<view class="search-item-conent"> |
||||
<uni-easyinput prefixIcon="search" type="text" placeholder="搜索" :inputBorder="false" v-model="query.taskName" @focus="searchFlag = true" /> |
||||
</view> |
||||
</view> |
||||
<view class="search-item flex justify-center" v-if="!searchFlag" @tap="showPopup"> |
||||
<view :class="filterFlag ? 'search-item-conent active': 'search-item-conent'"> |
||||
<uni-icons customPrefix="customicons" type="filter" size="20" color="#666" /> |
||||
<view>筛选</view> |
||||
</view> |
||||
</view> |
||||
<view v-else> |
||||
<view class="cancel-btn" @tap="cancleSearch">取消</view> |
||||
</view> |
||||
</view> |
||||
<view> |
||||
<view class="flex gap-16 task-item card" v-for="item in tasks" @tap="open(item)" > |
||||
<template v-if="item.taskType === 'testing_alcohol'"> |
||||
<view> |
||||
<image src="../../static/icon/ic_wine.png" style="width: 44px; height: 44px"></image> |
||||
</view> |
||||
<view style="width: calc(100% - 60px)"> |
||||
<view class="flex justify-between header"> |
||||
<view class="title">{{ item.taskName }}</view> |
||||
<view class="date">{{ item.createTime }}</view> |
||||
</view> |
||||
<view> |
||||
<view class="row"> |
||||
<view class="col col-24"> |
||||
<view class="label">督察单位:</view> |
||||
<view class="content">{{ item.supDepartName }}</view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">抽检人员:</view> |
||||
<view class="content">{{ item.totalNumber }}人</view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">检查时间:</view> |
||||
<view class="content">{{ item.beginTime }} ~ {{ item.endTime }}</view> |
||||
</view> |
||||
</view> |
||||
<view style="color: #FF0000;" v-if="item.taskStatus === 'todo'">待处理</view> |
||||
<view v-else>已办结</view> |
||||
</view> |
||||
</view> |
||||
</template> |
||||
<template v-if="item.taskType === 'inspection'"> |
||||
<view> |
||||
<image src="../../static/icon/ic_task.png" style="width: 44px; height: 44px"></image> |
||||
</view> |
||||
<view style="width: calc(100% - 60px)"> |
||||
<view class="flex justify-between header"> |
||||
<view class="title">{{ item.taskName }}</view> |
||||
<view class="date">{{ item.createTime }}</view> |
||||
</view> |
||||
<view> |
||||
<view class="row"> |
||||
<view class="col col-24"> |
||||
<view class="label">督察单位:</view> |
||||
<view class="content">{{ item.supDepartName }}</view> |
||||
</view> |
||||
<view class="col col-12"> |
||||
<view class="label">督察类型:</view> |
||||
<view class="content">{{ item.supervisionType }}</view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">督察内容:</view> |
||||
<view class="content">{{ item.taskContent }}</view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">检查时间:</view> |
||||
<view class="content">{{ item.beginTime }} ~ {{ item.endTime }}</view> |
||||
</view> |
||||
</view> |
||||
<view style="color: #FF0000;" v-if="item.taskStatus === 'todo'">{{ !item.hasSign? '待签收' : '待处理'}}</view> |
||||
<view v-else>已办结</view> |
||||
</view> |
||||
</view> |
||||
</template> |
||||
<template v-if="item.taskType === 'selfexamination'"> |
||||
<view> |
||||
<image src="../../static/icon/ic_selfexamination.png" style="width: 44px; height: 44px"></image> |
||||
</view> |
||||
<view style="width: calc(100% - 60px)"> |
||||
<view class="flex justify-between header"> |
||||
<view class="title">{{ item.taskName }}</view> |
||||
<view class="date">{{ item.createTime }}</view> |
||||
</view> |
||||
<view> |
||||
<view class="row"> |
||||
<view class="col col-24"> |
||||
<view class="label">自查单位:</view> |
||||
<view class="content">{{ item.supDepartName }}</view> |
||||
</view> |
||||
<view class="col col-12"> |
||||
<view class="label">自查类型:</view> |
||||
<view class="content">{{ item.type }}</view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">自查要求:</view> |
||||
<view class="content">{{ item.requirement }}</view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">任务时间:</view> |
||||
<view class="content">{{ item.beginTime }} ~ {{ item.endTime }}</view> |
||||
</view> |
||||
</view> |
||||
<view style="color: #FF0000;" v-if="item.taskStatus === 'todo'">{{ !item.hasSign? '待签收' : '待处理'}}</view> |
||||
<view v-else>已办结</view> |
||||
</view> |
||||
</view> |
||||
</template> |
||||
<template v-if="item.taskType === 'negative'"> |
||||
<view> |
||||
<image src="../../static/icon/ic_question.png" style="width: 44px; height: 44px"></image> |
||||
</view> |
||||
<view style="width: calc(100% - 60px)"> |
||||
<view class="flex justify-between header"> |
||||
<view class="title">{{ item.taskName }}</view> |
||||
<view class="date">{{ item.createTime }}</view> |
||||
</view> |
||||
<view> |
||||
<view class="row"> |
||||
<view class="col col-24"> |
||||
<view class="label">业务类别:</view> |
||||
<view class="content">{{ item.businessTypeName }}</view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">涉及单位:</view> |
||||
<view class="content">{{ item.supDepartName }}</view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">问题内容:</view> |
||||
<view class="content">{{ item.taskContent }}</view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">涉嫌问题:</view> |
||||
<view class="content">{{ getDictLabelByArray(suspectProblems, item.involveProblem) || '/' }}</view> |
||||
</view> |
||||
</view> |
||||
<view style="color: #555;" v-if="item.flowKey === 'completed'">已办结</view> |
||||
<view style="color: #FF0000;" v-else>{{ getFlowLable(item.flowKey) }}</view> |
||||
</view> |
||||
</view> |
||||
</template> |
||||
</view> |
||||
<empty v-if="tasks.length === 0" /> |
||||
</view> |
||||
|
||||
<uni-popup ref="filterPopupRef" type="top"> |
||||
<view class="popup-container"> |
||||
<view class="popup-header"> |
||||
<view>全部筛选</view> |
||||
<uni-icons type="closeempty" class="close-btn" @tap="closePopup"></uni-icons> |
||||
</view> |
||||
<view class="popup-body"> |
||||
<view class="filter-container"> |
||||
<view class="filter-label">任务类型</view> |
||||
<filter-radio :data="taskTypes" v-model="query.taskType" @change="search" /> |
||||
<!-- <view class="filter-label">任务状态</view> |
||||
<filter-radio :data="taskStatus" v-model="query.taskStatus" /> --> |
||||
</view> |
||||
</view> |
||||
<view class="footer col-24 flex gap-8"> |
||||
<button class="col-12" @tap="reset">重置</button> |
||||
<button type="primary" @tap="handleSearch" class="col-12">完成</button> |
||||
</view> |
||||
</view> |
||||
</uni-popup> |
||||
</template> |
||||
<script> |
||||
import { listTask, getTaskCount } from '@/api/task' |
||||
import { getDictLabelByArray } from '@/common/util' |
||||
import { getDictOptions } from '@/common/dict' |
||||
|
||||
let _this; |
||||
let oldTasks = [] |
||||
export default { |
||||
inheritAttrs: false, |
||||
data() { |
||||
return { |
||||
tabOptions: [ |
||||
{ |
||||
text: '我的待办(0)', |
||||
value: 'todo' |
||||
}, |
||||
{ |
||||
text: '我的已办(0)', |
||||
value: 'done' |
||||
} |
||||
], |
||||
query: { |
||||
size: 100, |
||||
current: 1, |
||||
taskStatus: this.$page.options.taskStatus |
||||
}, |
||||
tasks: [], |
||||
searchFlag: false, |
||||
filterFlag: false, |
||||
loading: false, |
||||
taskTypes: [ |
||||
{ |
||||
text: '测酒任务', |
||||
value: 'testing_alcohol' |
||||
}, |
||||
{ |
||||
text: '督察任务', |
||||
value: 'inspection' |
||||
}, |
||||
{ |
||||
text: '所队自查', |
||||
value: 'selfexamination' |
||||
}, |
||||
{ |
||||
text: '问题', |
||||
value: 'negative' |
||||
}, |
||||
], |
||||
taskStatus: [ |
||||
{ |
||||
text: '待签收', |
||||
value: 'tobe_signed' |
||||
}, |
||||
{ |
||||
text: '待处理', |
||||
value: 'tobe' |
||||
}, |
||||
], |
||||
|
||||
} |
||||
}, |
||||
setup() { |
||||
const suspectProblems = getDictOptions('suspectProblem'); |
||||
return { |
||||
suspectProblems, |
||||
getDictLabelByArray |
||||
} |
||||
}, |
||||
watch: { |
||||
searchFlag(val) { |
||||
if (val) { |
||||
oldTasks = this.tasks; |
||||
this.tasks = [] |
||||
} else { |
||||
this.tasks = oldTasks |
||||
} |
||||
}, |
||||
'query.taskName': function(val) { |
||||
console.log(this) |
||||
if (_this.searchFlag && val) { |
||||
_this.getTasks() |
||||
} |
||||
}, |
||||
'query.taskStatus': function(val) { |
||||
this.getTasks() |
||||
} |
||||
}, |
||||
onLoad() { |
||||
_this = this; |
||||
}, |
||||
onShow() { |
||||
this.getTasks() |
||||
}, |
||||
methods: { |
||||
open(item) { |
||||
if (item.taskType === 'testing_alcohol') { |
||||
uni.navigateTo({ |
||||
url: `/pages/task/testingAlcohol/people?taskId=${item.id}&taskStatus=${item.taskStatus}` |
||||
}); |
||||
} |
||||
if (item.taskType === 'inspection') { |
||||
if (item.hasSign) { |
||||
uni.navigateTo({ |
||||
url: `/pages/task/inspection/list?taskId=${item.id}` |
||||
}); |
||||
} else { |
||||
uni.navigateTo({ |
||||
url: `/pages/task/inspection/info?taskId=${item.id}` |
||||
}); |
||||
} |
||||
} |
||||
if (item.taskType === 'selfexamination') { |
||||
uni.navigateTo({ |
||||
url: `/pages/task/selfexamination/index?taskId=${item.id}` |
||||
}); |
||||
} |
||||
if (item.taskType === 'negative') { |
||||
console.log(item.taskStatus) |
||||
if (item.taskStatus === 'todo') { |
||||
uni.navigateTo({ |
||||
url: `/pages/negative/action?id=${item.negativeId}&workId=${item.id}` |
||||
}); |
||||
} else { |
||||
uni.navigateTo({ |
||||
url: `/pages/negative/info?id=${item.negativeId}` |
||||
}); |
||||
} |
||||
|
||||
} |
||||
}, |
||||
getFlowLable(flowKey) { |
||||
const signFlows = ['second_sign'] |
||||
if (signFlows.indexOf(flowKey) > -1) { |
||||
return '待签收' |
||||
} |
||||
const distributeFlows = ['first_distribute', 'second_distribute'] |
||||
if (distributeFlows.indexOf(flowKey) > -1) { |
||||
return '待下发' |
||||
} |
||||
const verifyFlows = ['verify'] |
||||
if (verifyFlows.indexOf(flowKey) > -1) { |
||||
return '核查办理' |
||||
} |
||||
const approveFlows = ['second_approve'] |
||||
if (approveFlows.indexOf(flowKey) > -1) { |
||||
return '待审批' |
||||
} |
||||
return '' |
||||
}, |
||||
async getTasks() { |
||||
this.loading = true |
||||
uni.showLoading({ |
||||
title: '数据加载中' |
||||
}); |
||||
listTask(this.query).then(data => { |
||||
this.tasks = data.records |
||||
this.loading = false |
||||
uni.hideLoading(); |
||||
}) |
||||
getTaskCount(this.query).then(data => { |
||||
this.tabOptions[0].text = `待办任务(${data.todoCount})` |
||||
this.tabOptions[1].text = `已办任务(${data.doneCount})` |
||||
}) |
||||
}, |
||||
cancleSearch() { |
||||
this.searchFlag = false |
||||
this.query.taskName = '' |
||||
}, |
||||
showPopup() { |
||||
this.$refs.filterPopupRef.open() |
||||
}, |
||||
closePopup() { |
||||
this.$refs.filterPopupRef.close() |
||||
}, |
||||
search() { |
||||
if (this.query.taskType) { |
||||
this.filterFlag = true |
||||
} else { |
||||
this.filterFlag = false |
||||
} |
||||
this.getTasks() |
||||
}, |
||||
handleSearch() { |
||||
this.search() |
||||
this.closePopup() |
||||
}, |
||||
reset() { |
||||
this.filterFlag = false |
||||
let taskStatus = this.query.taskStatus; |
||||
this.query = { |
||||
size: 100, |
||||
current: 1, |
||||
taskStatus |
||||
} |
||||
this.getTasks() |
||||
} |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
.task-item { |
||||
.header { |
||||
margin-bottom: 12rpx; |
||||
|
||||
.title { |
||||
font-size: 28rpx; |
||||
line-height: 40rpx; |
||||
} |
||||
|
||||
.date { |
||||
font-size: 24rpx; |
||||
color: #666; |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
</style> |
||||
@ -0,0 +1,42 @@
|
||||
<template> |
||||
<view> |
||||
<view class="container" v-html="taskContentHtml"></view> |
||||
<view class="footer col-24"> |
||||
<button type="primary" @click="handleSign">任务签收</button> |
||||
</view> |
||||
</view> |
||||
</template> |
||||
|
||||
<script> |
||||
import { |
||||
getInspection, |
||||
signInspection |
||||
} from '@/api/inspection' |
||||
export default { |
||||
data() { |
||||
return { |
||||
taskContentHtml: '' |
||||
} |
||||
}, |
||||
onLoad() { |
||||
getInspection(this.$page.options.taskId).then(data => { |
||||
this.taskContentHtml = data.taskContentHtml |
||||
}) |
||||
|
||||
}, |
||||
methods: { |
||||
handleSign() { |
||||
signInspection(this.$page.options.taskId).then(() => { |
||||
uni.navigateTo({ |
||||
url: '/pages/task/inspection/list?taskId=' + this.$page.options.taskId |
||||
}); |
||||
}) |
||||
|
||||
} |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss"> |
||||
|
||||
</style> |
||||
@ -0,0 +1,131 @@
|
||||
<template> |
||||
<view class="flex search"> |
||||
<view class="search-item flex justify-center" :search="searchFlag"> |
||||
<view class="flex gap-8 search-item-conent"> |
||||
<uni-easyinput :style="{width: `60px`}" prefixIcon="search" type="text" v-model="query.taskName" |
||||
placeholder="搜索" :inputBorder="false" @focus="searchFlag = true" /> |
||||
|
||||
</view> |
||||
</view> |
||||
<view class="search-item flex justify-center" v-if="!searchFlag"> |
||||
<view class="flex gap-8 search-item-conent"> |
||||
<uni-icons customPrefix="customicons" type="filter" size="20" color="#666" /> |
||||
<view>筛选</view> |
||||
</view> |
||||
</view> |
||||
<view v-else> |
||||
<view class="cancel-btn" @tap="searchFlag = false">取消</view> |
||||
</view> |
||||
</view> |
||||
<view class="problem-container"> |
||||
<view class="problem-item" v-for="item in problems" @tap="open(item.id)"> |
||||
<view class="problem-item-img"> |
||||
<net-image :filepath="item.files[0].filePath" /> |
||||
</view> |
||||
<view class="problem-item-c"> |
||||
<view class="row" style="--label-width: 160rpx"> |
||||
<view class="col col-24" v-if="item.probmeType"> |
||||
<view class="label">问题类型:</view> |
||||
<view class="content">{{ item.probmeType }}</view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">被督察单位:</view> |
||||
<view class="content">{{ item.departName }}</view> |
||||
</view> |
||||
<view class="col col-24" v-if="item.peoples.length > 0"> |
||||
<view class="label">被督察人员:</view> |
||||
<view class="content">{{ item.peoples?.map(p => p.name).join(' ') }}</view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">情况描述:</view> |
||||
<view class="content">{{ item.thingDesc }}</view> |
||||
</view> |
||||
</view> |
||||
<view class="flex justify-between"> |
||||
<view></view> |
||||
<view class="problem-item-time">{{ item.createTime }}</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
<empty v-if="problems.length === 0" /> |
||||
</view> |
||||
<view class="footer col-24"> |
||||
<button type="primary" @click="handleAdd">添加记录</button> |
||||
</view> |
||||
</template> |
||||
<script setup> |
||||
import store from '@/store' |
||||
</script> |
||||
<script> |
||||
import { |
||||
listInspectionProblem |
||||
} from '@/api/inspection' |
||||
|
||||
export default { |
||||
props: ['taskId'], |
||||
data() { |
||||
return { |
||||
searchFlag: false, |
||||
query: {}, |
||||
taskContent: this.$page.options.taskContent, |
||||
problems: [] |
||||
} |
||||
}, |
||||
onLoad() { |
||||
|
||||
}, |
||||
onShow() { |
||||
listInspectionProblem(this.$page.options.taskId, this.query).then(data => { |
||||
this.problems = data.records |
||||
}) |
||||
}, |
||||
onBackPress(options) { |
||||
console.log(options) |
||||
return false |
||||
}, |
||||
methods: { |
||||
handleAdd() { |
||||
uni.navigateTo({ |
||||
url: '/pages/task/problem/add?taskId=' + this.$page.options.taskId |
||||
}); |
||||
}, |
||||
open(id) { |
||||
uni.navigateTo({ |
||||
url: '/pages/task/problem/index?id=' + id |
||||
}); |
||||
} |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
.problem-container { |
||||
padding: 0 24rpx; |
||||
} |
||||
|
||||
.problem-item { |
||||
display: flex; |
||||
gap: 0 20rpx; |
||||
padding: 24rpx 0; |
||||
box-shadow: inset 0 -1px 0 0 #DDDDDD; |
||||
|
||||
.problem-item-img { |
||||
width: 128rpx; |
||||
height: 128rpx; |
||||
|
||||
image { |
||||
width: 100%; |
||||
height: 100%; |
||||
} |
||||
} |
||||
|
||||
.problem-item-c { |
||||
width: calc(100% - 148rpx); |
||||
} |
||||
|
||||
.problem-item-time { |
||||
font-size: 12px; |
||||
color: #666; |
||||
} |
||||
} |
||||
</style> |
||||
@ -0,0 +1,138 @@
|
||||
<template> |
||||
<uni-forms ref="form" :modelValue="formData" :rules="rules" label-width="210rpx" style="margin: 12px"> |
||||
<uni-forms-item label="附件" name="files" label-position="top" required> |
||||
<upload v-model="formData.files" /> |
||||
</uni-forms-item> |
||||
<uni-forms-item label="是否存在问题" name="hasProblem" required> |
||||
<uni-data-checkbox v-model="formData.hasProblem" :localdata="hasProblem" /> |
||||
</uni-forms-item> |
||||
<uni-forms-item label="关联督察任务" v-if="needSeelctTaskFlag"> |
||||
<inspection-task-data-picker v-model="formData.taskId" /> |
||||
</uni-forms-item> |
||||
<uni-forms-item label="被督察单位" name="departId" required> |
||||
<uni-data-picker :localdata="departs" placeholder="请选择被督察单位" :border="false" |
||||
:map="{text:'shortName', value: 'id'}" v-model="formData.departId" /> |
||||
</uni-forms-item> |
||||
<uni-forms-item label="问题类型" name="problemTypeCode" v-if="formData.hasProblem === true"> |
||||
<problem-picker v-model="formData.problemTypeCode" @nodeclick="(node) => formData.problemType = node.name" /> |
||||
</uni-forms-item> |
||||
<uni-forms-item label="被督察人员" name="peoples" v-if="formData.hasProblem === true"> |
||||
<police-picker v-model="formData.peoples" :departId="formData.departId" /> |
||||
</uni-forms-item> |
||||
<uni-forms-item label="情况描述" name="thingDesc" label-position="top" required v-if="formData.hasProblem === true"> |
||||
<uni-easyinput type="textarea" :input-border="false" placeholder="请输入具体情况" v-model="formData.thingDesc" /> |
||||
</uni-forms-item> |
||||
</uni-forms> |
||||
<view class="footer col-24 flex gap-8"> |
||||
<button class="col-12" @tap="back">取消</button> |
||||
<button type="primary" @tap="submit" class="col-12">确定</button> |
||||
</view> |
||||
</template> |
||||
|
||||
<script> |
||||
import { |
||||
departTree |
||||
} from '@/api/depart' |
||||
import { |
||||
addProblem |
||||
} from '@/api/taskProblem' |
||||
|
||||
let _this; |
||||
export default { |
||||
data() { |
||||
return { |
||||
formData: { |
||||
files: this.$page.options.files? JSON.parse(this.$page.options.files) : [], |
||||
taskId: this.$page.options.taskId || '' |
||||
}, |
||||
hasProblem: [ |
||||
{ |
||||
text: '是', |
||||
value: true |
||||
}, |
||||
{ |
||||
text: '否', |
||||
value: false |
||||
}, |
||||
], |
||||
departs: [], |
||||
rules: { |
||||
files: { |
||||
rules: [{ |
||||
validateFunction: function(rule,value,data,callback){ |
||||
if (!value || value.length === 0) { |
||||
callback('请上传附件') |
||||
} |
||||
return true |
||||
} |
||||
}] |
||||
}, |
||||
hasProblem: { |
||||
rules: [{ |
||||
required: true, |
||||
errorMessage: '请选择是否存在督察问题', |
||||
}] |
||||
}, |
||||
departId: { |
||||
rules: [{ |
||||
required: true, |
||||
errorMessage: '请选择被督察单位', |
||||
}] |
||||
}, |
||||
thingDesc: { |
||||
rules: [{ |
||||
required: true, |
||||
errorMessage: '请输入具体情况', |
||||
}] |
||||
}, |
||||
taskId: { |
||||
rules: [{ |
||||
required: true, |
||||
errorMessage: '请关联督察任务', |
||||
}] |
||||
} |
||||
}, |
||||
needSeelctTaskFlag: true |
||||
} |
||||
}, |
||||
onLoad() { |
||||
_this = this; |
||||
if (this.$page.options.taskId) { |
||||
this.needSeelctTaskFlag = false |
||||
} |
||||
departTree().then(data => { |
||||
this.departs = data[0].children |
||||
}) |
||||
}, |
||||
methods: { |
||||
submit() { |
||||
this.$refs.form.validate().then(res => { |
||||
addProblem(this.formData).then(data => { |
||||
_this.formData = { |
||||
files: [], |
||||
taskId: _this.$page.options.taskId || '' |
||||
} |
||||
uni.showToast({ |
||||
title: '新增成功', |
||||
icon: 'none', |
||||
duration: 5000 |
||||
}) |
||||
uni.navigateBack({ |
||||
|
||||
}); |
||||
}) |
||||
}).catch(err => { |
||||
console.log('表单错误信息:', err, this.formData); |
||||
}) |
||||
}, |
||||
back() { |
||||
uni.navigateBack({ |
||||
|
||||
}); |
||||
} |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style> |
||||
</style> |
||||
@ -0,0 +1,89 @@
|
||||
<template> |
||||
<view class="container"> |
||||
<view class="row" style="--label-width: 180rpx"> |
||||
<view class="col col-24"> |
||||
<view class="label">是否存在问题:</view> |
||||
<view class="content">{{ problem.hasProblem ? '是' : '否' }}</view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">问题来源:</view> |
||||
<view class="content">{{ getDictLabel(taskType, problem.taskType) }}</view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">录入时间:</view> |
||||
<view class="content">{{ problem.createTime }}</view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">被督察单位:</view> |
||||
<view class="content">{{ problem.departName }}</view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">被督察人员:</view> |
||||
<view class="content">{{ problem.peoples ? JSON.parse(problem.peoples).map(item => item.name).join('、') : '/' }}</view> |
||||
</view> |
||||
<view class="col col-24" v-if="problem.thingDesc"> |
||||
<view class="label">情况描述:</view> |
||||
<view class="content">{{ problem.thingDesc }}</view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">是否下发:</view> |
||||
<view class="content" v-if="problem.distributionState === '0'" style="color: red">未下发</view> |
||||
<view class="content" v-if="problem.distributionState === '1'">已下发</view> |
||||
</view> |
||||
</view> |
||||
<view class="mt-10 mb-6" style="font-size: 14px; color: #666">附件</view> |
||||
<view class="photo-container" v-if="problem.files"> |
||||
<view v-for="photo in JSON.parse(problem.files)" class="photo-item"> |
||||
<net-image :filepath="photo.filePath" /> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
|
||||
</template> |
||||
|
||||
<script> |
||||
import { getProblem } from '@/api/taskProblem'; |
||||
import { getDictOptions } from '@/common/dict' |
||||
import { getDictLabel } from '@/common/util' |
||||
|
||||
let _this; |
||||
export default { |
||||
inheritAttrs: false, |
||||
data() { |
||||
return { |
||||
problem: {} |
||||
} |
||||
}, |
||||
setup() { |
||||
const taskType = getDictOptions('taskType'); |
||||
return { |
||||
taskType, |
||||
getDictLabel |
||||
} |
||||
}, |
||||
onLoad() { |
||||
_this = this; |
||||
getProblem(this.$page.options.id).then(data => { |
||||
this.problem = data |
||||
}) |
||||
}, |
||||
methods: { |
||||
|
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style scoped> |
||||
.info { |
||||
padding: 12px; |
||||
box-shadow: inset 0 -1px 0 0 #eee; |
||||
} |
||||
.police-info-avatar { |
||||
width: 136rpx; |
||||
height: 205rpx; |
||||
image { |
||||
width: 100%; |
||||
height: 100%; |
||||
} |
||||
} |
||||
</style> |
||||
@ -0,0 +1,201 @@
|
||||
<template> |
||||
<view class="flex search"> |
||||
<view class="search-item flex justify-center" :search="searchFlag"> |
||||
<view class="search-item-conent"> |
||||
<uni-easyinput prefixIcon="search" type="text" v-model="query.thingDesc" placeholder="搜索" :inputBorder="false" @focus="searchFlag = true" /> |
||||
|
||||
</view> |
||||
</view> |
||||
<view class="search-item flex justify-center" v-if="!searchFlag" @tap="showPopup"> |
||||
<view :class="filterFlag ? 'search-item-conent active': 'search-item-conent'"> |
||||
<uni-icons customPrefix="customicons" type="filter" size="20" color="#666" /> |
||||
<view>筛选</view> |
||||
</view> |
||||
</view> |
||||
<view v-else> |
||||
<view class="cancel-btn" @tap="searchFlag = false">取消</view> |
||||
</view> |
||||
</view> |
||||
<view class="negative-container"> |
||||
<view class="card negative-item" v-for="item in problems" @tap="open(item)"> |
||||
<view class="row"> |
||||
<view class="col col-24"> |
||||
<view class="label">录入时间:</view> |
||||
<view class="content">{{ item.createTime }}</view> |
||||
</view> |
||||
<view class="col col-12"> |
||||
<view class="label">涉及单位:</view> |
||||
<view class="content">{{ item.departName }}</view> |
||||
</view> |
||||
<view class="col col-12"> |
||||
<view class="label">涉及人员:</view> |
||||
<view class="content">{{ item.peoples || '/' }}</view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">问题类型:</view> |
||||
<view class="content">{{ item.problemType || '/' }}</view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">问题内容:</view> |
||||
<view class="content">{{ item.thingDesc }}</view> |
||||
</view> |
||||
</view> |
||||
<view class="negative-bottom"> |
||||
<view v-if="item.distributionState === '0'" style="color: var(--danger-color)">未下发</view> |
||||
<view v-if="item.distributionState === '1'" style="color: #ff5722">已下发</view> |
||||
</view> |
||||
</view> |
||||
<empty v-if="problems.length === 0" /> |
||||
</view> |
||||
|
||||
<uni-popup ref="filterPopupRef" type="top"> |
||||
<view class="popup-container"> |
||||
<view class="popup-header"> |
||||
<view>全部筛选</view> |
||||
<uni-icons type="closeempty" class="close-btn" @tap="closePopup"></uni-icons> |
||||
</view> |
||||
<view class="popup-body"> |
||||
<view class="filter-container"> |
||||
|
||||
<view class="filter-label mt-10">涉及单位</view> |
||||
<view class="mb-10"> |
||||
<uni-data-picker :localdata="departs" placeholder="请选择涉及单位" :border="false" |
||||
:map="{text:'shortName', value: 'id'}" v-model="query.departId" @change="search" /> |
||||
</view> |
||||
|
||||
</view> |
||||
</view> |
||||
<view class="footer col-24 flex gap-8"> |
||||
<button class="col-12" @tap="reset">重置</button> |
||||
<button type="primary" @tap="handleSearch" class="col-12">完成</button> |
||||
</view> |
||||
</view> |
||||
</uni-popup> |
||||
</template> |
||||
<script> |
||||
import store from '@/store' |
||||
import { getDictOptions } from '@/common/dict' |
||||
import { listProblem } from '@/api/taskProblem.js' |
||||
import { |
||||
departTree |
||||
} from '@/api/depart' |
||||
import { getDictLabel } from '@/common/util' |
||||
|
||||
|
||||
let oldList; |
||||
let _this; |
||||
|
||||
export default { |
||||
data() { |
||||
return { |
||||
problems: [], |
||||
query: { |
||||
size: 100, |
||||
current: 1, |
||||
taskType: 'problem_shooting' |
||||
}, |
||||
departs: [], |
||||
searchFlag: false, |
||||
filterFlag: false, |
||||
} |
||||
}, |
||||
setup(props, context) { |
||||
const taskType = getDictOptions('taskType'); |
||||
return { |
||||
taskType, |
||||
getDictLabel |
||||
} |
||||
}, |
||||
watch: { |
||||
searchFlag(val) { |
||||
if (val) { |
||||
oldList = this.problems; |
||||
this.problems = [] |
||||
} else { |
||||
this.problems = oldList |
||||
} |
||||
}, |
||||
'query.thingDesc': function(val) { |
||||
if (_this.searchFlag) { |
||||
if (val) { |
||||
_this.getProblems() |
||||
} else { |
||||
this.problems = [] |
||||
} |
||||
|
||||
} |
||||
} |
||||
}, |
||||
onLoad() { |
||||
_this = this; |
||||
this.getProblems(); |
||||
departTree().then(data => { |
||||
this.departs = data[0].children |
||||
}) |
||||
}, |
||||
methods: { |
||||
open(item) { |
||||
uni.navigateTo({ |
||||
url: '/pages/task/problem/index?id=' + item.id |
||||
}); |
||||
}, |
||||
getProblems() { |
||||
uni.showLoading({ |
||||
title: '数据加载中' |
||||
}); |
||||
listProblem(this.query).then(data => { |
||||
this.problems = data.records |
||||
uni.hideLoading(); |
||||
}); |
||||
}, |
||||
showPopup() { |
||||
this.$refs.filterPopupRef.open() |
||||
}, |
||||
closePopup() { |
||||
this.$refs.filterPopupRef.close() |
||||
}, |
||||
search() { |
||||
if (this.query.taskType || this.query.departId) { |
||||
this.filterFlag = true |
||||
} else { |
||||
this.filterFlag = false |
||||
} |
||||
this.getProblems() |
||||
}, |
||||
handleSearch() { |
||||
this.search() |
||||
this.closePopup() |
||||
}, |
||||
reset() { |
||||
this.filterFlag = false |
||||
this.query = { |
||||
size: 100, |
||||
current: 1, |
||||
taskType: 'problem_shooting' |
||||
} |
||||
this.getProblems() |
||||
} |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
.negative-container { |
||||
max-height: calc(100vh - 98rpx); |
||||
overflow: auto; |
||||
} |
||||
.negative-title { |
||||
display: flex; |
||||
justify-content: space-between; |
||||
margin-bottom: 12rpx; |
||||
font-weight: 500; |
||||
font-size: 16px; |
||||
} |
||||
.negative-bottom { |
||||
display: flex; |
||||
justify-content: space-between; |
||||
.negative-tag { |
||||
color: #FF0000; |
||||
} |
||||
} |
||||
</style> |
||||
@ -0,0 +1,106 @@
|
||||
<template> |
||||
<uni-forms ref="form" :modelValue="formData" :rules="rules" label-width="210rpx" style="margin: 12px"> |
||||
<uni-forms-item label="附件" name="files" label-position="top" required> |
||||
<upload v-model="formData.files" /> |
||||
</uni-forms-item> |
||||
<uni-forms-item label="是否存在问题" name="hasProblem" required> |
||||
<uni-data-checkbox v-model="formData.hasProblem" :localdata="hasProblem" /> |
||||
</uni-forms-item> |
||||
<uni-forms-item label="涉及人员" name="peoples" v-if="formData.hasProblem === true"> |
||||
<police-picker v-model="formData.peoples" :departId="formData.departId" /> |
||||
</uni-forms-item> |
||||
<uni-forms-item label="检查情况" name="thingDesc" label-position="top" required v-if="formData.hasProblem === true"> |
||||
<uni-easyinput type="textarea" :input-border="false" placeholder="请输入检查情况" v-model="formData.thingDesc" /> |
||||
</uni-forms-item> |
||||
</uni-forms> |
||||
<view class="footer col-24 flex gap-8"> |
||||
<button class="col-12" @tap="back">取消</button> |
||||
<button type="primary" @tap="submit" class="col-12">确定</button> |
||||
</view> |
||||
</template> |
||||
|
||||
<script> |
||||
import { |
||||
departTree |
||||
} from '@/api/depart' |
||||
import { |
||||
addProblem |
||||
} from '@/api/taskProblem.js' |
||||
|
||||
let _this; |
||||
export default { |
||||
data() { |
||||
return { |
||||
formData: { |
||||
files: this.$page.options.files? JSON.parse(this.$page.options.files) : [], |
||||
taskId: this.$page.options.taskId || '', |
||||
contentId: this.$page.options.contentId, |
||||
departId: this.$page.options.departId |
||||
}, |
||||
hasProblem: [ |
||||
{ |
||||
text: '是', |
||||
value: true |
||||
}, |
||||
{ |
||||
text: '否', |
||||
value: false |
||||
}, |
||||
], |
||||
rules: { |
||||
files: { |
||||
rules: [{ |
||||
validateFunction: function(rule,value,data,callback){ |
||||
if (!value || value.length === 0) { |
||||
callback('请上传附件') |
||||
} |
||||
return true |
||||
} |
||||
}] |
||||
}, |
||||
hasProblem: { |
||||
rules: [{ |
||||
required: true, |
||||
errorMessage: '请选择是否存在问题', |
||||
}] |
||||
}, |
||||
thingDesc: { |
||||
rules: [{ |
||||
required: true, |
||||
errorMessage: '请输入检测情况', |
||||
}] |
||||
}, |
||||
}, |
||||
needSeelctTaskFlag: true |
||||
} |
||||
}, |
||||
onLoad() { |
||||
_this = this; |
||||
}, |
||||
methods: { |
||||
submit() { |
||||
this.$refs.form.validate().then(res => { |
||||
addProblem(this.formData.taskId, this.formData).then(data => { |
||||
_this.formData = { |
||||
files: [], |
||||
taskId: _this.$page.options.taskId || '' |
||||
} |
||||
uni.navigateBack({ |
||||
|
||||
}); |
||||
}) |
||||
}).catch(err => { |
||||
console.log('表单错误信息:', err, this.formData); |
||||
}) |
||||
}, |
||||
back() { |
||||
uni.navigateBack({ |
||||
|
||||
}); |
||||
} |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style> |
||||
</style> |
||||
@ -0,0 +1,85 @@
|
||||
<template> |
||||
<view v-if="!selfexamination.hasSign"> |
||||
<view class="container" v-html="selfexamination.requirementHtml"></view> |
||||
<view class="footer col-24"> |
||||
<button type="primary" @click="handleSign">任务签收</button> |
||||
</view> |
||||
</view> |
||||
<view v-else> |
||||
<view v-for="(item, index) in selfexamination.contents" class="content-item" @tap="open(item.id)"> |
||||
<view class="content-item-title"> |
||||
<text>{{ index + 1 }} {{ item.title }}</text> |
||||
<uni-tag type="warning" text="待检查" :inverted="true" v-if="item.status === 'todo'" /> |
||||
<uni-tag type="success" text="已检查" :inverted="true" v-else /> |
||||
</view> |
||||
<view class="content-item-c">{{ item.content }}</view> |
||||
</view> |
||||
</view> |
||||
</template> |
||||
|
||||
<script> |
||||
import { |
||||
getTaskSelfexamination, |
||||
signTaskSelfexamination |
||||
} from '@/api/selfexamination' |
||||
import { submitTask } from '@/api/task' |
||||
|
||||
let _this; |
||||
export default { |
||||
data() { |
||||
return { |
||||
selfexamination: {} |
||||
} |
||||
}, |
||||
onLoad() { |
||||
_this = this; |
||||
}, |
||||
onShow() { |
||||
getTaskSelfexamination(this.$page.options.taskId).then(data => { |
||||
this.selfexamination = data |
||||
if (data.contents.filter(item => item.status === 'todo').length === 0) { |
||||
uni.showModal({ |
||||
content: `本次自查内容以全部检查,\n请确认是否结束本次任务`, |
||||
success: function (res) { |
||||
if (res.confirm) { |
||||
submitTask(_this.$page.options.taskId).then(data => { |
||||
uni.navigateTo({ |
||||
url: '/pages/task/index?taskStatus=todo' |
||||
}); |
||||
}) |
||||
} |
||||
} |
||||
}); |
||||
} |
||||
}) |
||||
}, |
||||
methods: { |
||||
async handleSign() { |
||||
await signTaskSelfexamination(this.$page.options.taskId) |
||||
this.selfexamination.hasSign = true |
||||
}, |
||||
open(conentId) { |
||||
uni.navigateTo({ |
||||
url: `/pages/task/selfexamination/add?taskId=${this.$page.options.taskId}&contentId=${conentId}&departId=${this.selfexamination.supDepartId}` |
||||
}); |
||||
} |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
.content-item { |
||||
padding: 24rpx 0; |
||||
margin: 0 24rpx; |
||||
box-shadow: inset 0 -1px 0 0 #DDDDDD; |
||||
.content-item-title { |
||||
margin-bottom: 12rpx; |
||||
display: flex; |
||||
justify-content: space-between; |
||||
} |
||||
.content-item-c { |
||||
font-size: 12px; |
||||
color: #666; |
||||
} |
||||
} |
||||
</style> |
||||
@ -0,0 +1,82 @@
|
||||
<template> |
||||
<view class="container"> |
||||
|
||||
<view class="row" style="--label-width: 180rpx"> |
||||
<view class="col col-24"> |
||||
<view class="label">任务名称:</view> |
||||
<view class="content">{{ task.taskName }}</view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">自查类型:</view> |
||||
<view class="content">{{ task.type }}</view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">自查单位:</view> |
||||
<view class="content">{{ task.supDepartName }}</view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">自查时间:</view> |
||||
<view class="content">{{ task.beginTime }}</view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">任务状态:</view> |
||||
<view class="content"> |
||||
<uni-tag text="自查中" type="primary" v-if="task.taskStatus === 'todo'"></uni-tag> |
||||
<uni-tag text="已完结" v-else></uni-tag> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
<view class="h1">任务要求</view> |
||||
<view v-html="task.requirementHtml"></view> |
||||
<view class="h1">自查内容</view> |
||||
<view v-for="(item, index) in task.contents" class="content-item"> |
||||
<view class="content-item-title">{{ index + 1 }} {{ item.title }}</view> |
||||
<view class="content-item-c">{{ item.content }}</view> |
||||
</view> |
||||
</view> |
||||
|
||||
</template> |
||||
|
||||
<script> |
||||
import { getTaskSelfexamination } from '@/api/selfexamination.js'; |
||||
import { getDictOptions } from '@/common/dict' |
||||
import { getDictLabel } from '@/common/util' |
||||
|
||||
let _this; |
||||
export default { |
||||
inheritAttrs: false, |
||||
data() { |
||||
return { |
||||
task: {} |
||||
} |
||||
}, |
||||
setup() { |
||||
const taskType = getDictOptions('taskType'); |
||||
return { |
||||
taskType, |
||||
getDictLabel |
||||
} |
||||
}, |
||||
onLoad() { |
||||
_this = this; |
||||
getTaskSelfexamination(this.$page.options.id).then(data => { |
||||
this.task = data |
||||
}) |
||||
}, |
||||
methods: { |
||||
|
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
.h1 { |
||||
color: #ff5722; |
||||
margin-top: 24rpx; |
||||
margin-bottom: 12rpx; |
||||
font-weight: bold; |
||||
} |
||||
.content-item { |
||||
margin-bottom: 12rpx; |
||||
} |
||||
</style> |
||||
@ -0,0 +1,193 @@
|
||||
<template> |
||||
<view class="flex search"> |
||||
<view class="search-item flex justify-center" :search="searchFlag"> |
||||
<view class="search-item-conent"> |
||||
<uni-easyinput prefixIcon="search" type="text" v-model="query.taskName" placeholder="搜索" :inputBorder="false" @focus="searchFlag = true" /> |
||||
|
||||
</view> |
||||
</view> |
||||
<view class="search-item flex justify-center" v-if="!searchFlag" @tap="showPopup"> |
||||
<view :class="filterFlag ? 'search-item-conent active': 'search-item-conent'"> |
||||
<uni-icons customPrefix="customicons" type="filter" size="20" color="#666" /> |
||||
<view>筛选</view> |
||||
</view> |
||||
</view> |
||||
<view v-else> |
||||
<view class="cancel-btn" @tap="searchFlag = false">取消</view> |
||||
</view> |
||||
</view> |
||||
<view class="negative-container"> |
||||
<view class="card negative-item" v-for="item in list" @tap="open(item)"> |
||||
<view class="negative-title"> |
||||
<view>{{ item.taskName }}</view> |
||||
<view></view> |
||||
</view> |
||||
<view class="row"> |
||||
<view class="col col-24"> |
||||
<view class="label">自查类型:</view> |
||||
<view class="content">{{ item.type }}</view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">自查单位:</view> |
||||
<view class="content">{{ item.supDepartName }}</view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">自查时间:</view> |
||||
<view class="content">{{ item.beginTime }} ~ {{ item.endTime }}</view> |
||||
</view> |
||||
</view> |
||||
<view class="negative-bottom"> |
||||
<uni-tag text="自查中" type="primary" v-if="item.taskStatus === 'todo'"></uni-tag> |
||||
<uni-tag text="已完结" v-else></uni-tag> |
||||
</view> |
||||
</view> |
||||
<empty v-if="list.length === 0" /> |
||||
</view> |
||||
|
||||
<uni-popup ref="filterPopupRef" type="top"> |
||||
<view class="popup-container"> |
||||
<view class="popup-header"> |
||||
<view>全部筛选</view> |
||||
<uni-icons type="closeempty" class="close-btn" @tap="closePopup"></uni-icons> |
||||
</view> |
||||
<view class="popup-body"> |
||||
<view class="filter-container"> |
||||
|
||||
<view class="filter-label mt-10">自查单位</view> |
||||
<view class="mb-10"> |
||||
<uni-data-picker :localdata="departs" placeholder="请选择自查单位" :border="false" |
||||
:map="{text:'shortName', value: 'id'}" v-model="query.supDepartId" @change="search" /> |
||||
</view> |
||||
|
||||
</view> |
||||
</view> |
||||
<view class="footer col-24 flex gap-8"> |
||||
<button class="col-12" @tap="reset">重置</button> |
||||
<button type="primary" @tap="handleSearch" class="col-12">完成</button> |
||||
</view> |
||||
</view> |
||||
</uni-popup> |
||||
</template> |
||||
<script> |
||||
import store from '@/store' |
||||
import { getDictOptions } from '@/common/dict' |
||||
import { listTaskSelfexamination } from '@/api/selfexamination.js' |
||||
import { |
||||
departTree |
||||
} from '@/api/depart' |
||||
import { getDictLabel } from '@/common/util' |
||||
|
||||
|
||||
let oldList; |
||||
let _this; |
||||
|
||||
export default { |
||||
data() { |
||||
return { |
||||
list: [], |
||||
query: { |
||||
size: 100, |
||||
current: 1 |
||||
}, |
||||
departs: [], |
||||
searchFlag: false, |
||||
filterFlag: false |
||||
} |
||||
}, |
||||
setup(props, context) { |
||||
return { |
||||
getDictLabel |
||||
} |
||||
}, |
||||
watch: { |
||||
searchFlag(val) { |
||||
if (val) { |
||||
oldList = this.list; |
||||
this.list = [] |
||||
} else { |
||||
this.list = oldList |
||||
} |
||||
}, |
||||
'query.taskName': function(val) { |
||||
if (_this.searchFlag) { |
||||
if (val) { |
||||
_this.getList() |
||||
} else { |
||||
this.list = [] |
||||
} |
||||
|
||||
} |
||||
} |
||||
}, |
||||
onLoad() { |
||||
_this = this; |
||||
this.getList(); |
||||
departTree().then(data => { |
||||
this.departs = data[0].children |
||||
}) |
||||
}, |
||||
methods: { |
||||
open(item) { |
||||
uni.navigateTo({ |
||||
url: `/pages/task/selfexamination/info?id=${item.id}` |
||||
}); |
||||
}, |
||||
getList() { |
||||
uni.showLoading({ |
||||
title: '数据加载中' |
||||
}); |
||||
listTaskSelfexamination(this.query).then(data => { |
||||
this.list = data.records |
||||
uni.hideLoading(); |
||||
}); |
||||
}, |
||||
showPopup() { |
||||
this.$refs.filterPopupRef.open() |
||||
}, |
||||
closePopup() { |
||||
this.$refs.filterPopupRef.close() |
||||
}, |
||||
search() { |
||||
if (this.query.supDepartId) { |
||||
this.filterFlag = true |
||||
} else { |
||||
this.filterFlag = false |
||||
} |
||||
this.getList() |
||||
}, |
||||
handleSearch() { |
||||
this.search() |
||||
this.closePopup() |
||||
}, |
||||
reset() { |
||||
this.filterFlag = false |
||||
this.query = { |
||||
size: 100, |
||||
current: 1 |
||||
} |
||||
this.getList() |
||||
} |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
.negative-container { |
||||
max-height: calc(100vh - 98rpx); |
||||
overflow: auto; |
||||
} |
||||
.negative-title { |
||||
display: flex; |
||||
justify-content: space-between; |
||||
margin-bottom: 12rpx; |
||||
font-weight: 500; |
||||
font-size: 16px; |
||||
} |
||||
.negative-bottom { |
||||
display: flex; |
||||
justify-content: space-between; |
||||
.negative-tag { |
||||
color: #FF0000; |
||||
} |
||||
} |
||||
</style> |
||||
@ -0,0 +1,193 @@
|
||||
<template> |
||||
<view class="flex gap-16 info"> |
||||
<view class="police-info-avatar"> |
||||
<net-image :filepath="people.avatarUrl" v-if="people.avatarUrl" /> |
||||
<image src="/static/police.png" v-else></image> |
||||
</view> |
||||
<view style="width: calc(100% - 168rpx)"> |
||||
<view> |
||||
<view class="row"> |
||||
<view class="col col-12"> |
||||
<view class="label">姓名:</view> |
||||
<view class="content">{{ people.name }}</view> |
||||
</view> |
||||
<view class="col col-12"> |
||||
<view class="label">警号:</view> |
||||
<view class="content">{{ people.empNo }}</view> |
||||
</view> |
||||
<view class="col col-12"> |
||||
<view class="label">所属单位:</view> |
||||
<view class="content">{{ people.departName }}</view> |
||||
</view> |
||||
<view class="col col-12"> |
||||
<view class="label">职位:</view> |
||||
<view class="content">{{ people.position }}</view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">联系电话:</view> |
||||
<view class="content">{{ people.mobile || '/' }}</view> |
||||
</view> |
||||
</view> |
||||
|
||||
</view> |
||||
<view style="color: red">待检测</view> |
||||
</view> |
||||
</view> |
||||
<uni-forms ref="form" :modelValue="formData" :rules="rules" label-width="80px" style="margin: 12px"> |
||||
<uni-forms-item label="检测时间" name="testingTime" required> |
||||
<uni-datetime-picker type="datetime" v-model="formData.testingTime" :border="false" placeholder="请选择检测时间" /> |
||||
</uni-forms-item> |
||||
<uni-forms-item label="检测情况" name="testingResult" required> |
||||
<uni-data-checkbox v-model="formData.testingResult" :localdata="testingResult" /> |
||||
</uni-forms-item> |
||||
<uni-forms-item label="测酒结果" name="drinkResult" required v-if="formData.testingResult === '已检测'"> |
||||
<uni-data-checkbox v-model="formData.drinkResult" :localdata="drinkResult" /> |
||||
</uni-forms-item> |
||||
<uni-forms-item label="酒精含量" name="alcoholContent" required v-if="formData.testingResult === '已检测' && formData.drinkResult === '饮酒'"> |
||||
<uni-easyinput type="number" v-model="formData.alcoholContent" placeholder="请输入酒精含量" :inputBorder="false" /> |
||||
</uni-forms-item> |
||||
<uni-forms-item label="测酒照片" name="testingFiles" label-position="top" required |
||||
v-if="formData.testingResult === '已检测'"> |
||||
<upload v-model="formData.testingFiles" /> |
||||
</uni-forms-item> |
||||
<uni-forms-item label="情况说明" name="unTestingDesc" required v-if="formData.testingResult === '未检测'"> |
||||
<uni-easyinput type="textarea" v-model="formData.unTestingDesc" placeholder="请输入未检测现场情况说明" |
||||
:inputBorder="false" /> |
||||
</uni-forms-item> |
||||
</uni-forms> |
||||
<view class="footer col-24 flex gap-8"> |
||||
<button class="col-12" @tap="back">取消</button> |
||||
<button type="primary" @tap="submit" class="col-12">确定</button> |
||||
</view> |
||||
</template> |
||||
|
||||
<script> |
||||
import store from '@/store' |
||||
import { now } from '@/common/util' |
||||
|
||||
import { |
||||
updateTestingAlcoholPeople |
||||
} from '@/api/testingAlcohol' |
||||
|
||||
let _this; |
||||
export default { |
||||
data() { |
||||
return { |
||||
BASE_PATH: store.state.fileRequestUrl, |
||||
people: JSON.parse(this.$page.options.people), |
||||
formData: { |
||||
testingTime: now('YYYY-MM-DD HH:mm:ss'), |
||||
testingFiles: [] |
||||
}, |
||||
rules: { |
||||
testingTime: { |
||||
rules: [ |
||||
{ |
||||
required: true, |
||||
errorMessage: '请选择检测时间', |
||||
} |
||||
] |
||||
}, |
||||
testingResult: { |
||||
rules: [ |
||||
{ |
||||
required: true, |
||||
errorMessage: '请选择检测情况', |
||||
} |
||||
] |
||||
}, |
||||
drinkResult: { |
||||
rules: [ |
||||
{ |
||||
required: true, |
||||
errorMessage: '请选择测酒结果', |
||||
} |
||||
] |
||||
}, |
||||
alcoholContent: { |
||||
rules: [ |
||||
{ |
||||
required: true, |
||||
errorMessage: '请输入酒精含量', |
||||
} |
||||
] |
||||
}, |
||||
unTestingDesc: { |
||||
rules: [ |
||||
{ |
||||
required: true, |
||||
errorMessage: '请输入未检测现场情况说明', |
||||
} |
||||
] |
||||
}, |
||||
testingFiles: { |
||||
rules: [{ |
||||
validateFunction: function(rule,value,data,callback){ |
||||
if (!value || value.length === 0) { |
||||
callback('请上传测酒现场照片') |
||||
} |
||||
return true |
||||
} |
||||
}] |
||||
}, |
||||
}, |
||||
testingResult: [{ |
||||
text: '已检测', |
||||
value: '已检测' |
||||
}, |
||||
{ |
||||
text: '未检测', |
||||
value: '未检测' |
||||
} |
||||
], |
||||
drinkResult: [{ |
||||
text: '未饮酒', |
||||
value: '未饮酒' |
||||
}, |
||||
{ |
||||
text: '饮酒', |
||||
value: '饮酒' |
||||
}, |
||||
] |
||||
} |
||||
}, |
||||
onLoad() { |
||||
_this = this; |
||||
}, |
||||
methods: { |
||||
submit() { |
||||
this.$refs.form.validate().then(res=>{ |
||||
this.formData.empNo = this.people.empNo |
||||
updateTestingAlcoholPeople(this.people.taskId, this.formData).then(data => { |
||||
uni.navigateBack({ |
||||
|
||||
}); |
||||
}) |
||||
}).catch(err =>{ |
||||
console.log('表单错误信息:', err); |
||||
}) |
||||
|
||||
}, |
||||
back() { |
||||
uni.navigateBack({ |
||||
|
||||
}); |
||||
} |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss"> |
||||
.info { |
||||
padding: 12px; |
||||
box-shadow: inset 0 -1px 0 0 #eee; |
||||
} |
||||
.police-info-avatar { |
||||
width: 136rpx; |
||||
height: 205rpx; |
||||
image { |
||||
width: 100%; |
||||
height: 100%; |
||||
} |
||||
} |
||||
</style> |
||||
@ -0,0 +1,104 @@
|
||||
<template> |
||||
<view class="flex gap-16 info"> |
||||
<view class="police-info-avatar"> |
||||
<net-image :filepath="people.avatarUrl" v-if="people.avatarUrl" /> |
||||
<image src="/static/police.png" v-else></image> |
||||
</view> |
||||
<view style="width: calc(100% - 168rpx)"> |
||||
<view> |
||||
<view class="row"> |
||||
<view class="col col-12"> |
||||
<view class="label">姓名:</view> |
||||
<view class="content">{{ people.name }}</view> |
||||
</view> |
||||
<view class="col col-12"> |
||||
<view class="label">警号:</view> |
||||
<view class="content">{{ people.empNo }}</view> |
||||
</view> |
||||
<view class="col col-12"> |
||||
<view class="label">所属单位:</view> |
||||
<view class="content">{{ people.departName }}</view> |
||||
</view> |
||||
<view class="col col-12"> |
||||
<view class="label">职位:</view> |
||||
<view class="content">{{ people.position }}</view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">联系电话:</view> |
||||
<view class="content">{{ people.mobile || '/' }}</view> |
||||
</view> |
||||
</view> |
||||
|
||||
</view> |
||||
</view> |
||||
</view> |
||||
<view class="container"> |
||||
<view class="row"> |
||||
<view class="col col-24"> |
||||
<view class="label">测酒时间:</view> |
||||
<view class="content">{{ people.testingTime }}</view> |
||||
</view> |
||||
<view class="col col-12"> |
||||
<view class="label">检测情况:</view> |
||||
<view class="content"> |
||||
<view v-if="people.testingResult === '未检测'" style="color: var(--danger-color)">{{ people.testingResult }}</view> |
||||
<view v-else>{{ people.testingResult }}</view> |
||||
</view> |
||||
</view> |
||||
<view class="col col-12"> |
||||
<view class="label">饮酒结果:</view> |
||||
<view class="content"> |
||||
<uni-tag :text="people.drinkResult" type="success" v-if="people.drinkResult === '未饮酒'" /> |
||||
<uni-tag :text="people.drinkResult" type="error" v-else /> |
||||
</view> |
||||
</view> |
||||
<view class="col col-12" v-if="people.alcoholContent"> |
||||
<view class="label">酒精含量:</view> |
||||
<view class="content">{{ people.alcoholContent }}</view> |
||||
</view> |
||||
<view class="col col-24" v-if="people.unTestingDesc"> |
||||
<view class="label">未检测原因:</view> |
||||
<view class="content">{{ people.unTestingDesc }}</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
</template> |
||||
|
||||
<script> |
||||
import store from '@/store' |
||||
import { now } from '@/common/util' |
||||
|
||||
import { |
||||
updateTestingAlcoholPeople |
||||
} from '@/api/testingAlcohol' |
||||
|
||||
let _this; |
||||
export default { |
||||
data() { |
||||
return { |
||||
BASE_PATH: store.state.fileRequestUrl, |
||||
people: JSON.parse(this.$page.options.people) |
||||
} |
||||
}, |
||||
onLoad() { |
||||
_this = this; |
||||
}, |
||||
methods: { |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss"> |
||||
.info { |
||||
padding: 12px; |
||||
box-shadow: inset 0 -1px 0 0 #eee; |
||||
} |
||||
.police-info-avatar { |
||||
width: 136rpx; |
||||
height: 205rpx; |
||||
image { |
||||
width: 100%; |
||||
height: 100%; |
||||
} |
||||
} |
||||
</style> |
||||
@ -0,0 +1,293 @@
|
||||
<template> |
||||
<tabs :options="tabOptions" v-model="query.status" v-if="!searchFlag && taskStatus === 'todo'" /> |
||||
<view class="flex search"> |
||||
<view class="search-item flex justify-center" :search="searchFlag"> |
||||
<view class="search-item-conent"> |
||||
<uni-easyinput prefixIcon="search" type="text" v-model="query.queryTxt" placeholder="搜索" :inputBorder="false" @focus="searchFlag = true" /> |
||||
|
||||
</view> |
||||
</view> |
||||
<view class="search-item flex justify-center" v-if="!searchFlag" @tap="showPopup"> |
||||
<view :class="filterFlag ? 'search-item-conent active': 'search-item-conent'"> |
||||
<uni-icons customPrefix="customicons" type="filter" size="20" color="#666" /> |
||||
<view>筛选</view> |
||||
</view> |
||||
</view> |
||||
<view v-else> |
||||
<view class="cancel-btn" @tap="searchFlag = false">取消</view> |
||||
</view> |
||||
</view> |
||||
<view class="people-container"> |
||||
<view class="flex gap-16 card" v-for="item in peoples" @tap="open(item)"> |
||||
<view class="people-img"> |
||||
<net-image :filepath="item.avatarUrl" v-if="item.avatarUrl" /> |
||||
<image src="/static/police.png" v-else></image> |
||||
</view> |
||||
<view style="width: calc(100% - 84px)"> |
||||
<view> |
||||
<view class="row"> |
||||
<view class="col col-12"> |
||||
<view class="label">姓名:</view> |
||||
<view class="content">{{ item.name }}</view> |
||||
</view> |
||||
<view class="col col-12"> |
||||
<view class="label">警号:</view> |
||||
<view class="content">{{ item.empNo }}</view> |
||||
</view> |
||||
<view class="col col-12"> |
||||
<view class="label">所属单位:</view> |
||||
<view class="content">{{ item.departName }}</view> |
||||
</view> |
||||
<view class="col col-12"> |
||||
<view class="label">职位:</view> |
||||
<view class="content">{{ item.position }}</view> |
||||
</view> |
||||
<view class="col col-24"> |
||||
<view class="label">联系电话:</view> |
||||
<view class="content">{{ item.mobile || '/' }}</view> |
||||
</view> |
||||
<template v-if="item.status === 'done'"> |
||||
<view class="col col-24"> |
||||
<view class="label">测酒时间:</view> |
||||
<view class="content">{{ item.testingTime }}</view> |
||||
</view> |
||||
<view class="col col-12"> |
||||
<view class="label">检测情况:</view> |
||||
<view class="content"> |
||||
<view v-if="item.testingResult === '未检测'" style="color: var(--danger-color)">{{ item.testingResult }}</view> |
||||
<view v-else>{{ item.testingResult }}</view> |
||||
</view> |
||||
</view> |
||||
<view class="col col-12"> |
||||
<view class="label">饮酒结果:</view> |
||||
<view class="content"> |
||||
<uni-tag :text="item.drinkResult" type="success" v-if="item.drinkResult === '未饮酒'" /> |
||||
<uni-tag :text="item.drinkResult" type="error" v-else /> |
||||
</view> |
||||
</view> |
||||
<view class="col col-12" v-if="item.alcoholContent"> |
||||
<view class="label">酒精含量:</view> |
||||
<view class="content">{{ item.alcoholContent }}</view> |
||||
</view> |
||||
<view class="col col-24" v-if="item.unTestingDesc"> |
||||
<view class="label">未检测原因:</view> |
||||
<view class="content">{{ item.unTestingDesc }}</view> |
||||
</view> |
||||
</template> |
||||
</view> |
||||
</view> |
||||
<view style="color: #FF0000;" v-if="item.status === 'todo'">待检测</view> |
||||
</view> |
||||
</view> |
||||
<empty v-if="peoples.length === 0" /> |
||||
</view> |
||||
|
||||
<uni-popup ref="filterPopupRef" type="top"> |
||||
<view class="popup-container"> |
||||
<view class="popup-header"> |
||||
<view>全部筛选</view> |
||||
<uni-icons type="closeempty" class="close-btn" @tap="closePopup"></uni-icons> |
||||
</view> |
||||
<view class="popup-body"> |
||||
<view class="filter-container"> |
||||
<view class="filter-label">职位</view> |
||||
<filter-radio :data="positions" v-model="query.position" @change="search" /> |
||||
<view v-if="query.status === 'done'"> |
||||
<view class="filter-label">检测情况</view> |
||||
<filter-radio :data="testingResults" v-model="query.testingResult" @change="search" /> |
||||
</view> |
||||
<view v-if="query.status === 'done'"> |
||||
<view class="filter-label">饮酒结果</view> |
||||
<filter-radio :data="drinkResults" v-model="query.drinkResult" @change="search" /> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
<view class="footer col-24 flex gap-8"> |
||||
<button class="col-12" @tap="reset">重置</button> |
||||
<button type="primary" @tap="handleSearch" class="col-12">完成</button> |
||||
</view> |
||||
</view> |
||||
</uni-popup> |
||||
</template> |
||||
<script> |
||||
import store from '@/store' |
||||
import { listTestingAlcoholPeople, countTestingAlcoholPeople } from '@/api/testingAlcohol' |
||||
import { submitTask } from '@/api/task' |
||||
|
||||
let oldPeoples; |
||||
let _this; |
||||
export default { |
||||
inheritAttrs: false, |
||||
data() { |
||||
return { |
||||
BASE_PATH: store.state.fileRequestUrl, |
||||
tabOptions: [ |
||||
{ |
||||
text: '待测人员(0)', |
||||
value: 'todo' |
||||
}, |
||||
{ |
||||
text: '已测人员(0)', |
||||
value: 'done' |
||||
} |
||||
], |
||||
searchFlag: false, |
||||
peoples: [], |
||||
query: { |
||||
size: 100, |
||||
current: 1, |
||||
status: this.$page.options.taskStatus |
||||
}, |
||||
taskStatus: this.$page.options.taskStatus, |
||||
filterFlag: false, |
||||
positions: [ |
||||
{ |
||||
text: '正职', |
||||
value: '正职' |
||||
}, |
||||
{ |
||||
text: '副职', |
||||
value: '副职' |
||||
}, |
||||
], |
||||
testingResults: [ |
||||
{ |
||||
text: '已检测', |
||||
value: '已检测' |
||||
}, |
||||
{ |
||||
text: '未检测', |
||||
value: '未检测' |
||||
}, |
||||
], |
||||
drinkResults: [ |
||||
{ |
||||
text: '饮酒', |
||||
value: '饮酒' |
||||
}, |
||||
{ |
||||
text: '未饮酒', |
||||
value: '未饮酒' |
||||
}, |
||||
] |
||||
} |
||||
}, |
||||
watch: { |
||||
searchFlag(val) { |
||||
if (val) { |
||||
oldPeoples = this.peoples; |
||||
this.peoples = [] |
||||
} else { |
||||
this.peoples = oldPeoples |
||||
} |
||||
}, |
||||
'query.queryTxt': function(val) { |
||||
if (_this.searchFlag) { |
||||
if (val) { |
||||
_this.getPeoples() |
||||
} else { |
||||
this.peoples = [] |
||||
} |
||||
|
||||
} |
||||
}, |
||||
'query.status': function(val) { |
||||
if (val === 'todo') { |
||||
this.query.testingResult = '' |
||||
this.query.drinkResult = '' |
||||
} |
||||
this.getPeoples() |
||||
} |
||||
}, |
||||
onLoad() { |
||||
_this = this; |
||||
|
||||
}, |
||||
onShow() { |
||||
console.log('onShow') |
||||
this.getPeoples() |
||||
}, |
||||
methods: { |
||||
open(item) { |
||||
if (item.status === 'todo') { |
||||
uni.navigateTo({ |
||||
url: '/pages/task/testingAlcohol/add?people=' + JSON.stringify(item) |
||||
}); |
||||
} |
||||
if (item.status === 'done') { |
||||
uni.navigateTo({ |
||||
url: '/pages/task/testingAlcohol/info?people=' + JSON.stringify(item) |
||||
}); |
||||
} |
||||
}, |
||||
getPeoples() { |
||||
listTestingAlcoholPeople(this.$page.options.taskId, this.query).then(data => { |
||||
this.peoples = data.records |
||||
}); |
||||
countTestingAlcoholPeople(this.$page.options.taskId).then(data => { |
||||
this.tabOptions[0].text = `待测人员(${data.todoCount})` |
||||
this.tabOptions[1].text = `已测人员(${data.doneCount})` |
||||
if (data.todoCount === 0 && this.query.status === 'todo' && this.taskStatus === 'todo') { |
||||
uni.showModal({ |
||||
content: `本次检测人数${data.doneCount},\n请确认是否提交本次检测结果并结束任务`, |
||||
confirmText: '提交', |
||||
success: function (res) { |
||||
if (res.confirm) { |
||||
console.log('用户点击确定'); |
||||
submitTask(_this.$page.options.taskId).then(data => { |
||||
uni.navigateTo({ |
||||
url: '/pages/task/index?taskStatus=todo' |
||||
}); |
||||
}) |
||||
} |
||||
} |
||||
}); |
||||
} |
||||
}) |
||||
}, |
||||
showPopup() { |
||||
this.$refs.filterPopupRef.open() |
||||
}, |
||||
closePopup() { |
||||
this.$refs.filterPopupRef.close() |
||||
}, |
||||
search() { |
||||
this.filterFlag = !!this.query.position || !!this.query.testingResult || !!this.query.drinkResult |
||||
console.log(this.filterFlag) |
||||
this.getPeoples() |
||||
}, |
||||
handleSearch() { |
||||
this.search() |
||||
this.closePopup() |
||||
}, |
||||
reset() { |
||||
this.filterFlag = false |
||||
let taskStatus = this.query.taskStatus; |
||||
this.query = { |
||||
size: 10, |
||||
current: 1, |
||||
taskStatus |
||||
} |
||||
this.getPeoples() |
||||
} |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss"> |
||||
.people-container { |
||||
max-height: calc(100vh - 96px); |
||||
/* #ifdef H5 */ |
||||
max-height: calc(100vh - 140px); |
||||
/* #endif */ |
||||
overflow: auto; |
||||
} |
||||
.people-img { |
||||
width: 136rpx; |
||||
height: 205rpx; |
||||
image { |
||||
width: 100%; |
||||
height: 100%; |
||||
} |
||||
} |
||||
</style> |
||||
@ -0,0 +1,232 @@
|
||||
<template> |
||||
<view class="page"> |
||||
<view class="feedback-title"> |
||||
<text>问题和意见</text> |
||||
<text class="feedback-quick" @tap="chooseMsg">快速键入</text> |
||||
</view> |
||||
<view class="feedback-body"><textarea placeholder="请详细描述你的问题和意见..." v-model="sendDate.content" class="feedback-textare"></textarea></view> |
||||
<view class="feedback-title"><text>图片(选填,提供问题截图,总大小10M以下)</text></view> |
||||
<view class="feedback-body feedback-uploader"> |
||||
<view class="uni-uploader"> |
||||
<view class="uni-uploader-head"> |
||||
<view class="uni-uploader-title">点击预览图片</view> |
||||
<view class="uni-uploader-info">{{ imageList.length }}/5</view> |
||||
</view> |
||||
<view class="uni-uploader-body"> |
||||
<view class="uni-uploader__files"> |
||||
<block v-for="(image, index) in imageList" :key="index"> |
||||
<view class="uni-uploader__file" style="position: relative;"> |
||||
<image class="uni-uploader__img" :src="image" @tap="previewImage(index)"></image> |
||||
<view class="close-view" @click="close(index)">x</view> |
||||
</view> |
||||
</block> |
||||
<view class="uni-uploader__input-box" v-show="imageList.length < 5"><view class="uni-uploader__input" @tap="chooseImg"></view></view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
<view class="feedback-title"><text>QQ/邮箱</text></view> |
||||
<view class="feedback-body"><input class="feedback-input" v-model="sendDate.contact" placeholder="(选填,方便我们联系你 )" /></view> |
||||
<view class="feedback-title feedback-star-view"> |
||||
<text>应用评分</text> |
||||
<view class="feedback-star-view"><uni-rate v-model="sendDate.score" color="#bbb"></uni-rate></view> |
||||
</view> |
||||
<button type="default" class="feedback-submit" @tap="send">提交</button> |
||||
<view class="feedback-title"><text>用户反馈的结果可在app打包后于DCloud开发者中心查看</text></view> |
||||
</view> |
||||
</template> |
||||
|
||||
<script> |
||||
export default { |
||||
data() { |
||||
return { |
||||
msgContents: ['界面显示错乱', '启动缓慢,卡出翔了', 'UI无法直视,丑哭了', '偶发性崩溃'], |
||||
stars: [1, 2, 3, 4, 5], |
||||
imageList: [], |
||||
sendDate: { |
||||
score: 0, |
||||
content: '', |
||||
contact: '' |
||||
} |
||||
}; |
||||
}, |
||||
onLoad() { |
||||
this.deviceInfo = { |
||||
// appid: plus.runtime.appid, |
||||
appid: '__UNI__5D0B0CA', |
||||
imei: plus.device.imei, //设备标识 |
||||
p: plus.os.name === 'Android' ? 'a' : 'i', //平台类型,i表示iOS平台,a表示Android平台。 |
||||
md: plus.device.model, //设备型号 |
||||
app_version: plus.runtime.version, |
||||
plus_version: plus.runtime.innerVersion, //基座版本号 |
||||
os: plus.os.version, |
||||
net: '' + plus.networkinfo.getCurrentType() |
||||
}; |
||||
this.sendDate = Object.assign(this.deviceInfo, this.sendDate); |
||||
}, |
||||
methods: { |
||||
/** |
||||
* 关闭图片 |
||||
* @param {Object} e |
||||
*/ |
||||
close(e) { |
||||
this.imageList.splice(e, 1); |
||||
}, |
||||
|
||||
/** |
||||
* 快速输入 |
||||
*/ |
||||
chooseMsg() { |
||||
uni.showActionSheet({ |
||||
itemList: this.msgContents, |
||||
success: res => { |
||||
this.sendDate.content = this.msgContents[res.tapIndex]; |
||||
} |
||||
}); |
||||
}, |
||||
|
||||
/** |
||||
* 选择图片 |
||||
*/ |
||||
chooseImg() { |
||||
//选择图片 |
||||
uni.chooseImage({ |
||||
sourceType: ['camera', 'album'], |
||||
sizeType: 'compressed', |
||||
count: 5 - this.imageList.length, |
||||
success: res => { |
||||
this.imageList = this.imageList.concat(res.tempFilePaths); |
||||
} |
||||
}); |
||||
}, |
||||
|
||||
/** |
||||
* 评分 |
||||
* @param {Object} e |
||||
*/ |
||||
chooseStar(e) { |
||||
//点击评星 |
||||
this.sendDate.score = e; |
||||
}, |
||||
/** |
||||
* 预览图片 |
||||
* @param {Object} index |
||||
*/ |
||||
previewImage(index) { |
||||
uni.previewImage({ |
||||
urls: this.imageList, |
||||
current: this.imageList[index] |
||||
}); |
||||
}, |
||||
|
||||
/** |
||||
* 提交 |
||||
*/ |
||||
send() { |
||||
//发送反馈 |
||||
if (this.sendDate.content.length === 0) { |
||||
uni.showModal({ |
||||
content: '请输入问题和意见', |
||||
showCancel: false |
||||
}); |
||||
return; |
||||
} |
||||
uni.showLoading({ |
||||
title: '上传中...' |
||||
}); |
||||
let imgs = this.imageList.map((value, index) => { |
||||
return { |
||||
name: 'images' + index, |
||||
uri: value |
||||
}; |
||||
}); |
||||
// TODO 服务端限制上传文件一次最大不超过 2M, 图片一次最多不超过5张 |
||||
this.request(this.sendDate, imgs) |
||||
.then(res => { |
||||
if (typeof res.data === 'string') { |
||||
res.data = JSON.parse(res.data); |
||||
} |
||||
if (res.statusCode === 200 && res.data && res.data.ret === 0) { |
||||
uni.showModal({ |
||||
content: '反馈成功', |
||||
showCancel: false |
||||
}); |
||||
this.imageList = []; |
||||
this.sendDate = Object.assign(this.deviceInfo, { |
||||
score: 0, |
||||
content: '', |
||||
contact: '' |
||||
}); |
||||
} else if (res.statusCode !== 200) { |
||||
uni.showModal({ |
||||
content: '反馈失败,错误码为:' + res.statusCode, |
||||
showCancel: false |
||||
}); |
||||
} else { |
||||
uni.showModal({ |
||||
content: '反馈失败', |
||||
showCancel: false |
||||
}); |
||||
} |
||||
}) |
||||
.catch(err => { |
||||
console.log(err); |
||||
}); |
||||
}, |
||||
|
||||
/** |
||||
* 发送请求到后台 |
||||
*/ |
||||
request(sendDate, imgs) { |
||||
return new Promise((resolve, reject) => { |
||||
let fromData = { |
||||
url: 'https://service.dcloud.net.cn/feedback', |
||||
success: res => { |
||||
resolve(res); |
||||
}, |
||||
fail: res => { |
||||
reject(res); |
||||
}, |
||||
complete() { |
||||
uni.hideLoading(); |
||||
} |
||||
}; |
||||
|
||||
if (imgs.length > 0) { |
||||
fromData.files = imgs; |
||||
fromData.formData = sendDate; |
||||
uni.uploadFile(fromData); |
||||
} else { |
||||
fromData.data = sendDate; |
||||
fromData.method = 'POST'; |
||||
uni.request(fromData); |
||||
} |
||||
}); |
||||
} |
||||
} |
||||
}; |
||||
</script> |
||||
|
||||
<style> |
||||
page { |
||||
background-color: #efeff4; |
||||
} |
||||
|
||||
.input-view { |
||||
font-size: 28rpx; |
||||
} |
||||
|
||||
.close-view { |
||||
text-align: center; |
||||
line-height: 14px; |
||||
height: 16px; |
||||
width: 16px; |
||||
border-radius: 50%; |
||||
background: #ff5053; |
||||
color: #ffffff; |
||||
position: absolute; |
||||
top: -6px; |
||||
right: -4px; |
||||
font-size: 12px; |
||||
} |
||||
</style> |
||||
@ -0,0 +1,64 @@
|
||||
<template> |
||||
<view> |
||||
<page-head :title="title"></page-head> |
||||
<view class="uni-padding-wrap uni-common-mt"> |
||||
<view class="uni-btn-v"> |
||||
<button type="primary" @tap="getOrient">获取设备的方向信息</button> |
||||
<button type="primary" @tap="watchOrient">监听设备的方向变化</button> |
||||
<button type="primary" @tap="watchStop">停止监听</button> |
||||
</view> |
||||
<view class="uni-textarea"> |
||||
<textarea :value="value" /> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
</template> |
||||
<script> |
||||
var id = null |
||||
export default { |
||||
data() { |
||||
return { |
||||
title: 'orientation', |
||||
value: '' |
||||
} |
||||
}, |
||||
onUnload() { |
||||
this.watchStop(); |
||||
}, |
||||
methods: { |
||||
getOrient: function () { |
||||
var that = this; |
||||
plus.orientation.getCurrentOrientation(function (o) { |
||||
that.value = "alpha:" + o.alpha + "\nbeta:" + o.beta + "\ngamma:" + o.gamma; |
||||
}, function (e) { |
||||
console.log("获取失败:" + e.message); |
||||
}); |
||||
}, |
||||
watchOrient: function () { |
||||
var that = this; |
||||
if (id) { |
||||
return; |
||||
} |
||||
id = plus.orientation.watchOrientation(function (o) { |
||||
that.value = "监听设备方向变化信息\n" + "alpha:" + o.alpha + "\nbeta:" + o.beta + "\ngamma:" + o.gamma; |
||||
}, function (e) { |
||||
plus.orientation.clearWatch(id); |
||||
id = null; |
||||
console.log("监听失败:" + e.message); |
||||
}); |
||||
}, |
||||
watchStop: function () { |
||||
if (id) { |
||||
plus.orientation.clearWatch(id); |
||||
id = null; |
||||
} else { |
||||
console.log("没有监听设备方向变化"); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style> |
||||
|
||||
</style> |
||||
@ -0,0 +1,69 @@
|
||||
<template> |
||||
<view> |
||||
<page-head :title="title"></page-head> |
||||
<view class="uni-padding-wrap uni-common-mt"> |
||||
<view class="uni-hello-text"> |
||||
手机顶部听筒处有传感器监听距离手机屏幕的障碍物,覆盖该传感器会触发本事件变化 |
||||
</view> |
||||
<view class="uni-btn-v uni-common-mt"> |
||||
<button type="primary" @tap="getProximity">获取距离传感器信息</button> |
||||
<button type="primary" @tap="watchProximity">监听距离传感器变化</button> |
||||
<button type="primary" @tap="watchStop">停止监听</button> |
||||
</view> |
||||
<view class="uni-textarea uni-common-mt"> |
||||
<textarea :value="value" /> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
</template> |
||||
<script> |
||||
var id = null |
||||
var bright = null |
||||
export default { |
||||
data() { |
||||
return { |
||||
title: 'proximity', |
||||
value: '' |
||||
} |
||||
}, |
||||
methods: { |
||||
getProximity: function () { |
||||
var that = this; |
||||
plus.proximity.getCurrentProximity(function (d) { |
||||
that.value = "距离为:" + d; |
||||
}, function (e) { |
||||
that.value = "获取失败:" + e.message; |
||||
}); |
||||
}, |
||||
watchProximity: function () { |
||||
var that = this; |
||||
if (id) { |
||||
return; |
||||
} |
||||
bright = plus.screen.getBrightness(); |
||||
id = plus.proximity.watchProximity(function (d) { |
||||
that.value = "距离变化:" + d; |
||||
plus.screen.setBrightness((d < 1) ? 0.01 : bright); |
||||
}, function (e) { |
||||
plus.proximity.clearWatch(id); |
||||
id = null; |
||||
that.value = "监听失败:" + e.message; |
||||
}); |
||||
}, |
||||
watchStop: function () { |
||||
var that = this; |
||||
if (id) { |
||||
that.value = "停止监听设备距离传感器信息"; |
||||
plus.proximity.clearWatch(id); |
||||
id = null; |
||||
} else { |
||||
that.value = "没有监听设备距离传感器"; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style> |
||||
|
||||
</style> |
||||
@ -0,0 +1,81 @@
|
||||
<template> |
||||
<view> |
||||
<page-head :title="title"></page-head> |
||||
<view class="uni-padding-wrap" v-if="provider[0]"> |
||||
<view class="uni-btn-v uni-common-mt"> |
||||
<button type="primary" @tap="listenTranMsg">监听透传数据</button> |
||||
</view> |
||||
<view class="uni-btn-v uni-common-mt"> |
||||
<button type="primary" @tap="requireTranMsg">发送"透传数据"消息</button> |
||||
</view> |
||||
<view class="uni-title uni-common-mt">透传内容:</view> |
||||
<view class="uni-textarea"> |
||||
<textarea v-model="tranMsg" /> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
</template> |
||||
<script> |
||||
export default { |
||||
data() { |
||||
return { |
||||
title: 'push', |
||||
provider: [], |
||||
pushServer: 'http://demo.dcloud.net.cn/push/?', |
||||
tranMsg:'' |
||||
} |
||||
}, |
||||
onLoad: function () { |
||||
uni.getProvider({ |
||||
service: "push", |
||||
success: (e) => { |
||||
console.log("success", e); |
||||
this.provider = e.provider; |
||||
}, |
||||
fail: (e) => { |
||||
console.log("获取推送通道失败", e); |
||||
} |
||||
}); |
||||
}, |
||||
onUnload:function(){ |
||||
this.tranMsg = '' |
||||
}, |
||||
methods: { |
||||
listenTranMsg() { |
||||
// IOS端在客户端在运行时收到推送消息触发receive事件,离线接收到的推送消息全部进入系统消息中心。点击消息中心的消息触发click |
||||
plus.push.addEventListener('click', (msg)=> { |
||||
this.tranMsg = JSON.stringify(msg) |
||||
}); |
||||
plus.push.addEventListener('receive',(msg)=>{ |
||||
this.tranMsg = JSON.stringify(msg) |
||||
}) |
||||
uni.showToast({ |
||||
title: '开始监听透传数据', |
||||
icon: 'success' |
||||
}) |
||||
}, |
||||
requireTranMsg() { //请求‘透传数据’推送消息 |
||||
var inf = plus.push.getClientInfo(); |
||||
var url = this.pushServer + 'type=tran&appid=' + encodeURIComponent(plus.runtime.appid); |
||||
inf.id && (url += '&id=' + inf.id); |
||||
url += ('&cid=' + encodeURIComponent(inf.clientid)); |
||||
if (plus.os.name == 'iOS') { |
||||
url += ('&token=' + encodeURIComponent(inf.token)); |
||||
} |
||||
url += ('&title=' + encodeURIComponent('Hello uniapp')); |
||||
url += ('&content=' + encodeURIComponent('带透传数据推送通知!')); |
||||
if(plus.os.name === 'iOS'){ |
||||
url += ('&payload=' + encodeURIComponent('{"title":"Hello uniapp Test","content":"test content"}')); |
||||
}else{ |
||||
url += ('&payload=' + encodeURIComponent('\'{"title":"Hello uniapp Test","content":"test content"}\'')); |
||||
} |
||||
url += ('&version=' + encodeURIComponent(plus.runtime.version)); |
||||
plus.runtime.openURL(url); |
||||
} |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style> |
||||
|
||||
</style> |
||||
@ -0,0 +1,106 @@
|
||||
<template> |
||||
<view class="root" :style="{backgroundImage:'url('+img+')'}"> |
||||
<view :class="[show ? 'up' : '','shake-up']"> |
||||
<image mode="aspectFit" src="https://web-assets.dcloud.net.cn/unidoc/zh/shakeup.png"></image> |
||||
</view> |
||||
<view :class="[show ? 'down' : '','shake-down']"> |
||||
<image mode="aspectFit" src="https://web-assets.dcloud.net.cn/unidoc/zh/shakedown.png"></image> |
||||
</view> |
||||
</view> |
||||
</template> |
||||
<script> |
||||
export default { |
||||
data() { |
||||
return { |
||||
img: 'https://web-assets.dcloud.net.cn/unidoc/zh/1.jpg', |
||||
show: false, |
||||
isOpened: false, |
||||
index: 1 |
||||
} |
||||
}, |
||||
computed:{ |
||||
pageIndex() { |
||||
if (this.index === 1) { |
||||
return 'shake-1' |
||||
} else if (this.index === 2) { |
||||
return 'shake-2' |
||||
} else if (this.index === 3) { |
||||
return 'shake-3' |
||||
} else if (this.index === 4) { |
||||
return 'shake-4' |
||||
} else { |
||||
return 'shake-1' |
||||
} |
||||
} |
||||
}, |
||||
onLoad: function () { |
||||
this.music = uni.createInnerAudioContext(); |
||||
this.music.src = 'https://web-assets.dcloud.net.cn/unidoc/zh/shake.wav'; |
||||
|
||||
let t = null; |
||||
uni.onAccelerometerChange((res) => { |
||||
if (Math.abs(res.x) + Math.abs(res.y) + Math.abs(res.z) > 20 && !this.show && this.isOpened) { |
||||
this.music.play(); |
||||
setTimeout(() => { |
||||
this.index++; |
||||
if (this.index > 4) { |
||||
this.index = 1 |
||||
} |
||||
this.img = 'https://web-ext-storage.dcloud.net.cn/hello-uni-app/' + this.pageIndex + '.jpg'; |
||||
}, 2000); |
||||
this.show = true; |
||||
if (t) { |
||||
clearTimeout(t); |
||||
} |
||||
t = setTimeout(() => { |
||||
t = null; |
||||
this.show = false; |
||||
}, 600) |
||||
} |
||||
}) |
||||
}, |
||||
onShow() { |
||||
this.isOpened = true; |
||||
}, |
||||
onUnload() { |
||||
this.show = false; |
||||
this.isOpened = false; |
||||
uni.stopAccelerometer(); |
||||
this.music.destroy(); |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style> |
||||
.root { |
||||
height: 100%; |
||||
display: flex; |
||||
flex-direction: column; |
||||
background-position: center center; |
||||
background-repeat: no-repeat; |
||||
} |
||||
|
||||
.shake-up, |
||||
.shake-down { |
||||
height: 50%; |
||||
overflow: hidden; |
||||
transition: all .5s ease-in-out; |
||||
-webkit-transition: all .5s ease-in-out; |
||||
background: #333; |
||||
} |
||||
|
||||
.up { |
||||
transform: translateY(-50%); |
||||
-webkit-transform: translateY(-50%); |
||||
} |
||||
|
||||
.down { |
||||
transform: translateY(50%); |
||||
-webkit-transform: translateY(50%); |
||||
} |
||||
|
||||
image { |
||||
height: 100%; |
||||
width: 100%; |
||||
} |
||||
</style> |
||||
@ -0,0 +1,105 @@
|
||||
<template> |
||||
<view> |
||||
<page-head :title="title"></page-head> |
||||
<view class="uni-padding-wrap uni-common-mt"> |
||||
<view class="uni-textarea"> |
||||
<textarea :value="value" placeholder="语音识别内容展示区域" disabled /> |
||||
</view> |
||||
<view class="uni-common-mt uni-btn-v"> |
||||
<button type="primary" @tap="startRecognize">开始语音识别</button> |
||||
<!-- <button type="primary" @tap="startRecognizeEnglish">开始语音识别(英语)</button> --> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
</template> |
||||
<script> |
||||
import permision from "@/common/permission.js" |
||||
export default { |
||||
data() { |
||||
return { |
||||
title: 'speech', |
||||
value: '' |
||||
} |
||||
}, |
||||
onUnload(){ |
||||
this.value = "" |
||||
}, |
||||
methods: { |
||||
async startRecognize () { |
||||
// #ifdef APP-PLUS |
||||
let status = await this.checkPermission(); |
||||
if (status !== 1) { |
||||
return; |
||||
} |
||||
// #endif |
||||
|
||||
// TODO ios 在没有请求过权限之前无法得知是否有相关权限,这种状态下需要直接调用语音,会弹出正在识别的toast |
||||
var options = {}; |
||||
var that = this; |
||||
options.engine = 'baidu'; |
||||
that.value = ""; |
||||
plus.speech.startRecognize(options, function (s) { |
||||
console.log(s); |
||||
that.value += s; |
||||
}, function (e) { |
||||
console.log("语音识别失败:" + e.message); |
||||
}); |
||||
}, |
||||
async startRecognizeEnglish () { |
||||
// #ifdef APP-PLUS |
||||
let status = await this.checkPermission(); |
||||
if (status !== 1) { |
||||
return; |
||||
} |
||||
// #endif |
||||
|
||||
// TODO ios 在没有请求过权限之前无法得知是否有相关权限,这种状态下需要直接调用语音,会弹出正在识别的toast |
||||
var options = {}; |
||||
var that = this; |
||||
options.engine = 'baidu'; |
||||
options.lang = 'en-us'; |
||||
that.value = ""; |
||||
plus.speech.startRecognize(options, function (s) { |
||||
console.log(s); |
||||
that.value += s; |
||||
}, function (e) { |
||||
console.log("语音识别失败:" + e.message); |
||||
}); |
||||
} |
||||
// #ifdef APP-PLUS |
||||
, |
||||
async checkPermission() { |
||||
let status = permision.isIOS ? await permision.requestIOS('record') : |
||||
await permision.requestAndroid('android.permission.RECORD_AUDIO'); |
||||
|
||||
if (status === null || status === 1) { |
||||
status = 1; |
||||
} else if (status === 2) { |
||||
uni.showModal({ |
||||
content: "系统麦克风已关闭", |
||||
confirmText: "确定", |
||||
showCancel: false, |
||||
success: function(res) { |
||||
} |
||||
}) |
||||
} else { |
||||
uni.showModal({ |
||||
content: "需要麦克风权限", |
||||
confirmText: "设置", |
||||
success: function(res) { |
||||
if (res.confirm) { |
||||
permision.gotoAppSetting(); |
||||
} |
||||
} |
||||
}) |
||||
} |
||||
return status; |
||||
} |
||||
// #endif |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style> |
||||
|
||||
</style> |
||||
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 5.5 KiB |
|
After Width: | Height: | Size: 5.7 KiB |
@ -0,0 +1,12 @@
|
||||
@font-face { |
||||
font-family: "customicons"; /* Project id 2878519 */ |
||||
src: url('/static/icon/iconfont.ttf?t=1744633630602') format('truetype'); |
||||
} |
||||
|
||||
.customicons { |
||||
font-family: "customicons" !important; |
||||
} |
||||
|
||||
.filter:before { |
||||
content: "\e64c"; |
||||
} |
||||
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 6.1 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 2.0 KiB |