feat(h5) adapt page

approve-sys
bob 2 years ago
parent 2c4623db81
commit 0f937e0ac6

@ -10025,13 +10025,11 @@
}
},
"postcss-px-to-viewport": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/postcss-px-to-viewport/-/postcss-px-to-viewport-1.1.1.tgz",
"integrity": "sha512-2x9oGnBms+e0cYtBJOZdlwrFg/mLR4P1g2IFu7jYKvnqnH/HLhoKyareW2Q/x4sg0BgklHlP1qeWo2oCyPm8FQ==",
"version": "git+https://github.com/evrone/postcss-px-to-viewport.git#9d6c5cee5eea367fb4c7cf0c3bb1117979b5fbf4",
"from": "git+https://github.com/evrone/postcss-px-to-viewport.git",
"dev": true,
"requires": {
"object-assign": ">=4.0.1",
"postcss": ">=5.0.2"
"object-assign": ">=4.0.1"
}
},
"postcss-reduce-initial": {
@ -13865,6 +13863,15 @@
"integrity": "sha1-u3J3n1+kZRhrH0OPZ0+jR/2121Q=",
"dev": true
},
"xy-postcss-px-to-viewport": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/xy-postcss-px-to-viewport/-/xy-postcss-px-to-viewport-1.0.0.tgz",
"integrity": "sha512-Yn098par28rlPycunPvOTIU+LIAkAjpL9hEqNEbN1g7BHNadsI6yrjr6tF7U5onnwiyhRxi3N3lTt1drzlTBUQ==",
"dev": true,
"requires": {
"object-assign": ">=4.0.1"
}
},
"y18n": {
"version": "4.0.3",
"resolved": "https://registry.npm.taobao.org/y18n/download/y18n-4.0.3.tgz?cache=0&sync_timestamp=1617822642544&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fy18n%2Fdownload%2Fy18n-4.0.3.tgz",

@ -75,7 +75,7 @@
"eslint": "7.15.0",
"eslint-plugin-vue": "7.2.0",
"lint-staged": "10.5.3",
"postcss-px-to-viewport": "^1.1.1",
"postcss-px-to-viewport": "git+https://github.com/evrone/postcss-px-to-viewport.git",
"runjs": "4.4.2",
"sass": "1.32.13",
"sass-loader": "10.1.1",

@ -1,35 +0,0 @@
// vue h5
// base.scss
$maxWidth: 540px;
@mixin MaxWidth {
@media screen and (min-width: 540px) {
@content;
}
}
@mixin MaxWidth-center {
@media screen and (min-width: 540px) {
max-width: $maxWidth;
left: 50%;
transform: translateX(-50%);
}
}
html {
margin: auto;
max-width: $maxWidth;
height: 100%;
font-size: 10vw;
// background: #ccc;
font-family: -apple-system, system-ui, BlinkMacSystemFont, Helvetica Neue, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif;
@include MaxWidth() {
font-size: calc((#{$maxWidth} - 17px) / 10);
}
}
body {
margin: auto;
max-width: $maxWidth;
height: 100%;
font-size: 16px;
-webkit-text-size-adjust: none !important;
}

@ -7,7 +7,7 @@ import { getToken } from '@/utils/auth'
NProgress.configure({ showSpinner: false })
const whiteList = ['/login', '/auth-redirect', '/bind', '/register']
const whiteList = ['/login','/h5login', '/auth-redirect', '/bind', '/register']
router.beforeEach((to, from, next) => {
NProgress.start()

@ -0,0 +1,27 @@
module.exports = ({ file }) => {
return {
plugins: {
autoprefixer: {},
'postcss-px-to-viewport': {
unitToConvert: 'px',
viewportWidth: 1500, // UI设计稿的宽度
// viewportHeight: 1080,
unitPrecision: 3, // 精度
propList: [
// 指定转换的css属性的单位*代表全部css属性的单位都进行转换
'*', '!max-width'
],
viewportUnit: 'rem', // 指定需要转换成的视窗单位
fontViewportUnit: 'rem', // 指定字体需要转换成的视窗单位
selectorBlackList: [],
minPixelValue: 1, // 默认值1小于或等于1px则不进行转换
mediaQuery: false, // 是否在媒体查询的css代码中也进行转换默认false
replace: true, // 是否转换后直接更换属性值
include:[/h5/],
landscape: true, // 是否处理横屏情况
landscapeUnit: 'vw',
landscapeWidth: 568
}
}
}
}

@ -43,6 +43,21 @@ export const constantRoutes = [
component: (resolve) => require(['@/views/login'], resolve),
hidden: true
},
{
path: '/h5login',
component: (resolve) => require(['@/views/h5login'], resolve),
hidden: true
},
{
path: '/h5todo',
component: (resolve) => require(['@/views/h5/h5todo'], resolve),
hidden: true
},
{
path: '/h5record',
component: (resolve) => require(['@/views/h5/h5record'], resolve),
hidden: true
},
{
path: '/404',
component: (resolve) => require(['@/views/error/404'], resolve),

@ -0,0 +1,203 @@
<template>
<div class="login">
<el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form">
<h3 class="title">工作流开发平台-H5登陆页</h3>
<el-form-item prop="username">
<el-input v-model="loginForm.username" type="text" auto-complete="off" placeholder="账号">
<svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon" />
</el-input>
</el-form-item>
<el-form-item prop="password">
<el-input
v-model="loginForm.password"
type="password"
auto-complete="off"
placeholder="密码"
@keyup.enter.native="handleLogin"
>
<svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" />
</el-input>
</el-form-item>
<el-form-item prop="code">
<el-input
v-model="loginForm.code"
auto-complete="off"
placeholder="验证码"
style="width: 63%"
@keyup.enter.native="handleLogin"
>
<svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" />
</el-input>
<div class="login-code">
<img :src="codeUrl" @click="getCode" class="login-code-img"/>
</div>
</el-form-item>
<el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;"></el-checkbox>
<el-form-item style="width:100%;">
<el-button
:loading="loading"
size="medium"
type="primary"
style="width:100%;"
@click.native.prevent="handleLogin"
>
<span v-if="!loading"> </span>
<span v-else> ...</span>
</el-button>
</el-form-item>
</el-form>
<!-- 底部 -->
<div class="el-login-footer">
<span>Copyright © Xuan xuan.</span>
</div>
</div>
</template>
<script>
import { getCodeImg } from "@/api/login";
import Cookies from "js-cookie";
import { encrypt, decrypt } from '@/utils/jsencrypt'
export default {
name: "H5Login",
data() {
return {
codeUrl: "",
cookiePassword: "",
loginForm: {
username: "tony",
password: "123456",
rememberMe: false,
code: "",
uuid: ""
},
loginRules: {
username: [
{ required: true, trigger: "blur", message: "用户名不能为空" }
],
password: [
{ required: true, trigger: "blur", message: "密码不能为空" }
],
code: [{ required: true, trigger: "change", message: "验证码不能为空" }]
},
loading: false,
redirect: undefined
};
},
watch: {
$route: {
handler: function(route) {
this.redirect = route.query && route.query.redirect;
},
immediate: true
}
},
created() {
this.getCode();
this.getCookie();
},
methods: {
getCode() {
getCodeImg().then(res => {
this.codeUrl = "data:image/gif;base64," + res.img;
this.loginForm.uuid = res.uuid;
});
},
getCookie() {
const username = Cookies.get("username");
const password = Cookies.get("password");
const rememberMe = Cookies.get('rememberMe')
this.loginForm = {
username: username === undefined ? this.loginForm.username : username,
password: password === undefined ? this.loginForm.password : decrypt(password),
rememberMe: rememberMe === undefined ? false : Boolean(rememberMe)
};
},
handleLogin() {
this.$refs.loginForm.validate(valid => {
if (valid) {
this.loading = true;
if (this.loginForm.rememberMe) {
Cookies.set("username", this.loginForm.username, { expires: 30 });
Cookies.set("password", encrypt(this.loginForm.password), { expires: 30 });
Cookies.set('rememberMe', this.loginForm.rememberMe, { expires: 30 });
} else {
Cookies.remove("username");
Cookies.remove("password");
Cookies.remove('rememberMe');
}
this.$store.dispatch("Login", this.loginForm).then(() => {
this.$router.push({ path: this.redirect || "/" }).catch(()=>{});
}).catch(() => {
this.loading = false;
this.getCode();
});
}
});
}
}
};
</script>
<style rel="stylesheet/scss" lang="scss">
.login {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
background-image: url("../../../assets/images/login-background.jpg");
background-size: cover;
}
.title {
margin: 0px auto 30px auto;
text-align: center;
color: #707070;
}
.login-form {
border-radius: 6px;
background: #ffffff;
width: 400px;
padding: 25px 25px 5px 25px;
.el-input {
height: 38px;
input {
height: 38px;
}
}
.input-icon {
height: 39px;
width: 14px;
margin-left: 2px;
}
}
.login-tip {
font-size: 13px;
text-align: center;
color: #bfbfbf;
}
.login-code {
width: 33%;
height: 38px;
float: right;
img {
cursor: pointer;
vertical-align: middle;
}
}
.el-login-footer {
height: 40px;
line-height: 40px;
position: fixed;
bottom: 0;
width: 100%;
text-align: center;
color: #fff;
font-family: Arial;
font-size: 12px;
letter-spacing: 1px;
}
.login-code-img {
height: 38px;
}
</style>

@ -0,0 +1,28 @@
<template>
<div>
<flow-view :xmlData="xmlData" :taskList="taskData"/>
</div>
</template>
<script>
import FlowView from './flowview'
export default {
name: "Flow",
components: {
FlowView
},
props: {
xmlData: {
type: String,
default: ''
},
taskData: {
type: Array,
default: () => []
}
},
data() {
return {};
}
};
</script>

@ -0,0 +1,243 @@
<template>
<div class="containers main-box">
<el-button type="success"
size="small"
icon="el-icon-zoom-in"
@click="zoomViewport(true)">放大</el-button>
<el-button type="warning"
size="small"
icon="el-icon-zoom-out"
@click="zoomViewport(false)">缩小</el-button>
<el-button type="info"
size="small"
icon="el-icon-rank"
@click="fitViewport">适中</el-button>
<div class="canvas" ref="flowCanvas"></div>
</div>
</template>
<script>
import { CustomViewer as BpmnViewer } from "@/components/customBpmn";
export default {
name: "FlowView",
props: {
xmlData: {
type: String,
default: ''
},
taskList: {
type: Array,
default: () => []
}
},
data() {
return {
bpmnViewer: null
};
},
watch: {
xmlData: function(val) {
if (val) {
this.getImg(val)
}
}
},
mounted() {
//
this.bpmnViewer && this.bpmnViewer.destroy();
this.bpmnViewer = new BpmnViewer({
container: this.$refs.flowCanvas,
height: 'calc(100vh - 200px)',
});
this.getImg(this.xmlData)
},
methods: {
//
async getImg(xmlUrl) {
const self = this
try {
await self.bpmnViewer.importXML(xmlUrl);
self.fitViewport()
if (self.taskList !==undefined && self.taskList.length > 0 ) {
self.fillColor()
}
} catch (err) {
console.error(err.message, err.warnings)
}
},
// class
setNodeColor(nodeCodes, colorClass, canvas) {
for (let i = 0; i < nodeCodes.length; i++) {
canvas.addMarker(nodeCodes[i], colorClass);
}
},
//
fitViewport() {
this.zoom = this.bpmnViewer.get('canvas').zoom("fit-viewport", "auto")
},
//
zoomViewport(zoomIn = true) {
this.zoom = this.bpmnViewer.get('canvas').zoom()
this.zoom += (zoomIn ? 0.1 : -0.1)
if(this.zoom >= 0.2) this.bpmnViewer.get('canvas').zoom(this.zoom)
},
//
fillColor() {
const canvas = this.bpmnViewer.get('canvas')
this.bpmnViewer.getDefinitions().rootElements[0].flowElements.forEach(n => {
const completeTask = this.taskList.find(m => m.key === n.id)
const todoTask = this.taskList.find(m => !m.completed)
const endTask = this.taskList[this.taskList.length - 1]
if (n.$type === 'bpmn:UserTask') {
if (completeTask) {
canvas.addMarker(n.id, completeTask.completed ? 'highlight' : 'highlight-todo')
n.outgoing?.forEach(nn => {
const targetTask = this.taskList.find(m => m.key === nn.targetRef.id)
if (targetTask) {
if (todoTask && completeTask.key === todoTask.key && !todoTask.completed){
canvas.addMarker(nn.id, todoTask.completed ? 'highlight' : 'highlight-todo')
canvas.addMarker(nn.targetRef.id, todoTask.completed ? 'highlight' : 'highlight-todo')
}else {
canvas.addMarker(nn.id, targetTask.completed ? 'highlight' : 'highlight-todo')
canvas.addMarker(nn.targetRef.id, targetTask.completed ? 'highlight' : 'highlight-todo')
}
}
})
}
}
//
else if (n.$type === 'bpmn:ExclusiveGateway') {
if (completeTask) {
canvas.addMarker(n.id, completeTask.completed ? 'highlight' : 'highlight-todo')
n.outgoing?.forEach(nn => {
const targetTask = this.taskList.find(m => m.key === nn.targetRef.id)
if (targetTask) {
canvas.addMarker(nn.id, targetTask.completed ? 'highlight' : 'highlight-todo')
canvas.addMarker(nn.targetRef.id, targetTask.completed ? 'highlight' : 'highlight-todo')
}
})
}
}
//
else if (n.$type === 'bpmn:ParallelGateway') {
if (completeTask) {
canvas.addMarker(n.id, completeTask.completed ? 'highlight' : 'highlight-todo')
n.outgoing?.forEach(nn => {
const targetTask = this.taskList.find(m => m.key === nn.targetRef.id)
if (targetTask) {
canvas.addMarker(nn.id, targetTask.completed ? 'highlight' : 'highlight-todo')
canvas.addMarker(nn.targetRef.id, targetTask.completed ? 'highlight' : 'highlight-todo')
}
})
}
}
else if (n.$type === 'bpmn:StartEvent') {
n.outgoing.forEach(nn => {
const completeTask = this.taskList.find(m => m.key === nn.targetRef.id)
if (completeTask) {
canvas.addMarker(nn.id, 'highlight')
canvas.addMarker(n.id, 'highlight')
return
}
})
}
else if (n.$type === 'bpmn:EndEvent') {
if (endTask.key === n.id && endTask.completed) {
canvas.addMarker(n.id, 'highlight')
return
}
}
})
},
}
};
</script>
<style lang="scss">
@import "../../../../node_modules/bpmn-js/dist/assets/diagram-js.css";
@import "../../../../node_modules/bpmn-js/dist/assets/bpmn-font/css/bpmn.css";
@import "../../../../node_modules/bpmn-js/dist/assets/bpmn-font/css/bpmn-codes.css";
@import "../../../../node_modules/bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css";
.bjs-powered-by {
display: none;
}
.view-mode {
.el-header, .el-aside, .djs-palette, .bjs-powered-by {
display: none;
}
.el-loading-mask {
background-color: initial;
}
.el-loading-spinner {
display: none;
}
}
.containers {
// background-color: #ffffff;
width: 100%;
height: 100%;
.canvas {
width: 100%;
height: 100%;
}
.panel {
position: absolute;
right: 0;
top: 50px;
width: 300px;
}
.load {
margin-right: 10px;
}
.el-form-item__label{
font-size: 13px;
}
.djs-palette{
left: 0px!important;
top: 0px;
border-top: none;
}
.djs-container svg {
min-height: 650px;
}
.highlight.djs-shape .djs-visual > :nth-child(1) {
fill: green !important;
stroke: green !important;
fill-opacity: 0.2 !important;
}
.highlight.djs-shape .djs-visual > :nth-child(2) {
fill: green !important;
}
.highlight.djs-shape .djs-visual > path {
fill: green !important;
fill-opacity: 0.2 !important;
stroke: green !important;
}
.highlight.djs-connection > .djs-visual > path {
stroke: green !important;
}
.highlight-todo.djs-connection > .djs-visual > path {
stroke: orange !important;
stroke-dasharray: 4px !important;
fill-opacity: 0.2 !important;
}
.highlight-todo.djs-shape .djs-visual > :nth-child(1) {
fill: orange !important;
stroke: orange !important;
stroke-dasharray: 4px !important;
fill-opacity: 0.2 !important;
}
.overlays-div {
font-size: 10px;
color: red;
width: 100px;
top: -20px !important;
}
}
</style>

@ -0,0 +1,753 @@
<template>
<div class="app-container">
<el-card class="box-card" >
<div slot="header" class="clearfix">
<span class="el-icon-document">基础信息</span>
<el-button style="float: right;" type="primary" @click="goBack"></el-button>
</div>
<!--流程处理表单模块-->
<el-col :span="24" v-if="variableOpen">
<div>
<el-form ref="form" :model="form" :rules="rules" label-width="100px" :disabled="true">
<el-form-item label="所属项目">
<el-select v-model="form.projectId"
clearable
filterable
placeholder="请选择">
<el-option
v-for="(item,index) in projectList"
:key="index"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="项目问题">
<el-input type="textarea" v-model="form.issue"/>
</el-form-item>
<el-form-item label="解决方案">
<el-input type="textarea" v-model="form.solution"/>
</el-form-item>
<el-form-item label="工作记录">
<el-input type="textarea" v-model="form.workRecord"/>
</el-form-item>
<el-form-item label="图片上传" prop="remark">
<el-upload
class="upload-demo"
action="https://jsonplaceholder.typicode.com/posts/"
:on-preview="handlePreview"
:on-remove="handleRemove"
:file-list="fileList">
<el-button size="small" type="primary">点击上传</el-button>
<div slot="tip" class="el-upload__tip">只能上传jpg/png文件且不超过500kb</div>
</el-upload>
</el-form-item>
<el-form-item label="文件上传" prop="remark">
<el-upload
class="upload-demo"
action="https://jsonplaceholder.typicode.com/posts/"
:on-preview="handlePreview"
:on-remove="handleRemove"
multiple
:limit="3"
:file-list="fileList">
<el-button size="small" type="primary">点击上传</el-button>
<div slot="tip" class="el-upload__tip">只能上传jpg/png文件且不超过500kb</div>
</el-upload>
</el-form-item>
</el-form>
</div>
<div style="margin-left:10%;margin-bottom: 20px;font-size: 14px;" v-if="finished === 'true'">
<el-button icon="el-icon-edit-outline" type="success" size="mini" @click="handleComplete"></el-button>
<!-- <el-button icon="el-icon-edit-outline" type="primary" size="mini" @click="handleDelegate"></el-button>-->
<!-- <el-button icon="el-icon-edit-outline" type="primary" size="mini" @click="handleAssign"></el-button>-->
<!-- <el-button icon="el-icon-edit-outline" type="primary" size="mini" @click="handleDelegate"></el-button>-->
<!-- <el-button icon="el-icon-refresh-left" type="warning" size="mini" @click="handleReturn">退</el-button>-->
<el-button icon="el-icon-circle-close" type="danger" size="mini" @click="handleReject"></el-button>
</div>
</el-col>
<!--初始化流程加载表单信息-->
<el-col :span="24" v-if="formConfOpen" >
<div class="test-form">
<el-form ref="form" :model="form" :rules="rules" label-width="100px" :disabled=!applyIsRevoked>
<el-form-item label="所属项目">
<el-select v-model="form.projectId"
clearable
filterable
placeholder="请选择">
<el-option
v-for="(item,index) in projectList"
:key="index"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="项目问题">
<el-input type="textarea" v-model="form.issue"/>
</el-form-item>
<el-form-item label="解决方案">
<el-input type="textarea" v-model="form.solution"/>
</el-form-item>
<el-form-item label="工作记录">
<el-input type="textarea" v-model="form.workRecord"/>
</el-form-item>
<el-form-item label="图片上传" prop="remark">
<el-upload
class="upload-demo"
action="https://jsonplaceholder.typicode.com/posts/"
:on-preview="handlePreview"
:on-remove="handleRemove"
:file-list="fileList">
<el-button size="small" type="primary">点击上传</el-button>
<div slot="tip" class="el-upload__tip">只能上传jpg/png文件且不超过500kb</div>
</el-upload>
</el-form-item>
<el-form-item label="文件上传" prop="remark">
<el-upload
class="upload-demo"
action="https://jsonplaceholder.typicode.com/posts/"
:on-preview="handlePreview"
:on-remove="handleRemove"
multiple
:limit="3"
:file-list="fileList">
<el-button size="small" type="primary">点击上传</el-button>
<div slot="tip" class="el-upload__tip">只能上传jpg/png文件且不超过500kb</div>
</el-upload>
</el-form-item>
</el-form>
</div>
<div style="margin-left:10%;margin-bottom: 20px;font-size: 14px;" v-if=applyIsRevoked>
<el-button icon="el-icon-edit-outline" type="success" size="mini" @click="handleClaimAndComplete"></el-button>
</div>
</el-col>
</el-card>
<!--流程流转记录-->
<el-card class="box-card" v-if="flowRecordList">
<div slot="header" class="clearfix">
<span class="el-icon-notebook-1">审批记录</span>
</div>
<el-col :span="24" >
<div class="block">
<el-timeline>
<el-timeline-item
v-for="(item,index ) in flowRecordList"
:key="index"
:icon="setIcon(item.finishTime)"
:color="setColor(item.finishTime)"
>
<p style="font-weight: 700">{{item.taskName}}</p>
<el-card :body-style="{ padding: '10px' }">
<el-descriptions class="margin-top" :column="1" size="small" border>
<el-descriptions-item v-if="item.assigneeName" label-class-name="my-label">
<template slot="label"><i class="el-icon-user"></i>实际办理</template>
{{item.assigneeName}}
<el-tag type="info" size="mini">{{item.deptName}}</el-tag>
</el-descriptions-item>
<el-descriptions-item v-if="item.candidate" label-class-name="my-label">
<template slot="label"><i class="el-icon-user"></i>候选办理</template>
{{item.candidate}}
</el-descriptions-item>
<!-- <el-descriptions-item label-class-name="my-label">-->
<!-- <template slot="label"><i class="el-icon-date"></i>接收时间</template>-->
<!-- {{item.createTime}}-->
<!-- </el-descriptions-item>-->
<el-descriptions-item v-if="item.finishTime" label-class-name="my-label">
<template slot="label"><i class="el-icon-date"></i>处理时间</template>
<span v-if="form.submitDate !==undefined && form.submitDate !==''&& form.submitDate !==null">{{form.submitDate}}</span>
<span v-else>{{item.finishTime}}</span>
</el-descriptions-item>
<!-- <el-descriptions-item v-if="item.duration" label-class-name="my-label">-->
<!-- <template slot="label"><i class="el-icon-time"></i>耗时</template>-->
<!-- {{item.duration}}-->
<!-- </el-descriptions-item>-->
<el-descriptions-item v-if="item.comment" label-class-name="my-label">
<template slot="label"><i class="el-icon-tickets"></i>处理意见</template>
{{item.comment.comment}}
</el-descriptions-item>
</el-descriptions>
<!-- <p v-if="item.comment">-->
<!-- <el-tag type="success" v-if="item.comment.type === '1'"> {{item.comment.comment}}</el-tag>-->
<!-- <el-tag type="warning" v-if="item.comment.type === '2'"> {{item.comment.comment}}</el-tag>-->
<!-- <el-tag type="danger" v-if="item.comment.type === '3'"> {{item.comment.comment}}</el-tag>-->
<!-- </p>-->
</el-card>
</el-timeline-item>
</el-timeline>
</div>
</el-col>
</el-card>
<!-- <el-card class="box-card">-->
<!-- <div slot="header" class="clearfix">-->
<!-- <span class="el-icon-picture-outline">流程图</span>-->
<!-- </div>-->
<!-- <flow :xmlData="xmlData" :taskData="taskList"></flow>-->
<!-- </el-card>-->
<!--审批正常流程-->
<el-dialog :title="completeTitle" :visible.sync="completeOpen" :width="checkSendUser? '80%':'80%'" append-to-body>
<el-form ref="taskForm" :model="taskForm" label-width="80px" >
<el-form-item v-if="checkSendUser" prop="targetKey">
<el-row :gutter="20">
<!--部门数据-->
<el-col :span="6" :xs="24">
<h6>部门列表</h6>
<div class="head-container">
<el-input
v-model="deptName"
placeholder="请输入部门名称"
clearable
size="small"
prefix-icon="el-icon-search"
style="margin-bottom: 20px"
/>
</div>
<div class="head-container">
<el-tree
:data="deptOptions"
:props="defaultProps"
:expand-on-click-node="false"
:filter-node-method="filterNode"
ref="tree"
default-expand-all
@node-click="handleNodeClick"
/>
</div>
</el-col>
<el-col :span="10" :xs="24">
<h6>待选人员</h6>
<el-table
ref="singleTable"
:data="userList"
border
style="width: 100%"
@selection-change="handleSelectionChange">
<el-table-column type="selection" width="50" align="center" />
<el-table-column label="用户名" align="center" prop="nickName" />
<el-table-column label="部门" align="center" prop="dept.deptName" />
</el-table>
</el-col>
<el-col :span="8" :xs="24">
<h6>已选人员</h6>
<el-tag
v-for="(user,index) in userData"
:key="index"
closable
@close="handleClose(user)">
{{user.nickName}} {{user.dept.deptName}}
</el-tag>
</el-col>
</el-row>
</el-form-item>
<el-form-item label="处理意见" prop="comment" :rules="[{ required: true, message: '请输入处理意见', trigger: 'blur' }]">
<el-input type="textarea" v-model="taskForm.comment" placeholder="请输入处理意见"/>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="completeOpen = false"> </el-button>
<el-button type="primary" @click="taskComplete"> </el-button>
</span>
</el-dialog>
<!--退回流程-->
<el-dialog :title="returnTitle" :visible.sync="returnOpen" width="80%" append-to-body>
<el-form ref="taskForm" :model="taskForm" label-width="80px" >
<el-form-item label="退回节点" prop="targetKey">
<el-radio-group v-model="taskForm.targetKey">
<el-radio-button
v-for="item in returnTaskList"
:key="item.id"
:label="item.id"
>{{item.name}}</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="退回意见" prop="comment" :rules="[{ required: true, message: '请输入意见', trigger: 'blur' }]">
<el-input style="width: 50%" type="textarea" v-model="taskForm.comment" placeholder="请输入意见"/>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="returnOpen = false"> </el-button>
<el-button type="primary" @click="taskReturn"> </el-button>
</span>
</el-dialog>
<!--驳回流程-->
<el-dialog :title="rejectTitle" :visible.sync="rejectOpen" width="80%" append-to-body>
<el-form ref="taskForm" :model="taskForm" label-width="80px" >
<el-form-item label="驳回意见" prop="comment" :rules="[{ required: true, message: '请输入意见', trigger: 'blur' }]">
<el-input style="width: 50%" type="textarea" v-model="taskForm.comment" placeholder="请输入意见"/>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="rejectOpen = false"> </el-button>
<el-button type="primary" @click="taskReject"> </el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import {flowRecord} from "@/api/flowable/finished";
import Parser from '@/components/parser/Parser'
import {definitionStart, getProcessVariables, readXml, getFlowViewer} from "@/api/flowable/definition";
import {complete, rejectTask, returnList, returnTask, getNextFlowNode, delegate} from "@/api/flowable/todo";
import flow from '@/views/h5/h5record/flow'
import {treeselect} from "@/api/system/dept";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
import Treeselect from "@riophae/vue-treeselect";
import {listUser} from "@/api/system/user";
import {optionProject} from "@/api/system/project";
export default {
name: "H5Record",
components: {
Parser,
flow,
Treeselect
},
props: {},
data() {
return {
// xml
xmlData: "",
taskList: [],
//
deptName: undefined,
//
deptOptions: undefined,
//
userList: null,
defaultProps: {
children: "children",
label: "label"
},
//
queryParams: {
deptId: undefined
},
//
loading: true,
applyIsRevoked: false,
flowRecordList: [], //
formConfCopy: {},
src: null,
rules: {}, //
variablesForm: {}, //
taskForm:{
returnTaskShow: false, // 退
delegateTaskShow: false, // 退
defaultTaskShow: true, //
sendUserShow: false, //
multiple: false,
comment:"", //
procInsId: "", //
instanceId: "", //
deployId: "", //
taskId: "" ,//
procDefId: "", //
vars: "",
targetKey:""
},
userDataList:[], //
assignee: null,
formConf: {}, //
formConfOpen: false, //
variables: [], //
variablesData: {}, //
variableOpen: false, //
//
form: {
projectId: 0,
workRecord: '',
issue: '',
submitDate: '',
solution: '',
},
fileList: [],
projectList: [],
returnTaskList: [], // 退
finished: 'false',
completeTitle: null,
completeOpen: false,
returnTitle: null,
returnOpen: false,
rejectOpen: false,
rejectTitle: null,
userData:[],
checkSendUser: false //
};
},
created() {
this.taskForm.deployId = this.$route.query && this.$route.query.deployId;
this.taskForm.taskId = this.$route.query && this.$route.query.taskId;
this.taskForm.procInsId = this.$route.query && this.$route.query.procInsId;
this.taskForm.executionId = this.$route.query && this.$route.query.executionId;
this.taskForm.instanceId = this.$route.query && this.$route.query.procInsId;
//
this.taskForm.procDefId = this.$route.query && this.$route.query.procDefId;
//
this.getFlowViewer(this.taskForm.procInsId,this.taskForm.executionId);
this.getModelDetail(this.taskForm.deployId);
//
if (this.taskForm.taskId){
this.processVariables( this.taskForm.taskId)
this.getNextFlowNode(this.taskForm.taskId)
this.taskForm.deployId = null
}
this.optionList();
this.getFlowRecordList( this.taskForm.procInsId, this.taskForm.deployId);
this.finished = this.$route.query && this.$route.query.finished
},
methods: {
/** 查询部门下拉树结构 */
getTreeselect() {
treeselect().then(response => {
this.deptOptions = response.data;
});
},
/** 查询用户列表 */
getList() {
listUser(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
this.userList = response.rows;
this.total = response.total;
}
);
},
//
filterNode(value, data) {
if (!value) return true;
return data.label.indexOf(value) !== -1;
},
//
handleNodeClick(data) {
this.queryParams.deptId = data.id;
this.getList();
},
/** xml 文件 */
getModelDetail(deployId) {
// xml
readXml(deployId).then(res => {
this.xmlData = res.data
})
},
getFlowViewer(procInsId,executionId) {
getFlowViewer(procInsId,executionId).then(res => {
this.taskList = res.data
})
},
setIcon(val) {
if (val) {
return "el-icon-check";
} else {
return "el-icon-time";
}
},
setColor(val) {
if (val) {
return "#2bc418";
} else {
return "#b3bdbb";
}
},
//
handleSelectionChange(selection) {
if (selection) {
this.userData = selection
const selectVal = selection.map(item => item.userId);
if (selectVal instanceof Array) {
this.taskForm.values = {
"approval": selectVal.join(',')
}
} else {
this.taskForm.values = {
"approval": selectVal
}
}
}
},
//
handleClose(tag) {
this.userData.splice(this.userData.indexOf(tag), 1);
this.$refs.singleTable.toggleRowSelection(tag, false)
},
/** 流程变量赋值 */
handleCheckChange(val) {
if (val instanceof Array) {
this.taskForm.values = {
"approval": val.join(',')
}
} else {
this.taskForm.values = {
"approval": val
}
}
},
/** 流程流转记录 */
getFlowRecordList(procInsId, deployId) {
const params = {procInsId: procInsId, deployId: deployId}
flowRecord(params).then(res => {
this.flowRecordList = res.data.flowList;
//
// if (res.data.formData) {
this.form = res.data.form;
console.log("res.data.form;", res.data.form)
console.log("this.form ", this.form)
if (this.taskForm.executionId === undefined) {
this.formConfOpen = true
if (this.flowRecordList && this.flowRecordList.length !== 0) {
console.log("this.flowRecordList[0]", this.flowRecordList[0])
this.applyIsRevoked = this.flowRecordList[0].taskName === '提交汇报';
console.log("applyIsRevoked", this.applyIsRevoked)
}
}
// }
}).catch(res => {
this.goBack();
})
},
fillFormData(form, data) {
form.fields.forEach(item => {
const val = data[item.__vModel__]
if (val) {
item.__config__.defaultValue = val
}
})
},
/** 获取流程变量内容 */
processVariables(taskId) {
if (taskId) {
//
getProcessVariables(taskId).then(res => {
// this.variables = res.data.variables;
this.form = res.data;
this.variableOpen = true
});
}
},
/** 查询项目列表 */
optionList() {
this.loading = true;
optionProject().then(response => {
this.projectList = response.data;
this.loading = false;
});
},
/** 根据当前任务或者流程设计配置的下一步节点 */
getNextFlowNode(taskId) {
// todo
const params = {taskId: taskId}
getNextFlowNode(params).then(res => {
const data = res.data;
if (data) {
this.checkSendUser = true
if (data.type === 'assignee') { //
this.userDataList = res.data.userList;
} else if (data.type === 'candidateUsers') { // ()
this.userDataList = res.data.userList;
this.taskForm.multiple = true;
} else if (data.type === 'candidateGroups') { // ()
res.data.roleList.forEach(role => {
role.userId = role.roleId;
role.nickName = role.roleName;
})
this.userDataList = res.data.roleList;
this.taskForm.multiple = false;
} else if (data.type === 'multiInstance') { // ?
this.userDataList = res.data.userList;
this.taskForm.multiple = true;
}else if (data.type === 'fixed') { //
this.checkSendUser = false;
}
}
})
},
/** 审批任务选择 */
handleComplete() {
this.completeOpen = true;
this.completeTitle = "审批流程";
this.getTreeselect();
}, /** 确认并提交任务选择 */
handleClaimAndComplete() {
this.taskForm.comment = '提交任务';
this.taskForm.vars= JSON.stringify(this.form)
this.taskForm.taskId= this.flowRecordList[0].taskId
complete(this.taskForm).then(response => {
this.msgSuccess(response.msg);
this.goBack();
});
},
/** 审批任务 */
taskComplete() {
if (!this.taskForm.values && this.checkSendUser){
this.msgError("请选择流程接收人员");
return;
}
if (!this.taskForm.comment){
this.msgError("请输入审批意见");
return;
}
complete(this.taskForm).then(response => {
this.msgSuccess(response.msg);
this.goBack();
});
},
/** 委派任务 */
handleDelegate() {
this.taskForm.delegateTaskShow = true;
this.taskForm.defaultTaskShow = false;
},
handleAssign(){
},
/** 返回页面 */
goBack() {
//
this.$store.dispatch("tagsView/delView", this.$route);
this.$router.go(-1)
},
/** 接收子组件传的值 */
getData(data) {
if (data) {
const variables = [];
data.fields.forEach(item => {
let variableData = {};
variableData.label = item.__config__.label
//
if (item.__config__.defaultValue instanceof Array) {
const array = [];
item.__config__.defaultValue.forEach(val => {
array.push(val)
})
variableData.val = array;
} else {
variableData.val = item.__config__.defaultValue
}
variables.push(variableData)
})
this.variables = variables;
}
},
/** 申请流程表单数据提交 */
submitForm(data) {
if (data) {
const variables = data.valData;
const formData = data.formData;
formData.disabled = true;
formData.formBtns = false;
if (this.taskForm.procDefId) {
variables.variables = formData;
//
definitionStart(this.taskForm.procDefId, JSON.stringify(variables)).then(res => {
this.msgSuccess(res.msg);
this.goBack();
})
}
}
},
/** 驳回任务 */
handleReject() {
this.rejectOpen = true;
this.rejectTitle = "驳回流程";
},
/** 驳回任务 */
taskReject() {
this.$refs["taskForm"].validate(valid => {
if (valid) {
rejectTask(this.taskForm).then(res => {
this.msgSuccess(res.msg);
this.goBack();
});
}
});
},
/** 可退回任务列表 */
handleReturn() {
this.returnOpen = true;
this.returnTitle = "退回流程";
returnList(this.taskForm).then(res => {
this.returnTaskList = res.data;
this.taskForm.values = null;
})
},
/** 提交退回任务 */
taskReturn() {
this.$refs["taskForm"].validate(valid => {
if (valid) {
returnTask(this.taskForm).then(res => {
this.msgSuccess(res.msg);
this.goBack()
});
}
});
},
/** 取消回退任务按钮 */
cancelTask() {
this.taskForm.returnTaskShow = false;
this.taskForm.defaultTaskShow = true;
this.taskForm.sendUserShow = true;
this.returnTaskList = [];
},
/** 委派任务 */
submitDeleteTask() {
this.$refs["taskForm"].validate(valid => {
if (valid) {
delegate(this.taskForm).then(response => {
this.msgSuccess(response.msg);
this.goBack();
});
}
});
},
/** 取消回退任务按钮 */
cancelDelegateTask() {
this.taskForm.delegateTaskShow = false;
this.taskForm.defaultTaskShow = true;
this.taskForm.sendUserShow = true;
this.returnTaskList = [];
},
handleRemove(file, fileList) {
console.log(file, fileList);
},
handlePreview(file) {
console.log(file);
}
}
};
</script>
<style lang="scss" scoped>
.test-form {
margin: 15px auto;
width: 800px;
padding: 15px;
}
.clearfix:before,
.clearfix:after {
display: table;
content: "";
}
.clearfix:after {
clear: both
}
.box-card {
width: 100%;
margin-bottom: 20px;
}
.el-tag + .el-tag {
margin-left: 10px;
}
.my-label {
background: #E1F3D8;
}
.dialog-footer {
width: 80%;
}
</style>

@ -1,6 +1,6 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
<el-form :model="queryParams" ref="queryForm" v-show="showSearch" label-width="75px">
<el-form-item label="名称" prop="name">
<el-input
v-model="queryParams.name"
@ -41,21 +41,6 @@
</el-row>
<el-table v-loading="loading" :data="todoList" border @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center"/>
<el-table-column label="任务编号" align="center" prop="taskId" :show-overflow-tooltip="true"/>
<el-table-column label="流程名称" align="center" prop="procDefName"/>
<el-table-column label="任务节点" align="center" prop="taskName"/>
<el-table-column label="流程版本" align="center">
<template slot-scope="scope">
<el-tag size="medium" >v{{scope.row.procDefVersion}}</el-tag>
</template>
</el-table-column>
<el-table-column label="流程发起人" align="center">
<template slot-scope="scope">
<label>{{scope.row.startUserName}} <el-tag type="info" size="mini">{{scope.row.startDeptName}}</el-tag></label>
</template>
</el-table-column>
<el-table-column label="接收时间" align="center" prop="createTime" width="180"/>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button
@ -67,6 +52,23 @@
</el-button>
</template>
</el-table-column>
<el-table-column label="流程发起人" align="center">
<template slot-scope="scope">
<label>{{scope.row.startUserName}} <el-tag type="info" size="mini">{{scope.row.startDeptName}}</el-tag></label>
</template>
</el-table-column>
<el-table-column label="接收时间" align="center" prop="createTime" width="180"/>
<!-- <el-table-column type="selection" width="55" align="center"/>-->
<el-table-column label="任务编号" align="center" prop="taskId" :show-overflow-tooltip="true"/>
<!-- <el-table-column label="流程名称" align="center" prop="procDefName"/>-->
<el-table-column label="任务节点" align="center" prop="taskName"/>
<!-- <el-table-column label="流程版本" align="center">-->
<!-- <template slot-scope="scope">-->
<!-- <el-tag size="medium" >v{{scope.row.procDefVersion}}</el-tag>-->
<!-- </template>-->
<!-- </el-table-column>-->
</el-table>
<pagination
@ -142,7 +144,7 @@ export default {
},
//
handleProcess(row){
this.$router.push({ path: '/flowable/task/record/index',
this.$router.push({ path: '/h5record',
query: {
procInsId: row.procInsId,
executionId: row.executionId,

@ -127,7 +127,7 @@ export default {
Cookies.remove('rememberMe');
}
this.$store.dispatch("Login", this.loginForm).then(() => {
this.$router.push({ path: this.redirect || "/" }).catch(()=>{});
this.$router.push({ path: this.redirect || "/h5todo" }).catch(()=>{});
}).catch(() => {
this.loading = false;
this.getCode();

@ -114,35 +114,5 @@ module.exports = {
}
}
)
},
// vue 兼容h5样式配置
css: {
// loaderOptions: {
// sass: {
// additionalData: `@import "~@/base.scss";`
// },
// postcss: {
// plugins: [
// require('autoprefixer')({ overrideBrowserslist: ['Android 4.1', 'iOS 7.1', 'Chrome > 31', 'ff > 31', 'ie >= 8'] }),
// require('postcss-px-to-viewport')({
// unitToConvert: 'px',
// viewportWidth: 7500,
// unitPrecision: 5,
// propList: ['*', '!max-width'],
// viewportUnit: 'rem',
// fontViewportUnit: 'rem',
// selectorBlackList: ['html'],
// minPixelValue: 1,
// mediaQuery: false,
// replace: true,
// // exclude: [/node_modules/],
// include: [''],
// landscape: false,
// landscapeUnit: 'vw',
// landscapeWidth: 568
// })
// ]
// }
// }
}
}

Loading…
Cancel
Save