目录代码整合

This commit is contained in:
aixianling
2022-05-10 20:02:37 +08:00
parent 71049f7f65
commit 036ee91533
324 changed files with 4 additions and 8321 deletions

View File

@@ -0,0 +1,66 @@
<template>
<div class="doc-circulation ailist-wrapper">
<keep-alive :include="['List']">
<component ref="component" :is="component" @change="onChange" :params="params" :instance="instance" :dict="dict"></component>
</keep-alive>
</div>
</template>
<script>
import List from './components/List'
import Add from './components/Add'
export default {
name: 'AppApprover',
label: '审批负责人',
props: {
instance: Function,
dict: Object
},
data () {
return {
component: 'List',
params: {},
include: []
}
},
components: {
List,
Add
},
mounted () {
},
methods: {
onChange (data) {
if (data.type === 'Add') {
this.component = 'Add'
this.params = data.params
}
if (data.type === 'List') {
this.component = 'List'
this.params = data.params
this.$nextTick(() => {
if (data.isRefresh) {
this.$refs.component.getList()
}
})
}
}
}
}
</script>
<style lang="scss">
.doc-circulation {
height: 100%;
background: #F3F6F9;
overflow: auto;
}
</style>

View File

@@ -0,0 +1,125 @@
<template>
<ai-detail>
<template slot="title">
<ai-title :title="params.id ? '编辑审批负责人' : '添加审批负责人'" isShowBack isShowBottomBorder @onBackClick="cancel(false)">
</ai-title>
</template>
<template slot="content">
<ai-card title="基本信息">
<template #content>
<el-form ref="form" class="ai-form" :model="form" label-width="110px" label-position="right">
<el-form-item label="角色说明" style="width: 100%;" prop="">
<p style="color: red">网格员上报疑似风险/建议解除风险对象信息后需管理员确认纳入监测对象或解除风险</p>
</el-form-item>
<el-form-item label="姓名" prop="name" :rules="[{ required: true, message: '请选择人员', trigger: 'blur' }]">
<el-input disabled :value="form.name" size="small" placeholder="请选择人员">
<template slot="append">
<ai-wechat-selecter refs="addTags" :instance="instance" v-model="users" @change="onChooseUser">
<el-button size="small">选择人员</el-button>
</ai-wechat-selecter>
</template>
</el-input>
</el-form-item>
<el-form-item style="width: 100%!important;" label="所在地区" prop="areaId" :rules="[{ required: true, message: '请选择所在地区', trigger: 'change' }]">
<ai-area-select
v-model="form.areaId"
always-show
:instance="instance"
clearable
@fullname="v=>form.areaName = v"
:disabledLevel="disabledLevel"/>
</el-form-item>
</el-form>
</template>
</ai-card>
</template>
<template #footer>
<el-button @click="cancel">取消</el-button>
<el-button type="primary" @click="confirm">提交</el-button>
</template>
</ai-detail>
</template>
<script>
import { mapState } from 'vuex'
export default {
name: 'Add',
props: {
instance: Function,
dict: Object,
params: Object
},
data () {
return {
info: {},
users: [],
form: {
name: '',
areaName: '',
areaId: ''
},
id: '',
disabledLevel: 3
}
},
computed: {
...mapState(['user'])
},
created () {
this.form.areaName = this.user.info.areaName
this.form.areaId = this.user.info.areaId
this.disabledLevel = this.user.info.areaList.length
if (this.params && this.params.id) {
this.id = this.params.id
this.getInfo(this.params.id)
}
},
methods: {
getInfo (id) {
this.instance.post(`/app/apppreventionreturntopovertyriskperson/queryDetailById?id=${id}`).then(res => {
if (res.code === 0) {
this.form = {
...res.data
}
}
})
},
onChooseUser (v) {
},
confirm () {
this.$refs.form.validate((valid) => {
if (valid) {
this.instance.post(`/app/apppreventionreturntopovertyriskperson/addOrUpdate`, {
...this.form
}).then(res => {
if (res.code == 0) {
this.$message.success('提交成功')
setTimeout(() => {
this.cancel(true)
}, 600)
}
})
}
})
},
cancel (isRefresh) {
this.$emit('change', {
type: 'List',
isRefresh: !!isRefresh
})
}
}
}
</script>
<style scoped lang="scss">
</style>

View File

@@ -0,0 +1,140 @@
<template>
<ai-list class="notice">
<template slot="title">
<ai-title title="审批负责人" isShowBottomBorder :isShowArea="true" v-model="search.areaId" :instance="instance" @change="getList"></ai-title>
</template>
<template slot="content">
<ai-search-bar>
<template #left>
<el-button icon="iconfont iconAdd" type="primary" size="small" @click="toAdd('')">添加 </el-button>
</template>
<template #right>
<el-input
v-model="search.name"
size="small"
placeholder="审批负责人"
clearable
v-throttle="() => {search.current = 1, getList()}"
@clear="search.current = 1, search.name = '', getList()"
suffix-icon="iconfont iconSearch">
</el-input>
</template>
</ai-search-bar>
<ai-table
:tableData="tableData"
:col-configs="colConfigs"
:total="total"
style="margin-top: 12px;"
:current.sync="search.current"
:size.sync="search.size"
@selection-change="(v) => (ids = v.map((e) => e.id))"
@getList="getList">
<el-table-column slot="options" width="90px" fixed="right" label="操作" align="center">
<div class="table-options" slot-scope="{ row }">
<el-button type="text" @click="toAdd(row.id)">编辑</el-button>
<el-button type="text" @click="remove(row.id)">删除</el-button>
</div>
</el-table-column>
</ai-table>
</template>
</ai-list>
</template>
<script>
import { mapState } from 'vuex'
export default {
name: 'List',
props: {
instance: Function,
dict: Object
},
data() {
return {
search: {
current: 1,
size: 10,
title: '',
areaId: ''
},
ids: [],
total: 10,
tableData: []
}
},
computed: {
...mapState(['user']),
colConfigs () {
return [
{ prop: 'title', label: '审批负责人', align: 'left' },
{ prop: 'createUserName', label: '所属地区', align: 'center' },
{ prop: 'createTime', label: '操作时间', align: 'center' },
{ prop: 'createTime', label: '操作人', align: 'center' },
{ slot: 'options', label: '操作' }
]
}
},
created () {
this.search.areaId = this.user.info.areaId
this.dict.load('epidemicRecentTestResult').then(() => {
this.getList()
})
},
methods: {
getList() {
this.instance.post(`/app/appmininotice/list`, null, {
params: {
...this.search
}
}).then(res => {
if (res.code == 0) {
this.tableData = res.data.records
this.total = res.data.total
}
})
},
removeAll () {
var id = this.ids.join(',')
this.remove(id)
},
remove(id) {
this.$confirm('确定删除该数据?').then(() => {
this.instance.post(`/app/appmininotice/delete?ids=${id}`).then(res => {
if (res.code == 0) {
this.$message.success('删除成功!')
this.getList()
}
})
})
},
toDetail (id) {
this.$emit('change', {
type: 'Detail',
params: {
id: id || ''
}
})
},
toAdd(id) {
this.$emit('change', {
type: 'Add',
params: {
id: id || ''
}
})
}
}
}
</script>
<style lang="scss" scoped>
</style>

View File

@@ -0,0 +1,113 @@
<template>
<ai-list v-if="!isShowDetail">
<template slot="title">
<ai-title title="问卷表单" :isShowBottomBorder="false" :instance="instance" :isShowArea="currIndex === '0'" v-model="areaId" @change="changeArea"></ai-title>
</template>
<template slot="tabs">
<el-tabs v-model="currIndex">
<el-tab-pane v-for="(tab,i) in tabs" :key="i" :label="tab.label">
<component :areaId="areaId" :ref="tab.name" v-if="currIndex == i" :is="tab.comp" @change="onChange" lazy :instance="instance" :dict="dict" :permissions="permissions"/>
</el-tab-pane>
</el-tabs>
</template>
</ai-list>
<Add v-else-if="componentName === 'Add'" :areaId="areaId" :params="params" :instance="instance" :dict="dict" :permissions="permissions" @change="onChange"></Add>
<Statistics v-else-if="componentName === 'Statistics'" :areaId="areaId" :params="params" :instance="instance" :dict="dict" :permissions="permissions" @change="onChange"></Statistics>
</template>
<script>
import FormList from './components/FormList.vue'
import Template from './components/Template'
import Add from './components/Add'
import Statistics from './components/Statistics'
import { mapState } from 'vuex'
export default {
name: 'AppAskForm',
label: '问卷表单',
components: {
FormList,
Add,
Statistics,
Template
},
props: {
instance: Function,
dict: Object,
permissions: Function
},
computed: {
...mapState(['user']),
tabs () {
const tabList = [
{label: '表单列表', name: 'FormList', comp: FormList, permission: ''},
{label: '共享模板', name: 'Template', comp: Template, permission: ''}
].filter(item => {
return true
})
return tabList
}
},
data () {
return {
activeName: 'JoinEvent',
currIndex: '0',
componentName: '',
params: {},
areaId: '',
isShowDetail: false
}
},
created() {
this.areaId = this.user.info.areaId
},
methods: {
changeArea () {
this.$nextTick(() => {
this.$refs[this.tabs[Number(this.currIndex)].name][0].getList()
})
},
onChange (data) {
if (data.type === 'list') {
this.componentName = 'List'
this.isShowDetail = false
this.params = data.params
if (data.isQuote) {
this.currIndex = 0
}
}
if (data.type === 'detail') {
this.componentName = 'Detail'
this.isShowDetail = true
this.params = data.params
}
if (data.type === 'Statistics') {
this.componentName = 'Statistics'
this.isShowDetail = true
this.params = data.params
}
if (data.type === 'add') {
this.componentName = 'Add'
this.isShowDetail = true
this.params = data.params
}
}
}
}
</script>
<style lang="scss" scoped>
</style>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,761 @@
<template>
<ai-detail class="statistics">
<template slot="title">
<ai-title title="数据统计" isShowBack isShowBottomBorder @onBackClick="cancel(false)"></ai-title>
</template>
<template slot="content">
<ai-card title="表单信息">
<template #content>
<ai-wrapper label-width="90px">
<ai-info-item label="表单名称" :value="info.title" isLine></ai-info-item>
<ai-info-item label="发布状态"><span
:style="{color: dict.getColor('questionnaireStatus', info.status)}">已发布</span></ai-info-item>
<ai-info-item label="创建人" :value="info.createUserName"></ai-info-item>
<ai-info-item label="创建时间" :value="info.createTime"></ai-info-item>
<ai-info-item label="截止时间"
:value="info.periodValidityEndTime ? info.periodValidityEndTime : '永久有效'"></ai-info-item>
<ai-info-item label="提交次数限制" :value="info.commitType === '1' ? '限提交一次' : '不限次数' "></ai-info-item>
</ai-wrapper>
</template>
</ai-card>
<div class="statistics-wrapper">
<div class="statistics-wrapper__title">
<span :class="[currIndex === 0 ? 'active' : '']" @click="currIndex = 0">表单统计</span>
<span :class="[currIndex === 1 ? 'active' : '']" @click="currIndex = 1">居民统计</span>
</div>
<div class="statistics-wrapper__body">
<div v-show="currIndex === 0">
<div class="statistics-wrapper__body--info">
<span></span>
<i>{{ subjectList.length }}</i>
<span>其中</span>
<span v-for="(item, index) in fieldTypeCount" :key="index">
{{ mapType(item.field_type) }}<i>{{ item.c }}</i>{{ fieldTypeCount.length - 1 === index ? '' : '' }}
</span>
</div>
<div class="statistics-wrapper__body--list">
<div class="statistics-wrapper__body--item" v-for="(item, index) in subjectList" :key="index">
<div class="statistics-wrapper__body--top"
:style="{borderBottom: ['input', 'textarea', 'upload'].indexOf(item.type) > -1 ? 'none' : '1px solid #DDDDDD'}">
<div class="left">
<h2>{{ item.fieldName }}{{ item.fixedLabel }}</h2>
</div>
<div class="right">
<span></span>
<i>{{ fieldDataCount[`field_${index}`] }}</i>
<span>条数据</span>
</div>
</div>
<div class="statistics-wrapper__body--bottom"
v-if="['radio', 'checkbox', 'select'].indexOf(item.type) > -1">
<div class="statistics-wrapper__body--select" v-for="(item, i) in item.options" :key="i">
<div class="left">
<h2>{{ item.label }}</h2>
<span>{{ item.c || 0 }}</span>
</div>
<div class="right">
<div class="progress">
<div
:style="{width: `${(((item.c || 0) / fieldDataCount[`field_${index}`]) * 100).toFixed(2)}%`}"></div>
</div>
<i>{{ (((item.c || 0) / fieldDataCount[`field_${index}`]) * 100).toFixed(2) }}%</i>
</div>
</div>
</div>
</div>
</div>
</div>
<div v-show="currIndex === 1" style="padding: 16px;">
<ai-search-bar>
<template #right>
<el-input
v-model="search.name"
size="small"
placeholder="请输入居民名称或真实姓名"
clearable
v-throttle="() => {search.current = 1, getList()}"
@clear="search.current = 1, search.name = '', getList()"
suffix-icon="iconfont iconSearch">
</el-input>
</template>
</ai-search-bar>
<ai-table
class="detail-table__table"
:border="true"
style="margin-top: 4px;"
:tableData="tableData"
:col-configs="colConfigs"
:total="total"
:stripe="false"
:current.sync="search.current"
:size.sync="search.size"
@getList="getList">
<el-table-column slot="userinfo" label="居民" width="260px" align="left">
<template slot-scope="{ row }">
<div class="userinfo">
<img :src="row.avatarUrl || 'https://cdn.cunwuyun.cn/dvcp/h5/defaultAvatar.png'">
<!-- <h3>{{ row.nickName }}</h3> -->
<el-tooltip effect="dark"
:content="row.corpName ? row.nickName + '@' + row.corpFullName : row.nickName + ''"
placement="top">
<div class="userinfo-right__top">
<h3>{{ row.corpName ? row.nickName : row.nickName }}</h3>
<span class="ellipsis">{{ row.corpName ? '@' + row.corpName : '' }}</span>
</div>
</el-tooltip>
</div>
</template>
</el-table-column>
<el-table-column slot="tags" label="标签" align="center" width="240px">
<template slot-scope="{ row }">
<div class="table-tags" v-if="row.tagNames">
<el-tag type="info" v-for="(item, index) in row.tagNames.split(',')" size="medium" :key="index">
{{ item }}
</el-tag>
</div>
<span v-else></span>
</template>
</el-table-column>
<el-table-column slot="options" label="操作" align="center">
<template slot-scope="{ row }">
<div class="table-options">
<el-button type="text" @click="showForm(row.id)">查看表单</el-button>
</div>
</template>
</el-table-column>
</ai-table>
</div>
</div>
<ai-dialog
customFooter
:visible.sync="isShowForm"
@onConfirm="isShowForm = false"
width="800px"
title="表单">
<div class="middle-content form">
<div class="middle-content__wrapper">
<div>
<div class="left-item__item left-item__item--banner" key="banner" v-if="info.headPicture">
<img :src="info.headPicture">
</div>
<div class="left-item__item left-item__item--formname" key="title">
<h2>{{ info.title }}</h2>
</div>
<div class="left-item__item left-item__item--text" key="text">
<p>{{ info.tableExplain }}</p>
</div>
</div>
<div
class="left-item__item components-item"
v-for="(item, i) in targetList"
:key="i">
<div class="left-item__item--title">
<i :style="{opacity: item.required ? 1 : 0}">*</i>
<span>{{ i + 1 }}.</span>
<h2>{{ item.label }}</h2>
</div>
<div class="left-item__item--wrapper">
<template v-if="(item.type === 'radio')">
<div class="radio-item" v-for="(field, index) in item.options" :key="index">
<input type="radio" disabled :value="field.label" v-model="formInfo[`field_${i}`]"/>
<img :src="field.img[0].url" v-if="field.img.length">
<label>{{ field.label }}</label>
</div>
</template>
<template v-if="item.type === 'upload'">
<img style="width: 100%; height: 100%;" :src="formInfo[`field_${i}`]" v-if="formInfo[`field_${i}`]">
<div class="left-item__item--upload" v-else>
<span>图片</span>
</div>
</template>
<template v-if="item.type === 'select'">
<el-input resize="none" class="preview" type="textarea" style="color: #333" :placeholder="item.placeholder" v-model="formInfo[`field_${i}`]" disabled></el-input>
<!-- <span>{{ formInfo[`field_${i}`] }}</span> -->
<!-- <textarea :placeholder="item.placeholder" v-model="formInfo[`field_${i}`]" disabled></textarea> -->
<!-- <el-select placeholder="请选择" disabled v-model="formInfo[`field_${i}`]" style="width: 100%;">
<el-option
v-for="(item, index) in item.options"
:key="index"
:label="item.label"
:value="item.label">
</el-option>
</el-select> -->
</template>
<template v-if="(item.type === 'checkbox')">
<div class="radio-item" v-for="(field, index) in item.options" :key="index">
<input type="checkbox" disabled :value="field.label" v-model="formInfo[`field_${i}`]"/>
<img :src="field.img[0].url" v-if="field.img.length">
<label>{{ field.label }}</label>
</div>
</template>
<template v-if="(item.type === 'input')">
<div class="text-item">
<input :placeholder="item.placeholder" v-model="formInfo[`field_${i}`]" disabled>
</div>
</template>
<template v-if="(item.type === 'textarea')">
<div class="textarea-item" resize="none">
<textarea :placeholder="item.placeholder" v-model="formInfo[`field_${i}`]" disabled></textarea>
</div>
</template>
</div>
</div>
</div>
</div>
<template #footer>
<el-button @click="isShowForm = false">关闭</el-button>
</template>
</ai-dialog>
</div>
</template>
</ai-detail>
</template>
<script>
export default {
name: 'Statistics',
props: {
instance: Function,
dict: Object,
params: Object
},
data() {
return {
currIndex: 0,
search: {
name: '',
size: 10,
current: 1
},
info: {},
subjectList: [],
tableData: [],
total: 0,
form: {},
fieldTypeCount: [],
fieldValueDistribution: [],
fieldDataCount: {},
isShowForm: false,
targetList: [],
formInfo: {},
colConfigs: [
{slot: 'userinfo'},
{prop: 'residentName', label: '真实姓名', align: 'center', width: '100px'},
{prop: 'commitTime', label: '提交时间', align: 'center', width: '160px'},
{
prop: 'userType',
label: '微信类型',
align: 'center',
width: '100px',
formart: v => this.dict.getLabel('wxUserType', v)
},
{prop: 'wxUserNames', label: '所属员工', align: 'center', width: '100px'},
{slot: 'tags', label: '标签', align: 'center', width: '268px'},
{prop: 'totalScore', label: '分值', align: 'center'}
]
}
},
mounted() {
this.getInfo()
this.getFormInfo()
this.dict.load(['wxUserType']).then(() => {
this.getList()
})
},
methods: {
getList() {
this.instance.post(`/app/appquestionnairetemplate/statisticsResident?id=${this.params.id}`, null, {
params: {
...this.search
}
}).then(res => {
if (res.code == 0) {
this.tableData = res.data.records
this.total = res.data.total
}
})
},
showForm(id) {
this.instance.post(`/app/appquestionnairetemplate/queryDataInfoById?id=${this.params.id}&dataId=${id}`).then(res => {
if (res.code == 0) {
this.formInfo = res.data
this.targetList.forEach((item, index) => {
if (item.type === 'checkbox' && this.formInfo[`field_${index}`]) {
this.formInfo[`field_${index}`] = this.formInfo[`field_${index}`].split(',')
}
})
this.isShowForm = true
}
})
},
mapType(type) {
return {
upload: '上传图片',
input: '单行填空',
textarea: '多行填空',
radio: '单选',
checkbox: '多选',
select: '单下拉框'
}[type]
},
getFormInfo() {
this.instance.post(`/app/appquestionnairetemplate/statisticsTable?id=${this.params.id}`, null, {
params: {
...this.search
}
}).then(res => {
if (res.code == 0) {
this.fieldDataCount = res.data.fieldDataCount
this.fieldTypeCount = res.data.fieldTypeCount
this.fieldValueDistribution = res.data.fieldValueDistribution
this.subjectList = res.data.appQuestionnaireTemplate.fields.map((item, index) => {
const fieldInfo = JSON.parse(item.fieldInfo)
let options = fieldInfo.options
if (['radio', 'checkbox', 'select'].indexOf(item.fieldType) > -1) {
options = fieldInfo.options.map(v => {
res.data.fieldValueDistribution[`field_${index}`].forEach(info => {
if (info.fieldValue === v.label) {
v.c = info.c
}
})
return v
})
}
return {
...item,
...fieldInfo,
options
}
})
}
})
},
getInfo() {
this.instance.post(`/app/appquestionnairetemplate/queryDetailById?id=${this.params.id}`).then(res => {
if (res.code == 0) {
this.info = res.data
this.targetList = res.data.fields.map(item => {
return JSON.parse(item.fieldInfo)
})
}
})
},
cancel(isRefresh) {
this.$emit('change', {
type: 'list',
isRefresh: !!isRefresh
})
}
}
}
</script>
<style scoped lang="scss">
.statistics {
* {
box-sizing: border-box;
font-weight: normal;
font-style: normal;
}
.preview {
::v-deep .el-textarea.is-disabled, ::v-deep .el-textarea__inner {
color: #666 !important;
}
}
.form {
.left-item__item--banner {
img {
width: 100%;
height: 235px;
}
.config-item__banner {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
width: 100%;
height: 235px;
line-height: 1;
border: 1px dashed #bbb;
span {
margin-top: 4px;
color: #555555;
font-size: 14px;
}
i {
font-size: 30px;
color: #8899bb;
}
}
}
.left-item__item--formname {
margin: 16px 0 32px;
padding: 0 12px;
color: #333333;
font-size: 15px;
font-weight: normal;
text-align: center;
word-break: break-all;
}
.left-item__item--text {
line-height: 20px;
// margin-bottom: 48px;
padding: 0 12px 20px;
text-align: justify;
color: #666;
font-size: 14px;
word-break: break-all;
}
.components-item {
position: relative;
padding: 16px 16px;
.left-item__item--wrapper {
& > img {
max-width: 300px;
}
}
.left-item__item--upload {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
width: 120px;
height: 120px;
border-radius: 6px;
border: 1px dashed #bbb;
i {
font-size: 24px;
color: #8899bb;
}
span {
margin-top: 4px;
font-size: 12px;
color: #555;
}
}
.text-item {
input {
display: block;
width: 100%;
height: 40px;
border: none;
border-bottom: 1px solid #ddd;
&:focus {
outline: none;
}
&:disabled {
background: #fff;
}
}
}
.textarea-item {
textarea {
width: 100%;
height: 120px;
resize: none;
border: 1px solid #ddd;
padding: 10px;
&:focus {
outline: none;
}
&:disabled {
background: #fff;
}
}
}
.radio-item {
display: flex;
margin-bottom: 10px;
input {
position: relative;
top: 2px;
}
&:last-child {
margin-bottom: 0;
}
label {
margin-left: 10px;
}
img {
width: 60px;
margin-left: 10px;
}
}
}
.left-item__item--title {
display: flex;
margin-bottom: 10px;
i {
position: relative;
top: 3px;
margin-right: 5px;
color: #E22120;
}
span {
position: relative;
top: 3px;
}
h2 {
color: #333333;
font-size: 15px;
}
}
}
.table-tags {
.el-tag {
margin-right: 8px;
margin-bottom: 8px;
border: 1px solid #D0D4DC;
background: #F3F4F7;
border-radius: 4px;
font-size: 13px;
color: #222222;
&:last-child {
margin-right: 0;
}
}
}
h2, h3 {
margin: 0;
}
.userinfo {
display: flex;
align-items: center;
img {
width: 40px;
height: 40px;
margin-right: 8px;
border-radius: 2px;
}
h3 {
font-size: 14px;
font-weight: normal;
color: #222222;
}
.userinfo-right__top {
display: flex;
align-items: center;
margin-bottom: 10px;
cursor: pointer;
white-space: nowrap;
}
span {
padding-left: 8px;
color: #2EA222;
font-size: 14px;
white-space: nowrap;
}
}
.statistics-wrapper {
background: #FFFFFF;
box-shadow: 0 4px 6px -2px rgba(15, 15, 21, 0.15);
border-radius: 2px;
.statistics-wrapper__title {
display: flex;
align-items: center;
height: 56px;
padding: 0 16px;
border-bottom: 1px solid #EEEEEE;
span {
height: 56px;
line-height: 56px;
color: #888888;
font-size: 16px;
font-weight: 600;
cursor: pointer;
user-select: none;
border-bottom: 3px solid transparent;
&:first-child {
margin-right: 32px;
}
&.active {
color: #222222;
border-color: #2266FF;
}
}
}
.statistics-wrapper__body--list {
padding: 0 40px 20px;
.statistics-wrapper__body--item {
margin-bottom: 20px;
background: #FFFFFF;
border-radius: 4px;
border: 1px solid #DDDDDD;
}
.statistics-wrapper__body--bottom {
padding: 20px;
.statistics-wrapper__body--select {
display: flex;
align-items: center;
justify-content: space-between;
height: 48px;
& > div {
display: flex;
align-items: center;
}
.left {
h2 {
max-width: 384px;
margin-right: 10px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 12px;
color: #222222;
}
span {
color: #888888;
font-size: 12px;
}
}
.right {
i {
width: 50px;
text-align: right;
color: #2266FF;
font-size: 12px;
}
.progress {
position: relative;
width: 500px;
height: 8px;
margin-right: 10px;
background: #EEEEEE;
border-radius: 5px;
div {
position: absolute;
top: 0;
left: 0;
height: 8px;
background: #2266FF;
border-radius: 5px;
}
}
}
}
}
.statistics-wrapper__body--top {
display: flex;
justify-content: space-between;
align-items: center;
height: 70px;
padding: 0 20px;
background: #FFFFFF;
border-radius: 4px 4px 0 0;
border-bottom: 1px solid #DDDDDD;
& > div {
display: flex;
align-items: center;
font-size: 14px;
}
.left {
flex: 1;
h2 {
color: #222222;
font-size: 14px;
}
}
.right {
span {
color: #888888;
}
i {
color: #2266FF;
padding: 0 4px;
}
}
}
}
.statistics-wrapper__body--info {
display: flex;
align-items: center;
height: 70px;
line-height: 1;
padding: 0 40px;
color: #555555;
font-size: 14px;
i {
padding: 0 4px;
font-weight: 600;
font-style: normal;
color: #2266FF;
font-size: 14px;
}
}
}
}
</style>

View File

@@ -0,0 +1,282 @@
<template>
<ai-list class="template" isTabs>
<template slot="content">
<ai-search-bar bottomBorder>
<template #left>
<ai-select
v-model="search.type"
@change="search.current = 1, getList()"
placeholder="项目类型"
:selectList="$dict.getDict('questionnaireType')">
</ai-select>
</template>
<template #right>
<el-input
v-model="search.title"
size="small"
placeholder="请输入模板名称或创建人"
clearable
v-throttle="() => {search.current = 1, getList()}"
@clear="search.current = 1, search.title = '', getList()"
suffix-icon="iconfont iconSearch">
</el-input>
</template>
</ai-search-bar>
<ai-search-bar style="margin-top: 12px;">
<template #left>
<el-button type="primary" @click="isShow = true">新建模板</el-button>
</template>
</ai-search-bar>
<ai-table
:tableData="tableData"
:col-configs="colConfigs"
:total="total"
style="margin-top: 6px;"
:current.sync="search.current"
:size.sync="search.size"
@getList="getList">
<el-table-column slot="type" width="120px" label="项目类型" align="center">
<template slot-scope="{ row }">
<div class="tags-wrapper">
<span class="tags" :class="'type-' + row.type">{{ dict.getLabel('questionnaireType', row.type) }}</span>
</div>
</template>
</el-table-column>
<el-table-column slot="options" width="160px" fixed="right" label="操作" align="center">
<template slot-scope="{ row }">
<div class="table-options">
<el-button type="text" @click="toEdit(row.id, row.type)">编辑</el-button>
<el-button type="text" @click="quote(row.id, row.type)">引用</el-button>
<el-button type="text" @click="remove(row.id)">删除</el-button>
</div>
</template>
</el-table-column>
</ai-table>
<ai-dialog
:visible.sync="isShow"
width="800px"
title="请选择新建模板类型"
@onConfirm="onConfirm">
<div class="type-list">
<div class="type-item" @click="currIndex = 0" :class="[currIndex === 0 ? 'active' : '']">
<svg class="icon" aria-hidden="true">
<use xlink:href="#iconwenjuandiaocha"></use>
</svg>
<span>问卷调查</span>
</div>
<div class="type-item" @click="currIndex = 1" :class="[currIndex === 1 ? 'active' : '']">
<svg class="icon" aria-hidden="true">
<use xlink:href="#iconkaoshiceping"></use>
</svg>
<span>考试测评</span>
</div>
<div class="type-item" @click="currIndex = 2" :class="[currIndex === 2 ? 'active' : '']">
<svg class="icon" aria-hidden="true">
<use xlink:href="#iconbaomingdengji"></use>
</svg>
<span>报名登记</span>
</div>
<div class="type-item" @click="currIndex = 3" :class="[currIndex === 3 ? 'active' : '']">
<svg class="icon" aria-hidden="true">
<use xlink:href="#iconmanyidiaocha"></use>
</svg>
<span>满意调查</span>
</div>
<div class="type-item" @click="currIndex = 4" :class="[currIndex === 4 ? 'active' : '']">
<svg class="icon" aria-hidden="true">
<use xlink:href="#icontoupiaopingxuan"></use>
</svg>
<span>投票评选</span>
</div>
</div>
</ai-dialog>
</template>
</ai-list>
</template>
<script>
export default {
name: 'Template',
props: {
instance: Function,
dict: Object
},
data() {
return {
search: {
current: 1,
status: '',
type: '',
size: 10,
templateType: 1,
title: ''
},
currIndex: 0,
isShow: false,
total: 10,
colConfigs: [
{prop: 'title', label: '模板名称', align: 'left'},
{slot: 'type', label: '项目类型', align: 'center'},
{prop: 'quoteCount', label: '引用次数', align: 'center'},
{prop: 'createUserName', label: '创建人', align: 'center'},
{prop: 'createUnitName', label: '创建单位', align: 'center'},
{prop: 'createTime', label: '创建时间', align: 'center'}
],
tableData: []
}
},
mounted() {
this.getList()
},
methods: {
getList() {
this.instance.post(`/app/appquestionnairetemplate/list`, null, {
params: {
...this.search
}
}).then(res => {
if (res.code == 0) {
this.tableData = res.data.records
this.total = res.data.total
}
})
},
quote(id, type) {
this.$emit('change', {
type: 'add',
params: {
id,
type,
isQuote: true,
templateType: 0
}
})
},
remove(id) {
this.$confirm('确定删除该数据?').then(() => {
this.instance.post(`/app/appquestionnairetemplate/deleteShareTemplate?ids=${id}`).then(res => {
if (res.code == 0) {
this.$message.success('删除成功!')
this.getList()
}
})
})
},
toAdd(id) {
this.$emit('change', {
type: 'Add',
params: {
id
}
})
},
toEdit(id, type) {
this.$emit('change', {
type: 'add',
params: {
id,
type,
templateType: 1
}
})
},
onConfirm() {
this.$emit('change', {
type: 'add',
params: {
id: '',
templateType: 1,
type: this.currIndex
}
})
}
}
}
</script>
<style lang="scss" scoped>
.template {
.tags-wrapper {
display: flex;
justify-content: center;
}
.type-list {
display: flex;
align-items: center;
.type-item {
display: flex;
align-items: center;
justify-content: center;
width: 128px;
height: 64px;
margin-right: 20px;
background: #FFFFFF;
// box-shadow: 0px 4px 8px 0px rgba(0, 0, 0, 0.08);
border-radius: 2px;
cursor: pointer;
border: 1px solid #E4E8EF;
svg {
width: 24px;
height: 24px;
margin-right: 8px;
}
&.active {
border: 1px solid #2266FF;
}
&:last-child {
margin-right: 0;
}
}
}
.tags {
display: block;
width: 64px;
height: 24px;
line-height: 24px;
text-align: center;
border-radius: 4px;
font-size: 12px;
}
.type-0 {
color: #2266FF;
background: rgba(34, 102, 255, 0.1);
}
.type-1 {
color: rgba(34, 170, 153, 1);
background: rgba(34, 170, 153, 0.1);
}
.type-2 {
color: rgba(248, 180, 37, 1);
background: rgba(248, 180, 37, 0.1);
}
.type-3 {
color: rgba(102, 119, 187, 1);
background: rgba(102, 119, 187, 0.1);
}
.type-4 {
color: rgba(236, 68, 97, 1);
background: rgba(236, 68, 97, 0.1);
}
}
</style>

View File

@@ -0,0 +1,181 @@
export const components = [
{
type: 'options',
tips: '(可重复添加)',
label: '选项',
children: [
{
type: 'radio',
label: '单选',
fixedLabel: '单选',
value: '',
points: '',
icon: 'iconradio',
isShowPoints: false,
required: true,
hasAnswer: false,
answer: '',
pointType: '0',
pointDict: [
{
dictName: '此题有唯一答案和分值',
dictValue: '0'
},
{
dictName: '每个选项都有对应分值',
dictValue: '1'
}
],
options: [
{
label: '选项1',
value: '',
point: '',
img: []
},
{
label: '选项2',
value: '',
point: '',
img: []
}
],
title: ''
},
{
type: 'checkbox',
label: '多选',
fixedLabel: '多选',
points: '',
icon: 'iconcheck_box',
isShowPoints: false,
required: true,
hasAnswer: false,
answer: [],
value: [],
pointType: '0',
pointDict: [
{
dictName: '此题有唯一答案和分值',
dictValue: '0'
},
{
dictName: '每个选项都有对应分值',
dictValue: '1'
},
{
dictName: '答对几项得几分,答错不得分',
dictValue: '2'
}
],
options: [
{
label: '选项1',
value: '',
point: '',
img: []
},
{
label: '选项2',
point: '',
value: '',
img: []
}
],
title: ''
},
{
type: 'select',
label: '单下拉框',
fixedLabel: '单下拉框',
value: '',
points: '',
icon: 'iconSelect',
isShowPoints: false,
required: true,
hasAnswer: false,
answer: '',
pointType: '0',
pointDict: [
{
dictName: '此题有唯一答案和分值',
dictValue: '0'
},
{
dictName: '每个选项都有对应分值',
dictValue: '1'
}
],
options: [
{
label: '选项1',
value: '',
point: '',
img: []
},
{
label: '选项2',
value: '',
point: '',
img: []
}
],
title: ''
}
]
},
{
type: 'input',
tips: '(可重复添加)',
label: '填空',
children: [
{
type: 'input',
label: '单行填空',
fixedLabel: '单行填空',
value: '',
pointType: '0',
icon: 'icontext_box',
isShowPoints: false,
points: '',
required: true,
hasAnswer: false,
placeholder: '请输入...',
answer: ''
},
{
type: 'textarea',
label: '多行填空',
fixedLabel: '多行填空',
pointType: '0',
icon: 'icontext_area',
points: '',
isShowPoints: false,
required: true,
hasAnswer: false,
answer: '',
placeholder: '请输入...',
value: ''
}
]
},
{
type: 'annex',
tips: '(可重复添加)',
label: '附件',
children: [
{
type: 'upload',
label: '上传图片',
fixedLabel: '上传图片',
value: '',
icon: 'iconpic',
isShowPoints: false,
points: '',
required: true,
hasAnswer: false,
answer: ''
}
]
}
];

View File

@@ -0,0 +1,66 @@
<template>
<div class="doc-circulation ailist-wrapper">
<keep-alive :include="['List']">
<component ref="component" :is="component" @change="onChange" :params="params" :instance="instance" :dict="dict"></component>
</keep-alive>
</div>
</template>
<script>
import Statistics from './components/Statistics'
import List from './components/List'
export default {
name: 'AppAssessment',
label: '工作考核',
props: {
instance: Function,
dict: Object
},
data () {
return {
component: 'Statistics',
params: {},
include: []
}
},
components: {
Statistics,
List
},
mounted () {
},
methods: {
onChange (data) {
if (data.type === 'List') {
this.component = 'List'
this.params = data.params
}
if (data.type === 'Statistics') {
this.component = 'Statistics'
this.params = data.params
this.$nextTick(() => {
if (data.isRefresh) {
this.$refs.component.getList()
}
})
}
}
}
}
</script>
<style lang="scss">
.doc-circulation {
height: 100%;
background: #F3F6F9;
overflow: auto;
}
</style>

View File

@@ -0,0 +1,120 @@
<template>
<ai-list class="notice">
<template slot="title">
<ai-title title="走访排查情况统计" isShowBottomBorder isShowBack @onBackClick="back"></ai-title>
</template>
<template slot="content">
<ai-search-bar>
<template #left>
<el-date-picker
value-format="yyyy-MM"
v-model="search.startDate"
type="month"
size="small"
unlink-panels
placeholder="请选择考核开始月份"
@change="search.current = 1, getList()" />
<el-date-picker
value-format="yyyy-MM"
v-model="search.endDate"
type="month"
size="small"
unlink-panels
placeholder="请选择考核结束月份"
@change="search.current = 1, getList()" />
</template>
<template #right>
<el-input
v-model="search.createUserName"
size="small"
placeholder="网格员姓名"
clearable
v-throttle="() => {search.current = 1, getList()}"
@clear="search.current = 1, search.createUserName = '', getList()"
suffix-icon="iconfont iconSearch">
</el-input>
</template>
</ai-search-bar>
<ai-table
:tableData="tableData"
:col-configs="colConfigs"
:total="total"
style="margin-top: 12px;"
:current.sync="search.current"
:size.sync="search.size"
@selection-change="(v) => (ids = v.map((e) => e.id))"
@getList="getList">
</ai-table>
</template>
</ai-list>
</template>
<script>
import { mapState } from 'vuex'
export default {
name: 'List',
props: {
instance: Function,
dict: Object
},
data() {
return {
search: {
current: 1,
size: 10,
createUserName: '',
endDate: '',
startDate: ''
},
total: 10,
tableData: []
}
},
computed: {
...mapState(['user']),
colConfigs () {
return [
{ prop: 'month', label: '考核月份', align: 'left' },
{ prop: 'createUserName', label: '网格员姓名', align: 'center' },
{ prop: 'phone', label: '网格员联系方式', align: 'center' },
{ prop: 'povertyNumber', label: '监测家庭数量', align: 'center' },
{ prop: 'logNumber', label: '开展走访次数', align: 'center' },
{ prop: 'povertyHouseholdNumber', label: '已走访家庭数量', align: 'center' },
{ prop: 'finishRate', label: '走访进度', align: 'center', formart: v => (v * 100).toFixed(1) + '%' }
]
}
},
created () {
this.getList()
},
methods: {
getList() {
this.instance.post(`/app/apppreventionreturntopovertylogstatistic/list`, null, {
params: {
...this.search
}
}).then(res => {
if (res.code == 0) {
this.tableData = res.data.records
this.total = res.data.total
}
})
},
back () {
this.$emit('change', {
type: 'Statistics'
})
}
}
}
</script>
<style lang="scss" scoped>
</style>

View File

@@ -0,0 +1,369 @@
<template>
<ai-list class="AppAssessment">
<template slot="title">
<ai-title title="工作考核" isShowBottomBorder :hideLevel="hideLevel" :isShowArea="true" v-model="search.areaId" :instance="instance" @change="onChange"></ai-title>
</template>
<template slot="content">
<div class="statistics-top">
<div class="statistics-top__item">
<span>监测家庭户数</span>
<h2 style="color: #2266FF;">{{ totalInfo['监测家庭户数'] }}</h2>
</div>
<div class="statistics-top__item">
<span>监测对象总数</span>
<h2 style="color: #22AA99;">{{ totalInfo['监测对象总数'] }}</h2>
</div>
<div class="statistics-top__item">
<span>解除风险人数</span>
<h2 style="color: #F8B425">{{ totalInfo['解除风险人数'] }}</h2>
</div>
<div class="statistics-top__item">
<span>解除风险户数</span>
<h2 style="color: red">{{ totalInfo['解除风险户数'] }}</h2>
</div>
</div>
<div class="info">
<ai-card title="饮用水和三保障情况">
<template #content>
<ai-wrapper label-width="120px">
<ai-info-item label="住房安全" :value="info['住房安全']"></ai-info-item>
<ai-info-item label="饮水安全" :value="info['饮水安全']"></ai-info-item>
<ai-info-item label="失学辍学" :value="info['失学辍学']"></ai-info-item>
<ai-info-item label="未参加医疗保险" :value="info['未参加医疗保险']"></ai-info-item>
<ai-info-item label="低收入家庭" :value="info['低收入家庭']"></ai-info-item>
<ai-info-item label="低于人均收入" :value="info['低于人均收入']"></ai-info-item>
</ai-wrapper>
</template>
</ai-card>
<ai-card title="本月网格员走访进度">
<template #right>
<el-button type="text" @click="toList">全部</el-button>
</template>
<template #content>
<div class="progress-wrapper">
<div class="progress">
<div class="item" v-for="(item, index) in logList" :key="index">
<h2>{{ item.createUserName }}</h2>
<el-progress :percentage="item.finishRate"></el-progress>
</div>
</div>
</div>
</template>
</ai-card>
</div>
<ai-card title="帮扶走访情况">
<template #content>
<ai-search-bar bottomBorder>
<template #left>
<el-date-picker
value-format="yyyy-MM-dd"
v-model="search.beginDate"
type="date"
size="small"
unlink-panels
placeholder="请选择开始日期"
@change="search.current = 1, getList()" />
<el-date-picker
value-format="yyyy-MM-dd"
v-model="search.endDate"
type="date"
size="small"
unlink-panels
placeholder="请选择结束日期"
@change="search.current = 1, getLogCount()" />
<ai-select
v-model="search.isGird"
clearable
placeholder="请选择是否关联网格"
:selectList="visitDict"
@change="search.current = 1, getLogCount()">
</ai-select>
<ai-select
v-model="search.isVisit"
clearable
placeholder="请选择走访次数"
:selectList="girdDict"
@change="search.current = 1, getLogCount()">
</ai-select>
<!-- <ai-download :instance="instance" url="/app/apppreventionreturntopovertyriskperson/export" :params="search" fileName="帮扶走访" :disabled="tableData.length == 0">
<el-button icon="iconfont iconExported" :disabled="tableData.length == 0">导出</el-button>
</ai-download> -->
</template>
<template #right>
<el-input
v-model="search.name"
size="small"
placeholder="户主姓名/身份证号/网格员"
clearable
v-throttle="() => {search.current = 1, getLogCount()}"
@clear="search.current = 1, search.name = '', getLogCount()"
suffix-icon="iconfont iconSearch">
</el-input>
</template>
</ai-search-bar>
<ai-table
:tableData="tableData"
:col-configs="colConfigs"
:total="total"
tableSize="small"
border
style="margin-top: 12px;"
:current.sync="search.current"
:size.sync="search.size"
@selection-change="(v) => (ids = v.map((e) => e.id))"
@getList="getLogCount">
</ai-table>
</template>
</ai-card>
</template>
</ai-list>
</template>
<script>
import { mapState } from 'vuex'
export default {
name: 'Statistics',
props: {
instance: Function,
dict: Object
},
data() {
return {
search: {
current: 1,
size: 10,
name: '',
areaId: '',
beginDate: '',
endDate: '',
isVisit: '',
isGird: ''
},
visitDict: [{
dictName: '否',
dictValue: '0'
}, {
dictName: '是',
dictValue: '1'
}],
girdDict: [{
dictName: '等于0次',
dictValue: '0'
}, {
dictName: '大于0次',
dictValue: '1'
}],
logList: [],
info: {},
ids: [],
total: 10,
hideLevel: 3,
totalInfo: {},
tableData: []
}
},
computed: {
...mapState(['user']),
colConfigs () {
return [
{ prop: 'name', label: '户主姓名', align: 'left' },
{ prop: 'sex', label: '性别', align: 'center', formart: v => this.dict.getLabel('sex', v) },
{ prop: 'idNumber', label: '身份证号', align: 'center' },
{ prop: 'householdPhone', label: '户主联系方式', align: 'center' },
{ prop: 'address', label: '家庭住址', align: 'center' },
{ prop: 'status', label: '状态', align: 'center', formart: v => this.dict.getLabel('fpRiskPersonStatus', v) },
{ prop: 'girdMemberName', label: '网格员', align: 'center' },
{ prop: 'girdMemberPhone', label: '网格员电话', align: 'center' },
{ prop: 'visitCount', label: '走访次数', align: 'center' }
]
}
},
created () {
this.search.areaId = this.user.info.areaId
this.hideLevel = this.user.info.areaList.length - 1
this.dict.load('fpRiskPersonStatus', 'sex').then(() => {
this.getLogCount()
})
this.getTotal()
this.getList()
},
methods: {
getList() {
this.instance.post(`/app/apppreventionreturntopovertylogstatistic/list`, null, {
params: {
size: 15,
current: 1
}
}).then(res => {
if (res.code == 0) {
this.logList = res.data.records.map(v => {
return {
...v,
finishRate: Number((v.finishRate * 100).toFixed(1))
}
})
}
})
},
getLogCount() {
this.instance.post(`/app/apppreventionreturntopovertylog/service-rating-list`, null, {
params: {
...this.search
}
}).then(res => {
if (res.code == 0) {
this.tableData = res.data.records
this.total = res.data.total
}
})
},
onChange () {
this.getTotal()
this.getLogCount()
},
getTotal() {
this.instance.post(`/app/statistics/preventionreturntopoverty/povertyReportNumber`, null, {
params: {
...this.search
}
}).then(res => {
if (res.code == 0) {
this.totalInfo = res.data
}
})
this.instance.post(`/app/statistics/preventionreturntopoverty/drinkingWaterCount`, null, {
params: {
...this.search
}
}).then(res => {
if (res.code == 0) {
this.info = res.data
}
})
},
removeAll () {
var id = this.ids.join(',')
this.remove(id)
},
remove(id) {
this.$confirm('确定删除该数据?').then(() => {
this.instance.post(`/app/appmininotice/delete?ids=${id}`).then(res => {
if (res.code == 0) {
this.$message.success('删除成功!')
this.getList()
}
})
})
},
toList () {
this.$emit('change', {
type: 'List',
params: {
id: ''
}
})
}
}
}
</script>
<style lang="scss" scoped>
.AppAssessment {
.info {
display: flex;
justify-content: space-between;
.ai-card {
flex: 1;
height: 300px;
overflow-y: auto;
&:first-child {
margin-right: 20px;
}
.progress {
overflow-y: auto;
height: 190px;
.item {
display: flex;
align-items: center;
margin-bottom: 12px;
.el-progress {
flex: 1;
}
h2 {
width: 90px;
margin-right: 30px;
font-size: 14px;
text-align: right;
color: #333;
}
}
}
}
}
.statistics-top {
display: flex;
align-items: center;
margin-bottom: 20px;
& > div {
flex: 1;
height: 96px;
line-height: 1;
margin-right: 20px;
padding: 16px 24px;
background: #FFFFFF;
box-shadow: 0px 4px 6px -2px rgba(15, 15, 21, 0.15);
border-radius: 4px;
&:last-child {
margin-right: 0;
}
h3 {
font-size: 24px;
}
span {
display: block;
margin-bottom: 16px;
color: #888888;
font-size: 16px;
}
}
}
::v-deep .ai-list__content {
width: 100%;
.ai-list__content--right {
width: 100%!important;
.ai-list__content--right-wrapper {
padding: 0!important;
background: transparent!important;
box-shadow: none!important;
}
}
}
}
</style>

View File

@@ -0,0 +1,101 @@
<template>
<section class="conference">
<ai-list v-if="!showDetail">
<template slot="title">
<ai-title title="会议管理"></ai-title>
</template>
<template slot="tabs">
<el-tabs v-model="currIndex" @tab-click="handleClick">
<el-tab-pane v-for="(tab,i) in tabs" :key="i" :label="tab.label" :name="String(i)">
<component :is="tab.comp" v-if="currIndex==i" :ref="currIndex" :instance="instance" :dict="dict"
:permissions="permissions" @goPage="goPage" :listType="listType" />
</el-tab-pane>
</el-tabs>
</template>
</ai-list>
<component v-else :is="currentComp" :instance="instance" :dict="dict" :detail="detailRow" :listType="listType" @gotoEdit="gotoAdd" ></component>
</section>
</template>
<script>
import addMeeting from './addMeeting';
import detail from './detail'
import list from './list'
export default {
name: 'AppConference',
label: "会议管理",
components: {addMeeting, detail, list},
provide() {
return {
top: this
}
},
props: {
instance: Function,
dict: Object,
permissions: Function,
},
data() {
return {
//会议状态0、草稿1、未开始2、进行中3、已取消4、已结束
//参会状态0、未确认1、已确认2、缺席
currIndex: "0",
currentComp: "",
showDetail: false,
detailRow: {},
listType: '1',
}
},
computed:{
tabs() {
return [
{label: "我参与的会议", name: "addMeeting", comp: list, detail: detail, permission: ""},
{label: "我发起的会议", name: "addMeeting", comp: list, detail: detail, permission: ""},
]
},
},
methods: {
goPage(params) {
this.detailRow = params.row
this.currentComp = params.comp
if(params.comp == 'detail' || params.comp == 'addMeeting') {
this.showDetail = true
}
},
handleClick() {
if (this.currIndex == 0) {
this.listType = '1'
} else {
this.listType = '0'
}
},
goBack() {
this.showDetail = false;
if (this.currIndex == '0') {
this.listType = '1'
} else {
this.listType = '0'
}
},
gotoAdd(obj) {
this.showDetail = true
this.detailRow = obj
this.currentComp = 'addMeeting'
},
},
}
</script>
<style lang="scss" scoped>
.conference {
height: 100%;
::v-deep .ai-list__content--right-wrapper {
background-color: transparent !important;
box-shadow: none !important;
}
}
</style>

View File

@@ -0,0 +1,244 @@
<template>
<ai-detail class="addMeeting">
<ai-title slot="title" title="发起会议" isShowBack isShowBottomBorder @onBackClick="$parent.goBack"/>
<template #content>
<ai-card title="会议信息">
<template #content>
<el-form :model="saveData" status-icon ref="ruleForm" :rules="rules" label-width="100px"
label-position="right">
<el-form-item label="会议标题:" prop="title">
<el-input v-model="saveData.title" size="small" placeholder="请输入..."
:maxlength="30" show-word-limit></el-input>
</el-form-item>
<el-row type="flex" justify="space-between">
<el-form-item label="开始时间:" prop="startTime">
<el-date-picker
:editable="false"
value-format="yyyy-MM-dd HH:mm:ss"
v-model="saveData.startTime"
:picker-options="pickerOptions"
type="datetime"
size="small"
placeholder="选择开始时间">
</el-date-picker>
</el-form-item>
<el-form-item label="结束时间:" prop="endTime">
<el-date-picker
:editable="false"
value-format="yyyy-MM-dd HH:mm:ss"
v-model="saveData.endTime"
:picker-options="pickerOptions"
type="datetime"
:disabled="!Boolean(saveData.startTime)"
size="small"
placeholder="选择结束时间">
</el-date-picker>
</el-form-item>
</el-row>
<el-form-item label="会议地点:" prop="address">
<el-input v-model="saveData.address" size="small" placeholder="请输入..."
:maxlength="30" show-word-limit></el-input>
</el-form-item>
<el-form-item label="会议内容:" prop="content">
<el-input v-model="saveData.content" size="small" placeholder="请输入..."
type="textarea" :rows="8" :maxlength="500" show-word-limit></el-input>
</el-form-item>
<el-row type="flex" justify="space-between">
<el-form-item label="参会提醒:" prop="noticeBefore">
<ai-select v-model="saveData.noticeBefore"
placeholder="请选择"
:selectList="dict.getDict('meetingNoticeBefore')"
></ai-select>
</el-form-item>
<el-form-item label="确认提醒:" prop="noticeAfter">
<ai-select v-model="saveData.noticeAfter"
placeholder="请选择"
:selectList="dict.getDict('meetingNoticeAfter')"
></ai-select>
</el-form-item>
</el-row>
<el-form-item label="会议资料:" prop="files">
<ai-uploader :instance="instance" @change="handleChange" isShowTip fileType="file"
v-model="saveData.fileList"
acceptType=".zip,.rar,.doc,.docx,.xls,.ppt,.pptx,.pdf,.txt,.jpg,.png,.xlsx"
:limit="9"></ai-uploader>
</el-form-item>
</el-form>
</template>
</ai-card>
<ai-card title="参会人员信息">
<template #right>
<ai-wechat-selecter slot="append" :instance="instance" v-model="saveData.attendees">
<el-button type="text" icon="iconfont iconAdd">选择参会人员</el-button>
</ai-wechat-selecter>
</template>
<template #content>
<ai-table
border
:tableData="saveData.attendees"
:colConfigs="colConfigs"
:isShowPagination="false">
<el-table-column label="操作" slot="option" align="center">
<template v-slot="{row}">
<el-button type="text" title="删除" @click="deletePer(row)">删除</el-button>
</template>
</el-table-column>
</ai-table>
</template>
</ai-card>
</template>
<template #footer>
<el-button @click="$parent.goBack">取消</el-button>
<el-button type="primary" @click="saveFrom(0)">保存草稿</el-button>
<el-button type="primary" @click="saveFrom(1)">保存并发布</el-button>
</template>
</ai-detail>
</template>
<script>
import {mapState} from "vuex";
import moment from 'dayjs'
export default {
name: "addMeeting",
inject: ['top'],
props: {
instance: Function,
dict: Object,
permissions: Function,
detail: Object
},
data() {
let endTimePass = (rule, value, callback) => {
if (value) {
if (moment(value).unix() - moment(this.saveData.startTime).unix() > 0) {
callback()
} else {
callback(new Error('结束时间要大于开始时间'));
}
} else {
callback(new Error('请选择结束时间'));
}
}
return {
saveData: {
noticeBefore: '4',
noticeAfter: '0',
attendees: [],
fileList: []
},
rules: {
title: [{required: true, message: '请填写会议标题', trigger: 'blur'}],
startTime: [{required: true, message: '请选择开始时间', trigger: 'blur'}],
endTime: [{required: true, validator: endTimePass, trigger: 'change'}],
address: [{required: true, message: '请填写会议地点', trigger: 'blur'}],
// content: [{required: true, message: '请填写会议内容', trigger: 'blur'}],
noticeBefore: [{required: true, message: '请选择参会提醒', trigger: 'blur'}],
noticeAfter: [{required: true, message: '请选择确认提醒', trigger: 'blur'}],
},
pickerOptions: {
disabledDate(time) {
return time.getTime() < Date.now() - 8.64e7;
}
},
showEdit: false,
total: 0,
}
},
methods: {
handleChange(e) {
this.saveData.fileList = e
},
deletePer(scope) {
this.$confirm('确认删除此参会人?')
.then(_ => {
if (this.detail.id) { //编辑
} else { //新增
this.saveData.attendees.map((item, index) => {
if (item.id == scope.id) {
this.saveData.attendees.splice(index, 1)
}
})
}
})
},
saveFrom(status) {
this.$refs["ruleForm"].validate((valid) => {
if (this.saveData.attendees.length == 0) {
return this.$message.error("参会人不能为空!")
}
if (moment(this.saveData.startTime).unix() - moment(Date.now()).unix() < 0) {
return this.$message.error("会议开始时间已过期,请重新选择!");
}
if (valid) {
this.saveData.files = []
this.saveData.fileList.map((item) => {
this.saveData.files.push(item.id)
})
this.instance.post(`/app/appmeetinginfo/add-update`, {
...this.saveData,
status: status,
}).then(res => {
if (res.code == 0) {
if (status != 1) {
this.$message.success("保存草稿成功")
} else {
this.$message.success("发布成功")
}
this.$parent.goBack();
}
});
}
});
},
getDetail() {
this.instance.post(`/app/appmeetinginfo/info-id?id=${this.detail.id}`).then(res => {
if (res?.data) {
this.saveData = {
...res.data,
};
this.saveData.fileList = res.data.files || []
}
});
}
},
created() {
this.dict.load("meetingNoticeAfter", "meetingNoticeBefore").then(
this.$nextTick(() => {
if (JSON.stringify(this.detail) == '{}') {
this.showEdit = false;
} else {
this.showEdit = true;
// this.saveData = {...this.detail};
// this.compereList = this.saveData.hosts;
// this.saveData.attendees = this.saveData.attendees || [];
this.getDetail()
}
})
)
},
computed: {
...mapState(['user']),
headerTitle() {
return this.showEdit ? '修改会议' : '发起会议'
},
colConfigs() {
return [
{prop: 'name', align: 'center', label: '姓名'},
{prop: 'departName', align: 'center', label: '所属单位'},
{slot: 'option'}
]
},
}
}
</script>
<style lang="scss" scoped>
.addMeeting {
::v-deep .el-button--text {
.iconfont {
color: inherit;
}
}
}
</style>

View File

@@ -0,0 +1,597 @@
<template>
<section class="meetingDetail detail-content">
<ai-detail>
<template #title>
<ai-title title="会议详情" isShowBottomBorder isShowBack @onBackClick="$parent.goBack">
<template #rightBtn>
<p class="conference_top_area" v-if="listType==0">
<!-- <el-button type="primary" v-if="detail.status==0" @click="changeMeeting('是否立即发布会议?')">立即发布</el-button> -->
<el-button type="primary" v-if="detail.status==1" @click="noticeMetting()">参会提醒</el-button>
<el-button type="primary" v-if="detail.status==0" @click="editMeeting()">修改会议</el-button>
<el-button class="del-btn-list" v-if="detail.status==1" @click="changeMeeting('是否取消会议?')">取消会议</el-button>
<el-button class="iconfont iconDelete del-btn-list" v-if="detail.status==0||detail.status==3"
@click="changeMeeting('是否删除会议?')">删除会议
</el-button>
</p>
<!-- v-if="detail.status==0||detail.status==3" -->
<p class="conference_top_area" v-if="listType==1&&info.status==1">
<el-button @click="toDo" style="width:80px;" class="del-btn-list">待定</el-button>
<el-button @click="innerVisible=true" v-if="info.joinStatus!=2" style="width:80px;" class="del-btn-list">
请假
</el-button>
<el-button type="primary" @click="changeMeeting('是否确认参会?')" v-if="info.joinStatus!=1" style="width:80px;">
确认参会
</el-button>
</p>
</template>
</ai-title>
</template>
<template #content>
<ai-dialog
title="确认请假"
:visible.sync="innerVisible"
@onConfirm="queMeeting('writeInfo')"
@onCancel="innerVisible=false;" @close="$refs.writeInfo.resetFields()"
width="520px">
<div class="addother_main" style="width:400px;margin:auto;">
<el-form :model="writeInfo" status-icon ref="writeInfo" label-width="100px" class="demo-ruleForm">
<el-form-item label="请假原因:" prop="reason" autocomplete="off"
:rules="{
required: true, message: '请假原因不能为空', trigger: 'blur'
}"
>
<el-input v-model.trim="writeInfo.reason" autocomplete="off" size="mini" placeholder="请输入..."
type="textarea" :rows="4" :maxlength="100" show-word-limit></el-input>
</el-form-item>
</el-form>
</div>
</ai-dialog>
<ai-card title="会议说明">
<template slot="content">
<ai-wrapper class="mar-t16" label-width="70px" :columnsNumber="1">
<ai-info-item label="会议标题:"><span>{{ info.title }}</span></ai-info-item>
</ai-wrapper>
<ai-wrapper class="mar-t16" label-width="70px" :columnsNumber="2">
<ai-info-item label="发起单位:" :value="info.unitName">
</ai-info-item>
<ai-info-item label="发起人:" :value="info.userName">
</ai-info-item>
</ai-wrapper>
<ai-wrapper class="mar-t16" label-width="70px" :columnsNumber="1">
<!-- <ai-info-item label="会议状态:" v-if="xq.joinStatus==1&&listType==1"><span>{{ xq.joinStatus }}</span>
</ai-info-item> -->
<ai-info-item label="发起时间:"><span>{{ info.createTime }}</span></ai-info-item>
</ai-wrapper>
<ai-wrapper class="mar-t16" label-width="70px" :columnsNumber="2">
<ai-info-item label="开始时间:"><span>{{ info.startTime }}</span></ai-info-item>
<ai-info-item label="结束时间:"><span>{{ info.endTime }}</span></ai-info-item>
</ai-wrapper>
<ai-wrapper class="mar-t16" label-width="70px" :columnsNumber="2">
<ai-info-item label="参会提醒:"><span>{{
dict.getLabel("meetingNoticeBefore", info.noticeBefore) || "-"
}}</span></ai-info-item>
<ai-info-item label="确认提醒:"><span>{{
dict.getLabel("meetingNoticeAfter", info.noticeAfter) || "-"
}}</span>
</ai-info-item>
</ai-wrapper>
<ai-wrapper class="mar-t16" label-width="70px" :columnsNumber="1">
<ai-info-item label="会议地点:"><span>{{ info.address }}</span></ai-info-item>
</ai-wrapper>
<ai-wrapper class="mar-t16" label-width="70px" :columnsNumber="1">
<ai-info-item label="会议内容:"><span v-html="info.content"></span></ai-info-item>
</ai-wrapper>
</template>
</ai-card>
<ai-card title="会议资料">
<template slot="content">
<ai-file-list :fileList="info.files" :fileOps="{name: 'name', size: 'fileSizeStr'}"></ai-file-list>
</template>
</ai-card>
<ai-card title="参会名单">
<template slot="content">
<ai-search-bar bottomBorder>
<template #left>
<el-select v-model="search.joinStatus" placeholder="确认状态" size="small" clearable class="vc-input-160" @change="searchMeetinguser">
<el-option
v-for="(item,k) in confirmStatus"
:key="k"
:label="item.label"
:value="k">
</el-option>
</el-select>
</template>
<template #right>
<!-- <ai-download :instance="instance" url="/app/appepidemicbackhomerecord/export" fileName="参会名单">
<el-button icon="iconfont iconExported">导出</el-button>
</ai-download> -->
</template>
</ai-search-bar>
<ai-table
:tableData="info.attendees"
:colConfigs="colConfigs"
style="margin-top: 12px;"
:isShowPagination="false">
<el-table-column slot="meetingUserName"
label="姓名"
align="center"
show-overflow-tooltip>
<div slot-scope="{row}">
<span>{{ row.meetingUserName }}</span>
</div>
</el-table-column>
<el-table-column slot="meetingUnitName"
label="所属部门"
align="center"
show-overflow-tooltip>
<div slot-scope="{row}">
<span>{{ row.meetingUnitName }}</span>
</div>
</el-table-column>
<el-table-column slot="joinStatus"
prop="joinStatus"
label="确认状态"
align="center"
show-overflow-tooltip>
<div slot-scope="{row}">
<p style="color:rgba(255,68,102,1);display:flex;justify-content:center;" v-if="row.joinStatus==2">
请假<i class="el-icon-warning" :title="row.absence" style="cursor: pointer;"></i>
</p>
<span v-else :style="{color:confirmStatus[row.joinStatus].color}"
v-text="confirmStatus[row.joinStatus].label"/>
</div>
</el-table-column>
<el-table-column slot="option"
label="操作"
align="center"
v-if="listType==0"
show-overflow-tooltip>
<div slot-scope="{row}" v-if="row.joinStatus==0">
<span class="el-icon-message-solid" style="cursor: pointer;" title="参会提醒"
@click="noticeMetting(row.meetingUserId)" v-if="detail.status==1"></span>
</div>
</el-table-column>
</ai-table>
</template>
</ai-card>
</template>
</ai-detail>
</section>
</template>
<script>
import {mapState} from "vuex";
export default {
name: 'meetingDetail',
inject: ['top'],
props: {
instance: Function,
dict: Object,
permissions: Function,
detail: Object,
listType: String
},
data() {
return {
navId: '1',
info: {},
total: 0,
writeInfo: {reason: ''},
meetingUserList: [],
innerVisible: false,
search: {joinStatus: ''}
}
},
created() {
this.dict.load("meetingNoticeAfter", "meetingNoticeBefore").then(() => this.searchDetail(this.detail.id))
},
computed: {
...mapState(['user']),
colConfigs() {
return [
{
slot: 'meetingUserName'
},
{
slot: 'meetingUnitName'
},
{
slot: 'joinStatus',
},
{ prop: 'signInStatus', align: 'center', label: '签到', formart: v => v === '1' ? '已签到' : '未签到' },
{
slot: 'option',
}
]
},
confirmStatus() {
return {
0: {label: '未确认', color: "rgba(255,136,34,1)"},
1: {label: '已确认', color: "rgba(34,102,255,1)"},
2: {label: '请假', color: "rgba(255,68,102,1)"},
3: {label: '待定', color: "rgba(255,136,34,1)"},
}
}
},
methods: {
toDo() {
this.$confirm("是否确认待定会议?").then(_ => {
this.instance.post("/app/appmeetinginfo/tobeConfirm", null, {
params: {
meetingId: this.detail.id,
}
}).then(res => {
if (res.code == 0) {
this.$message.success("会议待定");
setTimeout(_ => {
this.$parent.goBack();
}, 800)
}
})
})
},
searchMeetinguser() {
this.instance.post(`/app/appmeetinguser/list`, null, {
params: {...this.search, size: 999, meetingId: this.info.id}
}).then(res => {
if (res?.data) {
this.info.attendees = res.data.records;
this.total = res.data.total;
}
});
},
searchDetail(id) {
this.instance.post(`/app/appmeetinginfo/info-id`, null, {
params: {id}
}).then(res => {
if (res?.data) {
this.info = {
...res.data,
content: this.formatContent(res.data.content || ""),
files: res.data.files || []
};
this.searchMeetinguser()
}
});
},
changeMeeting(title, id) {
this.$confirm(title, {
type: 'warning'
}).then(() => {
if (title == '是否立即发布会议?') {
this.fbMeeting();
} else if (title == '是否删除会议?') {
this.sdMeeting();
} else if (title == '是否取消会议?') {
this.qxMeeting();
} else if (title == '是否确认参会?') {
this.qrMeeting();
} else if (title == '是否删除此参会人员?') {
this.deleteMeetingPer(id)
}
})
},
deleteMeetingPer(id) {
this.instance.post(`/app/appmeetinguser/delete`, null,
{
params: {
id
}
}
).then(res => {
if (res && res.code == 0) {
this.$message.success("删除成功!");
this.searchMeetinguser();
}
});
},
queMeeting(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
this.instance.post(`/app/appmeetinginfo/absent`, null,
{
params: {
meetingId: this.detail.id,
reason: this.writeInfo.reason
}
}
).then(res => {
if (res && res.code == 0) {
this.innerVisible = false;
this.$parent.goBack();
}
});
} else {
return false;
}
});
},
qrMeeting() {
this.instance.post(`/app/appmeetinginfo/confirm`, null,
{
params: {
meetingId: this.detail.id
}
}
).then(res => {
if (res && res.code == 0) {
this.$message.success("确认参会成功!")
this.$parent.goBack();
}
});
},
noticeMetting(meetingUserId) {
this.instance.post(`/app/appmeetinginfo/notice`, null, {
params: {
meetingId: this.detail.id, noticeALL: !meetingUserId, meetingUserId
}
}).then(res => {
if (res && res.code == 0) {
this.$message.success("提醒成功!")
}
});
},
fbMeeting() {
this.instance.post(`/app/appmeetinginfo/release`, null,
{
params: {
meetingId: this.detail.id
}
}
).then(res => {
if (res && res.code == 0) {
this.$message.success("发布成功!")
this.$parent.goBack();
}
});
},
sdMeeting() {
this.instance.post(`/app/appmeetinginfo/delete`, null,
{
params: {
meetingId: this.detail.id
}
}
).then(res => {
if (res && res.code == 0) {
this.$message.success("删除成功!");
this.$parent.goBack();
}
});
},
qxMeeting() {
this.instance.post(`/app/appmeetinginfo/cancel`, null,
{
params: {
meetingId: this.detail.id
}
}
).then(res => {
if (res && res.code == 0) {
this.$message.success("取消会议成功!");
this.$parent.goBack();
}
});
},
editMeeting() {
this.$parent.goBack();
this.$emit('gotoEdit', this.info)
},
}
}
</script>
<style lang="scss" scoped>
.meetingDetail {
width: 100%;
height: 100%;
background: rgba(255, 255, 255, 1);
.conference_top_area {
display: flex;
align-items: center;
}
.user-search {
width: 100%;
height: 48px;
display: flex;
justify-content: space-between;
align-items: center;
.float-right {
width: calc(100% - 200px);
text-align: right;
}
.input-162 {
display: inline-block;
width: 162px;
}
}
.content {
width: 1000px;
height: calc(100% - 50px);
overflow: hidden;
margin: auto;
display: flex;
justify-content: space-around;
.content-left {
width: 160px;
height: 100%;
.content-left-nav {
width: 158px;
background-color: #ffffff;
border-radius: 4px;
border: solid 1px #eeeeee;
margin-top: 56px;
overflow: hidden;
li {
height: 48px;
line-height: 48px;
padding-left: 24px;
font-size: 14px;
font-weight: normal;
font-stretch: normal;
letter-spacing: 0;
color: #666666;
cursor: pointer;
border-left: 3px solid transparent;
&:hover {
border-left: 3px solid #5088ff;
}
a {
display: block;
}
}
.navActive {
border-left: 3px solid #5088ff;
color: #5088ff;
}
}
}
.content-right {
width: 780px;
height: calc(100% - 80px);
overflow-y: auto;
margin-left: 40px;
box-sizing: border-box;
overflow-x: hidden;
.content-right-title {
width: 780px;
height: 56px;
margin-bottom: 16px;
box-shadow: inset 0px -1px 0px 0px #dad5d5;
display: flex;
justify-content: space-between;
align-items: center;
span {
display: block;
width: 150px;
height: 56px;
line-height: 56px;
color: #333333;
font-weight: bold;
&:nth-of-type(2) {
text-align: right;
width: 200px;
}
}
}
.flie {
width: 100%;
height: 40px;
line-height: 40px;
padding: 0 8px;
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 14px;
color: rgba(51, 51, 51, 1);
background: rgba(255, 255, 255, 1);
border-radius: 4px;
border: 1px solid rgba(208, 212, 220, 1);
margin-bottom: 16px;
cursor: pointer;
p {
display: flex;
justify-content: flex-start;
align-items: center
}
}
.meeting_name {
width: 100%;
padding-bottom: 25px;
font-size: 16px;
box-shadow: inset 0px -1px 0px 0px #dad5d5;
position: relative;
overflow: hidden;
.title {
color: #333333;
height: 28px;
line-height: 28px;
margin-left: 0;
font-weight: bold;
margin-top: 14px;
}
ul {
overflow: hidden;
li {
width: 33.3%;
float: left;
line-height: 28px;
font-size: 14px;
span {
width: 70px;
display: block;
float: left;
color: rgba(153, 153, 153, 1)
}
p {
width: calc(100% - 70px);
float: left;
color: rgba(51, 51, 51, 1);
}
;
}
}
.svg {
width: 88px;
height: 88px;
position: absolute;
right: -20px;
bottom: -20px;
}
}
}
}
}
</style>

View File

@@ -0,0 +1,259 @@
<template>
<ai-list isTabs>
<template #content>
<ai-search-bar>
<template #left>
<el-button type="primary" @click="addMetting()">发起会议</el-button>
<ai-select
v-model="search.meetingStatus"
@change="getTableData()"
placeholder="会议状态"
:selectList="dict.getDict($parent.name==0 ? 'meetingStatusSelect' : 'meetingStatus')"
></ai-select>
<ai-select
v-if="$parent.name==0"
v-model="search.confirmStatus"
@change="getTableData()"
placeholder="确认状态"
:selectList="dict.getDict('confirmStatus')"
></ai-select>
</template>
<template #right>
<el-input
v-model="search.param"
v-throttle="() => {search.current=1,getTableData()}"
@keyup.enter.native="search.current=1,getTableData()"
placeholder="会议标题/地点"
size="small" suffix-icon="iconfont iconSearch" clearable @clear="getTableData()"></el-input>
</template>
</ai-search-bar>
<div class="list_main">
<div class="no-data" style="height:160px;" v-if="tableData.length==0"></div>
<ul v-if="tableData.length>0">
<li v-for="(item,index) in tableData" :key="index" @click="goDetail(item)">
<p>
<span class="conference_title">{{ item.title }}</span>
<span class="time" v-if="item.status==1">{{ item.expirationTime }}</span>
</p>
<p style="width:80%;">
<el-row type="flex" align="middle" class="unit">发起人{{ item.userName }}
</el-row>
<el-row type="flex" align="middle" class="unit">发起单位{{ item.unitName }}
</el-row>
</p>
<p style="width:80%;">
<span class="unit">会议时间{{ item.startTime.substring(0, 16) + '至' + item.endTime.substring(0, 16) }}</span>
<el-tooltip :content="item.address" placement="top-start" effect="light">
<span class="unit" v-if="item.address.length>12">会议地点{{
item.address.substring(0, 12) + '....'
}}</span>
<span class="unit" v-else>会议地点{{ item.address }}</span>
</el-tooltip>
</p>
<!-- <p style="width:80%;">
<span
class="unit">会议时间{{
item.startTime.substring(0, 16) + '至' + item.endTime.substring(0, 16)
}}</span>
<el-tooltip :content="item.address" placement="top-start" effect="light">
<span class="unit address"
v-if="item.address.length>12">会议地点{{ item.address.substring(0, 12) + '....' }}</span>
<span class="unit address" v-else>会议地点{{ item.address }}</span>
</el-tooltip>
</p> -->
<h5 :class="{color0:item.status==0,color1:item.status==1,color2:item.status==2,color3:item.status==3,color4:item.status==4}">
<span v-if="item.status==0">草稿箱</span>
<span v-if="item.status==1">未开始</span>
<span v-if="item.status==2">进行中</span>
<span v-if="item.status==3">已取消</span>
<span v-if="item.status==4">已结束</span>
</h5>
<ai-icon class="svg" v-if="item.joinStatus==0" type="svg" icon="iconunidentified"/>
<ai-icon class="svg" v-else-if="item.joinStatus==1" type="svg" icon="iconidentified"/>
<ai-icon class="svg" v-else-if="item.joinStatus==2" type="svg" icon="iconyiqingjia"/>
<ai-icon class="svg" v-else-if="item.joinStatus==3" type="svg" icon="icondaiding"/>
</li>
</ul>
</div>
<div class="pagination" v-if="tableData.length>0">
<el-pagination
@current-change="handleCurrentChange"
@size-change="handleSizeChange"
background
:current-page.sync="search.current"
:page-sizes="[5, 10, 50, 100,200]"
:page-size="search.size"
layout="total,prev, pager, next,sizes,jumper"
:total="total">
</el-pagination>
</div>
</template>
</ai-list>
</template>
<script>
export default {
name: "list",
props: {
instance: Function,
dict: Object,
permissions: Function,
listType: String
},
data() {
return {
search: {
meetingStatus: '',
confirmStatus: '',
param: '',
current: 1,
size: 10,
listType: ''
},
tableData: [],
total: 0,
}
},
methods: {
goDetail(item) {
this.$emit('goPage', {
row: item,
comp: 'detail'
});
},
addMetting() {
this.$emit('goPage', {
row: {},
comp: 'addMeeting'
});
},
getTableData() {
this.instance.post(`/app/appmeetinginfo/list`, null, {
params: {
...this.search,
listType: this.listType
}
}).then(res => {
if (res && res.data) {
this.tableData = res.data.records;
this.total = res.data.total;
}
});
},
handleCurrentChange(val) {
this.search.current = val;
this.getTableData();
},
handleSizeChange(val) {
this.search.size = val;
this.getTableData();
},
},
created() {
this.dict.load("confirmStatus", "meetingStatus", "meetingStatusSelect").then(_ => this.getTableData())
}
}
</script>
<style lang="scss" scoped>
.list_main {
width: 100%;
ul {
overflow: hidden;
padding: 0;
margin: 0;
li {
width: 100%;
height: 107px;
background: rgba(255, 255, 255, 1);
border-radius: 4px;
border: 1px solid rgba(216, 224, 232, 1);
box-sizing: border-box;
padding: 16px 16px 16px 50px;
margin-top: 8px;
cursor: pointer;
position: relative;
overflow: hidden;
p {
width: 100%;
height: 25px;
display: flex;
justify-content: space-between;
align-items: center;
.conference_title {
color: rgba(51, 51, 51, 1);
font-size: 16px;
font-weight: bold;
}
.time {
font-size: 14px;
color: #2266FF;
}
.unit {
font-size: 14px;
width: 50%;
}
}
h5 {
width: 100px;
height: 20px;
line-height: 20px;
text-align: center;
position: absolute;
left: -22px;
top: 10px;
box-sizing: border-box;
padding-right: 8px;
font-size: 12px;
transform: rotate(-45deg);
background: #FFF3E8;
color: rgba(255, 136, 34, 1);
box-shadow: -1px 1px 0px 0px rgba(216, 224, 232, 1), 1px -1px 0px 0px rgba(216, 224, 232, 1);
margin: 0;
}
.color0 {
color: #2244FF;
background: #EFF6FF;
}
.color1 {
background: #FFF3E8;
color: rgba(255, 136, 34, 1);
}
.color2 {
background: #EFF6FF;
color: #2266FF;
}
.color3 {
background-color: #D8E0E8;
color: #999999;
}
.color4 {
color: #2EA222;
background-color: #D8E0E8;
}
.svg {
width: 88px;
height: 88px;
position: absolute;
right: -20px;
bottom: -20px;
}
}
}
}
</style>

View File

@@ -0,0 +1,68 @@
<template>
<div class="appDispatchManagement">
<keep-alive :include="['List']">
<component ref="component" :is="component" @change="onChange" :params="params" :instance="instance" :dict="dict"></component>
</keep-alive>
</div>
</template>
<script>
import Detail from './components/Detail'
import Add from './components/Add'
import List from './components/List'
export default {
name: "AppDispatchManagement",
label: '公文流转',
components: {List, Detail, Add},
props: {
instance: Function,
dict: Object,
permissions: Function
},
data() {
return {
component: 'List',
params: {},
include: []
}
},
created(){
},
methods:{
onChange (data) {
if (data.type === 'detail') {
this.component = 'Detail'
this.params = data.params
}
if (data.type === 'add') {
console.log(123)
this.component = 'Add'
this.params = data.params
}
if (data.type === 'list') {
this.component = 'List'
this.params = data.params
this.$nextTick(() => {
if (data.isRefresh) {
this.$refs.component.getList()
}
})
}
}
}
}
</script>
<style lang="scss" scoped>
.appDispatchManagement{
width: 100%;
height: 100%;
}
</style>

View File

@@ -0,0 +1,388 @@
<template>
<section class="managementDetail">
<ai-detail>
<template #title>
<ai-title title="公文登记" isShowBottomBorder isShowBack @onBackClick="cancel(true)"/>
</template>
<template #content>
<ai-card title="公文信息">
<template slot="content">
<div class="form_div mar-t16">
<el-form
ref="rules"
:model="form"
:rules="formRules"
size="small"
label-suffix=""
label-width="100px"
>
<el-form-item label="公文名称" prop="documentName">
<el-input
v-model="form.documentName"
placeholder="请输入..."
maxlength="50"
></el-input>
</el-form-item>
<div class="above">
<div class="left">
<el-form-item label="公文编号" prop="documentCode">
<el-input
v-model="form.documentCode"
placeholder="请输入..."
maxlength="50"
></el-input>
</el-form-item>
</div>
<div class="right">
<el-form-item label="公文类型" prop="documentType">
<el-select
v-model="form.documentType"
placeholder="请选择..."
clearable
>
<el-option
v-for="(item, i) in dict.getDict('officialDocumentName')"
:key="i"
:label="item.dictName"
:value="item.dictValue"
></el-option>
</el-select>
</el-form-item>
</div>
</div>
<div class="above">
<div class="left">
<el-form-item label="保密等级">
<el-select
v-model="form.confidentialityLevel"
placeholder="请选择..."
clearable
>
<el-option
v-for="(item, i) in dict.getDict('officialDocumentConfidentialityLevel')"
:key="i"
:label="item.dictName"
:value="item.dictValue"
></el-option>
</el-select>
</el-form-item>
</div>
<div class="right">
<el-form-item label="阅示类型" prop="readType">
<el-select @change="readTypeChange"
v-model="form.readType"
placeholder="请选择..."
clearable
>
<el-option
v-for="(item, i) in dict.getDict('officialDocumentReadType')"
:key="i"
:label="item.dictName"
:value="item.dictValue"
></el-option>
</el-select>
</el-form-item>
</div>
</div>
<div class="above">
<div class="left">
<el-form-item label="紧急程度">
<el-select
v-model="form.emergencyLevel"
placeholder="请选择..."
clearable
>
<el-option
v-for="(item, i) in dict.getDict('officialDocumentEmergencyLevel')"
:key="i"
:label="item.dictName"
:value="item.dictValue"
></el-option>
</el-select>
</el-form-item>
</div>
</div>
<div class="above">
<div class="left">
<el-form-item label="发文机关">
<el-input
v-model="form.issuingUnit"
placeholder="请输入..."
maxlength="50"
></el-input>
</el-form-item>
</div>
<div class="right">
<el-form-item label="发文字号">
<el-input
v-model="form.issuingFont"
placeholder="请输入..."
maxlength="50"
></el-input>
</el-form-item>
</div>
</div>
<div class="above">
<div class="left">
<el-form-item label="签发人">
<el-input
v-model="form.signer"
placeholder="请输入..."
maxlength="50"
></el-input>
</el-form-item>
</div>
</div>
<el-form-item label="备注">
<el-input
v-model="form.remark"
type="textarea"
:rows="5"
maxlength="200"
show-word-limit
placeholder="请输入..."
></el-input>
</el-form-item>
<el-form-item label="附件">
<div class="upload">
<ai-uploader :instance="instance" v-model="form.files" fileType="file" :limit="9" @change="onChange"></ai-uploader>
</div>
</el-form-item>
</el-form>
</div>
</template>
</ai-card>
<ai-card title="流转信息">
<template #content>
<span class="form-label">流转对象</span>
<div class="user-content">
<ai-wechat-selecter slot="append" :instance="instance" v-model="form.flowUsers" isShowUser :isMultiple="isMultiple"></ai-wechat-selecter>
</div>
</template>
</ai-card>
</template>
<template #footer>
<el-button class="delete-btn footer-btn" @click="cancel(true)">取消</el-button>
<el-button class="footer-btn" type="primary" @click="save('rules', '1')">保存并流转</el-button>
<el-button class="footer-btn" @click="save('rules', '0')">保存</el-button>
</template>
</ai-detail>
</section>
</template>
<script>
export default {
name: "managementDetail",
props: {
instance: Function,
dict: Object,
permissions: Function,
params: Object
},
data() {
return {
form: {
documentName: '',
documentCode: '',
documentType: '',
confidentialityLevel: '',
readType: '',
emergencyLevel: '',
issuingTime: '',
issuingUnit: '',
issuingFont: '',
signer: '',
overDescription: '',
overTime: '',
deliver: '',
remark: '',
files: [],
fileIds: [],
flowUsers: [],
},
isMultiple: true,
};
},
computed: {
formRules(){
return {
documentName: [{required: true, message: "请输入公文名称", trigger: 'change' }],
documentCode: [{required: true, message: "请输入公文编号", trigger: 'change' }],
documentType: [{required: true, message: "请选择公文类型", trigger: 'change' }],
readType: [{required: true, message: "请选择阅示类型", trigger: 'change' }],
}
},
colConfigs(){
return [
{
prop: 'meetingUserName',
align: 'center',
label: '姓名',
},
{
prop: 'meetingUserPhone',
align: 'center',
label: '手机号码',
},
{
prop: 'meetingUnitName',
align: 'center',
label: '所属部门',
},
{
slot: 'joinStatus',
},
{
slot: 'option',
}
]
},
},
created() {
this.dict.load('issuingUnit','officialDocumentEmergencyLevel', 'officialDocumentReadType', 'officialDocumentConfidentialityLevel', 'officialDocumentName');
},
mounted() {
if(this.params.id) {
this.getDetail()
}
},
methods: {
onChange() {
},
readTypeChange() {
if(this.form.readType == 0) {
this.isMultiple = false
if(this.form.flowUsers.length > 1) {
this.form.flowUsers = []
}
}else {
this.isMultiple = true
}
},
getDetail() {
this.instance.post(`/app/appofficialdocumentinfo/queryDetailById?id=${this.params.id}&flag=0`, null).then((res) => {
if (res.code == 0) {
this.form = {...res.data}
this.form.files = this.form.files || []
}
});
},
save(formName, status){
this.$refs[formName].validate((valid) => {
if (valid) {
this.submit(status)
} else {
return false;
}
});
},
submit(status) {
var flowUsers = []
this.form.flowUsers.map(item => {
var info = {
flowUserId: item.id,
flowUserName: item.name,
avatar: item.avatar
}
flowUsers.push(info)
})
this.form.fileIds = []
if(this.form.files.length) {
this.form.files.map((item) => {
this.form.fileIds.push(item.id)
})
}
this.instance.post(`/app/appofficialdocumentinfo/addOrUpdate`, {
...this.form,
status: status,
flowUsers: flowUsers
}, null).then((res) => {
if (res.code == 0) {
if(this.params.id){
this.$message.success("编辑成功");
}else{
this.$message.success("提交成功");
}
this.cancel(true)
}
});
},
cancel(isRefresh) {
this.$emit('change', {
type: 'list',
isRefresh: !!isRefresh
})
},
downFileAll () {
if (this.form.files.length > 0) {
this.instance.post('/app/appofficialdocumentinfo/downLoadAllFileForDetail', null, {
responseType: 'blob',
params: {
id: this.form.id
}
}).then((res) => {
const link = document.createElement('a')
let blob = new Blob([res], { type: 'application/vnd.ms-excel' })
link.style.display = 'none'
link.href = URL.createObjectURL(blob)
var num = ''
for (let i = 0; i < 10; i++) {
num += Math.ceil(Math.random() * 10)
}
link.setAttribute('download', '公文文件' + '.zip')
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
})
} else {
this.$message.error('暂无附件提供下载')
}
},
},
};
</script>
<style lang="scss" scoped>
.managementDetail {
height: 100%;
overflow: auto;
background: #f3f6f9;
.above{
overflow: hidden;
width: 100%;
.left{
width: 50%;
float: left;
}
.right{
width: 50%;
float: right;
}
.el-select{
width: 100%;
}
.el-date-editor.el-input{
width: 100%;
}
}
.iconEdit,.Edit{
color:#5088FF;
font-size: 12px;
cursor: pointer;
padding-left: 8px;
}
.form-label{
display: inline-block;
width: 100px;
color: #666;
font-size: 14px;
text-align: right;
}
.user-content{
display: inline-block;
width: calc(100% - 100px);
}
}
</style>

View File

@@ -0,0 +1,563 @@
<template>
<section class="managementDetail">
<ai-detail>
<template #title>
<ai-title title="公文详情" isShowBottomBorder isShowBack @onBackClick="cancel(true)">
<template #rightBtn>
<ai-wechat-selecter :instance="instance" v-model="addUser" :isMultiple="form.readType == '0' ? false : true" @change="onChange" v-if="form.status === '0'">
<el-button
size="small"
type="primary"
icon="iconfont iconMediaPlayer_Play">
开始流转
</el-button>
</ai-wechat-selecter>
<ai-wechat-selecter :instance="instance" v-model="addUser" :isMultiple="form.readType == '0' ? false : true" @change="onChange" v-if="form.status === '2' && form.readType == '0'">
<el-button
size="small"
type="primary"
icon="iconfont iconResetting">
再次流转
</el-button>
</ai-wechat-selecter>
<el-button
@click="endCirculation"
v-if="form.status === '1'"
size="small"
icon="iconfont iconReject">
结束流转</el-button>
</template>
</ai-title>
</template>
<template #content>
<ai-card :title="form.documentName">
<template slot="content">
<ai-wrapper class="mar-t16" label-width="80px" :columnsNumber="3">
<ai-info-item label="公文编号:"><span>{{form.documentCode || '-'}}</span></ai-info-item>
<ai-info-item label="公文类型:"><span>{{$dict.getLabel("officialDocumentName", form.documentType) || '-'}}</span></ai-info-item>
<ai-info-item label="保密等级:"><span>{{$dict.getLabel("officialDocumentConfidentialityLevel", form.confidentialityLevel) || '-'}}</span></ai-info-item>
</ai-wrapper>
<ai-wrapper label-width="80px" :columnsNumber="3">
<ai-info-item label="阅示类型:"><span>{{$dict.getLabel("officialDocumentReadType", form.readType) || '-'}}</span></ai-info-item>
<ai-info-item label="紧急程度:"><span>{{$dict.getLabel("officialDocumentEmergencyLevel", form.emergencyLevel) || '-'}}</span></ai-info-item>
<ai-info-item label="发文机关:"><span>{{dict.getLabel('issuingUnit',form.issuingUnit)|| '-'}}</span></ai-info-item>
</ai-wrapper>
<ai-wrapper label-width="80px" :columnsNumber="3">
<ai-info-item label="发文字号:"><span>{{form.issuingFont || '-'}}</span></ai-info-item>
<ai-info-item label="签发人:"><span>{{form.signer || '-'}}</span></ai-info-item>
<ai-info-item label="发文时间:"><span>{{form.createTime || '-'}}</span></ai-info-item>
</ai-wrapper>
<ai-wrapper label-width="80px" :columnsNumber="1">
<ai-info-item label="备注:"><span>{{form.remark || '-'}}</span></ai-info-item>
</ai-wrapper>
<ai-bar title="附件" >
<template slot="right" v-if="form.files && form.files.length">
<span class="Edit" @click="downFileAll"><i class="iconfont iconDownload"></i>下载全部</span>
</template>
</ai-bar>
<ai-file-list v-if="form.files && form.files.length"
:fileList="form.files"
:fileOps="{ name: 'name', size: 'fileSizeStr' }"
></ai-file-list>
</template>
</ai-card>
<ai-card title="流转信息">
<template #right>
<ai-wechat-selecter :instance="instance" v-model="addFlow" @change="addPeople" v-if="form.readType==0 && form.status !== '2'">
<el-button
size="small"
type="primary"
icon="iconfont iconAdd">
指派人员
</el-button>
</ai-wechat-selecter>
</template>
<template #content>
<ai-wrapper
label-width="70px"
:columnsNumber="3">
<ai-info-item label="流转状态:"><span :class="'status-' + form.status">{{ dict.getLabel('documentStatus', form.status) }}</span></ai-info-item>
<ai-info-item label="当前流转对象:" label-width="98px" v-if="form.readType === '0'">{{ form.flowUserName || '-' }}</ai-info-item>
<ai-info-item></ai-info-item>
</ai-wrapper>
</template>
</ai-card>
<ai-card title="流转记录">
<template #right>
<ai-wechat-selecter :instance="instance" v-model="addFlow" @change="addFlowChange" v-if="form.readType === '1' && (form.status === '1' || form.status === '0') && $permissions('app_appofficialdocumentinfo_edit')">
<el-button
size="small"
type="primary"
icon="iconfont iconAdd">
添加人员
</el-button>
</ai-wechat-selecter>
</template>
<template #content>
<div class="ai-steps" v-if="form.readType === '0'">
<div class="ai-steps__item" v-for="(item, index) in form.flowUsers" :key="index">
<div class="ai-steps__item--left">
<div class="ai-steps__item__avatar">
<img :src="item.avatar" v-if="item.avatar">
<h2 v-else>{{ formatName(item.flowUserName) }}</h2>
<i class="iconfont iconSteps_Finished"></i>
</div>
<div class="ai-steps__item--content">
<span>{{ dict.getLabel('documentFlowStatus', item.flowStatus) }}</span>
<h2>{{ item.flowUserName }}</h2>
<p v-if="item.description">{{ item.description }}</p>
</div>
</div>
<div class="ai-steps__item--right">{{ item.flowTime }}</div>
</div>
</div>
<ai-table
class="table"
v-if="form.readType === '1'"
:tableData="tableData"
:col-configs="colConfigs"
:total="total"
:isShowPagination="false"
:current.sync="search.current"
:size.sync="search.size"
:border="true">
<el-table-column slot="options" label="操作" align="center" width="120px">
<template slot-scope="{ row }">
<span
v-if="$permissions('app_appofficialdocumentinfo_edit')"
class="iconfont iconDelete"
title="删除"
style="cursor: pointer;"
@click="remove(row.id)">
</span>
</template>
</el-table-column>
</ai-table>
</template>
</ai-card>
</template>
</ai-detail>
</section>
</template>
<script>
export default {
name: "managementDetail",
props: {
instance: Function,
dict: Object,
permissions: Function,
params: Object
},
data() {
return {
form: {
documentName: '',
documentCode: '',
documentType: '',
confidentialityLevel: '',
readType: '',
emergencyLevel: '',
issuingTime: '',
issuingUnit: '',
issuingFont: '',
signer: '',
overDescription: '',
overTime: '',
deliver: '',
remark: '',
files: [],
fileIds: [],
flowUsers: [],
},
isAdd: true,
isMultiple: true,
addUser: [],
addFlow: [],
tableData: [],
search: {
size: 10,
current: 1
},
total: 10,
colConfigs: [
{ prop: 'flowUserName', label: '姓名', align: 'center' },
{ prop: 'readTime', label: '时间', align: 'center' },
{
prop: 'readStatus',
label: '阅示情况',
align: 'center',
render: (h, params) => {
return h('span', {
style: {
color: params.row.readStatus === '0' ? '#FF8822' : '#2EA222'
}
}, this.$dict.getLabel('readingStatus', params.row.readStatus))
}
},
{ slot: 'options', label: '操作', align: 'center' }
],
};
},
computed: {
formRules(){
return {
documentName: [{required: true, message: "请输入公文名称", trigger: 'change' }],
documentCode: [{required: true, message: "请输入公文编号", trigger: 'change' }],
documentType: [{required: true, message: "请选择公文类型", trigger: 'change' }],
readType: [{required: true, message: "请选择阅示类型", trigger: 'change' }],
}
},
},
created() {
this.dict.load('issuingUnit','officialDocumentEmergencyLevel', 'officialDocumentReadType', 'officialDocumentConfidentialityLevel', 'officialDocumentName', 'documentFlowStatus', 'readingStatus');
},
mounted() {
this.form = this.params
this.showDetail = true
this.isAdd = false
this.getDetail()
},
methods: {
remove (id) {
if(this.form.flowUsers.length<=1){
return this.$message.error("至少留一个流转对象!");
}
this.$confirm('确定删除该传阅人员吗?').then(() => {
this.instance.post(`/app/appofficialdocumentflow/delete?ids=${id}`).then(res => {
if (res.code == 0) {
this.$message.success('删除成功!')
this.getDetail()
}
})
})
},
formatName (name) {
if(name == undefined){
return
}
return name.substr(name.length - 2, name.length > 2 ? (name.length - 1) : name.length)
},
addPeople() { //指派人员
this.instance.post(`/app/appofficialdocumentinfo/flowById`,null,{
params:{
flowUserId:this.addFlow[0].id,
flowUserName:this.addFlow[0].name,
avatar:this.addFlow[0].avatar,
flag:0,
id:this.form.id,
}
}).then(res => {
if (res.code == 0) {
this.$message({
message:"指派成功",
type:"success"
})
this.getDetail()
this.addFlow = []
}
})
},
addFlowChange() { //添加传阅人员
let data = this.form
const fileIds = data.files.length ? data.files.map(item => item.id) : []
const flowUsers = [...this.addFlow].map(item => {
return {
flowUserId: item.id,
flowUserName: item.name,
avatar: item.avatar
}
})
delete data.files
this.instance.post(`/app/appofficialdocumentflow/add`, {
id: this.form.id,
...data,
status: '1',
flowUsers,
fileIds
}).then(res => {
if (res.code == 0) {
this.$message.success('添加成功')
this.getDetail()
this.addFlow = []
}
})
},
onChange() {
if (!this.addUser.length) {
return this.$message.error('请选择流转人员')
}
if (this.form.readType === '0' && this.form.status === '0') {
// 开始流转
let data = this.form
const flowUsers = [...this.addUser].map(item => {
return {
flowUserId: item.id,
flowUserName: item.name,
avatar: item.avatar
}
})
const fileIds = data.files.length ? data.files.map(item => item.id) : []
delete data.files
this.instance.post(`/app/appofficialdocumentinfo/addOrUpdate`, {
id: this.form.id,
...data,
status: '1',
flowUsers: flowUsers,
fileIds
}).then(res => {
if (res.code == 0) {
this.$message.success('流转成功')
this.getDetail()
}
})
} else {
// 再次流转
this.instance.post(`/app/appofficialdocumentinfo/flowById`, null, {
params: {
flag: '1',
flowUserId: this.addUser[0].id,
flowUserName: this.addUser[0].name,
avatar: this.addUser[0].avatar,
id: this.form.id
}
}).then(res => {
if (res.code == 0) {
this.$message.success('添加成功')
this.getDetail(this.id)
}
})
}
},
readTypeChange() {
if(this.form.readType == 0) {
this.isMultiple = false
if(this.form.flowUsers.length > 1) {
this.form.flowUsers = []
}
}else {
this.isMultiple = true
}
},
getDetail() {
this.instance.post(`/app/appofficialdocumentinfo/queryDetailById?id=${this.params.id}&flag=0`, null).then((res) => {
if (res.code == 0) {
this.form = {...res.data}
this.form.files = this.form.files || []
if (res.data.readType === '1') {
this.tableData = res.data.flowUsers
this.total = res.data.flowUsers.length
}
}
});
},
save(formName, status){
this.$refs[formName].validate((valid) => {
if (valid) {
this.submit(status)
} else {
return false;
}
});
},
submit(status) {
this.form.flowUsers.map(item => {
item.flowUserId = item.id,
item.flowUserName = item.name
})
this.form.fileIds = []
if(this.form.files.length) {
this.form.files.map((item) => {
this.form.fileIds.push(item.id)
})
}
this.instance.post(`/app/appofficialdocumentinfo/addOrUpdate`, {
...this.form,
status: status
}, null).then((res) => {
if (res.code == 0) {
if(!this.isAdd){
this.$message.success("编辑成功");
}else{
this.$message.success("提交成功");
this.cancel(true)
}
}
});
},
addCancel() {
if(this.params.id) { //新增
this.cancel(true)
}else {
this.showDetail = true
}
},
cancel(isRefresh) {
this.$emit('change', {
type: 'list',
isRefresh: !!isRefresh
})
},
downFileAll () {
if (this.form.files.length > 0) {
this.instance.post('/app/appofficialdocumentinfo/downLoadAllFileForDetail', null, {
responseType: 'blob',
params: {
id: this.form.id
}
}).then((res) => {
const link = document.createElement('a')
let blob = new Blob([res], { type: 'application/vnd.ms-excel' })
link.style.display = 'none'
link.href = URL.createObjectURL(blob)
var num = ''
for (let i = 0; i < 10; i++) {
num += Math.ceil(Math.random() * 10)
}
link.setAttribute('download', '公文文件' + '.zip')
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
})
} else {
this.$message.error('暂无附件提供下载')
}
},
endCirculation () {
this.$confirm('确定结束流转?').then(() => {
this.instance.post(`/app/appofficialdocumentinfo/finishById?id=${this.form.id}`).then(res => {
if (res.code == 0) {
this.$message.success('操作成功')
this.cancel(true)
} else {
this.$message.error(res.msg)
}
})
})
},
},
};
</script>
<style lang="scss" scoped>
.managementDetail {
height: 100%;
overflow: auto;
background: #f3f6f9;
.above{
overflow: hidden;
width: 100%;
.left{
width: 50%;
float: left;
}
.right{
width: 50%;
float: right;
}
.el-select{
width: 100%;
}
.el-date-editor.el-input{
width: 100%;
}
}
.iconEdit,.Edit{
color:#5088FF;
font-size: 12px;
cursor: pointer;
padding-left: 8px;
}
}
.ai-steps {
padding-bottom: 40px;
.ai-steps__item {
display: flex;
position: relative;
align-items: center;
justify-content: space-between;
padding-bottom: 44px;
&:after {
position: absolute;
left: 20px;
top: 40px;
width: 1px;
height: 44px;
background: #DDDDDD;
content: ' ';
}
&:last-child {
padding-bottom: 0;
&:after {
display: none;
}
}
.ai-steps__item--left {
display: flex;
position: relative;
.ai-steps__item--content {
span {
color: #333;
font-size: 16px;
}
h2 {
margin-top: 4px;
color: #666666;
font-size: 14px;
}
p {
margin-top: 8px;
color: #666666;
font-size: 14px;
}
}
.ai-steps__item__avatar {
position: relative;
width: 40px;
height: 40px;
margin-right: 16px;
i {
position: absolute;
bottom: 4px;
right: 0;
color: #2ea222;
font-size: 12px;
}
img, h2 {
width: 40px;
height: 40px;
line-height: 40px;
text-align: center;
border-radius: 50%;
color: #fff;
font-size: 14px;
background: #2266FF;
}
}
}
.ai-steps__item--right {
margin-left: 20px;
flex-shrink: 0;
color: #999999;
font-size: 14px;
}
}
}
</style>

View File

@@ -0,0 +1,311 @@
<template>
<ai-list class="AppDispatchManagement">
<template slot="title">
<ai-title title="公文流转" isShowBottomBorder></ai-title>
</template>
<template slot="content">
<ai-search-bar>
<template slot="left">
<ai-select
v-model="searchObj.documentType"
placeholder="选择公文类型"
clearable
@change="(page.current = 1), getList()"
:selectList="dict.getDict('officialDocumentName')"
></ai-select>
<ai-select
v-model="searchObj.confidentialityLevel"
placeholder="选择保密等级"
clearable
@change="(page.current = 1), getList()"
:selectList="dict.getDict('officialDocumentConfidentialityLevel')"
></ai-select>
<ai-select
v-model="searchObj.status"
placeholder="选择流转状态"
clearable
@change="(page.current = 1), getList()"
:selectList="dict.getDict('documentStatus')"
></ai-select>
<ai-select
v-model="searchObj.readType"
placeholder="选择阅示类型"
clearable
@change="(page.current = 1), getList()"
:selectList="dict.getDict('officialDocumentReadType')"
></ai-select>
<!-- <el-row class="dateRange" type="flex" align="middle">
<span class="dateLabel">操作时间</span>
<el-date-picker
size="small"
v-model="searchObj.createTimeStart"
placeholder="开始日期"
@change="page.current = 1, getList()"
value-format="yyyy-MM-dd" />
<el-date-picker
size="small"
v-model="searchObj.createTimeEnd"
placeholder="结束日期"
@change="page.current = 1, getList()"
value-format="yyyy-MM-dd" />
</el-row> -->
</template>
<template slot="right">
<el-input placeholder="输入公文名称/编号"
v-model="searchObj.name"
size="small"
v-throttle="() => {page.current = 1, getList()}"
clearable
@clear="page.current = 1, searchObj.name = '', getList()"
prefix-icon="iconfont iconSearch"/>
</template>
</ai-search-bar>
<ai-search-bar class="mt10">
<template slot="left">
<el-button type="primary" icon="iconfont iconAdd" @click="toAdd({})"
>添加
</el-button
>
</template>
</ai-search-bar>
<ai-table
:tableData="tableData"
:col-configs="colConfigs"
:total="page.total"
ref="aitableex"
:current.sync="page.current"
row-key="id"
default-expand-all
:tree-props="{ children: 'merchandiseList' }"
:size.sync="page.size"
@getList="getList"
@selection-change="handleSelectionChange"
>
<el-table-column slot="selection" type="selection" width="55"></el-table-column>
<el-table-column slot="options" label="操作" align="center" width="200">
<template slot-scope="{ row }">
<el-button v-if="row.status != 0" type="text" @click="goDetail(row)">详情</el-button>
<el-button v-if="row.status == 0" type="text" @click="toAdd(row)">编辑</el-button>
<el-button type="text" @click="del(row)">删除</el-button>
</template>
</el-table-column>
</ai-table>
</template>
</ai-list>
</template>
<script>
export default {
name: "management",
props: {
instance: Function,
dict: Object,
permissions: Function,
areaId: String,
},
data() {
return {
searchObj: {
documentType: '',
confidentialityLevel: '',
readType: '',
createTimeStart: null,
createTimeEnd: null,
name: '',
},
page: {
size: 10,
current: 1,
total: 0,
},
tableData: [],
shopList: [],
ids: [],
};
},
computed: {
colConfigs() {
return [
{slot: "selection", label: "", align: "center"},
{
prop: "documentCode",
label: "公文编号",
width: 120,
align: "center",
},
{
prop: "documentName",
label: "公文名称",
},
{
prop: "documentType",
label: "公文类型",
width: 120,
align: "center",
formart: (documentType) =>
this.$dict.getLabel("officialDocumentName", documentType),
},
{
prop: "readType",
label: "阅示类型",
width: 120,
align: "center",
formart: (readType) =>
this.$dict.getLabel("officialDocumentReadType", readType),
},
{
prop: "confidentialityLevel",
label: "保密等级",
width: 120,
align: "center",
formart: (confidentialityLevel) =>
this.$dict.getLabel("officialDocumentConfidentialityLevel", confidentialityLevel),
},
{
prop: "flowUserName",
label: "当前流转对象",
width: 180,
align: "center",
},
{
prop: "status",
label: "流转状态",
width: 120,
align: "center",
render: (h, {row}) => {
return h('span', {style: {color: this.dict.getColor('documentStatus', row.status)}}, this.dict.getLabel('documentStatus', row.status))
},
},
{
prop: "createTime",
label: "操作时间",
width: 180,
align: "center",
},
{
prop: "createUserName",
label: "操作人",
width: 120,
align: "center",
},
{slot: "options", label: "操作"},
];
},
},
created() {
this.dict.load('officialDocumentName', 'officialDocumentConfidentialityLevel', 'officialDocumentReadType', 'documentStatus').then(() => {
this.$nextTick(() => this.getList())
})
},
methods: {
changeTime() {
this.page.current = 1
this.getList()
},
getList() {
this.instance.post(`/app/appofficialdocumentinfo/list`, null, {
params: {
...this.searchObj,
...this.page
},
}).then((res) => {
if (res.code == 0) {
this.tableData = res.data.records;
this.tableData.map((item) => {
if (item.createTime) {
item.createTime = item.createTime.substring(0, 10)
} else {
item.createTime = '-'
}
})
this.page.total = res.data.total;
}
});
},
reset() {
Object.keys(this.searchObj).forEach((e) => {
this.searchObj[e] = "";
});
this.searchObj.createTimeStart = null;
this.searchObj.createTimeEnd = null;
this.getList();
},
toAdd(params) {
this.$emit('change', {
type: 'add',
params: params
})
},
goDetail(row) {
this.$emit('change', {
type: 'detail',
params: {
...row
}
})
},
del(item) {
this.$confirm("删除后不可恢复,是否要删除该公文?", {
type: 'error'
}).then(() => {
this.instance
.post(`/app/appofficialdocumentinfo/delete?ids=${item.id}`)
.then((res) => {
if (res.code == 0) {
this.$message.success("删除成功!");
this.getList();
}
});
});
},
handleSelectionChange(val) {
this.ids = [];
val.forEach(e => {
this.ids.push(e.id)
})
}
},
};
</script>
<style lang="scss" scoped>
.AppDispatchManagement {
height: 100%;
overflow: auto;
background: #f3f6f9;
::v-deep .el-range-editor--small.el-input__inner {
width: 258px;
}
::v-deep .dateRange {
.dateLabel {
height: 32px;
border: 1px solid #D0D4DC;
line-height: 32px;
padding: 0 8px;
background: #F5F5F5;
}
.el-input__inner {
border-radius: 0;
transform: translateX(-1px);
}
}
.iconfont {
cursor: pointer;
margin-right: 8px;
}
.iconCorrect {
color: #53b43b;
}
.iconReject {
color: #e75555;
padding: 0 8px;
}
}
</style>

View File

@@ -0,0 +1,766 @@
<template>
<section class="statistics tabs-init el-tabs__content_f3f6f9">
<div style="margin-top: 16px;height: 270px;">
<div class="left">
<div class="item-left mar-b16">
<div class="item-left-title">公文总数</div>
<div class="item-left-num" style="color:#4B87FE;">{{totalOfficialDocumentStatistics}}</div>
</div>
<div class="item-left">
<div class="item-left-title">本月新增</div>
<div class="item-left-num" style="color:#2EA222;">{{newMonthonStatistics}}</div>
</div>
</div>
<div class="right">
<div class="chart-content" style="padding-right:0;">
<div class="chart-line">
<div class="chart-title">近12个月公文登记情况</div>
<div v-if="lineChartData.length"
class="chart-info"
style="
width: 100%;
height: 206px;
padding: 16px 16px 20px 0;
box-sizing: border-box;
"
id="chartLine"
></div>
<ai-empty v-else style="height: 148px;"></ai-empty>
</div>
</div>
</div>
</div>
<div class="chart-content">
<div class="chart-line" style="margin-right: 16px;">
<div class="chart-title">阅示类型统计</div>
<div style="overflow:hidden;">
<div
class="chart-info"
style="
width: 288px;
height: 288px;
padding: 16px 0 0 16px;
box-sizing: border-box;
float:left;
"
id="readType"
></div>
<div class="list-type mar-t102">
<div class="item" v-for="(item, index) in readTypeList" :key="index">
<div class="type-title">
<span class="item-color-bg" :style="{'backgroundColor': item.bgColor}"></span>{{item.title}}
</div>
<div class="num">{{item.num}}</div>
</div>
</div>
</div>
</div>
<div class="chart-line">
<div class="chart-title">公文类型统计</div>
<div style="overflow:hidden;">
<div
class="chart-info"
style="
width: 288px;
height: 288px;
padding: 16px 0 0 16px;
box-sizing: border-box;
float:left;
"
id="docType"
></div>
<div class="list-type mar-t60">
<div class="item" v-for="(item, index) in docTypeList" :key="index">
<div class="type-title">
<span class="item-color-bg" :style="{'backgroundColor': item.bgColor}"></span>{{item.title}}
</div>
<div class="num">{{item.num}}</div>
</div>
</div>
</div>
</div>
</div>
</section>
</template>
<script>
import { mapState } from "vuex";
import charts from "echarts";
export default {
name: "statistics",
props: {
instance: Function,
dict: Object,
permissions: Function,
},
data() {
return {
readTypeList: [
{
title: '传阅',
num: '0',
bgColor: '#4B87FE'
},
{
title: '批示',
num: '0',
bgColor: '#FFAA44'
}
],
docTypeList: [
{
title: '决议',
num: '0',
bgColor: '#FF4466'
},
{
title: '决定',
num: '0',
bgColor: '#FFAA44'
},
{
title: '通知',
num: '0',
bgColor: '#4B87FE'
},
{
title: '通告',
num: '0',
bgColor: '#45A3FF'
},
{
title: '函',
num: '0',
bgColor: '#2EA222'
},
{
title: '其它',
num: '0',
bgColor: '#B244FF'
},
],
lineChartTitle: [],
lineChartData: [],
totalOfficialDocumentStatistics: 0,
newMonthonStatistics: 0,
};
},
computed: {
...mapState(["user"]),
},
mounted() {
this.getInfo()
},
methods: {
getInfo() {
this.instance.post(`/app/appofficialsenddeliverinfo/getStatistics`).then((res) => {
if (res.code == 0) {
this.newMonthonStatistics = res.data.newMonthonStatistics || 0
this.totalOfficialDocumentStatistics = res.data.totalOfficialSendStatistics || 0
if(res.data.officialRegistrationStatistics && res.data.officialRegistrationStatistics.length) {
res.data.officialRegistrationStatistics.map(item => {
this.lineChartTitle.push(item.name)
this.lineChartData.push(item.v1)
})
this.$nextTick(() => {
this.setLineChart()
})
}
if(res.data.readTheTypeStatistics && res.data.readTheTypeStatistics.length) {
res.data.readTheTypeStatistics.map(item => {
if(item.name == 0){
this.readTypeList[1].num = item.v1 || 0
}
if(item.name == 1){
this.readTypeList[0].num = item.v1 || 0
}
})
this.setReadChart()
}
if(res.data.officialSendTypeStatistics && res.data.officialSendTypeStatistics.length) {
res.data.officialSendTypeStatistics.map(item => {
if(item.name == 0){
this.docTypeList[0].num = item.v1
}
if(item.name == 1){
this.docTypeList[1].num = item.v1
}
if(item.name == 3){
this.docTypeList[2].num = item.v1
}
if(item.name == 2){
this.docTypeList[3].num = item.v1
}
if(item.name == 4){
this.docTypeList[4].num = item.v1
}
if(item.name == 5){
this.docTypeList[5].num = item.v1
}
})
this.setDocChart()
}
}
});
},
setLineChart() {
var chartLine = charts.init(document.getElementById("chartLine"));
var option = {
title: {
text: "",
},
tooltip: {
trigger: "axis",
},
grid: {
top: "10%",
left: "2%",
right: "2%",
bottom: "2%",
containLabel: true,
},
xAxis: {
type: "category",
boundaryGap: false,
data: this.lineChartTitle,
},
yAxis: {
type: "value",
},
series: [
{
name: "",
type: "line",
itemStyle: {
normal: {
color: "#26f",
},
},
data: this.lineChartData,
},
],
};
chartLine.setOption(option);
},
setReadChart() {
var chart = charts.init(document.getElementById("readType"));
var option = {
tooltip: {
trigger: "item",
formatter: "{b}: {c} ({d}%)",
},
series: [
{
name: "",
type: "pie",
radius: ["50%", "80%"],
avoidLabelOverlap: false,
label: {
show: true,
position: 'inside',
formatter: '{d}%',
fontSize: '14',
},
emphasis: {
label: {
show: true,
fontSize: '14',
fontWeight: 'bold'
}
},
labelLine: {
show: false
},
data: [
{
value: this.readTypeList[0].num,
name: '传阅',
itemStyle: {
normal: {
color: '#4B87FE'
}
},
},
{
value: this.readTypeList[1].num,
name: '批示',
itemStyle: {
normal: {
color: '#FFAA44'
}
},
}
],
},
],
};
chart.setOption(option);
},
setDocChart() {
var chart = charts.init(document.getElementById("docType"));
var option = {
tooltip: {
trigger: "item",
formatter: "{b}: {c} ({d}%)",
},
series: [
{
name: "",
type: "pie",
radius: ["50%", "80%"],
avoidLabelOverlap: false,
label: {
show: true,
position: 'inside',
formatter: '{d}%',
fontSize: '14',
},
emphasis: {
label: {
show: true,
fontSize: '14',
fontWeight: 'bold'
}
},
labelLine: {
show: false
},
data: [
{
value: this.docTypeList[0].num,
name: '决议',
itemStyle: {
normal: {
color: '#FF4466'
}
},
},
{
value: this.docTypeList[1].num,
name: '决定',
itemStyle: {
normal: {
color: '#FFAA44'
}
},
},
{
value: this.docTypeList[2].num,
name: '通知',
itemStyle: {
normal: {
color: '#4B87FE'
}
},
},
{
value: this.docTypeList[3].num,
name: '通告',
itemStyle: {
normal: {
color: '#45A3FF'
}
},
},
{
value: this.docTypeList[4].num,
name: '函',
itemStyle: {
normal: {
color: '#2EA222'
}
},
},
{
value: this.docTypeList[5].num,
name: '其它',
itemStyle: {
normal: {
color: '#B244FF'
}
},
},
],
},
],
};
chart.setOption(option);
},
},
};
</script>
<style lang="scss" scoped>
.statistics {
height: 100%;
width: 100%;
overflow: auto;
display: flex;
flex-direction: column;
background: #f3f6f9;
// overflow: hidden;
.left{
width: 29%;
float: left;
margin-left: 16px;
.item-left{
padding: 0 20px;
width: 100%;
height: 120px;
background: #FFFFFF;
box-shadow: 0px 16px 32px 0px rgba(0, 0, 0, 0.02);
border-radius: 4px;
box-sizing: border-box;
.item-left-title{
color: #333;
font-size: 16px;
padding: 20px 0 16px 0;
}
.item-left-num{
font-size: 32px;
text-align: right;
}
}
}
.right{
width: calc(70% - 20px);
float: left;
}
.mar-t102{
margin-top: 102px;
}
.mar-t60{
margin-top: 60px;
}
.list-type{
width:calc(100% - 360px);
float:right;
margin-left: 20px;
font-size: 14px;
padding-right: 40px;
.item{
display: flex;
justify-content: space-between;
line-height: 20px;
margin-bottom: 8px;
}
.type-title{
color: #666;
.item-color-bg{
display: inline-block;
width: 8px;
height: 8px;
background: #4B87FE;
border-radius: 1px;
margin-right: 6px;
}
}
.num{
color: #333;
text-align: right;
}
}
.chart-content {
width: 100%;
// height: 336px;
border-radius: 4px;
padding: 0 16px 16px 16px;
box-sizing: border-box;
display: flex;
.chart-line {
width: 100%;
height: 100%;
background-color: #fff;
box-shadow: 0px 16px 32px 0px rgba(0, 0, 0, 0.02);
}
.chart-title {
line-height: 48px;
border-bottom: 1px solid #e6e8ee;
padding-left: 16px;
color: #333;
font-size: 16px;
}
div {
flex: 1;
}
}
.tab-row {
padding: 16px 16px 16px 16px;
width: 100%;
box-sizing: border-box;
display: flex;
justify-content: space-between;
.tab-col {
height: 64px;
flex: 1;
background-color: #fff;
margin-right: 20px;
border-radius: 4px;
border: 1px solid rgba(216, 224, 232, 1);
overflow: hidden;
.tab-title {
display: inline-block;
font-size: 14px;
color: #333;
height: 14px;
line-height: 14px;
vertical-align: super;
}
.tab-num {
height: 24px;
font-size: 20px;
font-weight: bold;
color: #333;
line-height: 24px;
font-family: DINAlternate-Bold, serif;
float: right;
line-height: 64px;
padding-right: 16px;
}
}
.tab-col:nth-last-child(1) {
margin-right: 0;
}
}
.icon {
display: inline-block;
width: 24px;
height: 24px;
padding: 20px 8px 0 16px;
}
.card-panel {
flex: 1;
background: #fff;
border: 1px solid #d8e0e8;
border-radius: 4px;
box-sizing: border-box;
padding: 12px 16px 0 16px;
b {
font-size: 16px;
font-weight: 600;
color: rgba(51, 51, 51, 1);
line-height: 22px;
}
#ASBarChart {
height: 286px;
& + .no-data {
margin: 83px auto;
}
}
#PartyAgePieChart,
#PartyEduPieChart {
height: 264px;
& + .no-data {
margin: 72px auto;
}
}
}
.party_title {
height: 48px;
line-height: 48px;
background: #fff;
text-indent: 16px;
font-weight: bold;
}
.party_content {
flex: 1;
display: flex;
padding: 16px;
.party_left {
width: 280px;
background: #eaedf1;
border: 1px solid #d8dce3;
position: relative;
border-radius: 4px;
display: flex;
flex-direction: column;
.p {
height: 28px;
line-height: 28px;
background: #d9e0e9;
font-size: 12px;
color: #333;
text-indent: 16px;
}
.left_tree {
padding: 8px;
flex: 1;
display: flex;
flex-direction: column;
position: relative;
.left_cont {
width: 95%;
position: absolute;
top: 38px;
margin-top: 8px;
height: calc(100% - 80px);
overflow-y: auto;
.el-tree {
background: #eaedf1;
}
.right_btn {
width: 96px;
background: #fff;
border-radius: 2px;
font-size: 12px;
padding: 4px 0;
position: fixed;
z-index: 999;
li {
height: 28px;
line-height: 28px;
cursor: pointer;
text-indent: 12px;
}
li:hover {
background-color: #eff6ff;
color: #5088ff;
}
}
}
}
.btn_img {
position: absolute;
bottom: 0;
background: #f5f6f7;
height: 32px;
line-height: 32px;
width: 100%;
display: flex;
text-align: center;
border-top: 1px solid #d8dce3;
border-radius: 0 0 4px 4px;
span {
flex: 1;
width: 16px;
height: 16px;
cursor: pointer;
}
}
}
.party_right {
flex: 1;
overflow: auto;
margin-left: 11px;
.total-panel {
margin-bottom: 21px;
li {
flex: 1;
margin-right: 32px;
display: flex;
background: #fff;
border: 1px solid #d8e0e8;
border-radius: 4px;
color: #333;
padding: 20px;
font-weight: bold;
height: 97px;
box-sizing: border-box;
.icon {
width: 24px;
height: 24px;
margin-right: 8px;
}
&:last-child {
margin-right: 0;
}
p {
font-size: 14px;
color: rgba(51, 51, 51, 1);
line-height: 24px;
}
b {
font-size: 20px;
color: rgba(51, 51, 51, 1);
line-height: 40px;
}
}
}
}
}
.operation {
overflow: hidden;
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 64px;
line-height: 64px;
display: flex;
z-index: 1000;
align-items: center;
justify-content: center;
background-color: #f3f6f9;
box-shadow: inset 0px 1px 0px 0px #eeeeee;
button {
width: 92px;
height: 32px;
padding: 0 !important;
}
.delete-btn {
background-color: #fff;
}
}
.mask {
.content {
padding-bottom: 100px;
}
.el-table {
border: 1px solid #d8e0e8;
border-bottom: 0;
}
p {
line-height: 28px;
text-align: right;
cursor: pointer;
color: #5088ff;
width: 88px;
float: right;
padding-bottom: 8px;
}
}
.vc-input-120 {
width: 120px !important;
float: right;
padding-right: 16px;
.el-input__inner {
width: 120px !important;
}
}
}
</style>

View File

@@ -0,0 +1,66 @@
<template>
<div class="doc-circulation">
<keep-alive :include="['List']">
<component ref="component" :is="component" @change="onChange" :params="params" :instance="instance" :dict="dict"></component>
</keep-alive>
</div>
</template>
<script>
import List from './components/List'
import Add from './components/Add'
export default {
name: 'AppForm',
label: '配置表单',
props: {
instance: Function,
dict: Object
},
data () {
return {
component: 'List',
params: {},
include: []
}
},
components: {
Add,
List
},
mounted () {
},
methods: {
onChange (data) {
if (data.type === 'Add') {
this.component = 'Add'
this.params = data.params
}
if (data.type === 'list') {
this.component = 'List'
this.params = data.params
this.$nextTick(() => {
if (data.isRefresh) {
this.$refs.component.getList()
}
})
}
}
}
}
</script>
<style lang="scss">
.doc-circulation {
height: 100%;
background: #F3F6F9;
overflow: auto;
}
</style>

View File

@@ -0,0 +1,281 @@
<template>
<ai-detail class="form-add" :class="[currIndex === 1 ? 'form-add__active' : '']">
<ai-title title="表单配置" slot="title" isShowBottomBorder isShowBack @onBackClick="cancel(false)"></ai-title>
<template #content>
<div class="ai-step">
<div class="ai-step__item"
:class="[currIndex >= index ? 'ai-step__item--active' : '']"
v-for="(item, index) in statusList"
:key="index">
<div class="ai-step__item--icon" v-if="currIndex <= index">
<i v-if="currIndex === index"></i>
</div>
<div class="el-icon-success" v-if="currIndex > index">
</div>
<span>{{ item }}</span>
</div>
</div>
<basic-info ref="basicInfo" v-model="basicInfo" v-show="currIndex === 0" :dict="dict" :instance="instance"></basic-info>
<form-layout :appType="basicInfo.appType" :currIndex="currIndex" class="form-config__wrapper" v-model="tableInfos" ref="form" v-show="currIndex === 1" :dict="dict" :instance="instance"></form-layout>
<form-config
ref="config"
:showListFields="showListFields"
:btns="btns"
:fuzzyQueryFields="fuzzyQueryFields"
:tableInfos="tableInfos"
:orderFields="orderFields"
v-if="currIndex === 2">
</form-config>
</template>
<template #footer>
<el-button @click="cancel">取消</el-button>
<el-button @click="back" v-if="currIndex > 0">上一步</el-button>
<el-button @click="next" type="primary">{{ currIndex === 2 ? '完成' : '下一步' }}</el-button>
</template>
</ai-detail>
</template>
<script>
import BasicInfo from './BasicInfo.vue'
import FormLayout from './FormLayout.vue'
import FormConfig from './FormConfig.vue'
export default {
name: 'add',
props: {
instance: Function,
dict: Object,
params: Object,
type: String
},
components: {
FormLayout,
BasicInfo,
FormConfig
},
data () {
return {
currIndex: 0,
basicInfo: {
saasPlatformId: '',
menuLeve1Style: '',
saasPlatformName: '',
menuLevel1Name: '',
menuLevel3Name: '',
menuLevel2Name: '',
appType: ''
},
orderFields: [],
showListFields: [],
fuzzyQueryFields: [],
btns: [],
btnKeys: ['insertEnable', 'importEnable', 'exportEnalbe', 'editEnable', 'deleteEnable', 'batchDelEnable'],
configInfo: {
btns: [],
orderType: '0',
fieldName: ''
},
info: {},
tableInfos: [],
statusList: ['基础设置', '表单设计', '列表设计']
}
},
mounted () {
if (this.params.id) {
this.getInfo()
}
},
methods: {
cancel (isRefresh) {
this.$emit('change', {
type: 'list',
isRefresh: isRefresh ? true : false,
isQuote: this.params.isQuote ? true : false
})
},
confirm () {
},
back () {
this.currIndex = this.currIndex - 1
},
confirmBasicInfo () {
return this.$refs.basicInfo.validate()
},
getInfo () {
this.instance.post(`/app/appapplicationinfo/queryDetailById?id=${this.params.id}`).then(res => {
if (res.code === 0) {
this.info = res.data
this.basicInfo = {
saasPlatformId: res.data.saasPlatformId,
menuLeve1Style: res.data.menuLeve1Style,
saasPlatformName: res.data.saasPlatformName,
menuLevel1Name: res.data.menuLevel1Name,
menuLevel3Name: res.data.menuLevel3Name,
menuLevel2Name: res.data.menuLevel2Name,
appType: res.data.appType,
corpId: res.data.corpId,
corpName: res.data.corpName
}
this.fuzzyQueryFields = res.data.fuzzyQueryFields
this.tableInfos = res.data.tableInfos
this.showListFields = res.data.showListFields
this.orderFields = res.data.orderFields
this.btns = Object.keys(res.data).filter(v => {
return this.btnKeys.indexOf(v) > -1 && res.data[v] === '1'
})
}
})
},
submit (info) {
this.instance.post(`/app/appapplicationinfo/addOrUpdate`, {
...this.info,
...this.basicInfo,
tableInfos: this.tableInfos,
...info.btns,
id: this.params.id,
applicationName: this.basicInfo.menuLevel3Name || this.basicInfo.menuLevel2Name,
fuzzyQueryFields: info.fuzzyQueryFields,
orderType: info.orderType,
orderFields: info.orderFields,
showListFields: info.showListFields
}).then(res => {
if (res.code === 0) {
this.$message.success(this.params.id ? '编辑成功' : '添加成功')
this.cancel(true)
}
})
},
next () {
if (this.currIndex === 0) {
if (!this.$refs.basicInfo.validate()) return
}
if (this.currIndex === 1) {
this.$refs.form.onConfirm()
}
if (this.currIndex === 2) {
const info = this.$refs.config.validate()
if (!info) return
this.submit(info)
return false
}
this.currIndex = this.currIndex + 1
}
}
}
</script>
<style lang="scss" scoped>
.form-add {
&.form-add__active {
::v-deep .ai-detail__content--wrapper {
max-width: 100%!important;
height: 100%!important;
background: #F5F6F9;
}
.form-config__wrapper {
height: calc(100% - 52px);
overflow-y: hidden;
}
::v-deep .ai-detail__content {
height: calc(100% - 114px)!important;
padding: 0!important;
overflow: hidden!important;
}
}
.ai-step {
display: flex;
align-items: center;
justify-content: center;
margin-top: 4px;
margin-bottom: 24px;
.ai-step__item {
display: flex;
position: relative;
align-items: center;
margin-right: 216px;
&.ai-step__item--active {
span {
color: #2266FF;
}
.ai-step__item--icon {
display: flex;
align-items: center;
justify-content: center;
border-color: #2266FF;
i {
width: 12px;
height: 12px;
border-radius: 50%;
background: #2266FF;
}
}
}
&:after {
position: absolute;
top: 50%;
right: -208px;
width: 200px;
height: 2px;
background: #D0D4DC;
content: ' ';
transform: translateY(-50%);
}
&:last-child {
margin-right: 0;
&::after {
display: none;
}
}
.ai-step__item--icon {
width: 24px;
height: 24px;
margin-right: 8px;
border-radius: 50%;
background: #FFFFFF;
border: 2px solid #D0D4DC;
}
.el-icon-success {
width: 24px;
height: 24px;
font-size: 24px;
margin-right: 8px;
color: #2266FF;
border-radius: 50%;
}
span {
color: #666666;
font-size: 14px;
}
}
}
}
</style>

View File

@@ -0,0 +1,151 @@
<template>
<div class="basicInfo">
<el-form ref="form" :model="form" label-width="110px" label-position="right">
<ai-card title="基本信息">
<template #content>
<div class="ai-form">
<el-form-item label="所属平台" prop="saasPlatformId" style="width: 100%;" :rules="[{ required: true, message: '请选择所属平台', trigger: 'change' }]">
<el-select
size="small"
style="width: 100%;"
placeholder="请选择所属平台"
clearable
@change="onChange"
v-model="form.saasPlatformId">
<el-option
v-for="(item, index) in sassList"
:key="index"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item v-if="form.saasPlatformId" style="width: 100%;" label="所属企业" prop="corpId" :rules="[{ required: true, message: '请选择所属企业', trigger: 'change' }]">
<ai-select
v-model="form.corpId"
placeholder="请选择所属企业"
clearable
@change="onCompanyChange"
:selectList="companyList">
</ai-select>
</el-form-item>
<el-form-item style="width: 100%;" label="一级菜单名称" prop="menuLevel1Name" :rules="[{ required: true, message: '请输入一级菜单名称', trigger: 'change' }]">
<el-input size="small" placeholder="请输入一级菜单名称" :maxlength="8" v-model="form.menuLevel1Name"></el-input>
</el-form-item>
<el-form-item style="width: 100%;" label="二级菜单名称" prop="menuLevel2Name" :rules="[{ required: true, message: '请输入二级菜单名称', trigger: 'change' }]">
<el-input size="small" placeholder="请输入二级菜单名称" :maxlength="8" v-model="form.menuLevel2Name"></el-input>
</el-form-item>
<el-form-item style="width: 100%;" label="三级菜单名称" prop="menuLevel3Name">
<el-input size="small" placeholder="请输入三级菜单名称" :maxlength="8" v-model="form.menuLevel3Name"></el-input>
</el-form-item>
<el-form-item style="width: 100%;" label="应用类型" prop="appType">
<ai-select
v-model="form.appType"
placeholder="请选择应用类型"
clearable
:selectList="dict.getDict('diyAppType')">
</ai-select>
</el-form-item>
</div>
</template>
</ai-card>
</el-form>
</div>
</template>
<script>
export default {
name: 'basicInfo',
model: {
prop: 'value',
event: 'change',
},
props: {
instance: Function,
dict: Object,
value: Object
},
data () {
return {
form: {
saasPlatformId: '',
menuLeve1Style: '',
saasPlatformName: '',
menuLevel1Name: '',
menuLevel2Name: '',
menuLevel3Name: '',
appType: '',
corpId: '',
corpName: ''
},
companyList: [],
sassList: []
}
},
watch: {
value (v) {
this.form = JSON.parse(JSON.stringify(v))
if (this.form.saasPlatformId) {
this.getCompanyList()
}
}
},
created () {
this.dict.load('diyAppType')
},
mounted () {
this.getSassList()
this.form = JSON.parse(JSON.stringify(this.value))
},
methods: {
onChange (e) {
this.form.saasPlatformName = this.sassList.filter(v => v.id === e)[0].name
this.form.saasPlatformId && this.getCompanyList()
},
validate () {
let result = false
this.$refs.form.validate(valid => {
result = valid
})
this.$emit('change', this.form)
return result
},
onCompanyChange (e) {
this.form.corpName = this.companyList.filter(v => v.dictValue === e)[0].dictName
},
getCompanyList () {
this.instance.post(`/app/appCorp/page?current=1&size=1000&saasId=${this.form.saasPlatformId}`).then(res => {
if (res.data.records.length) {
this.companyList = res.data.records.map(v => {
return {
dictValue: v.corpId,
dictName: v.name
}
})
}
})
},
getSassList () {
this.instance.post(`/app/appSaas/listAll`).then(res => {
if (res.data) {
this.sassList = res.data
}
})
}
}
}
</script>
<style scoped lang="scss">
</style>

View File

@@ -0,0 +1,244 @@
<template>
<div class="basicInfo">
<ai-card title="搜索字段" class="search-wrapper">
<template #content>
<el-checkbox-group v-model="queryFields">
<el-checkbox
:label="`${item.fieldDbName}~${item.fieldName}`"
v-for="(item, index) in tableInfos"
:key="index">
{{ item.fieldName }}
</el-checkbox>
</el-checkbox-group>
</template>
</ai-card>
<ai-card title="表格字段">
<template #content>
<div class="ai-table">
<div class="el-table el-table--border ai-header__border">
<el-scrollbar>
<table cellspacing="0" cellpadding="0" border="0" class="el-table__body">
<draggable element="thead" animation="500" class="el-table__header is-leaf ai-table__header" :sort="true" v-model="showFields">
<th v-for="(item, index) in showFields" style="background: #f3f4f5; text-align: center;" class="ai-table__header" :key="index">{{ item.fieldName }}</th>
</draggable>
<tbody element="tbody">
<tr>
<td @click="handleShow(index, item.isShow)" v-for="(item, index) in showFields" :key="index">{{ item.isShow ? '已显示' : '已隐藏' }}</td>
</tr>
</tbody>
</table>
</el-scrollbar>
</div>
</div>
</template>
</ai-card>
<ai-card title="排序和操作按钮">
<template #content>
<el-form ref="form" class="ai-form" :model="form" label-width="110px" label-position="right">
<el-form-item label="排序字段" prop="field">
<el-select
size="small"
placeholder="默认按创建时间排序"
clearable
v-model="form.field">
<el-option
v-for="(filed, index) in tableInfos"
:key="index"
:label="filed.fieldName"
:value="`${filed.fieldDbName}~${filed.fieldName}`">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="排序类型" prop="orderType" :rules="[{ required: true, message: '请输入排序类型', trigger: 'change' }]">
<el-radio-group v-model="form.orderType">
<el-radio label="asc">升序</el-radio>
<el-radio label="desc">降序</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="按钮配置" prop="btns" style="width: 100%;" :rules="[{ required: true, message: '请输入按钮配置', trigger: 'change' }]">
<el-checkbox-group v-model="form.btns">
<el-checkbox label="insertEnable">添加</el-checkbox>
<el-checkbox label="importEnable">导入</el-checkbox>
<el-checkbox label="exportEnalbe">导出</el-checkbox>
<el-checkbox label="editEnable">编辑</el-checkbox>
<el-checkbox label="deleteEnable">删除</el-checkbox>
<el-checkbox label="batchDelEnable">批量删除</el-checkbox>
</el-checkbox-group>
</el-form-item>
</el-form>
</template>
</ai-card>
</div>
</template>
<script>
import draggable from 'vuedraggable'
export default {
name: 'configForm',
props: {
tableInfos: Array,
btns: Array,
showListFields: Array,
orderFields: Array,
fuzzyQueryFields: Array
},
components: {
draggable
},
data () {
return {
queryFields: [],
tableData: [{}],
btnKeys: ['insertEnable', 'importEnable', 'exportEnalbe', 'editEnable', 'deleteEnable', 'batchDelEnable'],
form: {
btns: [],
orderType: 'asc',
field: ''
},
showFields: []
}
},
mounted () {
const showIds = this.showListFields.map(v => v.fieldDbName)
this.showFields = JSON.parse(JSON.stringify(this.tableInfos)).map(item => {
item.isShow = showIds.indexOf(item.fieldDbName) > -1 ? true : false
return item
})
if (!this.showListFields.length) {
this.showFields.map(v => {
v.isShow = true
return v
})
}
this.tableInfos.map(item => {
this.tableData[0][item.fieldDbName] = '删除'
})
if (this.btns.length) {
this.form.btns = this.btns
}
const tableInfosIds = this.tableInfos.map(v => v.fieldDbName)
if (this.orderFields.length) {
let arr = this.orderFields.filter(v => {
return tableInfosIds.indexOf(v.fieldDbName) > -1
}).map(item => {
return `${item.fieldDbName}~${item.fieldName}`
})
if (arr.length) {
this.form.field = arr[0]
}
}
if (this.fuzzyQueryFields.length) {
this.queryFields = this.fuzzyQueryFields.filter(v => {
return tableInfosIds.indexOf(v.fieldDbName) > -1
}).map(item => {
return `${item.fieldDbName}~${item.fieldName}`
})
}
},
methods: {
validate () {
let result = false
this.$refs.form.validate(valid => {
result = valid
})
if (!result) {
return false
}
const btns = {}
this.btnKeys.forEach(item => {
btns[item] = this.form.btns.indexOf(item) > -1 ? 1 : 0
})
return {
btns,
orderFields: [{
fieldName: this.form.field.split('~')[1],
fieldDbName: this.form.field.split('~')[0],
orderType: this.form.orderType
}],
showListFields: this.showFields.filter(v => v.isShow).map((v, index) => {
return {
fieldName: v.fieldName,
fieldDbName: v.fieldDbName,
showListIndex: index
}
}),
fuzzyQueryFields: this.queryFields.map(v => {
return {
fieldName: v.split('~')[1],
fieldDbName: v.split('~')[0]
}
})
}
},
handleShow (index, isShow) {
const total = this.showFields.map(v => v.isShow).filter(v => !!v)
if (total.length <= 1 && isShow) {
return this.$message.error('表格列数不能小于1')
}
this.$set(this.showFields[index], 'isShow', !isShow)
}
}
}
</script>
<style scoped lang="scss">
.basicInfo {
.search-wrapper {
::v-deep .el-checkbox-group {
display: flex;
flex-wrap: wrap;
.el-checkbox {
width: 16.66%;
margin-bottom: 10px;
}
}
}
}
.ai-table {
.el-table--border {
border: 1px solid #d0d4dc;
border-bottom: none;
border-right: none;
}
table {
min-width: 100%;
}
th, tr {
min-width: 100px;
cursor: move;
}
tr {
td {
cursor: pointer;
color: #26f;
text-align: center;
user-select: none;
&:hover {
opacity: 0.7;
}
}
}
}
</style>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,182 @@
<template>
<ai-list class="appform">
<template slot="title">
<ai-title title="表单配置" isShowBottomBorder></ai-title>
</template>
<template slot="content">
<ai-search-bar class="search-bar">
<template #left>
<el-button size="small" type="primary" icon="iconfont iconAdd" @click="toAdd('')">添加</el-button>
</template>
<template slot="right">
<el-input
v-model="search.applicationName"
size="small"
v-throttle="() => {search.current = 1, getList()}"
placeholder="请输入菜单名称"
clearable
@clear="search.current = 1, search.applicationName = '', getList()"
suffix-icon="iconfont iconSearch">
</el-input>
</template>
</ai-search-bar>
<ai-table
:tableData="tableData"
:col-configs="colConfigs"
:total="total"
v-loading="loading"
style="margin-top: 6px;"
:current.sync="search.current"
:size.sync="search.size"
@getList="getList">
<el-table-column slot="options" width="180px" fixed="right" label="操作" align="center">
<template slot-scope="{ row }">
<div class="table-options">
<el-button type="text" @click="push(row.id)" v-if="row.pushStatus === '0'">推送</el-button>
<el-button type="text" @click="operate(row.id, row.status)">{{ row.status === '1' ? '停用' : '启用' }}</el-button>
<el-button type="text" @click="toAdd(row.id)">编辑</el-button>
<el-button type="text" @click="remove(row.id)">删除</el-button>
</div>
</template>
</el-table-column>
</ai-table>
</template>
</ai-list>
</template>
<script>
import { mapState } from 'vuex'
export default {
name: 'List',
props: {
instance: Function,
dict: Object
},
data() {
return {
search: {
current: 1,
size: 10,
applicationName: ''
},
loading: false,
total: 10,
colConfigs: [
{ prop: 'saasPlatformName', label: '所属平台' },
{ prop: 'menuLevel1Name', label: '一级菜单名称'},
{ prop: 'menuLevel2Name', label: '二级菜单名称'},
{ prop: 'menuLevel3Name', label: '三级菜单名称'},
{ prop: 'createUserName', label: '编辑人' },
{ prop: 'createTime', label: '编辑时间' },
{
prop: 'status',
label: '状态',
align: 'center',
render (h, {row}) {
return h('span',{
style: {
color: row.status === '1' ? '#2EA222' : '#F46'
}
}, row.status === '1' ? '启用' : '停用')
}
},
{
prop: 'pushStatus',
label: '推送状态',
align: 'center',
render (h, {row}) {
return h('span',{
style: {
color: row.pushStatus === '1' ? '#2EA222' : '#F46'
}
}, row.pushStatus === '1' ? '成功' : '失败')
}
}
],
tableData: [],
ids: ''
}
},
computed: {
...mapState(['user'])
},
mounted() {
this.getList()
},
methods: {
getList () {
this.loading = true
this.instance.post(`/app/appapplicationinfo/list`, null, {
params: {
...this.search
}
}).then(res => {
if (res.code == 0) {
this.tableData = res.data.records
this.total = res.data.total
this.$nextTick(() => {
this.loading = false
})
} else {
this.loading = false
}
}).catch(() => {
this.loading = false
})
},
removeAll () {
if (!this.ids) return
this.remove(this.ids)
},
push (id) {
this.instance.post(`/app/appapplicationinfo/push?id=${id}`).then(res => {
if (res.code == 0) {
this.$message.success(`推送成功`)
this.getList()
}
})
},
operate (id, status) {
this.instance.post(`/app/appapplicationinfo/enable?id=${id}`).then(res => {
if (res.code == 0) {
this.$message.success(`${status === '1' ? '停用成功' : '启用成功'}`)
this.getList()
}
})
},
remove (id) {
this.$confirm('确定删除该数据?').then(() => {
this.instance.post(`/app/appapplicationinfo/delete?ids=${id}`).then(res => {
if (res.code == 0) {
this.$message.success('删除成功!')
this.getList()
}
})
})
},
toAdd(id) {
this.$emit('change', {
type: 'Add',
params: {
id: id || ''
}
})
}
}
}
</script>
<style lang="scss" scoped>
</style>

View File

@@ -0,0 +1,272 @@
export const components = [
{
type: 'info',
tips: '(不能重复添加同一元素)',
label: '信息',
children: [
{
type: 'name',
fieldName: '姓名',
fieldTips: '请输入姓名',
fixedLabel: '姓名',
disable: '0',
grid: 0.5,
defaultValue: '',
icon: 'icontext_box',
mustFill: '1',
maxLength: 20
},
{
type: 'idNumber',
fieldName: '身份证号',
fixedLabel: '身份证号',
fieldTips: '请输入身份证号',
defaultValue: '',
icon: 'icontext_area',
mustFill: '1',
maxLength: 20,
disable: '0',
grid: 0.5
},
{
type: 'phone',
fieldName: '联系方式',
fixedLabel: '联系方式',
fieldTips: '请输入联系方式',
defaultValue: '',
icon: 'icontext_area',
mustFill: '1',
maxLength: 20,
disable: '0',
grid: 0.5
},
{
type: 'area',
fieldName: '地区',
fixedLabel: '地区',
fieldTips: '请选择地区',
defaultValue: '',
icon: 'icontext_area',
mustFill: '1',
areaPattern: '',
disable: '0',
grid: 0.5
}
]
},
{
type: 'options',
tips: '(可重复添加)',
label: '选项',
children: [
{
type: 'radio',
fieldName: '单选',
fixedLabel: '单选',
fieldTips: '请选择',
grid: 0.5,
icon: 'iconradio',
mustFill: '1',
disable: '0',
defaultValue: '',
options: [
{
label: '选项1',
value: ''
},
{
label: '选项2',
value: ''
}
],
title: ''
},
{
type: 'checkbox',
fieldName: '多选',
fixedLabel: '多选',
fieldTips: '请选择',
icon: 'iconcheck_box',
mustFill: '1',
grid: 0.5,
disable: '0',
defaultValue: [],
options: [
{
label: '选项1',
value: ''
},
{
label: '选项2',
value: ''
}
],
title: ''
},
{
type: 'select',
fieldName: '单下拉框',
fixedLabel: '单下拉框',
grid: 0.5,
fieldTips: '请选择',
icon: 'iconSelect',
mustFill: '1',
defaultValue: '',
disable: '0',
options: [
{
label: '选项1',
value: ''
},
{
label: '选项2',
value: ''
}
],
title: ''
},
{
type: 'onOff',
fieldName: '开关',
fixedLabel: '开关',
grid: 0.5,
fieldTips: '请选择开关',
icon: 'iconSelect',
mustFill: '1',
defaultValue: '0',
disable: '0',
title: ''
},
{
type: 'date',
fieldName: '日期',
fixedLabel: '日期',
grid: 0.5,
datetimePattern: 'yyyy-MM-dd',
fieldTips: '请选择日期',
icon: 'iconSelect',
mustFill: '1',
disable: '0',
title: ''
},
{
type: 'time',
fieldName: '时间',
fixedLabel: '时间',
grid: 0.5,
datetimePattern: 'HH:mm:ss',
fieldTips: '请选择时间',
icon: 'iconSelect',
mustFill: '1',
disable: '0',
title: ''
},
{
type: 'datetime',
fieldName: '日期时间',
fixedLabel: '日期时间',
grid: 0.5,
datetimePattern: 'yyyy-MM-dd HH:mm:ss',
fieldTips: '请选择日期时间',
icon: 'iconSelect',
mustFill: '1',
disable: '0',
title: ''
}
]
},
{
type: 'input',
tips: '(可重复添加)',
label: '填空',
children: [
{
type: 'input',
fieldName: '单行填空',
fieldTips: '请输入',
fixedLabel: '单行填空',
disable: '0',
grid: 0.5,
defaultValue: '',
icon: 'icontext_box',
mustFill: '1',
maxLength: 50
},
{
type: 'textarea',
fieldName: '多行填空',
fixedLabel: '多行填空',
fieldTips: '请输入',
lineNumber: 4,
defaultValue: '',
icon: 'icontext_area',
mustFill: '1',
maxLength: 500,
disable: '0',
grid: 1
},
{
type: 'number',
fieldName: '数字输入',
fixedLabel: '数字输入',
fieldTips: '请输入数字',
defaultValue: '',
icon: 'icontext_area',
mustFill: '1',
maxValue: 10000,
decimalPlaces: 0,
minValue: 0,
maxLength: 500,
disable: '0',
grid: 0.5
},
{
type: 'rtf',
fieldName: '富文本',
fixedLabel: '富文本',
fieldTips: '请输入',
defaultValue: '',
icon: 'icontext_area',
mustFill: '1',
maxLength: 5000,
disable: '0',
grid: 1
}
]
},
{
type: 'annex',
tips: '(可重复添加)',
label: '附件',
children: [
{
type: 'upload',
fieldTips: '请上传',
fieldName: '上传附件',
fixedLabel: '上传附件',
disable: '0',
fileChoseSize: 10,
fileMaxCount: 9,
defaultValue: '',
icon: 'iconpic',
mustFill: '1',
grid: 1
}
]
},
{
type: 'layout',
tips: '(可重复添加)',
label: '分组',
children: [
{
type: 'group',
fieldName: '卡片',
fixedLabel: '卡片',
icon: 'iconpic',
groupName: '分组标题',
column: []
}
]
}
];

View File

@@ -0,0 +1,42 @@
<template>
<section class="AppHelpedResident">
<component :is="currentComponent" :instance="instance" :dict="dict" :permissions="permissions"/>
</section>
</template>
<script>
import HrAdd from "./hrAdd";
import HrDetail from "./hrDetail";
import HrList from "./hrList";
export default {
name: "AppHelpedResident",
components: {HrList, HrDetail, HrAdd},
label: "监测对象(防返贫帮扶对象)",
props: {
instance: Function,
dict: Object,
permissions: Function
},
computed: {
currentComponent() {
return this.$route.hash == "#add" ? HrAdd :
this.$route.query.id ? HrDetail : HrList
}
},
created() {
this.dict.load("fpYear", "sex", "fpNation", "fpPrtpStatus", "fpHealth", "fpStudentsInSchool", 'fpYesOrNo', "fpRelationship",
"yesOrNo", "fpLaborSkills", "fpEducation", "fpPoliticalOutlook","fpType", "fpRiskType", "fpAssistanceMeasures",
"fpPublicWelfarePostAssistance","fpHealthAssistance","fpFnancialAssistance","fpEmploymentAssistance","fpEducationalAssistance",
"fpIndustrialAssistance","fpSocialAssistance", "fpRiskEliminationMethod", "fpNaturalDisaster", "fpHouseType", "fpHouseRoadType",
"fpFuelType", "fpDisabilityType", "fpEmploymentChannels")
}
}
</script>
<style lang="scss" scoped>
.AppHelpedResident {
height: 100%;
}
</style>

View File

@@ -0,0 +1,148 @@
<template>
<section class="hrLog">
<ai-card title="走访日志">
<template #right>
<!-- <ai-select placeholder="档案状态" v-model="search.status" :selectList="dict.getDict('fpPrtpStatus')" @change="page.current=1,getTableData()"/> -->
<el-button type="text" icon="el-icon-plus" @click="dialog=true" v-if="$permissions('app_apppreventionreturntopovertylog_edit')">添加</el-button>
</template>
<template #content>
<div class="logItem" v-for="row in tableData" :key="row.id">
<el-row type="flex" align="middle" justify="space-between">
<b v-text="row.createUserName"/>
<span v-text="row.createTime"/>
</el-row>
<p>操作类型{{row.operationDesc}}</p>
<div class="content" v-text="row.detail"/>
<ai-uploader v-model="row.files" disabled/>
<div class="btns" v-if="row.bizType == 0">
<el-button type="text" @click="handleEdit(row)" v-if="$permissions('app_apppreventionreturntopovertylog_edit')">编辑</el-button>
<el-button type="text" @click="handleDelete(row.id)" v-if="$permissions('app_apppreventionreturntopovertylog_del')">删除</el-button>
</div>
</div>
<ai-empty v-if="tableData.length==0"/>
</template>
</ai-card>
<ai-dialog :visible.sync="dialog" :title="addTitle" @closed="form={}" @onConfirm="submit" width="600px">
<el-form :model="form" :rules="rules" ref="DialogForm" size="small" label-width="80px">
<el-form-item label="走访日志" prop="detail">
<el-input type="textarea" v-model="form.detail" placeholder="请输入" maxlength="500" show-word-limit rows="5"/>
</el-form-item>
<el-form-item label="图片" prop="files">
<ai-uploader v-model="form.files" :instance="instance" acceptType=".jpg,.jpeg,.png">
<template #tips>
最多9张,仅支持10M以内的jpgjpegpng格式照片
</template>
</ai-uploader>
</el-form-item>
</el-form>
</ai-dialog>
</section>
</template>
<script>
import {mapState} from "vuex";
export default {
name: "hrLog",
props: {
instance: Function,
dict: Object,
permissions: Function
},
computed: {
...mapState(['user']),
addTitle() {
return this.form.id ? "编辑走访日志" : "新建走访日志"
}
},
data() {
return {
dialog: false,
form: {},
rules: {
detail: {required: true, message: "请输入走访日志"}
},
tableData: []
}
},
methods: {
getTableData() {
let {id: pid} = this.$route.query
this.instance.post("/app/apppreventionreturntopovertylog/list", null, {
params: {size: 9999, pid, type: 0}
}).then(res => {
if (res?.data) {
this.tableData = res.data?.records || []
}
})
},
submit() {
this.$refs.DialogForm.validate(v => {
if (v) {
let {id: pid} = this.$route.query
this.instance.post(`/app/apppreventionreturntopovertylog/addOrUpdate`, {
...this.form,
pid,
type: 0
}).then(res => {
if (res.code == 0) {
this.form = {}
this.$message.success('提交成功!');
this.dialog = false
this.getTableData()
}
})
}
})
},
handleEdit(row) {
this.dialog = true
this.form = JSON.parse(JSON.stringify(row))
},
handleDelete(ids) {
this.$confirm("是否要删除走访日志").then(() => {
this.instance.post("/app/apppreventionreturntopovertylog/delete", null, {
params: {ids: ids?.toString()}
}).then(res => {
if (res?.code == 0) {
this.$message.success("删除成功!")
this.getTableData()
}
})
}).catch(() => 0)
},
},
created() {
this.getTableData()
}
}
</script>
<style lang="scss" scoped>
.hrLog {
.logItem {
position: relative;
padding: 8px 16px;
border-radius: 4px;
&:hover {
background: #eee;
.btns {
display: block;
}
}
.content {
margin: 8px 0;
}
.btns {
display: none;
position: absolute;
right: 8px;
bottom: 8px;
}
}
}
</style>

View File

@@ -0,0 +1,150 @@
<template>
<section class="hrMeasure">
<ai-card title="帮扶措施">
<template #right>
<el-button type="text" icon="el-icon-plus" @click="dialog=true">添加</el-button>
</template>
<template #content>
<div class="logItem" v-for="row in tableData" :key="row.id">
<el-row type="flex" align="middle" justify="space-between">
<b v-text="row.createUserName"/>
<span v-text="row.createTime"/>
</el-row>
<p>帮扶类型:{{dict.getLabel('fpAssistanceMeasures', row.operationDesc)}}</p>
<div class="content" v-text="row.detail"/>
<ai-uploader v-model="row.files" disabled/>
<div class="btns">
<el-button type="text" @click="handleEdit(row)">编辑</el-button>
<el-button type="text" @click="handleDelete(row.id)">删除</el-button>
</div>
</div>
<ai-empty v-if="tableData.length==0"/>
</template>
</ai-card>
<ai-dialog :visible.sync="dialog" :title="addTitle" @closed="form={}" @onConfirm="submit" width="600px">
<el-form :model="form" :rules="rules" ref="DialogForm" size="small" label-width="80px">
<el-form-item label="帮扶类型" prop="operationDesc">
<ai-select v-model="form.operationDesc" :selectList="dict.getDict('fpAssistanceMeasures')"/>
</el-form-item>
<el-form-item label="帮扶措施">
<el-input type="textarea" v-model="form.detail" placeholder="请输入" maxlength="500" show-word-limit rows="5"/>
</el-form-item>
<el-form-item label="图片">
<ai-uploader v-model="form.files" :instance="instance" acceptType=".jpg,.jpeg,.png">
<template #tips>
最多9张,仅支持10M以内的jpgjpegpng格式照片
</template>
</ai-uploader>
</el-form-item>
</el-form>
</ai-dialog>
</section>
</template>
<script>
import {mapState} from "vuex";
export default {
name: "hrMeasure",
props: {
instance: Function,
dict: Object,
permissions: Function
},
computed: {
...mapState(['user']),
addTitle() {
return this.form.id ? "编辑措施" : "新建措施"
}
},
data() {
return {
dialog: false,
form: {},
rules: {
operationDesc: {required: true, message: "请输入帮扶措施"}
},
tableData: []
}
},
methods: {
getTableData() {
let {id: pid} = this.$route.query
this.instance.post("/app/apppreventionreturntopovertylog/list", null, {
params: {size: 9999, pid, type: 1}
}).then(res => {
if (res?.data) {
this.tableData = res.data?.records || []
}
})
},
submit() {
this.$refs.DialogForm.validate(v => {
if (v) {
let {id: pid} = this.$route.query
this.instance.post(`/app/apppreventionreturntopovertylog/addOrUpdate`, {
...this.form,
pid,
type: 1
}).then(res => {
if (res.code == 0) {
this.form = {}
this.$message.success('提交成功!');
this.dialog = false
this.getTableData()
}
})
}
})
},
handleEdit(row) {
this.dialog = true
this.form = JSON.parse(JSON.stringify(row))
},
handleDelete(ids) {
this.$confirm("是否要删除帮扶措施").then(() => {
this.instance.post("/app/apppreventionreturntopovertylog/delete", null, {
params: {ids: ids?.toString()}
}).then(res => {
if (res?.code == 0) {
this.$message.success("删除成功!")
this.getTableData()
}
})
}).catch(() => 0)
},
},
created() {
this.getTableData()
}
}
</script>
<style lang="scss" scoped>
.hrMeasure {
.logItem {
position: relative;
padding: 8px 16px;
border-radius: 4px;
&:hover {
background: #eee;
.btns {
display: block;
}
}
.content {
margin: 8px 0;
}
.btns {
display: none;
position: absolute;
right: 8px;
bottom: 8px;
}
}
}
</style>

View File

@@ -0,0 +1,546 @@
<template>
<section class="hrAdd">
<ai-detail>
<ai-title slot="title" :title="addTitle" isShowBottomBorder isShowBack @onBackClick="back"/>
<template #content>
<el-form :model="form" ref="ruleForm" :rules="rules" label-width="160px" label-position="right" size="small">
<ai-card title="基本信息">
<template #content>
<div flex class="half wrap">
<div flex class="column">
<el-form-item label="户主姓名" prop="name">
<el-input size="small" class="user-selecter" v-model="form.name" placeholder="请输入姓名" clearable :disabled="isEdit || isSelectUser">
<template slot="append">
<ai-person-select :instance="instance" @selectPerson="checkName"
:url="'/app/appresident/list?auditStatus=1&householdName=1&areaId='+user.info.areaId"/>
</template>
</el-input>
</el-form-item>
<el-form-item label="联系方式" prop="phone">
<el-input v-model="form.phone" placeholder="请输入联系方式" :maxlength="11" show-word-limit/>
</el-form-item>
<el-form-item label="证件号码" prop="idNumber">
<el-input v-model="form.idNumber" placeholder="请输入证件号码" :maxlength="20" :disabled="isEdit || isSelectUser"
@change="handleIdNumberAutocomplete"/>
</el-form-item>
</div>
<el-form-item label="个人照片" prop="photo">
<ai-avatar :instance="instance" v-model="form.photo"/>
</el-form-item>
<el-form-item label="性别" prop="sex">
<ai-select v-model="form.sex" :selectList="dict.getDict('sex')" disabled/>
</el-form-item>
<el-form-item label="出生日期" prop="birthDate">
<el-date-picker disabled value-format="yyyy-MM-dd HH:mm:ss" format="yyyy-MM-dd" v-model="form.birthDate" type="date" placeholder="选择日期"/>
</el-form-item>
<!-- <el-form-item label="年龄" prop="age">
<el-input disabled v-model="form.age" placeholder="请输入年龄" type="number"/>
</el-form-item> -->
<el-form-item label="民族">
<ai-select v-model="form.nation" :selectList="dict.getDict('fpNation')"/>
</el-form-item>
<el-form-item label="文化程度">
<ai-select v-model="form.education" :selectList="dict.getDict('fpEducation')"/>
</el-form-item>
<el-form-item label="政治面貌">
<ai-select v-model="form.politicsStatus" :selectList="dict.getDict('fpPoliticalOutlook')"/>
</el-form-item>
<el-form-item label="在校生状况">
<ai-select v-model="form.schoolStatus" :selectList="dict.getDict('fpStudentsInSchool')"/>
</el-form-item>
</div>
<el-form-item label="健康状况">
<el-checkbox-group v-model="form.healthyStatusList">
<el-checkbox :label="item.dictValue" v-for="(item, index) in dict.getDict('fpHealth')" :key="index">{{ item.dictName }}</el-checkbox>
</el-checkbox-group>
</el-form-item>
<div flex class="half wrap">
<el-form-item label="残疾类别">
<ai-select v-model="form.disabilityType" :selectList="dict.getDict('fpDisabilityType')"/>
</el-form-item>
<el-form-item label="残疾办证年度">
<ai-select v-model="form.disabilityCertificateYear" :selectList="dict.getDict('fpYear')"/>
</el-form-item>
</div>
<el-form-item label="基础保险">
<el-checkbox-group v-model="form.basicsList">
<el-checkbox :label="item.value" v-for="(item, index) in basicsCheckList" :key="index">{{ item.label }}</el-checkbox>
</el-checkbox-group>
</el-form-item>
<el-form-item label="保障措施">
<el-checkbox-group v-model="form.guaranteeList">
<el-checkbox :label="item.value" v-for="(item, index) in guaranteeCheckList" :key="index">{{ item.label }}</el-checkbox>
</el-checkbox-group>
</el-form-item>
<div flex class="half wrap">
<el-form-item label="劳动技能">
<ai-select v-model="form.labourStatus" :selectList="dict.getDict('fpLaborSkills')"/>
</el-form-item>
<el-form-item label="是否会讲普通话">
<ai-select v-model="form.mandarin" :selectList="dict.getDict('fpYesOrNo')"/>
</el-form-item>
<el-form-item label="务工时间(月)">
<el-input type="number" v-model="form.workeMonths" placeholder="请输入" clearable @input="numberInput('workeMonths')"/>
</el-form-item>
<el-form-item label="就业渠道">
<ai-select v-model="form.employmentChannels" :selectList="dict.getDict('fpEmploymentChannels')"/>
</el-form-item>
<el-form-item label="务工企业名称">
<el-input v-model="form.migrantEnterprises" placeholder="请输入" clearable/>
</el-form-item>
<el-form-item label="公益性岗位">
<el-input v-model="form.publicWelfarePosts" placeholder="请输入" clearable/>
</el-form-item>
<el-form-item label="是否国外务工">
<ai-select v-model="form.foreignWorkers" :selectList="dict.getDict('fpYesOrNo')"/>
</el-form-item>
<el-form-item label="公益性岗位(月数)">
<el-input type="number" v-model="form.publicWelfarePostsMonths" placeholder="请输入" clearable @input="numberInput('publicWelfarePostsMonths')"/>
</el-form-item>
</div>
<el-form-item label="务工所在地">
<el-input v-model="form.foreignWorkersAddress" placeholder="请输入" clearable maxlength="30" show-word-limit/>
</el-form-item>
<el-form-item label="现住址" prop="currentAreaId">
<ai-area-get :instance="instance" v-model="form.currentAreaId" :root="rootArea" valueLevel="5"/>
<el-form-item prop="currentAddress">
<el-input v-model="form.currentAddress" placeholder="详细地址" maxlength="30" show-word-limit clearable/>
</el-form-item>
</el-form-item>
</template>
</ai-card>
<ai-card title="生产生活条件">
<template slot="content">
<div flex class="half wrap">
<el-form-item label="住房面积(m²)">
<el-input v-model="form.houseArea" placeholder="请输入" :maxlength="8"/>
</el-form-item>
<el-form-item label="户类型">
<ai-select v-model="form.houseType" :selectList="dict.getDict('fpHouseType')"/>
</el-form-item>
<el-form-item label="与村主干路距离(公里)">
<el-input v-model="form.trunkRoadDistance" placeholder="请输入" :maxlength="8"/>
</el-form-item>
<el-form-item label="入户路类型">
<ai-select v-model="form.houseRoadType" :selectList="dict.getDict('fpHouseRoadType')"/>
</el-form-item>
<el-form-item label="是否危房">
<ai-select v-model="form.dilapidatedHousehold" :selectList="dict.getDict('fpYesOrNo')"/>
</el-form-item>
<el-form-item label="是否住房损耗">
<ai-select v-model="form.houseDamage" :selectList="dict.getDict('fpYesOrNo')"/>
</el-form-item>
<el-form-item label="是否解决安全饮水">
<ai-select v-model="form.drinkingWaterSafety" :selectList="dict.getDict('fpYesOrNo')"/>
</el-form-item>
<el-form-item label="是否饮水设施损坏">
<ai-select v-model="form.drinkingWaterDamage" :selectList="dict.getDict('fpYesOrNo')"/>
</el-form-item>
<el-form-item label="是否有卫生厕所">
<ai-select v-model="form.toilet" :selectList="dict.getDict('fpYesOrNo')"/>
</el-form-item>
<el-form-item label="主要燃料类型">
<ai-select v-model="form.fuelType" :selectList="dict.getDict('fpFuelType')"/>
</el-form-item>
<el-form-item label="是否通生活用电">
<ai-select v-model="form.electric" :selectList="dict.getDict('fpYesOrNo')"/>
</el-form-item>
<el-form-item label="是否通广播电视">
<ai-select v-model="form.television" :selectList="dict.getDict('fpYesOrNo')"/>
</el-form-item>
<el-form-item label="耕地面积(亩)">
<el-input v-model="form.cultivatedLandArea" placeholder="请输入" :maxlength="8"/>
</el-form-item>
<el-form-item label="林地面积(亩)">
<el-input v-model="form.woodlandArea" placeholder="请输入" :maxlength="8"/>
</el-form-item>
<el-form-item label="林果面积(亩)">
<el-input v-model="form.orchardArea" placeholder="请输入" :maxlength="8"/>
</el-form-item>
<el-form-item label="退耕还林面积(亩)">
<el-input v-model="form.grainForGreenArea" placeholder="请输入" :maxlength="8"/>
</el-form-item>
<el-form-item label="牧草地面积(亩)">
<el-input v-model="form.grazingGrasslandArea" placeholder="请输入" :maxlength="8"/>
</el-form-item>
<el-form-item label="水面面积(亩)">
<el-input v-model="form.watersArea" placeholder="请输入" :maxlength="8"/>
</el-form-item>
<el-form-item label="是否加入农民专业合作社">
<ai-select v-model="form.nongheshe" :selectList="dict.getDict('fpYesOrNo')"/>
</el-form-item>
<el-form-item label="是否有龙头企业带动">
<ai-select v-model="form.longtouqiye" :selectList="dict.getDict('fpYesOrNo')"/>
</el-form-item>
<el-form-item label="是否有创业致富人带头人带动">
<ai-select v-model="form.cyzfdtr" :selectList="dict.getDict('fpYesOrNo')"/>
</el-form-item>
<el-form-item label="是否通生产通电">
<ai-select v-model="form.produceElectric" :selectList="dict.getDict('fpYesOrNo')"/>
</el-form-item>
</div>
</template>
</ai-card>
<ai-card title="家庭风险情况">
<template slot="content">
<div flex class="half wrap">
<el-form-item label="监测对象类型" prop="objectType">
<ai-select v-model="form.objectType" :selectList="dict.getDict('fpType')"/>
</el-form-item>
<el-form-item label="是否军烈属">
<ai-select v-model="form.militaryMartyrs" :selectList="dict.getDict('fpYesOrNo')"/>
</el-form-item>
<el-form-item label="风险因素" prop="riskType">
<ai-select v-model="form.riskType" :selectList="dict.getDict('fpRiskType')"/>
</el-form-item>
<el-form-item label="脱贫年度">
<ai-select v-model="form.povertyYear" :selectList="dict.getDict('fpYear')"/>
</el-form-item>
<el-form-item label="因自然灾害子项">
<ai-select v-model="form.naturalDisasterType" :selectList="dict.getDict('fpNaturalDisaster')"/>
</el-form-item>
<el-form-item label="是否义务阶段失学辍学">
<ai-select v-model="form.dropOutOfSchool" :selectList="dict.getDict('fpYesOrNo')"/>
</el-form-item>
</div>
<el-form-item label="义务阶段未上学原因">
<el-input v-model="form.dropOutOfSchoolReason" type="textarea" placeholder="请输入" maxlength="500" show-word-limit clearable/>
</el-form-item>
<el-form-item label="备注说明">
<el-input v-model="form.detail" placeholder="请输入" type="textarea" maxlength="500" show-word-limit clearable/>
</el-form-item>
<el-form-item label="图片最多9张">
<ai-uploader
:isShowTip="true"
:instance="instance"
v-model="form.files"
fileType="img"
acceptType=".png,.jpg,.jpeg"
:limit="9">
<template slot="tips">最多上传9张图片,单张图片最大10MB<br/>支持.png,.jpg,.jpeg格式</template>
</ai-uploader>
</el-form-item>
</template>
</ai-card>
<ai-card title="家庭收支情况">
<template slot="content">
<div flex class="half wrap">
<el-form-item label="纳入监测对象的收入参考范围">
<el-input v-model="form.income1" placeholder="请输入" type="number" @input="decimalInput('income1')" clearable/>
</el-form-item>
<el-form-item label="纳入监测对象的人均收入参考范围">
<el-input v-model="form.income2" placeholder="请输入" type="number" @input="decimalInput('income2')" clearable/>
</el-form-item>
<el-form-item label="工资性收入(元)">
<el-input v-model="form.income3" placeholder="请输入" type="number" @input="decimalInput('income3')" clearable/>
</el-form-item>
<el-form-item label="生产经营性收入(元)">
<el-input v-model="form.income4" placeholder="请输入" type="number" @input="decimalInput('income4')" clearable/>
</el-form-item>
<el-form-item label="计划生育金(元)">
<el-input v-model="form.income5" placeholder="请输入" type="number" @input="decimalInput('income5')" clearable/>
</el-form-item>
<el-form-item label="资产收益扶贫分红收入">
<el-input v-model="form.income6" placeholder="请输入" type="number" @input="decimalInput('income6')" clearable/>
</el-form-item>
<el-form-item label="低保金(元)">
<el-input v-model="form.income7" placeholder="请输入" type="number" @input="decimalInput('income7')" clearable/>
</el-form-item>
<el-form-item label="特困供养金(元)">
<el-input v-model="form.income8" placeholder="请输入" type="number" @input="decimalInput('income8')" clearable/>
</el-form-item>
<el-form-item label="养老保险金(元)">
<el-input v-model="form.income9" placeholder="请输入" type="number" @input="decimalInput('income9')" clearable/>
</el-form-item>
<el-form-item label="生态补偿金(元)">
<el-input v-model="form.income10" placeholder="请输入" type="number" @input="decimalInput('income10')" clearable/>
</el-form-item>
<el-form-item label="转移性收入(元)">
<el-input v-model="form.income11" placeholder="请输入" type="number" @input="decimalInput('income11')" clearable/>
</el-form-item>
<el-form-item label="其它转移性收入(元)">
<el-input v-model="form.income12" placeholder="请输入" type="number" @input="decimalInput('income12')" clearable/>
</el-form-item>
<el-form-item label="财产性收入(元)">
<el-input v-model="form.income13" placeholder="请输入" type="number" @input="decimalInput('income13')" clearable/>
</el-form-item>
<el-form-item label="其它财产收入(元)">
<el-input v-model="form.income14" placeholder="请输入" type="number" @input="decimalInput('income14')" clearable/>
</el-form-item>
<el-form-item label="生产经营性支出(元)">
<el-input v-model="form.income15" placeholder="请输入" type="number" @input="decimalInput('income15')" clearable/>
</el-form-item>
</div>
</template>
</ai-card>
<ai-card title="风险消除情况" v-if="form.status == 3">
<template slot="content">
<div flex class="half wrap">
<el-form-item label="工资性收入情况">
<el-input v-model="form.fxxcIncome1" placeholder="请输入" type="number" @input="decimalInput('fxxcIncome1')" clearable/>
</el-form-item>
<el-form-item label="生产经营性收入情况">
<el-input v-model="form.fxxcIncome2" placeholder="请输入" type="number" @input="decimalInput('fxxcIncome2')" clearable/>
</el-form-item>
<el-form-item label="财产性收入情况">
<el-input v-model="form.fxxcIncome3" placeholder="请输入" type="number" @input="decimalInput('fxxcIncome3')" clearable/>
</el-form-item>
<el-form-item label="转移性收入情况">
<el-input v-model="form.fxxcIncome4" placeholder="请输入" type="number" @input="decimalInput('fxxcIncome4')" clearable/>
</el-form-item>
<el-form-item label="理赔收入情况">
<el-input v-model="form.fxxcIncome5" placeholder="请输入" type="number" @input="decimalInput('fxxcIncome5')" clearable/>
</el-form-item>
<el-form-item label="生产经营性支出情况">
<el-input v-model="form.fxxcIncome6" placeholder="请输入" type="number" @input="decimalInput('fxxcIncome6')" clearable/>
</el-form-item>
<el-form-item label="合规自然收支情况">
<el-input v-model="form.fxxcIncome7" placeholder="请输入" type="number" @input="decimalInput('fxxcIncome7')" clearable/>
</el-form-item>
<el-form-item label="家庭纯收入情况">
<el-input v-model="form.fxxcIncome8" placeholder="请输入" type="number" @input="decimalInput('fxxcIncome8')" clearable/>
</el-form-item>
<el-form-item label="家庭人均纯收入情况">
<el-input v-model="form.fxxcIncome9" placeholder="请输入" type="number" @input="decimalInput('fxxcIncome9')" clearable/>
</el-form-item>
</div>
</template>
</ai-card>
</el-form>
</template>
<template #footer>
<el-button @click="back">取消</el-button>
<el-button type="primary" @click="submit">提交</el-button>
</template>
</ai-detail>
</section>
</template>
<script>
import {mapState} from "vuex";
export default {
name: "hrAdd",
props: {
instance: Function,
dict: Object,
permissions: Function
},
computed: {
...mapState(['user']),
isEdit() {
return !!this.$route.query.id
},
addTitle() {
return this.isEdit ? "编辑监测对象" : "添加监测对象"
},
rules() {
return {
idNumber: [{required: true, message: "请输入证件号"}],
name: [{required: true, message: "请输入姓名"}],
sex: [{required: true, message: "请选择性别"}],
phone: [{required: true, message: "请输入联系方式"}],
currentAreaId: [
{required: true, message: "请选择现住址"},
{pattern: /[^0]0{0,2}$/, message: "请选择到村/社区"},
],
isHousehold: [{required: true, message: "请选择是否户主"}],
householdRelation: [{required: true, message: "请选择与户主关系"}],
householdIdNumber: [{required: true, message: "请选择户主证件号"}],
riskType: [{required: true, message: "请选择风险因素"}],
objectType: [{required: true, message: "请选择监测对象类型"}],
}
},
rootArea() {
return this.user.info?.areaId?.replace(/(\d{6})\d+/g, '$1' + Array(7).join("0")) || ""
},
guaranteeCheckList() {
return [
{label: '享受农村最低生活保障', value: '0'},
{label: '是否特困供养人员', value: '1'},
{label: '分散供养五保户转集中供养(减少)', value: '2'},
{label: '是否接受医疗救助', value: '3'},
{label: '是否接受其它健康扶贫', value: '4'},
]
},
basicsCheckList() {
return [
{label: '城乡居民基本医疗保险', value: '0'},
{label: '城镇职工基本医疗保险', value: '1'},
{label: '大病保险', value: '2'},
{label: '商业补充医疗保险', value: '3'},
{label: '城乡居民基本养老保险', value: '4'},
{label: '城镇职工基本养老保险', value: '5'},
{label: '享受人身意外保险补贴', value: '6'},
]
},
},
data() {
return {
form: {
householdRelation: "",
healthyStatus: '',
healthyStatusList: [],
guaranteeList: [],
basicsList: [],
file: [],
},
isSelectUser: false, //是否选择人员
}
},
methods: {
checkName(e) {
if (!e) {
this.isSelectUser = false
this.form.name = ''
this.form.idNumber = ''
this.form.phone = ''
this.form.currentAreaId = ''
this.form.currentAddress = ''
this.form.birthDate = ''
this.form.sex = ''
this.form.age = ''
return
}
this.form.name = e.name
this.form.idNumber = e.idNumber
this.form.phone = e.phone
this.form.currentAreaId = e.currentAreaId
this.form.currentAddress = e.currentAddress
this.handleIdNumberAutocomplete(e.idNumber)
this.isSelectUser = true
},
back() {
this.$router.push({})
},
getDetail() {
let {id} = this.$route.query
id && this.instance.post("/app/apppreventionreturntopoverty/queryDetailById", null, {
params: {id}
}).then(res => {
if (res?.data) {
res.data.healthyStatusList = []
res.data.basicsList = []
res.data.guaranteeList = []
if (res.data.healthyStatus) {
res.data.healthyStatusList = res.data.healthyStatus.split(',')
}
if (res.data.basicsCheck) {
res.data.basicsList = res.data.basicsCheck.split(',')
}
if (res.data.guaranteeCheck) {
res.data.guaranteeList = res.data.guaranteeCheck.split(',')
}
console.log(res.data)
this.form = {...res.data}
}
})
},
handleIdNumberAutocomplete(v) {
var idNumber = v
if (v.length == 20) {
idNumber = v.substring(0, 18)
}
let {birthday: birthDate, sex} = this.idCardNoUtil.getIdCardInfo(idNumber)
this.form = {...this.form, birthDate, sex, age: this.$calcAge(idNumber)}
},
submit() {
this.$refs.ruleForm.validate(v => {
if (v) {
this.form.isHousehold = 1
this.form.householdIdNumber = this.form.idNumber
if (this.form.healthyStatusList.length) {
this.form.healthyStatus = this.form.healthyStatusList.join(',')
}
if (this.user.info.girdCheckType == 1) {
this.form.girdId = this.user.info.girdId
}
if (this.form.basicsList.length) {
this.form.basicsCheck = this.form.basicsList.join(',')
}
if (this.form.guaranteeList.length) {
this.form.guaranteeCheck = this.form.basicsList.join(',')
}
if ([1, 2, 3].includes(2)) {
this.form.jcbxCxyiliao = '01'
} else {
this.form.jcbxCxyiliao = '02'
}
this.checkInit('jcbxCxyiliao', this.form.basicsList, '0')
this.checkInit('jcbxCzyiliao', this.form.basicsList, '1')
this.checkInit('jcbxDabing', this.form.basicsList, '2')
this.checkInit('jcbxShangye', this.form.basicsList, '3')
this.checkInit('jcbxCxyanglao', this.form.basicsList, '4')
this.checkInit('jcbxCzyanglao', this.form.basicsList, '5')
this.checkInit('jcbxRenshenyiwai', this.form.basicsList, '6')
this.checkInit('bzcsNongcundibao', this.form.guaranteeList, '0')
this.checkInit('bzcsTekungongyang', this.form.guaranteeList, '1')
this.checkInit('bzcsWubaohu', this.form.guaranteeList, '2')
this.checkInit('bzcsYiliaojiuzhu', this.form.guaranteeList, '3')
this.checkInit('bzcsQita', this.form.guaranteeList, '4')
let loading = this.$loading({text: "提交中..."})
this.instance.post(`/app/apppreventionreturntopoverty/addOrUpdate`, this.form).then(res => {
if (res.code == 0) {
this.$message.success('提交成功!');
this.back()
}
}).finally(() => {
loading.close()
})
}
})
},
checkInit(formName, list, value) {
if (list.includes(value)) {
this.form[formName] = '01'
} else {
this.form[formName] = '02'
}
},
decimalInput(name) {
if (!/^(([1-9]{1}\d*)|(0{1}))(\.\d{1,2})?$/g.test(this.form[name])) {
this.form[name] = ''
return this.$message.error('最多只保留两位小数点')
}
},
numberInput(name) {
if (!/^[0-9]*[1-9][0-9]*$/g.test(this.form[name])) {
this.form[name] = ''
return this.$message.error('请输入正整数')
}
},
},
created() {
this.getDetail()
}
}
</script>
<style lang="scss" scoped>
.hrAdd {
height: 100%;
.half {
align-items: flex-start;
& > .el-form-item, & > div {
width: 50%;
.el-form-item {
width: 100%;
}
}
}
.el-date-editor {
width: 100%;
}
::v-deep .AiPersonSelect .el-button {
color: #fff;
}
}
</style>

View File

@@ -0,0 +1,953 @@
<template>
<section class="hrDetail">
<ai-detail>
<ai-title slot="title" title="监测对象详情" isShowBottomBorder isShowBack @onBackClick="back">
<template #rightBtn>
<el-button type="primary" icon="iconfont iconEdit" @click="gotoEdit"
v-if="$permissions('app_apppreventionreturntopoverty_edit')">编辑
</el-button>
<template v-if="isGridAdmin">
<template v-if="detail.status == 0 || detail.status == 4">
<el-button type="primary" @click="applyMonitor('纳入监测', 1)" v-if="girdAdminApplyStatus != 1">纳入监测
</el-button>
<el-button type="primary" @click="examine('纳入监测审批', 2)" v-if="girdAdminApplyStatus == 1">纳入监测审批
</el-button>
</template>
<el-button type="primary" @click="applyMonitor('纳入监测', 1)" v-if="detail.status == 3">纳入监测</el-button>
<el-button type="primary" @click="applyMonitor('解除风险', 4)" v-if="detail.status == 1">解除风险</el-button>
<el-button type="primary" @click="examine('解除风险审批', 5)" v-if="detail.status == 2">解除风险审批</el-button>
</template>
<template v-if="user.info.girdCheckType == 1">
<el-button type="primary" @click="applyMonitor('申请纳入监测', 0)"
v-if="detail.status == 4 || detail.status == 3">申请纳入监测
</el-button>
<el-button type="primary" @click="applyMonitor('申请解除风险', 3)" v-if="detail.status == 1">申请解除风险</el-button>
</template>
<template v-if="detail.status == 3 || detail.status == 4">
<el-button v-if="$permissions('app_apppreventionreturntopoverty_del') && user.info.girdCheckType != 0"
icon="iconfont iconDelete" @click="handleDelete(detail.id)">删除
</el-button>
</template>
</template>
</ai-title>
<template #content>
<el-form :model="detail" label-width="160px" label-position="right" size="small">
<el-tabs tabPosition="left" v-model="currentTab">
<el-tab-pane label="基本信息" lazy>
<ai-card :title="detail.name || '无名氏'">
<template #content>
<div flex class="flex-start">
<div flex class="half wrap fill">
<el-form-item label="联系电话">{{ detail.phone }}</el-form-item>
<el-form-item label="证件号">{{ detail.idNumber }}</el-form-item>
<el-form-item label="性别" prop="sex">{{ dict.getLabel("sex", detail.sex) }}</el-form-item>
<el-form-item label="出生日期">{{ detail.birthDate }}</el-form-item>
<!-- <el-form-item label="年龄" prop="age">{{ detail.age}}</el-form-item> -->
<el-form-item label="民族">{{ dict.getLabel("fpNation", detail.nation) }}</el-form-item>
<el-form-item label="文化程度">{{ dict.getLabel("fpEducation", detail.education) }}</el-form-item>
<el-form-item label="政治面貌">{{ dict.getLabel("fpPoliticalOutlook", detail.politicsStatus) }}
</el-form-item>
<el-form-item label="在校生状况">{{ dict.getLabel("fpStudentsInSchool", detail.schoolStatus) }}
</el-form-item>
</div>
<ai-avatar :instance="instance" v-model="detail.photo" :editable="false"/>
</div>
<el-form-item label="健康状况">
<span v-for="(item, index) in detail.healthyStatusList" :key="index"><span v-if="index > 0">,</span>{{
dict.getLabel("fpHealth", item)
}}</span>
</el-form-item>
<div flex class="half wrap">
<el-form-item label="残疾类别">{{ dict.getLabel("fpDisabilityType", detail.disabilityType) }}
</el-form-item>
<el-form-item label="残疾办证年度">{{ dict.getLabel("fpYear", detail.disabilityCertificateYear) }}
</el-form-item>
</div>
<div flex class="half wrap">
<el-form-item label="城乡居民基本医疗保险">{{ dict.getLabel("fpYesOrNo", detail.jcbxCxyiliao) }}
</el-form-item>
<el-form-item label="城镇职工基本医疗保险">{{ dict.getLabel("fpYesOrNo", detail.jcbxCzyiliao) }}
</el-form-item>
<el-form-item label="大病保险">{{ dict.getLabel("fpYesOrNo", detail.jcbxDabing) }}</el-form-item>
<el-form-item label="商业补充医疗保险">{{ dict.getLabel("fpYesOrNo", detail.jcbxShangye) }}</el-form-item>
<el-form-item label="城乡居民基本养老保险">{{ dict.getLabel("fpYesOrNo", detail.jcbxCxyanglao) }}
</el-form-item>
<el-form-item label="城镇职工基本养老保险">{{ dict.getLabel("fpYesOrNo", detail.jcbxCzyanglao) }}
</el-form-item>
<el-form-item label="享受人身意外保险补贴">{{ dict.getLabel("fpYesOrNo", detail.jcbxRenshenyiwai) }}
</el-form-item>
<el-form-item label="享受农村最低生活保障">{{ dict.getLabel("fpYesOrNo", detail.bzcsNongcundibao) }}
</el-form-item>
<el-form-item label="是否特困供养人员">{{ dict.getLabel("fpYesOrNo", detail.bzcsTekungongyang) }}
</el-form-item>
<el-form-item label="分散供养五保户转集中供养(减少)">{{ dict.getLabel("fpYesOrNo", detail.bzcsWubaohu) }}
</el-form-item>
<el-form-item label="是否接受医疗救助">{{ dict.getLabel("fpYesOrNo", detail.bzcsYiliaojiuzhu) }}
</el-form-item>
<el-form-item label="是否接受其它健康扶贫">{{ dict.getLabel("fpYesOrNo", detail.bzcsQita) }}</el-form-item>
<el-form-item label="劳动技能">{{ dict.getLabel("fpLaborSkills", detail.labourStatus) }}</el-form-item>
<el-form-item label="是否会讲普通话">{{ dict.getLabel("fpYesOrNo", detail.mandarin) }}</el-form-item>
<el-form-item label="务工时间(月)">{{ detail.workeMonths }}</el-form-item>
<el-form-item label="就业渠道">{{ dict.getLabel("fpEmploymentChannels", detail.employmentChannels) }}
</el-form-item>
<el-form-item label="务工企业名称">{{ detail.migrantEnterprises }}</el-form-item>
<el-form-item label="公益性岗位">{{ detail.publicWelfarePosts }}</el-form-item>
<el-form-item label="是否国外务工">{{ dict.getLabel("fpYesOrNo", detail.foreignWorkers) }}</el-form-item>
<el-form-item label="公益性岗位(月数)">{{ detail.publicWelfarePostsMonths }}</el-form-item>
</div>
<el-form-item label="务工所在地">{{ detail.foreignWorkersAddress }}
</el-form-item>
<el-form-item label="现住址">{{ currentFullAddress }}</el-form-item>
</template>
</ai-card>
<ai-card title="生产生活条件">
<template slot="content">
<div flex class="half wrap">
<el-form-item label="住房面积(m²)">{{ detail.houseArea }}</el-form-item>
<el-form-item label="户类型">{{ dict.getLabel("fpHouseType", detail.houseType) }}</el-form-item>
<el-form-item label="与村主干路距离(公里)">{{ detail.trunkRoadDistance }}</el-form-item>
<el-form-item label="入户路类型">{{ dict.getLabel("fpHouseRoadType", detail.houseRoadType) }}
</el-form-item>
<el-form-item label="是否危房">{{ dict.getLabel("fpYesOrNo", detail.dilapidatedHousehold) }}
</el-form-item>
<el-form-item label="是否住房损耗">{{ dict.getLabel("fpYesOrNo", detail.houseDamage) }}</el-form-item>
<el-form-item label="是否解决安全饮水">{{ dict.getLabel("fpYesOrNo", detail.drinkingWaterSafety) }}
</el-form-item>
<el-form-item label="是否饮水设施损坏">{{ dict.getLabel("fpYesOrNo", detail.drinkingWaterDamage) }}
</el-form-item>
<el-form-item label="是否有卫生厕所">{{ dict.getLabel("fpYesOrNo", detail.toilet) }}</el-form-item>
<el-form-item label="主要燃料类型">{{ dict.getLabel("fpFuelType", detail.fuelType) }}</el-form-item>
<el-form-item label="是否通生活用电">{{ dict.getLabel("fpYesOrNo", detail.electric) }}</el-form-item>
<el-form-item label="是否通广播电视">{{ dict.getLabel("fpYesOrNo", detail.television) }}</el-form-item>
<el-form-item label="耕地面积(亩)">{{ detail.cultivatedLandArea }}</el-form-item>
<el-form-item label="林地面积(亩)">{{ detail.woodlandArea }}</el-form-item>
<el-form-item label="林果面积(亩)">{{ detail.orchardArea }}</el-form-item>
<el-form-item label="退耕还林面积(亩)">{{ detail.grainForGreenArea }}</el-form-item>
<el-form-item label="牧草地面积(亩)">{{ detail.grazingGrasslandArea }}</el-form-item>
<el-form-item label="水面面积(亩)">{{ detail.watersArea }}</el-form-item>
<el-form-item label="是否加入农民专业合作社">{{ dict.getLabel("fpYesOrNo", detail.nongheshe) }}</el-form-item>
<el-form-item label="是否有龙头企业带动">{{ dict.getLabel("fpYesOrNo", detail.longtouqiye) }}</el-form-item>
<el-form-item label="是否有创业致富人带头人带动">{{ dict.getLabel("fpYesOrNo", detail.cyzfdtr) }}</el-form-item>
<el-form-item label="是否通生产通电">{{ dict.getLabel("fpYesOrNo", detail.produceElectric) }}
</el-form-item>
</div>
</template>
</ai-card>
<ai-card title="家庭风险情况">
<template slot="content">
<div flex class="half wrap">
<el-form-item label="监测对象类型" prop="objectType">{{ dict.getLabel("fpType", detail.objectType) }}
</el-form-item>
<el-form-item label="是否军烈属">{{ dict.getLabel("fpYesOrNo", detail.militaryMartyrs) }}</el-form-item>
<el-form-item label="风险因素" prop="riskType">{{ dict.getLabel("fpRiskType", detail.riskType) }}
</el-form-item>
<el-form-item label="脱贫年度">{{ dict.getLabel("fpYear", detail.povertyYear) }}</el-form-item>
<el-form-item label="因自然灾害子项">{{ dict.getLabel("fpNaturalDisaster", detail.naturalDisasterType) }}
</el-form-item>
<el-form-item label="是否义务阶段失学辍学">{{ dict.getLabel("fpYesOrNo", detail.dropOutOfSchool) }}
</el-form-item>
<el-form-item label="识别监测时间">{{ detail.createTime }}</el-form-item>
<el-form-item label="风险是否已消除">{{ dict.getLabel("fpYesOrNo", detail.riskEliminated) }}</el-form-item>
<el-form-item label="是否有家庭成员未参加医疗保险">
{{ dict.getLabel("fpYesOrNo", detail.notCoveredMedicalInsurance) }}
</el-form-item>
<el-form-item label="信息采集人">{{ detail.updateUserName }}</el-form-item>
<el-form-item label="信息采集人联系电话">{{ detail.updateUserPhone }}</el-form-item>
</div>
<el-form-item label="义务阶段未上学原因">{{ detail.dropOutOfSchoolReason }}</el-form-item>
<!-- <el-form-item label="备注说明">{{detail.detail}}</el-form-item>
<el-form-item label="图片">
<ai-uploader disabled v-model="detail.files"></ai-uploader>
</el-form-item> -->
</template>
</ai-card>
<ai-card title="家庭收支情况">
<template slot="content">
<div flex class="half wrap">
<el-form-item label="纳入监测对象的收入参考范围">{{ detail.income1 }}</el-form-item>
<el-form-item label="纳入监测对象的人均收入参考范围">{{ detail.income2 }}</el-form-item>
<el-form-item label="工资性收入(元)">{{ detail.income3 }}</el-form-item>
<el-form-item label="生产经营性收入(元)">{{ detail.income4 }}</el-form-item>
<el-form-item label="计划生育金(元)">{{ detail.income5 }}</el-form-item>
<el-form-item label="资产收益扶贫分红收入">{{ detail.income6 }}</el-form-item>
<el-form-item label="低保金(元)">{{ detail.income7 }}</el-form-item>
<el-form-item label="特困供养金(元)">{{ detail.income8 }}</el-form-item>
<el-form-item label="养老保险金(元)">{{ detail.income9 }}</el-form-item>
<el-form-item label="生态补偿金(元)">{{ detail.income10 }}</el-form-item>
<el-form-item label="转移性收入(元)">{{ detail.income11 }}</el-form-item>
<el-form-item label="其它转移性收入(元)">{{ detail.income12 }}</el-form-item>
<el-form-item label="财产性收入(元)">{{ detail.income13 }}</el-form-item>
<el-form-item label="其它财产收入(元)">{{ detail.income14 }}</el-form-item>
<el-form-item label="生产经营性支出(元)">{{ detail.income15 }}</el-form-item>
<el-form-item label="年收入(元)">{{ detail.income16 }}</el-form-item>
<el-form-item label="家庭纯收入(元)">{{ detail.familyIncome }}</el-form-item>
<el-form-item label="人均纯收入(元)">{{ detail.perCapitaIncome }}</el-form-item>
</div>
</template>
</ai-card>
<ai-card title="风险消除情况" v-if="detail.status == 3">
<template slot="content">
<div flex class="half wrap">
<el-form-item label="工资性收入情况">{{ detail.fxxcIncome1 }}</el-form-item>
<el-form-item label="生产经营性收入情况">{{ detail.fxxcIncome2 }}</el-form-item>
<el-form-item label="财产性收入情况">{{ detail.fxxcIncome3 }}</el-form-item>
<el-form-item label="转移性收入情况">{{ detail.fxxcIncome4 }}</el-form-item>
<el-form-item label="理赔收入情况">{{ detail.fxxcIncome5 }}</el-form-item>
<el-form-item label="生产经营性支出情况">{{ detail.fxxcIncome6 }}</el-form-item>
<el-form-item label="合规自然收支情况">{{ detail.fxxcIncome7 }}</el-form-item>
<el-form-item label="家庭纯收入情况">{{ detail.fxxcIncome8 }}</el-form-item>
<el-form-item label="家庭人均纯收入情况">{{ detail.fxxcIncome9 }}</el-form-item>
</div>
</template>
</ai-card>
<ai-card title="家庭成员">
<template #right>
<span style=" color: #2266ff; margin-left: 16px;cursor: pointer;font-size: 12px;"
@click="addFamily({})">添加</span>
</template>
<template #content>
<ai-table :tableData="detail.family" :colConfigs="colConfigs" :dict="dict" :isShowPagination="false">
<el-table-column slot="options" label="操作" align="center" width="200px">
<template slot-scope="{ row }">
<el-button type="text" @click="viewFamily(row)">详情</el-button>
<template v-if="row.isHousehold==0">
<el-button type="text" @click="addFamily(row)">编辑</el-button>
<el-button type="text" @click="delFamily(row)">删除</el-button>
</template>
</template>
</el-table-column>
</ai-table>
</template>
</ai-card>
<div style="height:20px;"></div>
</el-tab-pane>
<el-tab-pane label="走访日志" lazy name="HrLog"
v-if="$permissions('app_apppreventionreturntopovertylog_detail')">
<hr-log v-if="currentTab == 'HrLog'" :instance="instance" :dict="dict" :permissions="permissions"/>
</el-tab-pane>
<el-tab-pane label="帮扶措施" lazy name="HrMeasure">
<hr-measure v-if="currentTab == 'HrMeasure'" :instance="instance" :dict="dict"
:permissions="permissions"/>
</el-tab-pane>
</el-tabs>
</el-form>
<ai-dialog :visible.sync="isShowAdd" width="1000px" height="500px" title="添加家庭成员" @close="onClose"
@onConfirm="onConfirm">
<el-form :model="form" ref="ruleForm" :rules="rules" label-width="130px" label-position="right" size="small">
<div flex class="half wrap">
<div flex class="column">
<el-form-item label="成员姓名" prop="name">
<el-input size="small" class="user-selecter" v-model="form.name" placeholder="请输入姓名" clearable
:disabled="isEdit || isSelectUser">
<template slot="append">
<ai-person-select :instance="instance" @selectPerson="checkName"
:url="'/app/appresident/list?auditStatus=1&areaId='+user.info.areaId"></ai-person-select>
</template>
</el-input>
</el-form-item>
<el-form-item label="联系方式" prop="phone">
<el-input v-model="form.phone" placeholder="请输入联系方式" :maxlength="11" show-word-limit/>
</el-form-item>
<el-form-item label="证件号码" prop="idNumber">
<el-input v-model="form.idNumber" placeholder="请输入证件号码" :maxlength="18"
:disabled="isEdit || isSelectUser" @change="handleIdNumberAutocomplete"/>
</el-form-item>
</div>
<el-form-item label="个人照片" prop="photo">
<ai-avatar :instance="instance" v-model="form.photo"/>
</el-form-item>
<el-form-item label="性别" prop="sex">
<ai-select v-model="form.sex" :selectList="dict.getDict('sex')" disabled/>
</el-form-item>
<el-form-item label="出生日期" prop="birthDate">
<el-date-picker disabled value-format="yyyy-MM-dd HH:mm:ss" format="yyyy-MM-dd" v-model="form.birthDate"
type="date" placeholder="选择日期"/>
</el-form-item>
<el-form-item label="与户主关系" prop="householdRelation">
<ai-select v-model="form.householdRelation" :selectList="dict.getDict('fpRelationship')"/>
</el-form-item>
<!-- <el-form-item label="年龄" prop="age">
<el-input disabled v-model="form.age" placeholder="请输入年龄" type="number"/>
</el-form-item> -->
<el-form-item label="民族">
<ai-select v-model="form.nation" :selectList="dict.getDict('fpNation')"/>
</el-form-item>
<el-form-item label="文化程度">
<ai-select v-model="form.education" :selectList="dict.getDict('fpEducation')"/>
</el-form-item>
<el-form-item label="政治面貌">
<ai-select v-model="form.politicsStatus" :selectList="dict.getDict('fpPoliticalOutlook')"/>
</el-form-item>
<el-form-item label="在校生状况">
<ai-select v-model="form.schoolStatus" :selectList="dict.getDict('fpStudentsInSchool')"/>
</el-form-item>
</div>
<el-form-item label="健康状况">
<el-checkbox-group v-model="form.healthyStatusList">
<el-checkbox :label="item.dictValue" v-for="(item, index) in dict.getDict('fpHealth')" :key="index">
{{ item.dictName }}
</el-checkbox>
</el-checkbox-group>
</el-form-item>
<div flex class="half wrap">
<el-form-item label="残疾类别">
<ai-select v-model="form.disabilityType" :selectList="dict.getDict('fpDisabilityType')"
placeholder="请选择"/>
</el-form-item>
<el-form-item label="残疾办证年度">
<ai-select v-model="form.disabilityCertificateYear" :selectList="dict.getDict('fpYear')"/>
</el-form-item>
</div>
<el-form-item label="基础保险">
<el-checkbox-group v-model="form.basicsList">
<el-checkbox :label="item.value" v-for="(item, index) in basicsCheckList" :key="index">
{{ item.label }}
</el-checkbox>
</el-checkbox-group>
</el-form-item>
<el-form-item label="保障措施">
<el-checkbox-group v-model="form.guaranteeList">
<el-checkbox :label="item.value" v-for="(item, index) in guaranteeCheckList" :key="index">
{{ item.label }}
</el-checkbox>
</el-checkbox-group>
</el-form-item>
<div flex class="half wrap">
<el-form-item label="劳动技能">
<ai-select v-model="form.labourStatus" :selectList="dict.getDict('fpLaborSkills')"/>
</el-form-item>
<el-form-item label="是否会讲普通话">
<ai-select v-model="form.mandarin" :selectList="dict.getDict('fpYesOrNo')" placeholder="请选择"/>
</el-form-item>
<el-form-item label="务工时间(月)">
<el-input type="number" v-model="form.workeMonths" placeholder="请输入" clearable
@input="numberInput('workeMonths')"/>
</el-form-item>
<el-form-item label="就业渠道">
<ai-select v-model="form.employmentChannels" :selectList="dict.getDict('fpEmploymentChannels')"/>
</el-form-item>
<el-form-item label="务工企业名称">
<el-input v-model="form.migrantEnterprises" placeholder="请输入" clearable/>
</el-form-item>
<el-form-item label="公益性岗位">
<el-input v-model="form.publicWelfarePosts" placeholder="请输入" clearable/>
</el-form-item>
<el-form-item label="是否国外务工">
<ai-select v-model="form.foreignWorkers" :selectList="dict.getDict('fpYesOrNo')" placeholder="请选择"/>
</el-form-item>
<el-form-item label="公益性岗位(月数)">
<el-input type="number" v-model="form.publicWelfarePostsMonths" placeholder="请输入" clearable
@input="numberInput('publicWelfarePostsMonths')"/>
</el-form-item>
</div>
<el-form-item label="务工所在地">
<el-input v-model="form.foreignWorkersAddress" placeholder="请输入" clearable maxlength="30"
show-word-limit/>
</el-form-item>
<el-form-item label="现住址" prop="currentAreaId">
<ai-area-get :instance="instance" v-model="form.currentAreaId" :root="rootArea" valueLevel="5"/>
<el-form-item prop="currentAddress">
<el-input v-model="form.currentAddress" placeholder="详细地址" maxlength="30" show-word-limit clearable/>
</el-form-item>
</el-form-item>
</el-form>
</ai-dialog>
<ai-dialog customFooter :visible.sync="isShowDetail" width="1000px" height="500px" title="家庭成员详情">
<el-form :model="familyInfo" label-width="160px" label-position="right" size="small">
<div flex class="flex-start">
<div flex class="half wrap fill">
<el-form-item label="联系电话">{{ familyInfo.phone }}</el-form-item>
<el-form-item label="证件号">{{ familyInfo.idNumber }}</el-form-item>
<el-form-item label="性别" prop="sex">{{ dict.getLabel("sex", familyInfo.sex) }}</el-form-item>
<el-form-item label="出生日期">{{ familyInfo.birthDate }}</el-form-item>
<el-form-item label="与户主关系">{{ dict.getLabel("fpRelationship", familyInfo.householdRelation) }}
</el-form-item>
<!-- <el-form-item label="年龄" prop="age">{{ familyInfo.age}}</el-form-item> -->
<el-form-item label="民族">{{ dict.getLabel("fpNation", familyInfo.nation) }}</el-form-item>
<el-form-item label="文化程度">{{ dict.getLabel("fpEducation", familyInfo.education) }}</el-form-item>
<el-form-item label="政治面貌">{{ dict.getLabel("fpPoliticalOutlook", familyInfo.politicsStatus) }}
</el-form-item>
<el-form-item label="在校生状况">{{ dict.getLabel("fpStudentsInSchool", familyInfo.schoolStatus) }}
</el-form-item>
</div>
<ai-avatar :instance="instance" v-model="familyInfo.photo" :editable="false"/>
</div>
<el-form-item label="健康状况">
<span v-for="(item, index) in familyInfo.healthyStatusList" :key="index"><span
v-if="index > 0">,</span>{{ dict.getLabel("fpHealth", item) }}</span>
</el-form-item>
<div flex class="half wrap">
<el-form-item label="残疾类别">{{ dict.getLabel("fpDisabilityType", familyInfo.disabilityType) }}</el-form-item>
<el-form-item label="残疾办证年度">{{ dict.getLabel("fpYear", familyInfo.disabilityCertificateYear) }}</el-form-item>
</div>
<div flex class="half wrap">
<el-form-item label="城乡居民基本医疗保险">{{ dict.getLabel("fpYesOrNo", familyInfo.jcbxCxyiliao) }}</el-form-item>
<el-form-item label="城镇职工基本医疗保险">{{ dict.getLabel("fpYesOrNo", familyInfo.jcbxCzyiliao) }}</el-form-item>
<el-form-item label="大病保险">{{ dict.getLabel("fpYesOrNo", familyInfo.jcbxDabing) }}</el-form-item>
<el-form-item label="商业补充医疗保险">{{ dict.getLabel("fpYesOrNo", familyInfo.jcbxShangye) }}</el-form-item>
<el-form-item label="城乡居民基本养老保险">{{ dict.getLabel("fpYesOrNo", familyInfo.jcbxCxyanglao) }}</el-form-item>
<el-form-item label="城镇职工基本养老保险">{{ dict.getLabel("fpYesOrNo", familyInfo.jcbxCzyanglao) }}</el-form-item>
<el-form-item label="享受人身意外保险补贴">{{ dict.getLabel("fpYesOrNo", familyInfo.jcbxRenshenyiwai) }}</el-form-item>
<el-form-item label="享受农村最低生活保障">{{ dict.getLabel("fpYesOrNo", familyInfo.bzcsNongcundibao) }}</el-form-item>
<el-form-item label="是否特困供养人员">{{ dict.getLabel("fpYesOrNo", familyInfo.bzcsTekungongyang) }}</el-form-item>
<el-form-item label="分散供养五保户转集中供养(减少)">{{ dict.getLabel("fpYesOrNo", familyInfo.bzcsWubaohu) }}</el-form-item>
<el-form-item label="是否接受医疗救助">{{ dict.getLabel("fpYesOrNo", familyInfo.bzcsYiliaojiuzhu) }}</el-form-item>
<el-form-item label="是否接受其它健康扶贫">{{ dict.getLabel("fpYesOrNo", familyInfo.bzcsQita) }}</el-form-item>
<el-form-item label="劳动技能">{{ dict.getLabel("fpLaborSkills", familyInfo.labourStatus) }}</el-form-item>
<el-form-item label="是否会讲普通话">{{ dict.getLabel("fpYesOrNo", familyInfo.mandarin) }}</el-form-item>
<el-form-item label="务工时间(月)">{{ familyInfo.workeMonths }}</el-form-item>
<el-form-item label="就业渠道">{{ dict.getLabel("fpEmploymentChannels", familyInfo.employmentChannels) }}</el-form-item>
<el-form-item label="务工企业名称">{{ familyInfo.migrantEnterprises }}</el-form-item>
<el-form-item label="公益性岗位">{{ familyInfo.publicWelfarePosts }}</el-form-item>
<el-form-item label="是否国外务工">{{ dict.getLabel("fpYesOrNo", familyInfo.foreignWorkers) }}</el-form-item>
<el-form-item label="公益性岗位(月数)">{{ familyInfo.publicWelfarePostsMonths }}</el-form-item>
</div>
<el-form-item label="务工所在地">{{ familyInfo.foreignWorkersAddress }}</el-form-item>
<el-form-item label="现住址">{{ currentFullAddressFamily }}</el-form-item>
</el-form>
<template slot="footer">
<el-button @click="isShowDetail=false">关闭</el-button>
</template>
</ai-dialog>
<ai-dialog :visible.sync="isShowApply" :title="dialogTitle" @closed="applyInfo={},applyFileList=[]"
@onConfirm="submitApply" width="600px">
<el-form :model="applyInfo" :rules="rulesApply" ref="dialogApplyInfo" size="small" label-width="120px">
<el-form-item label="风险因素" prop="riskType" v-if="changeStatus == 0 || changeStatus == 1">
<ai-select v-model="applyInfo.riskType" :selectList="dict.getDict('fpRiskType')"/>
</el-form-item>
<el-form-item label="风险消除方式" prop="riskEliminationMethod" v-if="changeStatus == 3 || changeStatus == 4">
<ai-select v-model="applyInfo.riskEliminationMethod"
:selectList="dict.getDict('fpRiskEliminationMethod')"/>
</el-form-item>
<el-form-item label="备注说明">
<el-input type="textarea" v-model="applyInfo.opinion" placeholder="请输入" maxlength="500" show-word-limit
rows="5"/>
</el-form-item>
<el-form-item label="图片">
<ai-uploader v-model="applyFileList" :instance="instance" acceptType=".jpg,.jpeg,.png">
<template #tips>
最多9张,仅支持10M以内的jpgjpegpng格式照片
</template>
</ai-uploader>
</el-form-item>
</el-form>
</ai-dialog>
<ai-dialog :visible.sync="isShowExamine" :title="dialogTitle" width="800px" customFooter>
<el-steps :active="examineStep" align-center>
<el-step title="申请信息"></el-step>
<el-step title="处理意见"></el-step>
<el-step title="完成"></el-step>
</el-steps>
<div class="info" v-if="examineStep == 1">
<ai-wrapper label-width="120px" :columnsNumber="2" style="margin-top: 16px;">
<ai-info-item label="操作类型" :value="changeStatus == 2 ? '申请纳入监测' : '申请解除风险' "/>
<ai-info-item label="风险因素" :value="dict.getLabel('fpRiskType', examineInfo.bizDictValue)"
v-if="changeStatus == 2"/>
<ai-info-item label="风险消除方式" :value="dict.getLabel('fpRiskEliminationMethod', examineInfo.bizDictValue)"
v-if="changeStatus == 5"/>
<ai-info-item label="申请人" :value="examineInfo.operationUserName"/>
<ai-info-item label="申请时间" :value="examineInfo.createTime"/>
</ai-wrapper>
<ai-wrapper label-width="120px" :columnsNumber="1">
<ai-info-item label="备注说明" :value="examineInfo.detail"/>
</ai-wrapper>
<ai-uploader v-model="examineInfo.files" disabled style="padding-left:150px;"/>
</div>
<div class="form" v-if="examineStep == 2">
<el-form :model="examineFrom" size="small" label-width="80px">
<el-form-item label="审核结果" required>
<el-radio-group v-model="examineFrom.pass">
<el-radio :label="1" v-if="changeStatus == 5">解除风险</el-radio>
<el-radio :label="1" v-if="changeStatus == 2">纳入监测</el-radio>
<el-radio :label="0">驳回申请</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="备注说明">
<el-input type="textarea" v-model="examineFrom.opinion" placeholder="请输入" maxlength="500"
show-word-limit rows="5"/>
</el-form-item>
<el-form-item label="图片">
<ai-uploader v-model="examineFileList" :instance="instance" acceptType=".jpg,.jpeg,.png">
<template #tips>
最多9张,仅支持10M以内的jpgjpegpng格式照片
</template>
</ai-uploader>
</el-form-item>
</el-form>
</div>
<div class="success" v-if="examineStep == 3">
<i class="el-icon-success"></i>
<p>审核成功</p>
</div>
<template slot="footer" v-if="examineStep != 3">
<el-button @click="cancelExamine">{{ examineStep == 2 ? '上一步' : '取消' }}</el-button>
<el-button type="primary" @click="examineNext">下一步</el-button>
</template>
<template slot="footer" v-if="examineStep == 3">
<el-button @click="back">关闭</el-button>
</template>
</ai-dialog>
</template>
</ai-detail>
</section>
</template>
<script>
import {mapState} from "vuex";
import HrMeasure from "./detail/hrMeasure";
import HrLog from "./detail/hrLog";
export default {
name: "hrDetail",
components: {HrLog, HrMeasure},
props: {
instance: Function,
dict: Object,
permissions: Function,
},
computed: {
...mapState(["user"]),
colConfigs() {
return [
{
label: "与户主关系",
prop: "householdRelation",
dict: "fpRelationship",
},
{label: "姓名", prop: "name"},
{label: "性别", prop: "sex", dict: "sex"},
{label: "年龄", prop: "age"},
{
label: "证件号",
render: (h, {row}) =>
h("p", null, this.idCardNoUtil.hideId(row.idNumber)),
},
{slot: "options"},
];
},
isGridAdmin() {
return this.user.info.girdCheckType == 2;
},
currentFullAddress() {
let {countyName, townName, villageName, currentAddress} = this.detail;
return [countyName, townName, villageName, currentAddress].join("");
},
currentFullAddressFamily() {
let {countyName, townName, villageName, currentAddress} = this.familyInfo;
return [countyName, townName, villageName, currentAddress].join("");
},
rules() {
return {
idNumber: [{required: true, message: "请输入证件号"}],
name: [{required: true, message: "请输入姓名"}],
sex: [{required: true, message: "请选择性别"}],
phone: [{required: true, message: "请输入联系方式"}],
currentAreaId: [
{required: true, message: "请选择现住址"},
{pattern: /[^0]0{0,2}$/, message: "请选择到村/社区"},
],
isHousehold: [{required: true, message: "请选择是否户主"}],
householdRelation: [{required: true, message: "请选择与户主关系"}],
householdIdNumber: [{required: true, message: "请选择户主证件号"}],
};
},
rulesApply() {
return {
riskType: [{required: true, message: "请选择风险因素"}],
riskEliminationMethod: [{required: true, message: "请选择风险消除方式"}],
};
},
rootArea() {
return this.user.info?.areaId?.replace(/(\d{6})\d+/g, '$1' + Array(7).join("0")) || ""
},
guaranteeCheckList() {
return [
{label: '享受农村最低生活保障', value: '0'},
{label: '是否特困供养人员', value: '1'},
{label: '分散供养五保户转集中供养(减少)', value: '2'},
{label: '是否接受医疗救助', value: '3'},
{label: '是否接受其它健康扶贫', value: '4'},
]
},
basicsCheckList() {
return [
{label: '城乡居民基本医疗保险', value: '0'},
{label: '城镇职工基本医疗保险', value: '1'},
{label: '大病保险', value: '2'},
{label: '商业补充医疗保险', value: '3'},
{label: '城乡居民基本养老保险', value: '4'},
{label: '城镇职工基本养老保险', value: '5'},
{label: '享受人身意外保险补贴', value: '6'},
]
},
},
data() {
return {
detail: {},
currentTab: "",
isShowAdd: false,
form: {healthyStatusList: [], basicsList: [], guaranteeList: []},
isEdit: false,
isShowDetail: false,
familyInfo: {},
isSelectUser: false,
isShowApply: false,
dialogTitle: '',
applyInfo: {},
isShowExamine: false,
examineInfo: {},
examineStep: 1, //审批步骤
examineFrom: {pass: 1},
applyFileList: [],
examineFileList: [],
changeStatus: 0, //操作状态 0:申请纳入监测 1:纳入监测 2:纳入监测审批 3:申请解除风险 4:解除风险 5:解除风险审批
girdAdminApplyStatus: 0, //网格长纳入监测状态 0纳入监测 1纳入监测审批
};
},
methods: {
checkName(e) {
if (!e) {
this.isSelectUser = false
this.form.name = ''
this.form.idNumber = ''
this.form.phone = ''
this.form.areaId = ''
this.form.birthDate = ''
this.form.sex = ''
this.form.age = ''
this.form.currentAreaId = ''
this.form.currentAddress = ''
return
}
this.form.name = e.name
this.form.idNumber = e.idNumber
this.form.phone = e.phone
this.form.currentAreaId = e.currentAreaId
this.form.currentAddress = e.currentAddress
this.handleIdNumberAutocomplete(e.idNumber)
this.isSelectUser = true
},
addFamily(row) {
if (row && row.id) {
this.isEdit = true
}
row.healthyStatusList = []
row.basicsList = []
row.guaranteeList = []
if (row && row.healthyStatus) {
row.healthyStatusList = row.healthyStatus.split(',')
}
if (row && row.basicsCheck) {
row.basicsList = row.basicsCheck.split(',')
}
if (row && row.guaranteeCheck) {
row.guaranteeList = row.guaranteeCheck.split(',')
}
this.form = {...row}
this.isShowAdd = true
},
viewFamily(row) {
row.healthyStatusList = []
row.basicsList = []
row.guaranteeList = []
if (row.healthyStatus) {
row.healthyStatusList = row.healthyStatus.split(',')
}
if (row.basicsCheck) {
row.basicsList = row.basicsCheck.split(',')
}
if (row.guaranteeCheck) {
row.guaranteeList = row.guaranteeCheck.split(',')
}
this.familyInfo = {...row}
this.isShowDetail = true
},
delFamily(row) {
if (row.isHousehold == 1) {
return this.$message.error('户主信息不允许删除');
}
this.$confirm("是否删除该家庭成员").then(() => {
this.instance.post(`/app/apppreventionreturntopoverty/delete?ids=${row.id}`).then(res => {
if (res.code == 0) {
this.getDetail()
this.$message.success('删除成功!');
}
})
})
},
handleIdNumberAutocomplete(v) {
let {birthday: birthDate, sex} = this.idCardNoUtil.getIdCardInfo(v);
this.form = {...this.form, birthDate, sex, age: this.$calcAge(v)};
},
onConfirm() {
this.$refs.ruleForm.validate((v) => {
if (v) {
this.form.isHousehold = 0
this.form.householdIdNumber = this.detail.idNumber
if (this.form.healthyStatusList.length) {
this.form.healthyStatus = this.form.healthyStatusList.join(',')
}
if (this.form.basicsList.length) {
this.form.basicsCheck = this.form.basicsList.join(',')
}
if (this.form.guaranteeList.length) {
this.form.guaranteeCheck = this.form.basicsList.join(',')
}
this.checkInit('jcbxCxyiliao', this.form.basicsList, '0')
this.checkInit('jcbxCzyiliao', this.form.basicsList, '1')
this.checkInit('jcbxDabing', this.form.basicsList, '2')
this.checkInit('jcbxShangye', this.form.basicsList, '3')
this.checkInit('jcbxCxyanglao', this.form.basicsList, '4')
this.checkInit('jcbxCzyanglao', this.form.basicsList, '5')
this.checkInit('jcbxRenshenyiwai', this.form.basicsList, '6')
this.checkInit('bzcsNongcundibao', this.form.guaranteeList, '0')
this.checkInit('bzcsTekungongyang', this.form.guaranteeList, '1')
this.checkInit('bzcsWubaohu', this.form.guaranteeList, '2')
this.checkInit('bzcsYiliaojiuzhu', this.form.guaranteeList, '3')
this.checkInit('bzcsQita', this.form.guaranteeList, '4')
this.instance.post(`/app/apppreventionreturntopoverty/addOrUpdate`, this.form).then(res => {
if (res.code == 0) {
this.getDetail()
this.$message.success('提交成功!');
this.isShowAdd = false
}
})
}
});
},
checkInit(formName, list, value) {
if (list.includes(value)) {
this.form[formName] = '01'
} else {
this.form[formName] = '02'
}
},
onClose() {
this.isShowAdd = false;
},
back() {
this.$router.push({});
},
getDetail() {
let {id} = this.$route.query;
id &&
this.instance
.post("/app/apppreventionreturntopoverty/queryDetailById", null, {
params: {id},
})
.then((res) => {
if (res?.data) {
this.detail = res.data;
this.detail.family?.map((e) => {
e.householdRelation = e.householdRelation || "户主";
});
if (this.detail.healthyStatus) {
this.detail.healthyStatusList = this.detail.healthyStatus.split(',')
}
if (this.detail.basicsCheck) {
this.detail.basicsList = this.detail.basicsCheck.split(',')
}
if (this.detail.guaranteeCheck) {
this.detail.guaranteeList = this.detail.guaranteeCheck.split(',')
}
if (this.detail.status == 0 && this.isGridAdmin) {
this.instance.post(`/app/apppreventionreturntopoverty/popup?id=${this.detail.id}`).then(res => {
if (res.code == 0 && res.data) { //纳入监测审批
this.girdAdminApplyStatus = 1
}
})
}
}
});
},
gotoEdit() {
let {query} = this.$route;
this.$router.push({query, hash: "#add"});
},
applyMonitor(title, status) {
this.dialogTitle = title
this.changeStatus = status
this.isShowApply = true
},
submitApply() {
this.$refs.dialogApplyInfo.validate((v) => {
if (v) {
this.applyInfo.id = this.detail.id
if (this.changeStatus == 1 || this.changeStatus == 4) { //网格长直接纳入监测/解除风险
this.applyInfo.pass = 1
}
var url = `/app/apppreventionreturntopoverty/examine` //0, 1纳入监测
if (this.changeStatus == 3 || this.changeStatus == 4) { //3, 4解除风险
url = `/app/apppreventionreturntopoverty/relieve`
}
if (this.applyFileList.length) {
var ids = this.applyFileList.map((item) => {
return item.id
})
this.applyInfo.files = ids.join(',')
}
let fromData = new FormData()
for (let key in this.applyInfo) {
fromData.append(key, this.applyInfo[key])
}
this.instance.post(url, fromData).then(res => {
if (res.code == 0) {
this.getDetail()
this.$message.success('提交成功!');
this.isShowApply = false
}
})
}
});
},
examine(title, status) {
this.dialogTitle = title
this.changeStatus = status
this.instance.post(`/app/apppreventionreturntopoverty/popup?id=${this.detail.id}`).then(res => {
if (res.code == 0) {
this.examineInfo = res.data
this.isShowExamine = true
}
})
},
examineNext() {
if (this.examineStep == 2) { //审批操作
if (this.examineFileList.length) {
var ids = this.examineFileList.map((item) => {
return item.id
})
this.examineFrom.files = ids.join(',')
}
this.examineFrom.id = this.detail.id
var url = `/app/apppreventionreturntopoverty/examine` //2 纳入监测
if (this.changeStatus == 5) { //5 解除风险
url = `/app/apppreventionreturntopoverty/relieve`
}
let fromData = new FormData()
for (let key in this.examineFrom) {
fromData.append(key, this.examineFrom[key])
}
this.instance.post(url, fromData).then(res => {
if (res.code == 0) {
this.getDetail()
this.$message.success('提交成功!');
}
})
}
if (this.examineStep == 3) {
this.isShowExamine = false
this.examineFrom = {pass: 1}
return
}
this.examineStep++
},
cancelExamine() {
if (this.examineStep == 2) {
return this.examineStep--
}
this.isShowExamine = false
},
handleDelete(ids) {
this.$confirm("是否要删除监测对象").then(() => {
this.instance.post("/app/apppreventionreturntopoverty/delete", null, {params: {ids: ids?.toString()},}).then((res) => {
if (res?.code == 0) {
this.$message.success("删除成功!");
this.back();
}
});
})
},
numberInput(name) {
if (!/^[0-9]*[1-9][0-9]*$/g.test(this.form[name])) {
this.form[name] = ''
return this.$message.error('请输入正整数')
}
},
},
created() {
this.getDetail();
},
};
</script>
<style lang="scss" scoped>
.hrDetail {
.flex-start {
align-items: flex-start;
.AiAvatar {
margin-left: 20px;
}
}
.half {
align-items: flex-start;
& > .el-form-item,
& > div {
width: 50%;
.el-form-item {
width: 100%;
}
}
}
.success {
text-align: center;
padding-top: 20px;
.el-icon-success {
color: rgb(46, 162, 34);
font-size: 100px;
}
p {
text-align: center;
font-size: 16px;
padding-top: 20px;
color: #000;
}
}
::v-deep .ai-dialog__content--wrapper {
overflow-y: hidden !important;
}
::v-deep .AiPersonSelect .el-button {
color: #fff;
}
::v-deep.el-tabs__content {
max-height: calc(100vh - 136px);
overflow-y: auto;
}
::v-deep .el-step__icon {
border-color: #ccc !important;
}
::v-deep .el-step__line {
background-color: #ccc !important;
}
::v-deep .el-step__title,
::v-deep .is-wait {
color: #666 !important;
}
::v-deep .is-finish {
color: #26f !important;
}
::v-deep .is-finish .el-step__icon {
border-color: #26f !important;
}
}
</style>

View File

@@ -0,0 +1,173 @@
<template>
<section class="hrList">
<ai-list>
<ai-title slot="title" title="监测对象" isShowBottomBorder isShowArea v-model="search.areaId" :instance="instance"
@change="page.current=1,getTableData()">
<template #rightBtn>
<el-button type="primary" icon="iconfont iconSetting" @click="dialog=true" v-if="$permissions('app_apppreventionreturntopovertyalarmconfig_edit')">
预警规则
</el-button>
</template>
</ai-title>
<template #content>
<ai-search-bar>
<template #left>
<ai-select placeholder="档案状态" v-model="search.status" :selectList="dict.getDict('fpPrtpStatus')" @change="page.current=1,getTableData()"/>
<ai-select placeholder="监测对象类型" v-model="search.objectType" :selectList="dict.getDict('fpType')" @change="page.current=1,getTableData()"/>
<ai-select placeholder="风险因素" v-model="search.riskType" :selectList="dict.getDict('fpRiskType')" @change="page.current=1,getTableData()"/>
<el-date-picker value-format="yyyy-MM-dd HH:mm:ss" v-model="search.birthStart" type="date" size="small" unlink-panels placeholder="选择出生开始日期"
@change="page.current=1,getTableData()"/>
<el-date-picker value-format="yyyy-MM-dd HH:mm:ss" v-model="search.birthEnd" type="date" size="small" placeholder="选择出生结束日期" unlink-panels
@change="page.current=1,getTableData()"/>
<ai-select placeholder="性别" v-model="search.sex" :selectList="dict.getDict('sex')" @change="page.current=1,getTableData()"/>
<!-- <ai-select placeholder="文化程度" v-model="search.education" :selectList="dict.getDict('fpEducation')" @change="page.current=1,getTableData()"/>
<ai-select placeholder="民族" v-model="search.nation" :selectList="dict.getDict('fpNation')" @change="page.current=1,getTableData()"/>
<ai-select placeholder="政治面貌" v-model="search.politicsStatus" :selectList="dict.getDict('fpPoliticalOutlook')" @change="page.current=1,getTableData()"/> -->
</template>
<template #right>
<el-input size="small" placeholder="姓名/证件/联系方式" v-model="search.con" clearable @change="page.current=1,getTableData()"/>
</template>
</ai-search-bar>
<ai-search-bar>
<template #left>
<el-button type="primary" icon="iconfont iconAdd" @click="showEdit()" v-if="$permissions('app_apppreventionreturntopoverty_edit')">添加</el-button>
<el-button icon="iconfont iconDelete" :disabled="!ids.length" @click="handleDelete(ids)"
v-if="$permissions('app_apppreventionreturntopoverty_del')">删除
</el-button>
</template>
<template #right>
<ai-import :instance="instance" name="监测对象" title="导入监测对象"
suffixName="xlsx"
url="/app/apppreventionreturntopoverty/downloadTemplate"
importUrl="/app/apppreventionreturntopoverty/import"
@onSuccess="page.current=1,getTableData()"/>
<ai-download url="/app/apppreventionreturntopoverty/export" :params="{...search,ids}"
:instance="instance" fileName="监测对象导出文件"/>
</template>
</ai-search-bar>
<ai-table :tableData="tableData" :total="page.total" :current.sync="page.current" :size.sync="page.size"
@getList="getTableData" :col-configs="colConfigs" :dict="dict"
@selection-change="v=>ids=v.map(e=>e.id)">
<el-table-column slot="options" label="操作" fixed="right" align="center">
<template slot-scope="{row}">
<el-button type="text" @click="showDetail(row.id)" v-if="$permissions('app_apppreventionreturntopoverty_detail')">详情</el-button>
<el-button type="text" @click="handleDelete(row.id)" v-if="$permissions('app_apppreventionreturntopoverty_del') &&/[34]/.test(row.status)">删除
</el-button>
</template>
</el-table-column>
</ai-table>
</template>
</ai-list>
<ai-dialog :visible.sync="dialog" title="预警规则设置" @closed="form={}" @onConfirm="submitDialog" width="600px">
<el-form :model="form" :rules="rules" ref="DialogForm" size="small" label-width="160px">
<el-form-item label="家庭纯收入标准" prop="type0">
<el-input v-model.number="form.type0" placeholder="请输入" maxlength="8" show-word-limit/>
</el-form-item>
<el-form-item label="家庭人均纯收入标准" prop="type1">
<el-input v-model.number="form.type1" placeholder="请输入" maxlength="8" show-word-limit/>
</el-form-item>
</el-form>
</ai-dialog>
</section>
</template>
<script>
import {mapState} from "vuex";
export default {
name: "hrList",
props: {
instance: Function,
dict: Object,
permissions: Function
},
computed: {
...mapState(['user']),
colConfigs() {
return [
{type: 'selection'},
{label: "姓名", prop: "name", align: "center"},
{label: "性别", prop: "sex", dict: 'sex', align: "center"},
{label: "证件号", render: (h, {row}) => h('p', this.idCardNoUtil.hideId(row.idNumber))},
{label: "年龄", prop: "age", align: "center"},
{label: "民族", prop: "nation", align: "center", dict: "fpNation"},
{label: "文化程度", prop: "education", align: "center", dict: "fpEducation"},
{label: "监测对象类型", prop: "objectType", align: "center", dict: "fpType"},
{label: "风险因素", prop: "riskType", align: "center", dict: "fpRiskType"},
{label: "档案状态", prop: "status", dict: "fpPrtpStatus", align: "center"},
{slot: "options"}
]
}
},
data() {
return {
search: {name: '', objectType: '', riskType: '', isHousehold: 1},
page: {current: 1, size: 10, total: 0},
tableData: [],
ids: [],
dialog: false,
form: {},
rules: {
type0: [{required: true, message: "请输入家庭纯收入标准", trigger: "change"}],
type1: [{required: true, message: "请输入家庭人均纯收入标准", trigger: "change"}],
}
}
},
methods: {
getTableData() {
this.instance.post("/app/apppreventionreturntopoverty/list", null, {
params: {...this.page, ...this.search}
}).then(res => {
if (res?.data) {
this.tableData = res.data?.records
this.page.total = res.data.total
}
})
},
showEdit(id) {
this.$router.push({query: {id}, hash: "#add"})
},
showDetail(id) {
this.$router.push({query: {id}})
},
handleDelete(ids) {
this.$confirm("是否要删除监测对象").then(() => {
this.instance.post("/app/apppreventionreturntopoverty/delete", null, {
params: {ids: ids?.toString()}
}).then(res => {
if (res?.code == 0) {
this.$message.success("删除成功!")
this.getTableData()
}
})
}).catch(() => 0)
},
submitDialog() {
this.$refs.DialogForm.validate(v => {
if (v) {
let loading = this.$loading({text: "提交中..."})
this.instance.post(`/app/apppreventionreturntopovertyalarmconfig/addOrUpdate`, this.form).then(res => {
if (res.code == 0) {
this.$message.success('预警规则设置成功');
this.getTableData()
this.dialog = false
}
}).finally(() => {
loading.close()
})
}
})
}
},
created() {
this.search.areaId = this.user.info.areaId
this.getTableData()
}
}
</script>
<style lang="scss" scoped>
.hrList {
height: 100%;
}
</style>

View File

@@ -0,0 +1,73 @@
<template>
<div class="doc-circulation ailist-wrapper">
<keep-alive :include="['List']">
<component ref="component" :is="component" @change="onChange" :params="params" :instance="instance" :dict="dict"></component>
</keep-alive>
</div>
</template>
<script>
import List from './components/List'
import Add from './components/Add'
import Detail from './components/Detail'
export default {
name: 'AppRiskWarning',
label: '风险告知',
props: {
instance: Function,
dict: Object
},
data () {
return {
component: 'List',
params: {},
include: []
}
},
components: {
Add,
List,
Detail
},
mounted () {
},
methods: {
onChange (data) {
if (data.type === 'Add') {
this.component = 'Add'
this.params = data.params
}
if (data.type === 'Detail') {
this.component = 'Detail'
this.params = data.params
}
if (data.type === 'List') {
this.component = 'List'
this.params = data.params
this.$nextTick(() => {
if (data.isRefresh) {
this.$refs.component.getList()
}
})
}
}
}
}
</script>
<style lang="scss">
.doc-circulation {
height: 100%;
background: #F3F6F9;
overflow: auto;
}
</style>

View File

@@ -0,0 +1,173 @@
<template>
<ai-detail>
<template slot="title">
<ai-title :title="params.id ? '编辑风险人员' : '添加风险人员'" isShowBack isShowBottomBorder @onBackClick="cancel(false)">
</ai-title>
</template>
<template slot="content">
<ai-card title="基本信息">
<template #content>
<el-form ref="form" class="ai-form" :model="form" label-width="110px" label-position="right">
<el-form-item label="姓名" prop="name" :rules="[{ required: true, message: '请输入姓名', trigger: 'blur' }]">
<el-input v-model="form.name" size="small" placeholder="请输入姓名"></el-input>
</el-form-item>
<el-form-item label="联系方式" prop="phone" :rules="[{ required: true, validator: validatorPhone, trigger: 'blur' }]">
<el-input v-model="form.phone" :maxlength="11" size="small" placeholder="请输入..."></el-input>
</el-form-item>
<el-form-item label="风险类型" prop="riskType" :rules="[{ required: true, message: '请选择风险类型', trigger: 'blur' }]">
<ai-select
v-model="form.riskType"
clearable
placeholder="请选择风险类型"
:selectList="dict.getDict('fpRiskType')">
</ai-select>
</el-form-item>
<el-form-item label="身份证号" prop="idNumber" :rules="[{ required: true, validator: validatorId, trigger: 'blur' }]">
<el-input v-model="form.idNumber" :maxlength="20" size="small" placeholder="请输入..."></el-input>
</el-form-item>
<el-form-item
style="width: 100%!important;"
label="所在地区"
prop="areaId"
:rules="[{ required: true, pattern: /([^0]\d{2}|0[^0]\d|0\d[^0])$/, message: '请选择到村', trigger: 'change' }]">
<ai-area-select
v-model="form.areaId"
always-show
:instance="instance"
clearable
@fullname="v=>form.areaName = v"
:disabledLevel="disabledLevel"/>
</el-form-item>
<el-form-item label="联系地址" prop="address" style="width: 100%;">
<el-input v-model="form.address" :maxlength="30" size="small" placeholder="请输入联系地址"></el-input>
</el-form-item>
<el-form-item label="备注说明" prop="remarks" style="width: 100%;">
<el-input v-model="form.remarks" :rows="5" style="width: 100%;" type="textarea" :maxlength="500" size="small" placeholder="请简要说明风险情况"></el-input>
</el-form-item>
</el-form>
</template>
</ai-card>
</template>
<template #footer>
<el-button @click="cancel">取消</el-button>
<el-button type="primary" @click="confirm" :loading="isLoading">提交</el-button>
</template>
</ai-detail>
</template>
<script>
import { mapState } from 'vuex'
export default {
name: 'Add',
props: {
instance: Function,
dict: Object,
params: Object
},
data () {
const validatorId = (rule, value, callback) => {
if (value === '') {
callback(new Error('请输入身份证号'))
} else if (!this.idCardNoUtil.checkIdCardNo(value)) {
callback(new Error('身份证号格式错误'))
} else {
callback()
}
}
const validatorPhone = function (rule, value, callback) {
if (value === '') {
callback(new Error('请输入联系方式'))
} else if (!/^1\d{10}$/.test(value)) {
callback(new Error('手机号格式错误'))
} else {
callback()
}
}
return {
info: {},
validatorId,
validatorPhone,
form: {
name: '',
idNumber: '',
address: '',
areaId: '',
areaName: '',
remarks: '',
phone: '',
riskType: ''
},
id: '',
isLoading: false,
disabledLevel: 3
}
},
computed: {
...mapState(['user'])
},
created () {
this.form.areaName = this.user.info.areaName
this.form.areaId = this.user.info.areaId
this.disabledLevel = this.user.info.areaList.length
if (this.params && this.params.id) {
this.id = this.params.id
this.getInfo(this.params.id)
}
},
methods: {
getInfo (id) {
this.instance.post(`/app/apppreventionreturntopovertyriskperson/queryDetailById?id=${id}`).then(res => {
if (res.code === 0) {
this.form = {
...res.data,
images: res.data.images ? JSON.parse(res.data.images) : []
}
}
})
},
onClose () {
this.form.explain = ''
},
confirm () {
this.$refs.form.validate((valid) => {
if (valid) {
this.isLoading = true
this.instance.post(`/app/apppreventionreturntopovertyriskperson/addOrUpdate`, {
...this.form
}).then(res => {
if (res.code == 0) {
this.$message.success('提交成功')
setTimeout(() => {
this.cancel(true)
this.isLoading = false
}, 600)
} else {
this.isLoading = false
}
}).catch(() => {
this.isLoading = false
})
}
})
},
cancel (isRefresh) {
this.$emit('change', {
type: 'List',
isRefresh: !!isRefresh
})
}
}
}
</script>
<style scoped lang="scss">
</style>

View File

@@ -0,0 +1,69 @@
<template>
<ai-detail>
<template slot="title">
<ai-title title="详情" isShowBack isShowBottomBorder @onBackClick="cancel(false)">
</ai-title>
</template>
<template slot="content">
<ai-card title="基本信息">
<template #content>
<ai-wrapper>
<ai-info-item label="姓名" :value="info.name"></ai-info-item>
<ai-info-item label="联系方式" :value="info.phone"></ai-info-item>
<ai-info-item label="风险类型" :value="dict.getLabel('fpRiskType', info.riskType)"></ai-info-item>
<ai-info-item label="身份证号" :value="info.idNumber"></ai-info-item>
<ai-info-item label="所在地区" :value="info.areaName"></ai-info-item>
<ai-info-item label="联系地址" isLine :value="info.address"></ai-info-item>
<ai-info-item label="备注说明" isLine :value="info.remarks"></ai-info-item>
</ai-wrapper>
</template>
</ai-card>
</template>
</ai-detail>
</template>
<script>
export default {
name: 'Detail',
props: {
instance: Function,
dict: Object,
params: Object
},
data () {
return {
info: {},
id: ''
}
},
created () {
if (this.params && this.params.id) {
this.id = this.params.id
this.getInfo(this.params.id)
}
},
methods: {
getInfo (id) {
this.instance.post(`/app/apppreventionreturntopovertyriskperson/queryDetailById?id=${id}`).then(res => {
if (res.code === 0) {
this.info = res.data
}
})
},
cancel (isRefresh) {
this.$emit('change', {
type: 'List',
isRefresh: !!isRefresh
})
}
}
}
</script>
<style scoped lang="scss">
</style>

View File

@@ -0,0 +1,179 @@
<template>
<ai-list class="notice">
<template slot="title">
<ai-title title="风险告知" isShowBottomBorder></ai-title>
</template>
<template slot="content">
<ai-search-bar bottomBorder>
<template #left>
<ai-select
v-model="search.riskType"
clearable
placeholder="请选择风险类型"
:selectList="dict.getDict('fpRiskType')"
@change="search.current = 1, getList()">
</ai-select>
<el-button icon="iconfont iconAdd" type="primary" size="small" @click="toAdd('')">添加 </el-button>
</template>
<template #right>
<el-input
v-model="search.name"
size="small"
placeholder="姓名/备注说明/操作人"
clearable
v-throttle="() => {search.current = 1, getList()}"
@clear="search.current = 1, search.name = '', getList()"
suffix-icon="iconfont iconSearch">
</el-input>
</template>
</ai-search-bar>
<ai-search-bar bottomBorder style="margin-top: 12px;">
<template #left>
<el-button icon="iconfont iconDelete" size="small" @click="removeAll" :disabled="ids.length == 0">删除 </el-button>
</template>
<template #right>
<ai-download :instance="instance" url="/app/apppreventionreturntopovertyriskperson/export" :params="params" fileName="风险预警人员" :disabled="tableData.length == 0">
<el-button icon="iconfont iconExported" :disabled="tableData.length == 0">导出</el-button>
</ai-download>
<ai-import :instance="instance" :dict="dict" type="apppreventionreturntopovertyriskperson" name="风险预警人员" @success="getList()">
<el-button icon="iconfont iconImport">导入</el-button>
</ai-import>
</template>
</ai-search-bar>
<ai-table
:tableData="tableData"
:col-configs="colConfigs"
:total="total"
style="margin-top: 12px;"
:current.sync="search.current"
:size.sync="search.size"
@selection-change="(v) => (ids = v.map((e) => e.id))"
@getList="getList">
<el-table-column slot="tags" label="标签">
<template slot-scope="{ row }">
<div class="table-tags">
<el-tag type="info" v-for="(item, index) in row.tags" size="small" :key="index">{{ item }}</el-tag>
</div>
</template>
</el-table-column>
<el-table-column slot="options" width="120px" fixed="right" label="操作" align="center">
<div class="table-options" slot-scope="{ row }">
<el-button type="text" @click="toDetail(row.id)">详情</el-button>
<el-button type="text" @click="remove(row.id)">删除</el-button>
</div>
</el-table-column>
</ai-table>
</template>
</ai-list>
</template>
<script>
import { mapState } from 'vuex'
export default {
name: 'List',
props: {
instance: Function,
dict: Object
},
data() {
return {
search: {
current: 1,
size: 10,
title: '',
riskType: ''
},
ids: [],
total: 10,
colConfigs: [
{ type: 'selection' },
{prop: 'name', label: '姓名', align: 'left'},
{prop: 'phone', label: '联系方式', align: 'center' },
{prop: 'riskType', label: '风险类型', align: 'center', formart: v => this.dict.getLabel('fpRiskType', v) },
{prop: 'areaName', label: '所属区域', align: 'center' },
{prop: 'remarks', label: '备注说明', align: 'center' },
{prop: 'createTime', label: '操作时间', align: 'center'},
{prop: 'createUserName', label: '操作人', align: 'center' },
{prop: 'departmentName', label: '归口部门', align: 'center' },
{slot: 'options', label: '操作'}
],
tableData: []
}
},
computed: {
...mapState(['user']),
params () {
if (this.ids.length) {
return {
ids: this.ids
}
}
return this.search
}
},
created () {
this.dict.load('fpRiskType').then(() => {
this.getList()
})
},
methods: {
getList() {
this.instance.post(`/app/apppreventionreturntopovertyriskperson/list`, null, {
params: {
...this.search,
listType: 1
}
}).then(res => {
if (res.code == 0) {
this.tableData = res.data.records
this.total = res.data.total
}
})
},
removeAll () {
var id = this.ids.join(',')
this.remove(id)
},
remove(id) {
this.$confirm('确定删除该数据?').then(() => {
this.instance.post(`/app/apppreventionreturntopovertyriskperson/delete?ids=${id}`).then(res => {
if (res.code == 0) {
this.$message.success('删除成功!')
this.getList()
}
})
})
},
toDetail (id) {
this.$emit('change', {
type: 'Detail',
params: {
id: id || ''
}
})
},
toAdd(id) {
this.$emit('change', {
type: 'Add',
params: {
id: id || ''
}
})
}
}
}
</script>
<style lang="scss" scoped>
</style>

View File

@@ -0,0 +1,66 @@
<template>
<div class="doc-circulation ailist-wrapper">
<keep-alive :include="['List']">
<component ref="component" :is="component" @change="onChange" :params="params" :instance="instance" :dict="dict"></component>
</keep-alive>
</div>
</template>
<script>
import List from './components/List'
import Detail from './components/Detail'
export default {
name: 'AppVisitToVerify',
label: '走访核实',
props: {
instance: Function,
dict: Object
},
data () {
return {
component: 'List',
params: {},
include: []
}
},
components: {
List,
Detail
},
mounted () {
},
methods: {
onChange (data) {
if (data.type === 'Detail') {
this.component = 'Detail'
this.params = data.params
}
if (data.type === 'List') {
this.component = 'List'
this.params = data.params
this.$nextTick(() => {
if (data.isRefresh) {
this.$refs.component.getList()
}
})
}
}
}
}
</script>
<style lang="scss">
.doc-circulation {
height: 100%;
background: #F3F6F9;
overflow: auto;
}
</style>

View File

@@ -0,0 +1,182 @@
<template>
<ai-detail>
<template slot="title">
<ai-title title="详情" isShowBack isShowBottomBorder @onBackClick="cancel(false)">
<template #rightBtn>
<el-button
size="small"
type="primary"
@click="isShow = true"
v-if="(checkType === '1' || checkType === '2') && info.status !== '3' && info.status !== '2'">
{{ checkType === '1' ? '走访核实' : '处理结果' }}
</el-button>
</template>
</ai-title>
</template>
<template slot="content">
<ai-card title="基本信息">
<template #content>
<ai-wrapper>
<ai-info-item label="姓名" :value="info.name"></ai-info-item>
<ai-info-item label="联系方式" :value="info.phone"></ai-info-item>
<ai-info-item label="风险类型" :value="dict.getLabel('fpRiskType', info.riskType)"></ai-info-item>
<ai-info-item label="身份证号" :value="info.idNumber"></ai-info-item>
<ai-info-item label="所在地区" :value="info.areaName"></ai-info-item>
<ai-info-item label="联系地址" isLine :value="info.address"></ai-info-item>
<ai-info-item label="备注说明" isLine :value="info.remarks"></ai-info-item>
<ai-info-item label="操作人" :value="info.createUserName"></ai-info-item>
<ai-info-item label="归口部门" :value="info.departmentName"></ai-info-item>
<ai-info-item label="操作时间" isLine :value="info.createTime"></ai-info-item>
<ai-info-item label="状态" isLine :value="dict.getLabel('fpRiskPersonStatus', info.status)"></ai-info-item>
</ai-wrapper>
</template>
</ai-card>
<ai-card title="走访核实" v-if="info.visitTime">
<template #content>
<ai-wrapper>
<ai-info-item label="处理意见" :value="info.visitOpinion"></ai-info-item>
<ai-info-item label="处理时间" :value="info.visitTime"></ai-info-item>
<ai-info-item label="业务员" :value="info.visitUserName"></ai-info-item>
<ai-info-item label="照片" isLine>
<ai-uploader
disabled
:instance="instance"
v-model="info.visitFiles"
:limit="9">
</ai-uploader>
</ai-info-item>
</ai-wrapper>
</template>
</ai-card>
<ai-card title="处理结果" v-if="info.auditTime">
<template #content>
<ai-wrapper>
<ai-info-item label="处理意见" :value="info.auditOpinion"></ai-info-item>
<ai-info-item label="处理时间" :value="info.auditTime"></ai-info-item>
<ai-info-item label="业务员" :value="info.auditUserName"></ai-info-item>
<ai-info-item label="照片" isLine>
<ai-uploader
disabled
:instance="instance"
v-model="info.auditFiles"
:limit="9">
</ai-uploader>
</ai-info-item>
</ai-wrapper>
</template>
</ai-card>
<ai-dialog
:visible.sync="isShow"
width="800px"
@close="onClose"
title="审核"
@onConfirm="onConfirm">
<el-form class="ai-form" label-width="110px" :model="form" ref="form">
<el-form-item label="处理意见" prop="operation" style="width: 100%;" :rules="[{ required: true, message: '请选择处理意见' }]">
<el-radio-group v-model="form.operation">
<el-radio label="0" v-if="checkType === '1'">疑似风险</el-radio>
<el-radio label="1" v-if="checkType === '2'">纳入监测</el-radio>
<el-radio label="2">解除风险</el-radio>
</el-radio-group>
<!-- <span v-if="info.status != '2'">解除风险</span>
<span v-if="info.status === '0' && checkType === '1'">疑似风险</span>
<span v-if="info.status !== '2' && checkType === '2'">纳入监测</span> -->
</el-form-item>
<el-form-item label="备注说明" prop="opinion" style="width: 100%;" :rules="[{ required: true, message: '请输入备注说明' }]">
<el-input type="textarea" :rows="5" :maxlength="200" v-model="form.opinion" clearable placeholder="请输入备注说明" show-word-limit></el-input>
</el-form-item>
<el-form-item label="照片" prop="files" style="width: 100%;">
<ai-uploader
:instance="instance"
v-model="form.files"
:limit="9">
<template slot="tips">
<p>最多上传9张图片,单个文件最大10MB支持jpgjpegpng格式</p>
</template>
</ai-uploader>
</el-form-item>
</el-form>
</ai-dialog>
</template>
</ai-detail>
</template>
<script>
export default {
name: 'Detail',
props: {
instance: Function,
dict: Object,
params: Object
},
data () {
return {
info: {},
id: '',
checkType: '',
form: {
opinion: '',
operation: '',
ids: ''
},
isShow: false
}
},
created () {
if (this.params && this.params.id) {
this.id = this.params.id
this.getInfo(this.params.id)
}
},
methods: {
getInfo (id) {
this.instance.post(`/app/apppreventionreturntopovertyriskperson/queryDetailById?id=${id}`).then(res => {
if (res.code === 0) {
this.info = res.data
}
})
this.instance.post('/app/appgirdmemberinfo/checkLogOnUser').then((res) => {
if (res.code == 0) {
this.checkType = res.data.checkType
}
})
},
onClose () {
this.form.opinion = ''
this.form.operation = ''
},
onConfirm () {
this.$refs.form.validate(v => {
if (v) {
this.instance.post(`/app/apppreventionreturntopovertyriskperson/monitor`, {
...this.form,
ids: [this.params.id]
}).then(res => {
if (res.code == 0) {
this.$message.success('操作成功!')
this.isShow = false
this.getInfo(this.params.id)
}
})
}
})
},
cancel () {
this.$emit('change', {
type: 'List',
isRefresh: true
})
}
}
}
</script>
<style scoped lang="scss">
</style>

View File

@@ -0,0 +1,199 @@
<template>
<ai-list class="notice">
<template slot="title">
<ai-title title="走访核实" isShowBottomBorder :isShowArea="true" v-model="search.areaId" :instance="instance" @change="getList"></ai-title>
</template>
<template slot="content">
<ai-search-bar>
<template #left>
<ai-select
v-model="search.riskType"
clearable
placeholder="请选择风险类型"
:selectList="dict.getDict('fpRiskType')"
@change="search.current = 1, getList()">
</ai-select>
<ai-select
v-model="search.status"
clearable
placeholder="请选择状态"
:selectList="dict.getDict('fpRiskPersonStatus')"
@change="search.current = 1, getList()">
</ai-select>
<el-button size="small" v-if="checkType === '2'" :disabled="addIds.length == 0" type="primary" @click="addMonitor">纳入监测</el-button>
<el-button size="small" v-if="checkType !== '0'" :disabled="removeIds.length == 0" @click="removeAll">解除风险</el-button>
</template>
<template #right>
<el-input
v-model="search.name"
size="small"
placeholder="姓名/备注说明/操作人"
clearable
v-throttle="() => {search.current = 1, getList()}"
@clear="search.current = 1, search.name = '', getList()"
suffix-icon="iconfont iconSearch">
</el-input>
</template>
</ai-search-bar>
<ai-table
:tableData="tableData"
:col-configs="colConfigs"
:total="total"
style="margin-top: 12px;"
:current.sync="search.current"
:size.sync="search.size"
@selection-change="(v) => chooseList = v"
@getList="getList">
<el-table-column slot="options" width="90px" fixed="right" label="操作" align="center">
<div class="table-options" slot-scope="{ row }">
<el-button type="text" @click="toDetail(row.id)">详情</el-button>
</div>
</el-table-column>
</ai-table>
</template>
</ai-list>
</template>
<script>
import { mapState } from 'vuex'
export default {
name: 'List',
props: {
instance: Function,
dict: Object
},
data() {
return {
search: {
current: 1,
size: 10,
name: '',
areaId: '',
riskType: '',
status: ''
},
chooseList: [],
total: 10,
checkType: '',
tableData: []
}
},
computed: {
...mapState(['user']),
colConfigs () {
return [
{ type: 'selection' },
{ prop: 'name', label: '姓名', align: 'left'},
{ prop: 'phone', label: '联系方式', align: 'center' },
{ prop: 'riskType', label: '风险类型', align: 'center', formart: v => this.dict.getLabel('fpRiskType', v) },
{ prop: 'areaName', label: '所属区域', align: 'center' },
{ prop: 'remarks', label: '备注说明', align: 'center' },
{ prop: 'status', label: '状态', align: 'center', formart: v => this.dict.getLabel('fpRiskPersonStatus', v) },
{ prop: 'createTime', label: '处理时间', align: 'center' },
{ prop: 'createUserName', label: '处理人', align: 'center' }
]
},
addIds () {
if (!this.chooseList.length) {
return []
}
return this.chooseList.filter(v => v.status === '0' || v.status === '1').map(v => v.id)
},
removeIds () {
if (!this.chooseList.length) {
return []
}
return this.chooseList.filter(v => v.status === '0' || v.status === '1').map(v => v.id)
}
},
created () {
this.search.areaId = this.user.info.areaId
this.dict.load('fpRiskType', 'fpRiskPersonStatus').then(() => {
this.getList()
})
this.getInfo()
},
methods: {
getList() {
this.instance.post(`/app/apppreventionreturntopovertyriskperson/list`, null, {
params: {
...this.search
}
}).then(res => {
if (res.code == 0) {
this.tableData = res.data.records
this.total = res.data.total
}
})
},
getInfo () {
this.instance.post('/app/appgirdmemberinfo/checkLogOnUser').then((res) => {
if (res.code == 0) {
this.checkType = res.data.checkType
}
})
},
addMonitor () {
this.$confirm('是否纳入监测对象?').then(() => {
this.instance.post(`/app/apppreventionreturntopovertyriskperson/monitor`, {
ids: this.addIds,
operation: 1
}).then(res => {
if (res.code == 0) {
this.$message.success('操作成功!')
this.getList()
}
})
})
},
removeAll () {
this.$confirm('确定删除该数据?').then(() => {
this.instance.post(`/app/apppreventionreturntopovertyriskperson/monitor`, {
ids: this.removeIds,
operation: 2
}).then(res => {
if (res.code == 0) {
this.$message.success('操作成功!')
this.getList()
}
})
})
},
toDetail (id) {
this.$emit('change', {
type: 'Detail',
params: {
id: id || ''
}
})
},
toAdd(id) {
this.$emit('change', {
type: 'Add',
params: {
id: id || ''
}
})
}
}
}
</script>
<style lang="scss" scoped>
</style>

View File

@@ -0,0 +1,62 @@
<template>
<div class="AppVisitVondolence">
<keep-alive :include="['List']">
<component ref="component" :is="component" @change="onChange" :params="params" :instance="instance" :dict="dict"></component>
</keep-alive>
</div>
</template>
<script>
import List from './components/List.vue'
import Detail from './components/Detail.vue'
export default {
name: 'AppVisitVondolence',
label: '走访慰问',
components: {
List,
Detail
},
props: {
instance: Function,
dict: Object,
permissions: Function
},
data () {
return {
component: 'List',
params: {}
}
},
methods: {
onChange (data) {
if (data.type === 'Detail') {
this.component = 'Detail'
this.isShowDetail = true
this.params = data.params
}
if (data.type === 'list') {
this.component = 'List'
this.params = data.params
this.$nextTick(() => {
if (data.isRefresh) {
this.$refs.component.getList()
}
})
}
}
}
}
</script>
<style lang="scss" scoped>
.AppVisitVondolence {
height: 100%;
}
</style>

View File

@@ -0,0 +1,89 @@
<template>
<ai-detail>
<template slot="title">
<ai-title title="详情" isShowBack isShowBottomBorder @onBackClick="cancel(true)">
</ai-title>
</template>
<template slot="content">
<ai-card title="基本信息">
<template #content>
<ai-wrapper
label-width="120px">
<ai-info-item label="标题" :value="info.title" isLine></ai-info-item>
<ai-info-item label="描述" isLine :value="info.description"></ai-info-item>
<ai-info-item label="图片" isLine :value="info.idNumber">
<ai-uploader v-model="info.images" :instance="instance" :limit="9" disabled/>
</ai-info-item>
<ai-info-item label="慰问对象" :value="info.name"></ai-info-item>
<ai-info-item label="对象类型" :value="info.type"></ai-info-item>
<ai-info-item label="现实状态" isLine :value="dict.getLabel('visitCondolenceReality', info.reality)"></ai-info-item>
<ai-info-item label="走访人" :value="info.createUserName"></ai-info-item>
<ai-info-item label="走访时间" :value="info.visitTime"></ai-info-item>
</ai-wrapper>
</template>
</ai-card>
</template>
</ai-detail>
</template>
<script>
export default {
name: 'Detail',
props: {
instance: Function,
dict: Object,
params: Object
},
data () {
return {
info: {},
id: ''
}
},
created () {
this.id = this.params.id
this.dict.load(['visitCondolenceReality']).then(() => {
this.getDictList()
})
},
methods: {
getInfo (id) {
this.instance.post(`/app/appvisitvondolence/queryDetailById?id=${id}`).then(res => {
if (res.code === 0) {
this.info = res.data
this.info.images = res.data.images ? JSON.parse(res.data.images) : []
this.info.type = this.dictList.filter(v => v.dictValue === res.data.applicationId)[0].dictName
}
})
},
getDictList () {
this.instance.post(`/app/appapplicationinfo/queryApplicationListByType`).then(res => {
if (res.code == 0) {
this.dictList = res.data.map(v => {
return {
dictValue: v.id,
dictName: v.applicationName
}
})
this.getInfo(this.params.id)
}
})
},
cancel (isRefresh) {
this.$emit('change', {
type: 'list',
isRefresh: !!isRefresh
})
}
}
}
</script>
<style scoped lang="scss">
</style>

View File

@@ -0,0 +1,155 @@
<template>
<ai-list class="list">
<ai-title slot="title" title="走访慰问" isShowBottomBorder></ai-title>
<template slot="content">
<div class="content">
<ai-search-bar bottomBorder>
<template #left>
<ai-select
v-model="search.applicationId"
clearable
placeholder="请选择对象类型"
:selectList="dictList"
@change="search.current = 1, getList()">
</ai-select>
<ai-select
v-model="search.reality"
clearable
placeholder="请选择现实状态"
:selectList="dict.getDict('visitCondolenceReality')"
@change="search.current = 1, getList()">
</ai-select>
</template>
<template #right>
<el-input
v-model="search.title"
size="small"
placeholder="标题、慰问对象、走访人"
clearable
v-throttle="() => {search.current = 1, getList()}"
@clear="search.current = 1, search.title = '', getList()"
suffix-icon="iconfont iconSearch">
</el-input>
</template>
</ai-search-bar>
<ai-table
:tableData="tableData"
:col-configs="colConfigs"
:total="total"
style="margin-top: 16px;"
:current.sync="search.current"
:size.sync="search.size"
@getList="getList">
<el-table-column slot="options" width="120px" fixed="right" label="操作" align="center">
<template slot-scope="{ row }">
<div class="table-options">
<el-button type="text" @click="toDetail(row.id)">详情</el-button>
<el-button type="text" @click="remove(row.id)">删除</el-button>
</div>
</template>
</el-table-column>
</ai-table>
</div>
</template>
</ai-list>
</template>
<script>
import { mapState } from 'vuex'
export default {
name: 'List',
props: {
instance: Function,
dict: Object
},
data () {
return {
search: {
current: 1,
size: 10,
title: '',
reality: '',
menuLevel3Name: ''
},
dictList: [],
info: {},
colConfigs: [
{ prop: 'title', label: '标题' },
{ prop: 'visitTime', align: 'center', label: '走访时间' },
{ prop: 'name', align: 'center', label: '慰问对象' },
{ prop: 'menuLevel3Name', align: 'center', label: '对象类型' },
{ prop: 'reality', align: 'center', label: '现实状态', formart: v => v ? this.dict.getLabel('visitCondolenceReality', v) : '-' },
{ prop: 'createUserName', align: 'center', label: '走访人' }
],
tableData: [],
total: 0
}
},
computed: {
...mapState(['user'])
},
created () {
this.getDictList()
this.dict.load(['visitCondolenceReality']).then(() => {
this.getList()
})
},
methods: {
getList () {
this.instance.post(`/app/appvisitvondolence/list`, null, {
params: {
...this.search
}
}).then(res => {
if (res.code == 0) {
this.tableData = res.data.records
this.total = res.data.total
}
})
},
getDictList () {
this.instance.post(`/app/appapplicationinfo/queryApplicationListByType`).then(res => {
if (res.code == 0) {
this.dictList = res.data.map(v => {
return {
dictValue: v.id,
dictName: v.applicationName
}
})
}
})
},
remove(id) {
this.$confirm('确定删除该数据?').then(() => {
this.instance.post(`/app/appvisitvondolence/delete?ids=${id}`).then(res => {
if (res.code == 0) {
this.$message.success('删除成功!')
this.getList()
}
})
})
},
toDetail (id) {
this.$emit('change', {
type: 'Detail',
params: {
id: id || ''
}
})
}
}
}
</script>
<style scoped lang="scss">
.list {
}
</style>

View File

@@ -0,0 +1,94 @@
<template>
<section class="AppApprovalManage">
<ai-list v-if="showList">
<template slot="title">
<ai-title title="审批管理" :isShowBottomBorder="false"/>
</template>
<template slot="tabs">
<el-tabs class="tabs-page" v-model="currIndex">
<el-tab-pane v-for="(tab,i) in tabs" :key="i" :label="tab.label" :name="String(i)">
<component :is="tab.comp" v-if="currIndex==i" :ref="currIndex" :instance="instance" :dict="dict"
:permissions="permissions" :listType="tab.value" @goPage="goPage"/>
</el-tab-pane>
</el-tabs>
</template>
</ai-list>
<component v-if="!showList" :is="currentPage" :instance="instance" :listType="currentTab.value" :dict="dict"
:permissions="permissions" :detail="detail" @goBack="goBack"></component>
</section>
</template>
<script>
import forMyApproval from "./components/forMyApproval";
import approvalDetail from "./components/approvalDetail";
export default {
name: "AppApprovalManage",
label: "审批管理",
components: {approvalDetail},
provide() {
return {
approval: this
}
},
props: {
instance: Function,
dict: Object,
permissions: Function
},
data() {
return {
currIndex: '0',
showList: true,
currentPage: "",
detail: {},
}
},
computed: {
tabs() {
return [
{
label: "待我审批", name: "forMyApproval", value: "0", comp: forMyApproval, detail: approvalDetail,
permission: ""
},
{
label: "我已审批", name: "forMyApproval", value: "1", comp: forMyApproval, detail: approvalDetail,
permission: ""
},
{
label: "抄送我的", name: "forMyApproval", value: "3", comp: forMyApproval, detail: approvalDetail,
permission: ""
},
{
label: "超时督办", name: "forMyApproval", value: "4", comp: forMyApproval, detail: approvalDetail,
permission: ""
},
]
},
currentTab() {
return this.tabs[this.currIndex] || {}
}
},
methods: {
goPage(obj) {
this.currentPage = this.tabs[Number(this.currIndex)][obj.key];
obj.row && (this.detail = obj.row)
this.showList = false;
},
goBack() {
this.showList = true;
this.$nextTick(() => {
this.$refs[this.currIndex][0].getList();
})
},
}
}
</script>
<style lang="scss" scoped>
.AppApprovalManage {
width: 100%;
height: 100%;
background-color: #F3F6F9;
}
</style>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,218 @@
<template>
<div class="for-my-approval">
<ai-list isTabs>
<template #content>
<ai-search-bar>
<template #right>
<el-input
v-model="search.param"
size="small"
placeholder="标题/发起人"
v-throttle="() => {search.current = 1, getList()}"
@clear="reset"
clearable
suffix-icon="iconfont iconSearch"/>
</template>
</ai-search-bar>
<ul class="list-wrap">
<li v-for="(item,index) in tableData" :key="index" @click="goTo('detail',item)">
<div class="list-title">{{item.processDefName}}</div>
<div class="info">
<div class="item">
<label>发起人:</label>
<span>{{item.createUserName}}</span>
</div>
<div class="item">
<label>所属部门:</label>
<span>{{dict.getLabel('hbDepartment',item.department)}}</span>
</div>
<div class="item">
<label>所属分类:</label>
<span>{{item.classificationName}}</span>
</div>
<div class="item">
<label>发起时间:</label>
<span>{{item.createTime|format}}</span>
</div>
</div>
<svgIcon :class-name="icon(item.approvalStatus)" class="svg"></svgIcon>
</li>
</ul>
<div class="no-data" v-if="tableData.length==0"></div>
<el-pagination class="pagination" background :current-page="search.current" @current-change="handleCurrent"
layout="total,prev, pager, next,sizes, jumper"
:total="total"
@size-change="handleSizeChange"
:page-size="search.size"
:page-sizes="[10, 20, 50, 100,200]">
</el-pagination>
</template>
</ai-list>
</div>
</template>
<script>
import svgIcon from "./svgIcon";
import day from 'dayjs'
export default {
name: "forMyApproval",
components: {svgIcon},
props: {
instance: Function,
dict: Object,
permissions: Function,
listType: String,
},
data() {
return {
search: {
param:"",
current: 1,
size: 10,
},
tableData: [],
total: 0
}
},
methods: {
icon(icon) {
if(icon==0){
return "iconsp_ing"
}else if(icon==1){
return "iconsp-pass"
}else if(icon==2){
return "iconsp_refused"
}
return "iconcancel"
},
goTo(key = '', row) {
this.$emit('goPage', {key, row});
},
reset() {
this.search.param = ""
this.search.current = 1
this.search.size = 10
this.getList()
},
handleCurrent(val) {
this.search.current = val;
this.getList();
},
handleSizeChange(val) {
this.search.size = val;
this.getList();
},
getList() {
this.instance.post(`/app/approv-alapply-info/list`,null,{
params:{
listType: this.listType,
...this.search
}
}).then(res => {
if (res && res.data) {
this.tableData = res.data.records
this.total = res.data.total
}
})
}
},
filters:{
format(time){
return time ? day(time).format('YYYY-MM-DD HH:mm') : '-'
}
},
created(){
this.dict.load(['hbDepartment']).then(()=>{
this.getList()
})
},
}
</script>
<style lang="scss" scoped>
.for-my-approval {
height: 100%;
background: #f3f6f9;
overflow: auto;
.list-wrap {
width: 100%;
min-height: 100%;
li {
width: 100%;
height: 80px;
border-radius: 4px;
border: 1px solid #D8E0E8;
margin-bottom: 8px;
box-sizing: border-box;
padding: 16px 32px;
user-select: none;
cursor: pointer;
position: relative;
.list-title {
font-size: 16px;
font-weight: 600;
color: #333333;
padding-bottom: 6px;
}
.info {
width: 90%;
display: flex;
align-items: center;
justify-content: space-between;
.item {
width: 30%;
& > label {
color: #666666;
}
& > span {
color: #333333;
}
}
}
.svg {
width: 66px;
height: 61px;
position: absolute;
right: 0;
bottom: 0;
}
}
}
.no-data {
background-size: 120px 120px;
height: 160px;
margin: 48px auto 10px;
}
.pagination {
box-sizing: border-box;
padding: 24px 0 32px 0;
}
.iconfont {
user-select: none;
cursor: pointer;
}
::v-deep .AiSearchBar {
margin-bottom: 16px;
}
}
</style>

View File

@@ -0,0 +1,25 @@
<template>
<svg class="icon" aria-hidden="true" v-bind="$attrs">
<use :xlink:href="iconName"></use>
</svg>
</template>
<script>
export default {
name: "svgIcon",
props: {
className: {
type: String,
}
},
computed: {
iconName() {
return `#${this.className}`
}
}
}
</script>
<style lang="scss" scoped>
</style>

View File

@@ -0,0 +1,186 @@
<template>
<section class="AppCorporateSeal">
<ai-list v-if="showList">
<template slot="title">
<ai-title title="企业印章" :isShowBottomBorder="true"></ai-title>
</template>
<template slot="content">
<div class="signaturePane">
<div class="signatureCard" v-for="(op,i) in signatures" :key="i">
<div class="default" v-if="op.isDefault==1">默认</div>
<div class="body">
<el-image :src="`data:image/png;base64,${op.signSealData}`"/>
</div>
<div class="footer">
<el-button type="text" :disabled="op.isDefault==1" @click.stop="handleSetDefault(op.id)">设为默认</el-button>
<hr/>
<el-button type="text" :disabled="op.isDefault==1||op.signType==1" @click.stop="handleDelete(op.id)">删除
</el-button>
</div>
</div>
<div class="signatureCard add" @click="showList=false">
<ai-icon icon="iconAdd" size="32px"/>
<span>点击添加印章</span>
</div>
</div>
</template>
</ai-list>
<seal-detail v-else/>
</section>
</template>
<script>
import SealDetail from "./sealDetail";
export default {
name: "AppCorporateSeal",
label: "企业印章",
components: {SealDetail},
provide() {
return {
seal: this
}
},
props: {
instance: Function,
dict: Object,
permissions: Function
},
data() {
return {
signatures: [],
showList: true
}
},
created() {
this.getSignatures()
},
methods: {
getSignatures() {
this.instance.post("/app/syssignaccount/list", null, {
params: {
signType: 2,
size: 999
}
}).then(res => {
if (res?.data) {
this.signatures = res.data.records
}
})
},
handleSetDefault(id) {
this.$confirm("是否设置该印章为默认印章?").then(() => {
this.instance.post("/app/syssignaccount/default", null, {params: {id, listType: 1}}).then(res => {
if (res?.code == 0) {
this.$message.success("设置成功!")
this.getSignatures()
}
}).catch(() => 0)
})
},
handleDelete(ids) {
this.$confirm("是否删除该印章?").then(() => {
this.instance.post("/app/syssignaccount/delete", null, {params: {ids}}).then(res => {
if (res?.code == 0) {
this.$message.success("删除成功!")
this.getSignatures()
}
}).catch(() => 0)
})
},
}
}
</script>
<style lang="scss" scoped>
.AppCorporateSeal {
height: 100%;
background: #f3f6f9;
::v-deep .signaturePane {
display: flex;
gap: 16px;
flex-wrap: wrap;
padding: 16px;
.signatureCard {
width: 290px;
height: 258px;
background: #FFFFFF;
border-radius: 4px;
position: relative;
display: flex;
flex-direction: column;
overflow: hidden;
&.add {
justify-content: center;
align-items: center;
color: #666666;
cursor: pointer;
.AiIcon {
width: 32px;
height: 32px;
font-size: 32px;
}
& > span {
font-size: 12px;
line-height: 16px;
}
}
.default {
position: absolute;
width: 56px;
height: 24px;
background: #3573FF;
border-radius: 0 0 4px 0;
top: 0;
left: 0;
text-align: center;
line-height: 24px;
font-size: 12px;
color: #FFF;
}
.body {
min-height: 0;
flex: 1;
display: flex;
justify-content: center;
align-items: center;
padding: 50px;
cursor: pointer;
}
.footer {
flex-shrink: 0;
height: 40px;
background: rgba(#30426F, .5);
display: flex;
align-items: center;
padding: 8px 0;
box-sizing: border-box;
hr {
height: 100%;
border-color: rgba(#fff, .5);
}
& > .el-button {
flex: 1;
color: #fff;
&[disabled] {
color: rgba(#fff, .5);
}
}
}
}
}
}
</style>

View File

@@ -0,0 +1,233 @@
<template>
<section class="sealDetail">
<ai-detail>
<template #title>
<ai-title title="添加企业印章" isShowBack isShowBottomBorder @onBackClick="back"/>
</template>
<template #content>
<el-form size="small" ref="SealForm" :model="form" :rules="rules" label-suffix="" label-width="160px">
<ai-title title="单位信息" isShowBottomBorder/>
<el-form-item label="单位名称" prop="organizeName">
<el-input clearable v-model="form.organizeName" placeholder="请输入..." maxlength="25" show-word-limit/>
</el-form-item>
<el-form-item label="单位类型" prop="organizeType">
<el-select clearable v-model="form.organizeType" placeholder="请输入...">
<el-option v-for="(op,i) in $dict.getDict('organizeType')" :key="i" :value="op.dictValue"
:label="op.dictName"/>
</el-select>
</el-form-item>
<div class="flexFillRow">
<el-form-item label="企业注册类型" prop="organRegType">
<el-select clearable v-model="form.organRegType" placeholder="请输入...">
<el-option v-for="(op,i) in $dict.getDict('organRegType')" :key="i" :value="op.dictValue"
:label="op.dictName"/>
</el-select>
</el-form-item>
<el-form-item v-if="!!form.organRegType" :label="$dict.getLabel('organRegType',form.organRegType)"
prop="organCode">
<el-input clearable v-model="form.organCode" placeholder="请输入..."/>
</el-form-item>
<div v-else/>
</div>
<div class="flexFillRow">
<el-form-item label="注册类型" prop="registerType">
<el-select clearable v-model="form.registerType" placeholder="请输入...">
<el-option v-for="(op,i) in $dict.getDict('registerType')" :key="i" :value="op.dictValue"
:label="op.dictName"/>
</el-select>
</el-form-item>
<div/>
</div>
<template v-if="form.registerType==1">
<div class="flexFillRow">
<el-form-item label="代理人姓名" prop="agentName">
<el-input clearable v-model="form.agentName" placeholder="请输入..."/>
</el-form-item>
<el-form-item label="代理人身份证号" prop="agentIdNumber">
<el-input clearable v-model="form.agentIdNumber" placeholder="请输入..."/>
</el-form-item>
</div>
<div class="flexFillRow">
<el-form-item label="代理人手机号" prop="signPhone">
<el-input clearable v-model="form.signPhone" placeholder="请输入..."/>
</el-form-item>
<div/>
</div>
</template>
<template v-if="form.registerType==2">
<div class="flexFillRow">
<el-form-item label="法人姓名" prop="legalName">
<el-input clearable v-model="form.legalName" placeholder="请输入..."/>
</el-form-item>
<el-form-item label="法人身份证号" prop="legalIdNumber">
<el-input clearable v-model="form.legalIdNumber" placeholder="请输入..."/>
</el-form-item>
</div>
<div class="flexFillRow">
<el-form-item label="法人手机号" prop="signPhone">
<el-input clearable v-model="form.signPhone" placeholder="请输入..."/>
</el-form-item>
<div/>
</div>
</template>
<ai-title title="印章信息" isShowBottomBorder/>
<el-form-item class="sealImageTypes" label="生成印章类型" prop="organizeTemplateType">
<div v-for="(op,i) in sealImageTypes" :key="i" class="item" @click="form.organizeTemplateType=op.value">
<el-image :src="op.image" fit="contain"/>
<el-radio :label="op.value" v-model="form.organizeTemplateType">{{ op.name }}</el-radio>
</div>
</el-form-item>
<el-form-item label="横向文内容" prop="htext">
<el-input clearable v-model="form.htext" placeholder="0-8个字如合同专用章财务专用章等" maxlength="8" show-word-limit/>
</el-form-item>
<el-form-item label="下弦文内容" prop="qtext">
<el-input clearable v-model="form.qtext" placeholder="0-20个字下弦文是指的贵司公章底部一串防伪数字" maxlength="20"
show-word-limit/>
</el-form-item>
</el-form>
</template>
<template #footer>
<el-button @click="back">取消</el-button>
<el-button type="primary" @click="handleSubmit" v-loading="loading">提交</el-button>
</template>
</ai-detail>
</section>
</template>
<script>
export default {
name: "sealDetail",
inject: ['seal'],
data() {
return {
form: {
organizeTemplateType: "STAR",
organizeType: "4",
organRegType: "NORMAL",
registerType: "1"
},
loading: false
}
},
computed: {
sealImageTypes() {
return this.$dict.getDict("organizeTemplateType")?.map(e => ({
image: e.dictColor,
value: e.dictValue,
name: e.dictName
})) || []
},
rules() {
return {
organizeName: [{required: true, message: "请填写单位名称"}],
organCode: [{required: true, message: `请填写${this.$dict.getLabel('organRegType', this.form.organRegType)}`}],
legalName: [{required: true, message: "请填写法人姓名"}],
agentName: [{required: true, message: "请填写代理人姓名"}],
organizeTemplateType: [{required: true}],
htext: [{required: true, message: "请填写横向文内容"}],
qtext: [{required: true, message: "请填写下弦文内容"}],
organizeType: [{required: true, message: "请选择单位类型"}],
organRegType: [{required: true, message: "请选择企业注册类型"}],
registerType: [{required: true, message: "请选择注册类型"}],
signPhone: [
{required: true, message: "请填写手机号码"},
{pattern: /^1[3456789]\d{9}$/, message: "手机号码格式有误"}
],
legalIdNumber: [
{required: true, message: "请填写法人身份证号码"},
{validator: (r, v, cb) => cb(this.idCardNoUtil.checkIdCardNo(v) ? undefined : "身份证号码格式有误")}
],
agentIdNumber: [
{required: true, message: "请填写代理人身份证号码"},
{validator: (r, v, cb) => cb(this.idCardNoUtil.checkIdCardNo(v) ? undefined : "身份证号码格式有误")}
],
}
}
},
created() {
this.$dict.load("registerType", "organRegType", "organizeType", "organizeTemplateType")
},
methods: {
back() {
this.seal.showList = true
this.seal.getSignatures()
},
handleSubmit() {
this.$refs.SealForm.validate(v => {
if (v) {
this.loading = true
this.seal.instance.post("/app/syssignaccount/register", {
userType: 0,
signType: 2,
signPhone: this.form.signPhone,
registerInfo: {...this.form, legalArea: 0},
style: {...this.form, sealColor: "RED"}
}).then(res => {
this.loading = false
if (res?.code == 0) {
this.$message.success("添加成功!")
this.back()
}
}).catch(() => this.loading = false)
}
})
}
}
}
</script>
<style lang="scss" scoped>
.sealDetail {
height: inherit;
::v-deep .ai-detail__content--wrapper {
.el-form {
display: flex;
flex-direction: column;
gap: 24px;
}
.el-form-item {
margin-bottom: 0;
.el-select {
width: 100%;
}
&.sealImageTypes > .el-form-item__content {
display: flex;
gap: 40px;
.item {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 8px;
cursor: pointer;
.el-image {
width: 80px;
height: 80px;
}
}
}
}
.flexFillRow {
display: flex;
align-items: center;
& > * {
flex: 1;
min-width: 0;
}
}
}
::v-deep .ai-detail__footer > .el-button {
width: 92px;
height: 32px;
}
}
</style>

View File

@@ -0,0 +1,204 @@
<template>
<section class="examination-approval">
<ai-list v-if="!showList">
<template #title>
<ai-title title="审批分类" :isShowBottomBorder="true" :instance="instance"></ai-title>
</template>
<template #content>
<ai-search-bar>
<template #left>
<el-button type="primary" icon="iconfont iconAdd" @click="showList = true">添加分类</el-button>
</template>
<template #right>
<el-input
v-model="search.name"
size="small"
placeholder="分类名称/创建人"
v-throttle="() => {search.current = 1, getList()}"
@clear="reset"
clearable
suffix-icon="iconfont iconSearch"/>
</template>
</ai-search-bar>
<ai-table
:tableData="tableData"
:col-configs="colConfigs"
:total="total"
:header-cell-style="{fontWeight:'bold',color:'#333'}"
:current.sync="search.current"
:size.sync="search.size"
@getList="getList">
<el-table-column label="是否启用" slot="status" align="center" width="150">
<template v-slot="{row}">
<el-switch
v-model="row.status"
@change="onChange(row)" active-value="1" inactive-value="0"
active-color="#5088FF"
inactive-color="#D0D4DC">
</el-switch>
</template>
</el-table-column>
<el-table-column label="操作" slot="options" align="center" width="150">
<template v-slot="{row}">
<el-button type="text" title="修改" @click="editInfo(row)">修改</el-button>
<el-button type="text" title="删除" @click="deleteInfo(row)">删除</el-button>
</template>
</el-table-column>
</ai-table>
</template>
</ai-list>
<addClassification v-else @back="showList=false;row={},getList()" :instance="instance"
:row="row"></addClassification>
</section>
</template>
<script>
import addClassification from "./components/addClassification";
import day from 'dayjs'
export default {
name: "AppExaminationApproval",
label: "审批分类",
components: {addClassification},
props: {
instance: Function,
dict: Object,
permissions: Function
},
data() {
return {
search: {
current: 1,
size: 10,
name: "",
},
total: 0,
tableData: [],
row: {},
showList: false
}
},
computed: {
colConfigs() {
return [
{
prop: 'name',
align: 'left',
label: '分类名称',
},
{
prop: 'desc',
align: 'left',
label: '分类描述',
},
{
prop: 'createUserName',
align: 'center',
label: '创建人',
},
{
prop: 'createTime',
align: 'center',
label: '创建日期',
},
{
prop: 'showIndex',
align: 'center',
label: '排序',
},
{
slot: 'status',
align: 'center',
label: '是否启用',
},
{
slot: 'options',
align: 'center',
label: '操作',
},
]
},
},
methods: {
/**
* 编辑
* */
editInfo(row) {
this.row = row
this.showList = true
},
/**
* 启用、停用
*/
onChange(row) {
this.instance.post(`/app/zwspapprovalclassification/enable?id=${row.id}`).then(res => {
if (res?.code == 0) {
this.$message.success(+row.status ? "已启用" : '不启用')
this.getList()
}
})
},
reset() {
this.search.name = ""
this.getList()
},
getList() {
this.instance.post(`/app/zwspapprovalclassification/list`, null, {
params: {
...this.search,
},
}).then(res => {
if (res && res.data) {
this.tableData = res.data.records.map(e => ({
...e,
createTime: day(e.createTime).format("YYYY-MM-DD"),
}));
this.total = res.data.total;
}
})
},
/**
* 删除
*/
deleteInfo({id}) {
this.$confirm("是否删除?").then(() => {
this.instance.post(`/app/zwspapprovalclassification/delete?ids=${id}`).then(res => {
if (res.code == 0) {
this.$message.success("删除成功")
this.getList()
}
})
})
},
},
mounted() {
this.getList()
}
}
</script>
<style lang="scss" scoped>
.examination-approval {
height: 100%;
background: #f3f6f9;
overflow: auto;
.iconfont {
user-select: none;
cursor: pointer;
}
::v-deep .ai-table {
margin-top: 16px;
}
}
</style>

View File

@@ -0,0 +1,197 @@
<template>
<section class="add-classification">
<ai-detail>
<ai-title slot="title" :title="pageTitle" isShowBack isShowBottomBorder @onBackClick="$emit('back')"/>
<template #content>
<ai-card title="基本信息">
<template #content>
<el-form :model="form" :rules="rules" ref="addClassification" label-suffix="" label-width="100px"
size="small">
<el-form-item label="分类名称" prop="name">
<el-input v-model.trim="form.name" size="small" clearable placeholder="如“社会保障”限10个字" :maxlength="10"
show-word-limit/>
</el-form-item>
<el-form-item label="排序" prop="showIndex">
<el-input v-model.number="form.showIndex" size="small" clearable placeholder="请输入数字,数字越小排序越前"/>
</el-form-item>
<el-form-item label="分类描述" prop="desc">
<el-input v-model.trim="form.desc" type="textarea" size="small" clearable placeholder="限500个字"
:maxlength="500" show-word-limit :rows="4"/>
</el-form-item>
<el-form-item label="分类图标" prop="icon" class="icon-form">
<el-upload ref="iconUploader" action="#" :auto-upload="false" :on-change="handleUploadIcon" :limit="1"
:show-file-list="false">
<el-image v-if="!!form.icon" class="el-upload-list__item" :src="form.icon">
<i class="el-icon-picture-outline"/>
</el-image>
<div v-else class="el-upload--picture-card"><i class="el-icon-plus"/></div>
</el-upload>
</el-form-item>
<el-form-item label="是否启用" prop="status">
<el-radio v-model="form.status" label="1"></el-radio>
<el-radio v-model="form.status" label="0"></el-radio>
</el-form-item>
</el-form>
</template>
</ai-card>
</template>
<template #footer>
<el-button class="btn" @click="$emit('back')">取消</el-button>
<el-button class="btn" type="primary" @click="submit">提交</el-button>
</template>
</ai-detail>
</section>
</template>
<script>
export default {
name: "addClassification",
props: {
instance: Function,
row: Object,
},
data() {
return {
form: {
id: "",
name: "",
showIndex: "",
desc: "",
icon: "",
status: "1"
}
}
},
computed: {
pageTitle() {
return this.row?.id ? "编辑分类" : "添加分类"
},
rules() {
return {
name: [{required: true, message: '请输入分类名称', trigger: 'blur'}],
showIndex: [
{required: true, message: '请输入排序数字'},
{min: 1, max: 999, type: "number", message: '排序只能输入1~999之间的整数'},
],
desc: [{required: true, message: '请填写描述', trigger: 'blur'}],
icon: [{required: true, message: '请选择分类图标', trigger: 'blur'}],
status: [{required: true, message: '请选择是否启用', trigger: 'change'}],
}
}
},
methods: {
/**
* 提交
*/
submit() {
this.$refs['addClassification'].validate(valid => {
if (valid) {
this.instance.post(`/app/zwspapprovalclassification/addOrUpdate`, {
...this.form,
status: Number(this.form.status)
}).then(res => {
if (res.code == 0) {
this.$message.success(this.row.id ? "编辑成功" : "添加成功")
this.$emit('back')
}
})
}
})
},
/**
* 获取详情
*/
getDetail() {
this.instance.post(`/app/zwspapprovalclassification/queryDetailById?id=${this.row.id}`).then(res => {
if (res?.data) {
this.form = res.data
}
})
},
/**
* 上传图标
*/
handleUploadIcon(file) {
let data = new FormData()
data.append("file", file.raw)
this.instance.post(`/admin/file/add`, data).then(res => {
if (res?.data) {
this.form.icon = res.data?.[0].replace(/;.*/, '')
}
this.$refs.iconUploader?.clearFiles()
}).catch(() => this.$refs.iconUploader?.clearFiles());
}
},
created() {
if (this.row.id) {
this.getDetail()
}
}
}
</script>
<style lang="scss" scoped>
.add-classification {
height: 100%;
.iconAudit {
font-size: 36px;
color: #3D94FB;
}
.el-upload-list__item {
width: 80px;
height: 80px;
}
.icon-form {
::v-deep .el-form-item__content {
display: flex;
}
}
.select-icon {
width: 96px;
height: 28px;
line-height: 0;
}
.iconfont {
margin-right: 8px;
}
.icon-style {
display: flex;
flex-wrap: wrap;
.icon:hover {
border-color: #5088FF;
}
.icon_color {
border-color: #5088FF;
}
}
.icon {
width: 48px;
height: 48px;
border: 1px solid #ddd;
border-radius: 4px;
margin-right: 16px;
margin-bottom: 16px;
cursor: pointer;
}
.btn {
width: 92px;
height: 32px;
&:nth-child(2) {
margin-left: 24px;
}
}
}
</style>

View File

@@ -0,0 +1,101 @@
<template>
<section class="AppLeavingMessage">
<ai-list v-if="!showDetail">
<template slot="title">
<ai-title title="群众留言" :isShowBottomBorder="false" :instance="instance" :isShowArea="true" v-model="areaId" @change="changeArea"></ai-title>
</template>
<template slot="tabs">
<el-tabs v-model="activeName" @tab-click="handleClick" class="tabs-page">
<el-tab-pane v-for="(item, index) in paneList" :key="index" :label="item.label" :name="item.name">
<component :is="comp" ref="list" :instance="instance" :dict="dict" :activeName="activeName" @toDetail="toDetail"
:areaId="areaId"></component>
</el-tab-pane>
</el-tabs>
</template>
</ai-list>
<template v-if="showDetail">
<message-detail :instance="instance" :dict="dict" :detailId="detailId" @back="showDetail=false"></message-detail>
</template>
</section>
</template>
<script>
import {mapState} from "vuex";
import AlreadyList from "./components/alreadyList";
import MessageDetail from "./components/messageDetail";
export default {
name: 'AppMassesMessage',
label: "群众留言",
props: {
instance: Function,
dict: Object,
permissions: Function,
openim: Function
},
components: {AlreadyList, MessageDetail},
data() {
return {
activeName: '0',
comp:"AlreadyList",
paneList: [
{
label: '待我回复',
name: '0'
},
{
label: '我已回复',
name: '1'
},
{
label: '处理完成',
name: '2'
}
],
showDetail: false,
detailId: '',
oldActiveName: '',
areaId: '',
hideLevel: ''
}
},
computed: {
...mapState(['user'])
},
created() {
this.areaId = this.user.info.areaId
this.hideLevel = this.user.info.areaList.length
},
methods: {
changeArea() {
this.$nextTick(() => {
this.$refs.list.getAppLeaveMessage()
})
},
openIM() {
if (this.openim) this.openim()
},
handleClick(tab) {
if (this.oldActiveName == this.activeName) {
return
}
this.activeName = tab.name
this.$nextTick(() => {
this.$refs.list[0].getAppLeaveMessage()
this.$refs.list.search = {}
this.oldActiveName = tab.name
})
},
toDetail(id) {
this.detailId = id
this.showDetail = true
}
}
}
</script>
<style lang="scss" scoped>
.AppLeavingMessage {
height: 100%;
background-color: #f3f6f9;
}
</style>

View File

@@ -0,0 +1,273 @@
<template>
<section class="already-list">
<ai-list isTabs>
<template #content>
<ai-search-bar bottomBorder>
<template #right>
<el-input size="small" v-model="search.title" placeholder="标题/编号"
@keyup.enter.native="page.current=1,getAppLeaveMessage()"
prefix-icon="iconfont iconSearch" clearable></el-input>
<el-button size="mini" type="primary" icon="iconfont iconSearch" style="margin-left:5px;"
@click="page.current=1,getAppLeaveMessage()">查询
</el-button>
<el-button size="mini" icon="el-icon-refresh-right" style="margin-left:5px;" @click="resetSearch">
重置
</el-button>
</template>
</ai-search-bar>
<ai-table :tableData="tableData"
:col-configs="colConfigs"
:total="total"
ref="aitableex"
:current.sync="search.current"
:size.sync="search.size"
@getList="getAppLeaveMessage">
<el-table-column label="是否公示" slot="isPublic" align="center" width="150">
<template v-slot="{row}">
<el-switch v-model="row.isPublic" @change="onChange(row)" active-value="0" inactive-value="1"
active-color="#D0D4DC" inactive-color="#5088FF"/>
</template>
</el-table-column>
<el-table-column label="操作" slot="options" align="center" width="150">
<template v-slot="{row}">
<el-button type="text" title="详情" @click="toDetail(row.id)" v-if="$permissions('app_appleavemessagereply_detail')">详情</el-button>
</template>
</el-table-column>
</ai-table>
</template>
</ai-list>
</section>
</template>
<script>
import {mapState} from "vuex";
import day from 'dayjs'
export default {
name: "alreadyList",
props: {
instance: Function,
dict: Object,
permissions: Function,
activeName: String,
areaId: String
},
data() {
return {
tableData: [],
columns: [
{
label: '留言编号',
prop: 'msgCode',
type: '',
dict: ''
},
{
label: '留言类型',
prop: 'type',
type: 'select',
dict: 'leaveMessageType'
},
{
label: '标题',
prop: 'title',
type: '',
dict: ''
},
{
label: '留言人',
prop: 'leaveName',
type: '',
dict: ''
},
{
label: '创建时间',
prop: 'createTime',
type: 'time',
dict: ''
},
{
label: '最后回复时间',
prop: 'lastReplyTime',
type: 'time',
dict: ''
},
{
label: '处理状态0、待回复1、已回复',
prop: 'status',
type: '',
dict: ''
},
{
label: '操作',
prop: 'operate',
type: '',
dict: ''
},
],
search: {
style: {},
title: ""
},
page: {
current: 1,
size: 10,
},
total: 0,
detailId: '',
}
},
methods: {
onChange({id, isPublic}) {
this.instance.post(`/app/appleavemessage/public?id=${id}`).then(res => {
if (res.code == 0) {
console.log(isPublic)
this.$message.success(isPublic == 1 ? "已公示" : "不公示")
this.getAppLeaveMessage()
}
})
},
navClick(item) {
this.navStatus = item.status
},
isPermit(params) {
return this.permissions ? this.permissions(params) : false
},
resetSearch() {
this.page.current = 1
this.page.size = 10
this.columns.map(c => {
if (c.type) this.search[c.prop] = null
})
Object.keys(this.search).forEach((e) => {
this.search[e] = null;
})
this.getAppLeaveMessage()
},
handleCurrentChange(val) {
this.page.current = val
this.getAppLeaveMessage()
},
handleSizeChange(val) {
this.page.size = val;
this.getAppLeaveMessage();
},
getAppLeaveMessage() {
this.search.status = this.activeName
this.search.areaId = this.user.info.areaId
this.instance.post("/app/appleavemessage/list", null, {
params: {
...this.search,
...this.page,
areaId: this.areaId
}
}).then(res => {
this.tableData = res.data.records
this.total = res.data.total
}
)
},
addOrUpdateAppLeaveMessage() {
this.instance.post("/app/appleavemessage/addOrUpdate", this.dialog.add).then(() => {
this.getAppLeaveMessage()
this.$message.success("添加或修改成功!")
}
)
},
deleteAppLeaveMessage(ids) {
this.$confirm("是否要删除这些账号?", {
type: 'warning'
}).then(() => {
this.instance.post("/app/appleavemessage/delete", null, {
params: {
ids: ids
}
}).then(() => {
this.getAppLeaveMessage()
this.$message.success("删除成功!")
}
)
}).catch(() => {
}
)
},
toDetail(id) {
this.$emit('toDetail', id)
}
},
filters: {
format(time) {
return time ? day(time).format("YYYY-MM-DD HH:mm") : '-'
}
},
mounted() {
if (this.dict) this.dict.load(this.columns.map(e => e.type == 'select' ? e.dict : ''))
this.resetSearch()
},
computed: {
...mapState(['user']),
colConfigs() {
return [
{ prop: 'msgCode', label: '编号', align: 'center' },
{ prop: 'title', label: '标题', align: 'center' },
{ prop: 'type', label: '类型', align: 'center',
render:(h,{row})=>[<span>{this.dict.getLabel('leaveMessageType', row.type)}</span>] },
{ prop: 'leaveName', label: '留言人', align: 'center' },
{ prop: 'createTime', label: '留言提交时间', align: 'center' },
{ prop: 'lastReplyTime', label: '最后回复时间', align: 'center' },
{ slot: 'isPublic'},
{ slot: 'options'},
]
}
}
}
</script>
<style lang="scss" scoped>
.already-list {
background-color: #f3f6f9;
width: 100%;
height: 100%;
overflow: hidden;
.el-table::before {
background-color: #fff !important;
}
.header {
padding: 0 16px;
width: 100%;
background-color: #ffffff;
height: 48px;
line-height: 48px;
box-shadow: inset 0px -1px 0px 0px #d8dce3;
}
.main-content {
box-sizing: border-box;
margin: 16px;
height: calc(100% - 80px);
background-color: white;
border: 1px solid #eee;
padding: 12px 16px;
.searchBar {
.el-col {
margin-bottom: 12px;
}
}
}
}
</style>

View File

@@ -0,0 +1,461 @@
<template>
<div class="message-detail iconPhoto-content">
<ai-detail>
<ai-title slot="title" :title="titleText" isShowBack isShowBottomBorder @onBackClick="$emit('back')"></ai-title>
<template #rightBtn>
<p class="resident_top_area" style="text-align: right;" v-if="data.status != '2' && $permissions('app_appleavemessagereply_edit')">
<el-button type="primary" class="el-icon-edit" v-if="data.status == '0'" @click="maskShow = true" style="width:104px">回复留言</el-button>
<el-button class="el-icon-switch-button del-btn-list" @click="close()" style="width:104px">关闭留言</el-button>
</p>
</template>
<template #content>
<ai-card :title="data.title">
<template #content>
<div class="content-main">
<div class="main-header mar-b16">
<h6 style="font-weight:600;">{{ data.title }}</h6>
<div class="time">
<span class="time-label" style="width: 243px;"
>留言编号<span style="color:#333">{{ data.msgCode }}</span></span
>
<span class="time-label"
>留言时间<span style="color:#333">{{ data.createTime }}</span></span
>
<span class="time-label" style="width: 258px;text-align: right"
>留言人<span style="color:#333">{{ data.leaveName }}&nbsp;&nbsp;{{ data.leavePhone }}</span></span
>
<svg class="status-icon" aria-hidden="true">
<use xlink:href="#iconno_response" v-if="data.status == '0'"></use>
<use xlink:href="#iconreplied" v-if="data.status == '1'"></use>
<use xlink:href="#iconfinished" v-if="data.status == '2'"></use>
</svg>
</div>
<p class="message-text border-t" style="padding: 16px">{{ data.content }}</p>
<div v-if="data.images.length">
<div class="content-img" v-viewer>
<img v-for="(item, index) in data.images" :src="item.accessUrl" alt="" :key="index" />
</div>
</div>
</div>
<div class="main-list">
<div class="main-header mar-b16">
<h6 style="font-weight:600;">沟通记录</h6>
</div>
<div v-for="(item, index) in data.appLeaveMessageReplyList" :key="index" :class="item.headPortrait == null ? 'message-for reply' : 'message-for'" v-if="data.appLeaveMessageReplyList.length > 0">
<div class="message-title">
<img :src="item.headPortrait" alt="" class="user-img" v-if="item.headPortrait" />
<span class="iconfont iconProfile_Picture" v-else></span>
<span class="user-name" v-if="!item.headPortrait">
<span style="color:#5088FF">{{ item.createUnitName }} &nbsp;<span style="color:#333">&nbsp;回复</span></span
><br />
<span style="color:#999;font-size:12px">操作员{{ item.createUserName }}{{ item.createUserPhone }}</span>
</span>
<span class="user-name" v-else>{{ item.createUserName }}</span>
<span style="color:#999;vertical-align: text-bottom">{{ item.createTime }}</span>
</div>
<p class="message-text">{{ item.content }}</p>
<div v-if="item.images.length">
<div class="message-img-list" v-viewer>
<img class="message-img" v-for="(items, index) in item.images" :src="items.accessUrl" :key="index" v-if="items.accessUrl" />
</div>
</div>
</div>
<div v-if="data.appLeaveMessageReplyList.length == 0" style="width:100%;text-align:center;color:#999;font-size:14px">暂无沟通记录</div>
</div>
</div>
</template>
</ai-card>
</template>
</ai-detail>
<ai-dialog :title="maskText" :visible.sync="maskShow" @onConfirm="confirm('ruleForm')" @onCancel="hideMask" :before-close="hideMask" width="720px">
<el-form :rules="rules" ref="ruleForm" :model="ruleForm" label-width="auto">
<el-form-item label="回复内容:" prop="content">
<el-input type="textarea" v-model.trim="ruleForm.content" :row="4" show-word-limit :maxlength="1000" placeholder="请输入回复内容"></el-input>
</el-form-item>
<el-form-item label="图片附件:" class="user">
<span class="upload-more left-84">(最多9张)</span>
<el-upload class="upload-demo upload-list-small" ref="upload" multiple action list-type="picture-card" :file-list="images" :http-request="uploadFile" :on-remove="handleRemove" :on-change="handleChange" accept="jpeg/jpg/png">
<div class="upload-img-small">
<span class="iconfont iconPhoto iconPhoto2"></span>
<div class="upload-text">上传照片</div>
</div>
</el-upload>
</el-form-item>
</el-form>
</ai-dialog>
</div>
</template>
<script>
import { mapState } from 'vuex'
// import 'viewerjs/dist/viewer.css'
import Viewer from 'v-viewer'
import Vue from 'vue'
Vue.use(Viewer)
export default {
name: 'messageDetail',
props: {
instance: Function,
dict: Object,
permissions: Function,
detailId: String,
},
data() {
return {
titleText: '留言详情',
maskShow: false,
maskText: '回复留言',
images: [],
data: {
appLeaveMessageReplyList: [],
},
rules: {
content: [{ required: true, message: '请输入回复内容', trigger: 'blur' }],
},
ruleForm: {
content: '',
},
}
},
computed: {
...mapState(['user']),
},
created() {},
mounted() {
console.log(this.user)
this.getDetailInfo()
},
methods: {
getDetailInfo() {
this.data.appLeaveMessageReplyList = []
this.instance.post(`app/appleavemessage/queryDetailById?id=` + this.detailId).then((res) => {
this.data = res.data
this.data.images = JSON.parse(res.data.images)
if (this.data.appLeaveMessageReplyList.length) {
this.data.appLeaveMessageReplyList.map((item) => {
if (item.images) {
item.images = JSON.parse(item.images || '[]')
}
return item
})
}
this.data.appLeaveMessageReplyList.reverse()
})
},
confirm(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
this.confirmFn()
} else {
return false
}
})
},
confirmFn() {
let images = []
this.images.map((item) => {
images.push({ fileId: item.fileId, accessUrl: item.accessUrl })
})
let params = {
content: this.ruleForm.content,
images: JSON.stringify(images),
msgCode: this.data.msgCode,
userType: '1',
createUnitId: this.user.info.unitId,
createUnitName: this.user.info.unitName,
}
this.instance.post(`app/appleavemessagereply/addOrUpdate`, params).then((res) => {
console.log(res)
this.maskShow = false
this.getDetailInfo()
})
},
hideMask() {
this.maskShow = false
this.images = []
this.$nextTick(() => {
this.$refs.ruleForm.resetFields()
})
},
close() {
this.$confirm('关闭留言之后,双方都将无法再进行回复,是否确定关闭本次留言?', {
type: 'warning',
})
.then(() => {
let params = this.data
params.status = '2'
params.images = JSON.stringify(params.images)
if (params.appLeaveMessageReplyList.length) {
params.appLeaveMessageReplyList.map((item) => {
item.images = JSON.stringify(item.images)
return item
})
}
this.instance.post(`app/appleavemessage/addOrUpdate`, params).then((res) => {
this.getDetailInfo()
})
})
.catch(() => {})
},
// 上传照片
uploadFile(file) {
console.log(this.images.length > 9)
if (this.images.length > 9) {
this.$message.warning('上传图片不能超过9张')
this.images.map((item, index) => {
if (item.uid == file.file.uid) {
this.images.splice(index, 1)
}
return this.images
})
}
const isLt2M = file.file.size / 1024 / 1024 < 2
if (!isLt2M) {
this.$message.warning('图片大小不能超过 2MB!')
return
}
let formData = new FormData()
formData.append('file', file.file)
let file2 = formData
this.instance.post(`/admin/file/add`, file2, { withCredentials: false }).then((res) => {
if (res.code == 0) {
let imgInfo = res.data[0].split(';')
let img = {
fileId: imgInfo[1],
accessUrl: imgInfo[0],
}
this.images.map((item, index) => {
if (item.uid == file.file.uid) {
this.images[index].fileId = img.fileId
this.images[index].accessUrl = img.accessUrl
this.images[index].url = img.accessUrl
}
return this.images
})
}
})
},
handleChange(file, fileList) {
this.images = fileList
},
handleRemove(file, fileList) {
this.images = fileList
},
},
}
</script>
<style lang="scss" scoped>
.message-detail {
width: 100%;
height: 100%;
overflow: auto;
position: relative;
background-color: #f3f6f9;
.left-84 {
left: -84px;
}
.iconProfile_Picture {
font-size: 40px;
}
.iconBack_Large {
width: 16px;
height: 16px;
color: #2266ff;
cursor: pointer;
}
.content {
padding-top: 24px;
width: 100%;
height: calc(100% - 80px);
overflow-y: scroll;
.content-main {
width: 760px;
margin: 0 auto;
.main-header {
width: 100%;
box-sizing: border-box;
background-color: #fff;
border: 1px solid #eee;
h6 {
font-size: 16px;
color: #333;
padding: 0 16px;
min-height: 54px;
line-height: 54px;
box-sizing: border-box;
}
.time {
height: 54px;
line-height: 54px;
font-size: 12px;
padding: 0 16px;
box-sizing: border-box;
position: relative;
overflow: hidden;
.time-label {
color: #999;
display: inline-block;
}
}
.status-icon {
position: absolute;
width: 66px;
height: 66px;
top: -5px;
right: 0;
}
}
.main-list {
background-color: #fff;
padding-bottom: 80px;
.message-for {
width: 728px;
margin: 0 auto 24px auto;
padding: 16px 16px 8px;
box-sizing: border-box;
font-size: 14px;
.message-title {
height: 40px;
line-height: 40px;
margin-bottom: 6px;
.user-img {
display: inline-block;
width: 40px;
height: 40px;
border-radius: 50%;
background-color: red;
}
.user-name {
display: inline-block;
width: 510px;
color: #333;
vertical-align: text-bottom;
padding-left: 8px;
box-sizing: border-box;
}
}
.message-text {
padding-left: 48px;
color: #666;
margin-bottom: 16px;
}
.message-img-list {
padding-left: 48px;
.message-img {
display: inline-block;
width: 113px;
height: 113px;
margin: 0 16px 16px 0;
}
}
}
.reply {
background-color: #f5f6f7;
.message-title {
.user-name {
line-height: 20px;
}
}
}
}
}
}
.content-img {
padding: 0 16px;
img {
width: 84px;
height: 84px;
margin: 0 16px 16px 0;
}
}
.operation-foot {
overflow: hidden;
// position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 64px;
line-height: 64px;
display: flex;
align-items: center;
justify-content: center;
background-color: #f3f6f9;
box-shadow: inset 0px 1px 0px 0px #eeeeee;
button {
width: 92px;
height: 32px;
padding: 0 !important;
}
.delete-btn {
background-color: #fff;
}
}
.mask {
overflow: hidden;
.el-form-item__content {
float: left;
width: calc(100% - 100px) p {
font-size: 14px;
color: #222222;
}
}
.el-form-item__label {
display: inline-block;
width: 130px;
text-align: right;
font-size: 14px;
float: left;
}
.operation {
overflow: hidden;
// position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 64px;
line-height: 64px;
display: flex;
align-items: center;
justify-content: center;
background-color: #f3f6f9;
box-shadow: inset 0px 1px 0px 0px #eeeeee;
}
}
.status {
span {
display: inline-block;
width: 24px;
height: 24px;
line-height: 24px;
text-align: center;
}
}
.status0 {
background-color: #eff6ff;
color: #2266ff;
}
.status1 {
background-color: #e8ecff;
color: #2244ff;
}
.status2 {
background-color: #fff3e8;
color: #ff8822;
}
.status3 {
background-color: #eaf5e8;
color: #2ea222;
}
.icon {
display: inline-block;
width: 32px;
height: 32px;
margin-top: 16px;
}
}
</style>

View File

@@ -0,0 +1,82 @@
<template>
<section class="matters-config">
<ai-list v-if="!showDetail">
<template #title>
<ai-title title="事项配置" :isShowBottomBorder="false"></ai-title>
</template>
<template slot="tabs">
<el-tabs class="tabs-page" v-model="currIndex">
<el-tab-pane v-for="(tab,i) in tabs" :key="i" :label="tab.label" :name="String(i)">
<component :is="tab.comp" v-if="currIndex==i" :ref="currIndex" :instance="instance" :dict="dict"
:permissions="permissions" @goPage="goPage" :tab="currentTab"/>
</el-tab-pane>
</el-tabs>
</template>
</ai-list>
<component v-else :is="currentComp" :instance="instance" :dict="dict"
:processType="currentTab.value" :row="row"></component>
</section>
</template>
<script>
import addConfig from './components/addConfig'
import configList from "./components/configList";
import guidance from "./components/guidance";
export default {
name: "AppMattersConfig",
label: '事项配置',
components: {addConfig,guidance},
props: {
instance: Function,
dict: Object,
permissions: Function
},
data() {
return {
currIndex: "0",
row: {},
currentComp: "",
}
},
computed: {
tabs() {
return [
{label: "网上办事", name: "configList", value: "0", comp: configList, detail: addConfig, permission: ""},
{label: "办事指南", name: "configList", value: "2", comp: configList, detail: guidance, permission: ""},
]
},
currentTab() {
return this.tabs?.[this.currIndex] || {}
},
showDetail() {
return !!this.$route.query?.id || !!this.$route.query?.processType
}
},
methods: {
goPage(params) {
this.row = params.row
this.currentComp = params.comp
this.$router.push({query: {processType: this.currentTab.value}})
}
},
created() {
this.$router.push({query: {}});
this.$dict.load("hbDepartment", 'sex', 'nation', 'marital', 'native_place', 'education', 'candidateApproverType', 'scopeCandidates', 'nodeType')
}
}
</script>
<style lang="scss" scoped>
.matters-config {
height: 100%;
background: #f3f6f9;
overflow: auto;
.iconfont {
user-select: none;
cursor: pointer;
}
}
</style>

View File

@@ -0,0 +1,252 @@
<template>
<div class="add-config" :class="[activeStep == 1 ? 'formLayout' : '']">
<ai-detail>
<ai-title slot="title" :title="detailTitle" isShowBack isShowBottomBorder @onBackClick="handleBack"/>
<template slot="step">
<div class="step">
<el-steps :active="activeStep" simple>
<el-step v-for="(step,i) in processList" :key="i" v-bind="step" :icon="getStepIcon(i)"/>
</el-steps>
</div>
</template>
<template #content v-if="refresh">
<baseInfo ref="baseInfo" :instance="instance" :dict="dict" v-show="activeStep==0"/>
<applyForm ref="applyForm" :value="filedList" :instance="instance" :dict="dict" v-show="activeStep==1"/>
<attachmentMaterial ref="attachmentMaterial" :instance="instance" v-show="activeStep==2"/>
<processApproval ref="processApproval" :approvalSteps="applyForm.approvalSteps" :instance="instance"
:dict="dict" v-show="activeStep==3"/>
</template>
<template #footer>
<el-button class="btn" v-if="activeStep==0" @click="handleBack">取消</el-button>
<el-button class="btn" v-else @click="preStep">上一步</el-button>
<el-button class="btn" type="primary" v-if="[0,1,2].includes(activeStep)" @click="nextStep">下一步</el-button>
<el-button class="btn" type="primary" v-if="activeStep==3" @click="save">保存</el-button>
</template>
</ai-detail>
</div>
</template>
<script>
import {applyForm, attachmentMaterial, baseInfo, processApproval} from './index'
export default {
name: "addConfig",
provide() {
return {
config: this
}
},
props: {
instance: Function,
dict: Object,
row: Object,
processType: String
},
components: {baseInfo, applyForm, attachmentMaterial, processApproval},
data() {
return {
activeStep: 0,
baseInfo: {},
applyForm: {
tableId: "",
approvalSteps: "",
},
processAnnexDefs: [],
detailObj: {
tableInfo: {}
},
refresh: true,
filedList: [],
tableFieldInfos: []
}
},
computed: {
processList() {
return [
{title: '基本信息', activeIndex: 0},
{title: '申请表单', activeIndex: 1},
{title: '附件材料', activeIndex: 2},
{title: '审批流程', activeIndex: 3}
]
},
detailTitle() {
return this.detailObj?.id ? "编辑事项" : "添加事项"
}
},
methods: {
/**
* 上一步
* */
preStep() {
this.activeStep--
},
/**
* 下一步
*/
nextStep() {
switch (this.activeStep) {
case 0:
this.handleBaseInfo()
break
case 1:
this.$refs['applyForm'].onConfirm().then(res => {
if (!res.length) {
return this.$message.error('表单配置不能为空')
}
this.tableFieldInfos = res
this.activeStep++
})
break
case 2:
this.$refs['attachmentMaterial'].handleAttachmentMaterial().then(res => {
this.annexs = res
this.activeStep++
}).catch(err => {
console.error(err);
})
break
}
},
handleBaseInfo() {
this.$refs['baseInfo'].banseInfoForm().then(res => {
if (res) {
// this.$refs['applyForm'].getFormList()
this.baseInfo = res
this.activeStep++
}
})
},
/**
* 保存
*/
save() {
this.$refs['processApproval'].handleProcessApproval().then(res => {
this.instance.post(`/app/approval-process-def/add-update`, {
...this.detailObj,
...this.baseInfo,
processDefStatus: Number(this.baseInfo.processDefStatus),
tableInfo: {
...this.detailObj.tableInfo,
tableFieldInfos: this.tableFieldInfos
},
tableType: 0,
processAnnexDefs: this.annexs.map(e => ({...e, mustFill: Number(e.mustFill)})),
processNodeList: res.processNodeList,
processType: this.processType
}).then(res => {
if (res.code == 0) {
this.$message.success("保存成功")
this.$router.push({query:{}})
}
})
}).catch(err => {
console.error(err);
})
},
getDetail(id) {
this.instance.post(`/app/approval-process-def/info-id`, null, {params: {id}}).then(res => {
if (res?.data) {
this.detailObj = res.data
this.filedList = res.data.tableInfo.tableFieldInfos
this.refreshDetail()
}
})
},
getStepIcon(rowIndex) {
if (rowIndex < this.activeStep) return "iconfont iconSteps_Finished"
else if (this.activeStep == rowIndex) return "iconfont iconSteps_In_Progress"
return ""
},
refreshDetail() {
this.refresh = false
this.$nextTick(() => this.refresh = true)
},
handleBack() {
this.$router.push({query: {}})
}
},
created() {
if (this.row?.id) {
this.getDetail(this.row?.id)
}
}
}
</script>
<style lang="scss" scoped>
.add-config {
height: 100%;
&.formLayout {
::v-deep .ai-detail__content--wrapper {
max-width: 100%;
height: calc(100%)!important;
padding: 0!important;
overflow: hidden!important;
}
}
.step {
width: 100%;
height: 72px;
font-size: 14px;
.el-steps {
display: flex;
align-items: center;
height: 72px;
padding: 0 calc(50% - 380px);
::v-deep .el-step {
font-weight: bold;
::v-deep .el-step__icon {
width: 24px;
height: 24px;
background: #fff;
.iconfont {
font-size: 24px;
}
}
::v-deep .el-step__main {
display: flex;
align-items: center;
.el-step__arrow {
background: #D0D4DC;
margin: 0 8px;
height: 2px;
&:before, &:after {
display: none;
}
}
}
.is-process {
color: #2266FF;
}
.is-wait {
color: #666;
border-color: #D0D4DC;
}
}
}
}
.btn {
width: 92px;
height: 32px;
&:nth-child(2) {
margin-left: 24px;
}
}
}
</style>

View File

@@ -0,0 +1,895 @@
<template>
<div class="form-config">
<el-scrollbar class="left">
<div class="left-item" v-for="(component, index) in components" :key="index">
<div class="left-item__title">
<h2>{{ component.label }}</h2>
<span>{{ component.tips }}</span>
</div>
<div class="left-item__list">
<draggable
class="components-draggable"
:list="component.children"
:group="{ name: 'componentsGroup', pull: 'clone', put: false }"
:sort="false"
:move="onMove"
:clone="cloneComponent"
@end="onEnd">
<div class="left-item__item" v-for="(item, i) in component.children" :key="i" @click="clone(item)">
<i class="iconfont" :class="item.icon"></i>
<span>{{ item.fixedLabel }}</span>
</div>
</draggable>
</div>
</div>
</el-scrollbar>
<el-scrollbar class="middle">
<div class="middle-content">
<div class="middle-content__wrapper">
<el-form label-width="100px" label-position="right">
<draggable
class="middle-draggable"
style="height: 100%;"
:animation="340"
scroll
v-model="targetList"
element="div"
@end="onElEnd"
:sort="true">
<ai-card
:class="[groupIndex === j && isGroup ? 'active' : '']"
:data-index="j"
@click.native.stop="groupIndex = j, activeIndex = -1, isGroup = true"
:title="group.groupName" v-for="(group, j) in targetList"
:key="j">
<template #content>
<draggable
class="ai-form"
style="height: 100%;"
v-model="group.column"
:animation="340"
scroll
@end="onElEnd"
element="div"
draggable=".components-item"
group="componentsGroup"
:sort="true">
<div
class="components-item"
v-for="(item, i) in group.column"
:style="{width: item.grid * 100 + '%'}"
:class="[groupIndex === j && activeIndex === i ? 'active' : '']"
@click.stop="groupIndex = j, activeIndex = i, isGroup = false"
:key="i">
<div class="left-item__item--remove" title="删除字段" v-show="groupIndex === j && activeIndex === i" @click.stop="removeItem(j, i)">
<i class="iconfont iconDelete"></i>
<span>删除字段</span>
</div>
<el-form-item style="width: 100%;" :label="item.fieldName" :rules="[{ required: item.mustFill === '1' ? true : false }]">
<template v-if="item.fieldDataType === '1'">
<el-input :disabled="item.disable === '1'" size="small" placeholder="请输入" v-model="item.defaultValue"></el-input>
</template>
<template v-if="item.fieldDataType === '4'">
<el-radio-group v-model="item.defaultValue" :disabled="item.disable === '1'">
<el-radio :label="field.label" v-for="(field, index) in item.options" :key="index">{{ field.label }}</el-radio>
</el-radio-group>
</template>
<template v-if="item.fieldDataType === '0'">
<el-input-number style="width: 100%;" v-model="item.defaultValue" :placeholder="item.fieldTips"></el-input-number>
</template>
<template v-if="item.fieldDataType === '3'">
<el-date-picker
v-model="item.defaultValue"
size="small"
:placeholder="item.fieldTips">
</el-date-picker>
</template>
<template v-if="item.fieldDataType === '8'">
<el-date-picker
v-model="item.defaultValue"
size="small"
:placeholder="item.fieldTips">
</el-date-picker>
</template>
<template v-if="item.fieldDataType === '9'">
<el-select :disabled="item.disable === '1'" style="width: 100%;" size="small" :placeholder="item.fieldTips" v-model="item.defaultValue">
<el-option
v-for="(filed, index) in item.options"
:key="index"
:label="filed.label"
:value="filed.label">
</el-option>
</el-select>
</template>
<template v-if="item.fieldDataType === '5'" >
<el-checkbox-group v-model="item.defaultValue" :disabled="item.disable === '1'">
<el-checkbox :label="field.label" v-for="(field, index) in item.options" :key="index">{{ field.label }}</el-checkbox>
</el-checkbox-group>
</template>
</el-form-item>
</div>
</draggable>
</template>
</ai-card>
</draggable>
</el-form>
</div>
</div>
</el-scrollbar>
<el-scrollbar class="right">
<div class="right-item" v-if="isGroup">
<div class="right-item__title no-solid">
<h2>分组名称</h2>
</div>
<div class="right-item__content">
<el-input placeholder="请输入分组名称" :maxlength="32" show-word-limit v-model="currTarget.groupName"></el-input>
</div>
</div>
<div class="layout-right__del" @click="removeGroup" v-if="isGroup && targetList.length > 1">
<span>删除分组</span>
</div>
<div class="right-item" v-if="activeIndex > -1">
<div class="right-item__title no-solid">
<h2>标题名称</h2>
</div>
<div class="right-item__content">
<el-input placeholder="标题名称" :maxlength="32" show-word-limit v-model="currTarget.fieldName"></el-input>
</div>
</div>
<div class="right-item right-item__select" v-if="['9', '4', '5'].includes(currTarget.fieldDataType)">
<div class="right-item__title no-solid">
<h2>选项设置</h2>
</div>
<div class="right-item__select--wrapper">
<draggable
v-model="currTarget.options"
:animation="340"
group="select"
handle=".mover"
:sort="true">
<div class="select-item" v-for="(item, index) in currTarget.options" :key="index">
<i class="iconfont iconjdq_led_show mover"></i>
<el-input placeholder="请输入选项名" :maxlength="30" show-word-limit v-model="item.label"></el-input>
<i class="iconfont iconDelete" @click="removeOptions(index)"></i>
</div>
</draggable>
</div>
<el-button type="text" class="add-select" @click="addOptions">添加选项</el-button>
</div>
<div class="right-item__group" v-if="activeIndex > -1" key="radio">
<div class="right-item" v-if="currTarget.fieldDataType == 1 || currTarget.fieldDataType == 0">
<div class="right-item__title">
<h2>最多输入字符</h2>
</div>
<div class="right-item__content">
<el-input placeholder="字符个数" v-model="currTarget.fieldLength">
<span slot="append"></span>
</el-input>
</div>
</div>
<div class="right-item">
<div class="right-item__title no-solid">
<div class="right-item__title--left">
<h2>是否必填</h2>
</div>
<el-switch v-model="currTarget.mustFill" active-value="1" inactive-value="0"></el-switch>
</div>
</div>
</div>
</el-scrollbar>
</div>
</template>
<script>
import draggable from 'vuedraggable'
import { components } from './config'
export default {
name: 'applyForm',
props: {
instance: Function,
dict: Object,
params: Object,
type: String,
value: Array
},
components: {
draggable
},
data () {
return {
isGroup: false,
components: components,
targetList: [{
type: 'group',
fieldName: '卡片',
fixedLabel: '卡片',
icon: 'iconpic',
groupName: '基础信息',
column: []
}],
groupIndex: -1,
activeIndex: -1,
currTarget: {}
}
},
watch: {
activeIndex () {
if (this.activeIndex > -1 && this.groupIndex > -1 && !this.isGroup) {
const filed = this.targetList[this.groupIndex].column[this.activeIndex]
this.currTarget = filed
return
}
if (this.groupIndex > -1 && this.isGroup) {
this.currTarget = this.targetList[this.groupIndex].column[this.activeIndex]
return
}
this.currTarget = {}
},
groupIndex () {
if (this.activeIndex > -1 && this.groupIndex > -1 && !this.isGroup) {
const filed = this.targetList[this.groupIndex].column[this.activeIndex]
this.currTarget = filed
return
}
if (this.groupIndex > -1 && this.isGroup) {
this.currTarget = this.targetList[this.groupIndex]
return
}
this.currTarget = {}
}
},
mounted () {
this.init()
},
methods: {
removeItem (j, i) {
this.groupIndex = -1
this.activeIndex = -1
this.targetList[j].column.splice(i, 1)
},
init () {
if (this.value.length) {
let arr = this.value
let groups = this.unique(arr.map(v => v.groupName))
this.targetList = groups.map(groupName => {
const column = arr.filter(v => v.groupName === groupName).map(item => {
if (['9', '4', '5'].includes(item.fieldDataType)) {
item.options = item.selectValues.split('`').map(v => {
return {
label: v,
value: ''
}
})
}
if (item.fieldDataType === '5') {
item.defaultValue = []
}
return {
...item,
grid: 1
}
})
return {
type: 'group',
fieldName: '卡片',
fixedLabel: '卡片',
icon: 'iconpic',
groupName,
column: column
}
})
}
},
removeGroup () {
if (this.targetList.length === 1) {
return this.$message.error('分组不能小于1')
}
this.targetList.splice(this.groupIndex, 1)
this.groupIndex = 0
this.isGroup = true
this.activeIndex = -1
},
unique (arr) {
return arr.filter((item, index) => {
return arr.indexOf(item, 0) === index
})
},
onConfirm () {
let result = []
this.targetList.forEach((group, i) => {
group.column.forEach(item => {
result.push({
...item,
groupIndex: i,
groupName: group.groupName,
selectValues: item.options ? item.options.map(v => v.label).join('`') : ''
})
})
})
return new Promise(resolve => {
resolve(result)
})
},
addOptions () {
const len = this.targetList[this.groupIndex].column[this.activeIndex].options.length
let label = `选项${len + 1}`
const index= this.targetList[this.groupIndex].column[this.activeIndex].options.findIndex(v => label === v.label)
if (index > -1) {
label = `新选项${len + 1}`
}
this.targetList[this.groupIndex].column[this.activeIndex].options.push({
label: label,
value: ''
})
},
removeOptions (index) {
const len = this.targetList[this.groupIndex].column[this.activeIndex].options.length
if (len === 2) {
return this.$message.error('选项不能少于2个')
}
this.targetList[this.groupIndex].column[this.activeIndex].options.splice(index, 1)
},
onEnd (e) {
const el = e.to.parentElement.parentElement
this.isGroup = false
this.activeIndex = e.newIndex
this.groupIndex = Number(el.getAttribute('data-index'))
},
onElEnd (e) {
if (this.isGroup) {
this.groupIndex = e.newIndex
} else {
this.activeIndex = e.newIndex
}
},
clone (e) {
if (e.type === 'group') {
this.targetList.push(JSON.parse(JSON.stringify(e)))
this.$nextTick(() => {
this.isGroup = true
this.groupIndex = this.targetList.length - 1
this.activeIndex = -1
})
return
}
if (this.isGroup) {
this.targetList[this.groupIndex].column.push(JSON.parse(JSON.stringify(e)))
} else {
this.targetList[0].column.push(JSON.parse(JSON.stringify(e)))
}
this.$nextTick(() => {
this.groupIndex = this.isGroup ? this.groupIndex : 0
this.activeIndex = this.targetList[0].column.length - 1
})
},
onMove (e) {
const el = e.draggedContext.element
if (el.type === 'group') {
return false
}
return true
},
cloneComponent (e) {
if (e.type === 'group') {
this.targetList.push(JSON.parse(JSON.stringify(e)))
return
}
return JSON.parse(JSON.stringify(e))
}
}
}
</script>
<style lang="scss" scoped>
.layout-right__del {
position: absolute;
bottom: 100px;
left: 0;
z-index: 11;
width: 100%;
padding: 0 16px;
span {
display: block;
width: 100%;
height: 40px;
line-height: 40px;
text-align: center;
border-radius: 6px;
color: #F46;
cursor: pointer;
border: 1px solid #F46;
&:hover {
opacity: 0.7;
}
}
}
.form-config {
display: flex;
height: 100%;
padding: 10px 20px 0;
.ai-form .el-form-item {
margin-bottom: 0;
}
.right-item__maintitle {
height: 62px;
line-height: 62px;
margin-bottom: 20px;
border-bottom: 1px solid #EEEEEE;
color: #222222;
h2 {
font-size: 14px;
}
}
::v-deep .ai-card {
cursor: move;
&.active {
background: #f6f7ff;
}
}
::v-deep .ai-detail__content {
height: calc(100% - 52px)!important;
padding: 0!important;
overflow: hidden!important;
}
.ai-dialog__success {
::v-deep .ai-dialog__content {
max-height: initial!important;
}
}
.middle-draggable {
// display: flex;
// justify-content: space-between;
// flex-wrap: wrap;
.left-item__item {
width: 50%;
min-height: 73px;
}
.el-date-editor.el-input {
width: 100%;
}
& > span {
display: block;
width: 100%;
height: 100%;
min-height: 600px;
padding-bottom: 20px;
}
.components-item {
position: relative;
margin-bottom: 16px;
padding: 16px 16px;
cursor: move;
&::after {
position: absolute;
left: 0;
top: 0;
z-index: 1111;
width: 100%;
height: 100%;
content: ' ';
}
.left-item__item--remove {
display: flex;
position: absolute;
align-items: center;
justify-content: center;
right: 4px;
top: 4px;
z-index: 1113;
width: 84px;
height: 28px;
background: #FF4466;
border-radius: 2px;
cursor: pointer;
color: #fff;
font-size: 12px;
i {
margin-right: 6px;
font-size: 12px;
&:hover {
color: #fff;
}
}
&:hover {
opacity: 0.8;
}
}
&:hover {
background: #f6f7ff;
}
&.active {
background: #f6f7ff;
}
.left-item__item--upload {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
width: 120px;
height: 120px;
line-height: 1;
border-radius: 6px;
border: 1px dashed #bbb;
i {
font-size: 24px;
color: #8899bb;
}
span {
margin-top: 10px;
font-size: 12px;
color: #555;
}
}
.text-item {
input {
display: block;
width: 100%;
height: 40px;
border: none;
border-bottom: 1px solid #ddd;
&:focus {
outline: none;
}
&:disabled {
background: #fff;
}
}
}
.textarea-item {
textarea {
width: 100%;
height: 120px;
resize: none;
border: 1px solid #ddd;
padding: 10px;
&:focus {
outline: none;
}
&:disabled {
background: #fff;
}
}
}
.radio-item {
display: flex;
align-items: center;
margin-bottom: 10px;
&:last-child {
margin-bottom: 0;
}
label {
margin-left: 10px;
}
img {
margin-left: 10px;
}
}
}
.left-item__item--title {
display: flex;
align-items: center;
margin-bottom: 10px;
i {
margin-right: 5px;
color: #E22120;
}
h2 {
color: #333333;
font-size: 15px;
}
}
}
.middle-content {
width: 96%;
margin: 0 auto;
padding: 0px 0 1px;
.middle-content__wrapper {
// min-height: 800px;
// background: #fff;
& > div {
&.active {
background: #f6f7ff;
}
}
.radio-item {
img {
width: 40px;
height: 40px;
}
}
}
}
div {
box-sizing: border-box;
}
.right-item__select--wrapper {
.select-item {
display: flex;
align-items: center;
}
}
::v-deep .ai-detail__title {
margin: 0!important;
margin-bottom: 4px!important;
padding: 0 20px;
box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.08);
}
::v-deep .ai-detail__content--wrapper {
display: flex;
max-width: 100%!important;
height: 100%!important;
padding: 0!important;
background: #F5F6F9;
}
.middle {
flex: 1;
height: 100%;
::v-deep .el-scrollbar__view {
height: 100%;
}
}
.add-select {
height: auto;
line-height: 1;
margin: 10px 0 0 26px;
padding: 0;
}
.right-item__select--wrapper {
.select-item {
margin-bottom: 10px;
&:last-child {
margin-bottom: 0;
}
i {
margin-right: 8px;
color: #8c9dbd;
}
.mover {
cursor: move;
}
.iconDelete {
cursor: pointer;
margin-left: 10px;
}
}
::v-deep .el-upload-list__item {
width: 40px!important;
height: 40px!important;
object-fit: cover;
}
.config-item__select {
display: flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
border: 1px solid #D0D4DC;
&:hover {
opacity: 0.7;
}
i {
font-size: 18px;
}
}
}
.right {
width: 320px;
height: 100%;
overflow-y: auto;
overflow: hidden;
background: #FFFFFF;
.el-checkbox {
display: block;
margin-bottom: 10px;
&:last-child {
margin-bottom: 0;
}
}
.right-item {
margin-top: 20px;
padding: 0 20px;
.right-item__tips {
margin-top: 10px;
color: #888888;
font-size: 12px;
}
}
.right-item__title {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 10px;
.right-item__title--left {
display: flex;
align-items: center;
i {
color: #888888;
font-size: 12px;
font-style: normal;
}
}
h2 {
color: #222222;
font-size: 14px;
}
}
}
.left {
width: 280px;
height: 100%;
overflow-y: auto;
overflow: hidden;
background: #FFFFFF;
.left-item {
padding: 0 20px;
&:last-child {
padding-bottom: 20px;
}
.left-item__title {
display: flex;
align-items: baseline;
margin-bottom: 20px;
h2 {
color: #222222;
font-size: 14px;
font-weight: 700;
}
span {
color: #888888;
font-size: 12px;
}
}
}
.left-item {
margin-top: 20px;
}
}
}
.left-item__item {
display: flex;
align-items: center;
height: 40px;
margin-bottom: 10px;
width: 100%;
padding: 0 13px;
background: #FFFFFF;
border-radius: 2px;
color: #222222;
font-size: 12px;
border: 1px solid #E4E8EF;
cursor: move;
&:hover {
border: 1px dashed #2367ff;
color: #2367ff;
i {
color: #2367ff;
}
}
i {
margin-right: 13px;
font-size: 14px;
color: #8899BB;
}
&:last-child {
margin-bottom: 0px;
}
}
</style>

View File

@@ -0,0 +1,196 @@
<template>
<div class="attachment-material">
<ai-card title="附件材料">
<template #right>
<span class="iconfont iconAdd rightBtn"></span>
<span class="rightBtn" style="margin-left: 8px;" @click="dialog=true">新增行数</span>
</template>
<template #content>
<el-table
:data="materialList"
stripe
style="width: 100%"
header-cell-class-name="table-header"
align="center"
empty-text="材料列表信息为空点击标题右侧添加按钮进行添加"
>
<el-table-column align="left" prop="annexName" label="材料名称" width="280">
<template slot-scope="scope">
<div class="table-border">{{ scope.row.annexName }}</div>
</template>
</el-table-column>
<el-table-column align="center" prop="exampleFileId" label="样例">
<template slot-scope="{row}">
<el-upload action :on-exceed="list=>handleUpload({file:list[0]}).then(v=>row.exampleFileId=v)"
:http-request="args=>handleUpload(args).then(v=>row.exampleFileId=v)" :limit="1" accept=".jpg,.png">
<el-button style="width: 102px">{{ row.exampleFileId ? '重新选择图片' : '选择图片文件' }}</el-button>
</el-upload>
</template>
</el-table-column>
<el-table-column align="center" prop="emptyFileId" label="空表">
<template slot-scope="{row}">
<el-upload action :on-exceed="list=>handleUpload({file:list[0]}).then(v=>row.emptyFileId=v)"
:http-request="args=>handleUpload(args).then(v=>row.emptyFileId=v)" :limit="1" accept=".doc,.docx">
<el-button style="width: 102px">{{ row.emptyFileId ? '重新选择word' : '选择word文件' }}</el-button>
</el-upload>
</template>
</el-table-column>
<el-table-column align="center" prop="name" label="是否必填">
<template slot-scope="scope">
<el-switch
v-model="scope.row.mustFill"
active-value="1" inactive-value="0"
active-color="#5088FF"
inactive-color="#D0D4DC">
</el-switch>
</template>
</el-table-column>
<el-table-column align="center" label="操作">
<template slot-scope="scope">
<span class="iconfont iconEdit icon-color89B" title="编辑" @click="editInfo(scope.$index)" style="margin-right: 10px;"/>
<span class="iconfont iconDelete icon-color89B" title="删除" @click="deleteInfo(scope.$index)"/>
</template>
</el-table-column>
</el-table>
</template>
</ai-card>
<ai-dialog
title="添加附件材料"
:visible.sync="dialog"
@closed="form.annexName='',idAdd=true,index=null"
@onConfirm="onConfirm"
@onCancel="dialog=false"
width="720px">
<el-form :rules="rules" ref="materialForm" label-width="100px" :model="form">
<el-form-item label="材料名称:" prop="annexName">
<el-input v-model.trim="form.annexName" size="small" placeholder="请输入材料名称" show-word-limit :maxlength="32"/>
</el-form-item>
</el-form>
</ai-dialog>
</div>
</template>
<script>
export default {
name: "attachmentMaterial",
inject: ['config'],
props: {
instance: Function,
},
data() {
return {
materialList: [],
dialog: false,
idAdd: true,
index: null,
form: {
annexName: ""
},
}
},
computed: {
rules() {
return {
annexName: [{required: true, message: '请输入材料名称', trigger: 'blur'}]
}
}
},
methods: {
handleAttachmentMaterial() {
return Promise.resolve(this.materialList)
},
handleUpload(file) {
let formData = new FormData()
formData.append('file', file.file)
return this.instance.post(`/admin/file/add`, formData).then(res => {
if (res?.code == 0) {
this.$message.success('上传成功')
let data = res.data[0].split(';')
return data[1]
}
})
},
/**
* 添加附件材料
* */
onConfirm() {
this.$refs['materialForm'].validate(valid => {
if (valid) {
if(this.idAdd){
this.materialList.push({
annexName: this.form.annexName,
mustFill: "1",
exampleFileId: "",
emptyFileId: "",
})
}else {
this.materialList[this.index].annexName = this.form.annexName
}
this.dialog = false
}
})
},
/**
* 删除
*/
deleteInfo(index) {
this.$confirm("是否删除?").then(res => {
this.materialList.splice(index, 1)
})
},
/**
* 编辑标题
*/
editInfo(index) {
this.dialog = true
this.idAdd = false
this.index = index
this.form.annexName = JSON.parse(JSON.stringify(this.materialList[index].annexName))
}
},
created() {
if (this.config.detailObj?.id) {
this.materialList = JSON.parse(JSON.stringify(this.config.detailObj?.processAnnexDefs))
}
}
}
</script>
<style lang="scss" scoped>
.attachment-material {
.rightBtn {
font-size: 14px;
color: #5088FF;
user-select: none;
cursor: pointer;
}
.table-border {
width: 260px;
height: 32px;
box-sizing: border-box;
padding: 0 14px;
display: flex;
align-items: center;
border-radius: 2px;
border: 1px solid #D0D4DC;
color: #333333;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
::v-deep .el-upload-list {
display: none;
}
.iconDelete {
user-select: none;
cursor: pointer;
}
}
</style>

View File

@@ -0,0 +1,154 @@
<template>
<section class="base-info">
<ai-card title="基本信息">
<template #content>
<el-form :model="form" :rules="rules" ref="baseInfoForm" label-suffix="" label-width="100px">
<el-form-item label="事项名称" prop="processName">
<el-input v-model.trim="form.processName" size="small" clearable placeholder="请输入事项名称" :maxlength="30"
show-word-limit/>
</el-form-item>
<el-row type="type" justify="space-between" :gutter="20">
<el-col :span="12">
<el-form-item label="所属部门" prop="department">
<el-select placeholder="请选择" size="small" v-model="form.department" clearable style="width: 100%;">
<el-option
v-for="(item,i) in dict.getDict('hbDepartment')" :key="i"
:label="item.dictName"
:value="item.dictValue">
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="所属分类" prop="classificationId">
<el-select placeholder="请选择" size="small" v-model="form.classificationId" clearable
style="width: 100%;">
<el-option
v-for="(item,i) in classList" :key="i"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-form-item label="办结时限" prop="timeLimit">
<el-input v-model.trim="form.timeLimit" oninput="value=value.replace(/[^\d]/g,'')" size="small" clearable
placeholder="请输入天数" style="width: 270px;"/>
</el-form-item>
<el-form-item label="办理须知" prop="needToKnow">
<ai-editor v-model="form.needToKnow" :instance="instance" @validate="v=>valid=!v"/>
</el-form-item>
<el-form-item label="是否启用" prop="processDefStatus">
<el-switch
v-model="form.processDefStatus"
active-color="#5088FF"
inactive-color="#D0D4DC" active-value="1" inactive-value="0">
</el-switch>
</el-form-item>
</el-form>
</template>
</ai-card>
</section>
</template>
<script>
export default {
name: "baseInfo",
inject: ['config'],
props: {
instance: Function,
dict: Object,
},
data() {
const validTimeLimit = (rule, value, callback) => {
if (!value) {
return callback(new Error('请输入办结时限'));
} else {
if (+value <= 0) {
return callback(new Error('最小值为1'));
}
callback();
}
}
return {
form: {
processName: "",
department: "",
classificationId: "",
timeLimit: "",
needToKnow: "",
processDefStatus: "1",
},
valid:true,
classList: [],
rules: {
processName: [{required: true, message: '请输入事项名称', trigger: 'blur'}],
department: [{required: true, message: '请选择所属部门', trigger: 'change'}],
classificationId: [{required: true, message: '请选择所属分类', trigger: 'change'}],
timeLimit: [{required: true, validator: validTimeLimit, trigger: 'blur'}],
needToKnow: [
{required: true, message: '请输入办理须知', trigger: 'blur'},
{
validator: (r, v, cb) => {
if (this.valid) {
cb()
} else {
cb('字数超过限制')
}
}
}
],
processDefStatus: [{required: true, message: '请选择是否启用', trigger: 'change'}],
}
}
},
methods: {
banseInfoForm() {
return new Promise((resolve, reject) => {
this.$refs['baseInfoForm'].validate(valid => {
if (valid) {
resolve(this.form)
} else {
reject(false)
}
})
})
},
/**
* 获取分类
*/
getClassification() {
this.instance.post(`/app/zwspapprovalclassification/list`, null, {
params: {
current: 1,
status: 1,
size: 9999
}
}).then(res => {
if (res?.data) {
this.classList = res.data.records
}
})
}
},
created() {
this.getClassification()
if (this.config.detailObj?.id) {
this.$nextTick(_=>{
Object.keys(this.form).map(e => this.form[e] = this.config.detailObj[e])
})
}
}
}
</script>
<style lang="scss" scoped>
.base-info {
.iconAudit {
font-size: 36px;
color: #3D94FB;
}
}
</style>

View File

@@ -0,0 +1,203 @@
export const components = [
{
type: 'info',
tips: '(可重复添加)',
label: '信息',
children: [
{
type: 'name',
fieldName: '姓名',
fieldTips: '请输入姓名',
fixedLabel: '姓名',
disable: '0',
grid: 1,
fieldDataType: '1',
defaultValue: '',
icon: 'icontext_box',
mustFill: '1',
fieldLength: 20
},
{
type: 'idNumber',
fieldName: '身份证号',
fixedLabel: '身份证号',
fieldTips: '请输入身份证号',
defaultValue: '',
icon: 'icontext_area',
mustFill: '1',
fieldLength: 20,
disable: '0',
grid: 1,
fieldDataType: '1',
verifyType: 0
},
{
type: 'phone',
fieldName: '联系方式',
fixedLabel: '联系方式',
fieldTips: '请输入联系方式',
defaultValue: '',
icon: 'icontext_area',
mustFill: '1',
fieldLength: 11,
disable: '0',
grid: 1,
fieldDataType: '1',
verifyType: 1
}
]
},
{
type: 'options',
tips: '(可重复添加)',
label: '选项',
children: [
{
type: 'radio',
fieldName: '单选',
fixedLabel: '单选',
fieldTips: '请选择',
grid: 1,
icon: 'iconradio',
mustFill: '1',
disable: '0',
fieldDataType: '4',
defaultValue: '',
options: [
{
label: '选项1',
value: ''
},
{
label: '选项2',
value: ''
}
],
title: ''
},
{
type: 'checkbox',
fieldName: '多选',
fixedLabel: '多选',
fieldTips: '请选择',
icon: 'iconcheck_box',
fieldDataType: '5',
mustFill: '1',
grid: 1,
disable: '0',
defaultValue: [],
options: [
{
label: '选项1',
value: ''
},
{
label: '选项2',
value: ''
}
],
title: ''
},
{
type: 'select',
fieldName: '单下拉框',
fixedLabel: '单下拉框',
grid: 1,
fieldTips: '请选择',
icon: 'iconSelect',
mustFill: '1',
defaultValue: '',
fieldDataType: '9',
disable: '0',
options: [
{
label: '选项1',
value: ''
},
{
label: '选项2',
value: ''
}
],
title: ''
},
{
type: 'date',
fieldName: '日期',
fixedLabel: '日期',
grid: 1,
fieldDataType: '3',
datetimePattern: 'yyyy-MM-dd',
fieldTips: '请选择日期',
icon: 'iconSelect',
mustFill: '1',
disable: '0',
title: ''
},
{
type: 'datetime',
fieldName: '日期时间',
fixedLabel: '日期时间',
grid: 1,
fieldDataType: '8',
datetimePattern: 'yyyy-MM-dd HH:mm:ss',
fieldTips: '请选择日期时间',
icon: 'iconSelect',
mustFill: '1',
disable: '0',
title: ''
}
]
},
{
type: 'input',
tips: '(可重复添加)',
label: '填空',
children: [
{
type: 'input',
fieldName: '单行填空',
fieldTips: '请输入',
fixedLabel: '单行填空',
disable: '0',
grid: 1,
fieldDataType: '1',
defaultValue: '',
icon: 'icontext_box',
mustFill: '1',
fieldLength: 50
},
{
type: 'number',
fieldName: '数字输入',
fixedLabel: '数字输入',
fieldTips: '请输入数字',
defaultValue: '',
icon: 'icontext_area',
mustFill: '1',
maxValue: 10000,
decimalPlaces: 0,
fieldDataType: '0',
minValue: 0,
fieldLength: 50,
disable: '0',
grid: 1,
}
]
},
{
type: 'layout',
tips: '(可重复添加)',
label: '分组',
children: [
{
type: 'group',
fieldName: '卡片',
fixedLabel: '卡片',
icon: 'iconpic',
groupName: '分组标题',
column: []
}
]
}
];

View File

@@ -0,0 +1,214 @@
<template>
<div class="config-list">
<ai-list isTabs>
<template #content>
<ai-search-bar>
<template #left>
<el-select v-model="search.department" placeholder="请选择所属部门" @change="page.current=1,getList()"
size="small" clearable>
<el-option
v-for="(item,i) in dict.getDict('hbDepartment')" :key="i"
:label="item.dictName"
:value="item.dictValue">
</el-option>
</el-select>
<el-select v-model="search.classificationId" placeholder="请选择所属分类" @change="page.current=1,getList()"
size="small" clearable>
<el-option
v-for="(item,i) in classList" :key="i"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
</template>
<template #right>
<el-input
v-model="search.processName"
size="small"
placeholder="事项名称/创建人"
@clear="search={},page.current=1,getList()"
v-throttle="() => {page.current = 1, getList()}"
clearable
suffix-icon="iconfont iconSearch"/>
</template>
</ai-search-bar>
<ai-search-bar>
<template #left>
<el-button type="primary" icon="iconfont iconAdd" @click="goPage(tab.value==0 ? 'addConfig':'guidance')">添加{{tab.value==0?'事项':'办事指南'}}</el-button>
</template>
</ai-search-bar>
<ai-table
:tableData="tableData"
:col-configs="colConfigs"
:header-cell-style="{fontWeight:'bold',color:'#333'}"
:total="page.total"
:current.sync="page.current"
:size.sync="page.size"
@getList="getList">
<el-table-column label="是否启用" slot="processDefStatus" align="center" width="150">
<template v-slot="{row}">
<el-switch
v-model="row.processDefStatus"
@change="onChange(row)" active-value="1" inactive-value="0"
active-color="#5088FF"
inactive-color="#D0D4DC">
</el-switch>
</template>
</el-table-column>
<el-table-column label="操作" slot="options" align="center" width="150">
<template v-slot="{row}">
<div class="table-options">
<el-button type="text" title="编辑" @click="goPage(tab.value==0 ? 'addConfig':'guidance',row)">编辑</el-button>
<el-button type="text" title="删除" @click="delInfo(row)">删除</el-button>
</div>
</template>
</el-table-column>
</ai-table>
</template>
</ai-list>
</div>
</template>
<script>
import day from 'dayjs'
export default {
name: "configList",
props: {
instance: Function,
dict: Object,
permissions: Function,
tab: Object,
},
data() {
return {
search: {
department: "",
classificationId: "",
processName: "",
},
page: {current: 1, size: 10},
total: 0,
row: {},
tableData: [],
classList: [],
}
},
computed: {
colConfigs() {
return [
{
prop: 'processName',
align: 'left',
label: '事项名称',
},
{
prop: 'department',
align: 'left',
label: '所属部门',
render: (h, {row}) => [ < span > {this.dict.getLabel('hbDepartment', row.department)} < /span>]
},
{
prop: 'classificationName',
align: 'center',
label: '所属分类',
},
{
prop: 'timeLimit',
align: 'center',
label: '办结时限(日)',
},
{
prop: 'createUserName',
align: 'center',
label: '创建人',
},
{
prop: 'createTime',
align: 'center',
label: '最后修改时间',
render: (h, {row}) => [ < span > {day(row.createTime
).
format("YYYY-MM-DD HH:mm")
}<
/span>]
},
{slot: 'processDefStatus', align:'center', label:'是否启用',},
{ slot: 'options',align:'center',label:'操作',},
].filter(e=>this.tab.value==0 ? true : (e.prop!="timeLimit"))
},
},
methods: {
goPage(comp, row = {}) {
this.$emit("goPage", {comp, row})
},
/**
* 获取分类
*/
getClassification() {
this.instance.post(`/app/zwspapprovalclassification/list`, null, {
params:{
current: 1,
status: 1,
size: 9999
}
}).then(res => {
if (res && res.data) {
this.classList = res.data.records
}
})
},
/**
* 删除
* */
delInfo({id}) {
this.$confirm("是否删除").then(() => {
this.instance.post(`/app/approval-process-def/delete?id=${id}`).then(res => {
if (res.code == 0) {
this.$message.success("删除成功")
this.getList()
}
})
})
},
/**
* 启用,停用
*/
onChange({id, processDefStatus}) {
this.instance.post(`/app/approval-process-def/enable-disable`, null, {
params: {id}
}).then(res => {
if (res.code == 0) {
this.$message.success(processDefStatus == 0 ? "不启用" : "已启用")
this.getList()
}
})
},
getList() {
this.instance.post(`/app/approval-process-def/list`, null, {
params: {
...this.page,
...this.search,
processType: this.tab.value
},
}).then(res => {
if (res?.data) {
this.tableData = res.data.records
this.page.total = res.data.total;
}
})
},
},
mounted() {
this.getList()
this.getClassification()
},
}
</script>
<style lang="scss" scoped>
.config-list {
height: 100%;
}
</style>

View File

@@ -0,0 +1,219 @@
<template>
<div class="guidance">
<ai-detail>
<ai-title slot="title" :title="detailTitle" isShowBack isShowBottomBorder @onBackClick="handleBack"/>
<template #content>
<ai-card title="基本信息">
<template #content>
<el-form :model="form" :rules="rules" ref="baseInfoForm" label-suffix="" label-width="100px">
<el-form-item label="事项名称" prop="processName">
<el-input v-model.trim="form.processName" size="small" clearable placeholder="请输入事项名称" :maxlength="30"
show-word-limit/>
</el-form-item>
<el-row type="type" justify="space-between" :gutter="20">
<el-col :span="12">
<el-form-item label="所属部门" prop="department">
<el-select placeholder="请选择" size="small" v-model="form.department" clearable style="width: 100%;">
<el-option
v-for="(item,i) in dict.getDict('hbDepartment')" :key="i"
:label="item.dictName"
:value="item.dictValue">
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="所属分类" prop="classificationId">
<el-select placeholder="请选择" size="small" v-model="form.classificationId" clearable
style="width: 100%;">
<el-option
v-for="(item,i) in classList" :key="i"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-form-item label="办理须知" prop="needToKnow">
<ai-editor v-model.trim="form.needToKnow" :instance="instance"/>
</el-form-item>
<el-form-item label="是否启用" prop="processDefStatus">
<el-switch
v-model="form.processDefStatus"
active-color="#5088FF"
inactive-color="#D0D4DC" active-value="1" inactive-value="0">
</el-switch>
</el-form-item>
</el-form>
</template>
</ai-card>
</template>
<template #footer>
<el-button class="btn" @click="handleBack">取消</el-button>
<el-button class="btn" type="primary" @click="save">保存</el-button>
</template>
</ai-detail>
</div>
</template>
<script>
export default {
name: "addConfig",
props: {
instance: Function,
dict: Object,
row: Object,
processType: String
},
data() {
return {
form: {
processName: "",
department: "",
classificationId: "",
needToKnow: "",
processDefStatus: "1",
},
classList: [],
}
},
computed: {
rules() {
return {
processName: [{required: true, message: '请输入事项名称', trigger: 'blur'}],
department: [{required: true, message: '请选择所属部门', trigger: 'change'}],
classificationId: [{required: true, message: '请选择所属分类', trigger: 'change'}],
needToKnow: [{required: true, message: '请输入办理须知', trigger: 'blur'}],
processDefStatus: [{required: true, message: '请选择是否启用', trigger: 'change'}],
}
},
detailTitle() {
return this.row?.id ? "编辑办事指南" : "添加办事指南"
}
},
methods: {
/**
* 获取分类
*/
getClassification() {
this.instance.post(`/app/zwspapprovalclassification/list`, null, {
params: {
current: 1,
status: 1,
size: 9999
}
}).then(res => {
if (res?.data) {
this.classList = res.data.records
}
})
},
/**
* 保存
*/
save() {
this.$refs["baseInfoForm"].validate(valid => {
if (valid) {
this.instance.post(`/app/approval-process-def/add-update`, {
...this.form,
id: this.row.id,
processType: this.processType
}).then(res => {
if (res.code == 0) {
this.$message.success("保存成功")
this.$router.push({query: {}})
}
})
}
})
},
getDetail(id) {
this.instance.post(`/app/approval-process-def/info-id`, null, {params: {id}}).then(res => {
if (res?.data) {
Object.keys(this.form).map(e => this.form[e] = res.data[e])
}
})
},
handleBack() {
this.$router.push({query: {}})
}
},
created() {
this.getClassification()
if (this.row?.id) {
this.getDetail(this.row?.id)
}
}
}
</script>
<style lang="scss" scoped>
.add-config {
height: 100%;
.step {
width: 100%;
height: 72px;
font-size: 14px;
.el-steps {
display: flex;
align-items: center;
height: 72px;
padding: 0 calc(50% - 380px);
::v-deep .el-step {
font-weight: bold;
::v-deep .el-step__icon {
width: 24px;
height: 24px;
background: #fff;
.iconfont {
font-size: 24px;
}
}
::v-deep .el-step__main {
display: flex;
align-items: center;
.el-step__arrow {
background: #D0D4DC;
margin: 0 8px;
height: 2px;
&:before, &:after {
display: none;
}
}
}
.is-process {
color: #2266FF;
}
.is-wait {
color: #666;
border-color: #D0D4DC;
}
}
}
}
.btn {
width: 92px;
height: 32px;
&:nth-child(2) {
margin-left: 24px;
}
}
}
</style>

View File

@@ -0,0 +1,4 @@
export {default as baseInfo} from './baseInfo'
export {default as applyForm} from './applyForm'
export {default as attachmentMaterial} from './attachmentMaterial'
export {default as processApproval} from './processApproval'

View File

@@ -0,0 +1,482 @@
<template>
<div class="process-approval">
<ai-card title="流程设置">
<template #right>
<span class="iconfont iconAdd rightBtn"></span>
<span class="rightBtn" style="margin-left: 8px;" @click="addAppStep(1)">添加审批步骤</span>
</template>
<template #content>
<el-steps direction="vertical">
<el-step v-for="(item,index) in form.processNodeList" :key="index">
<div slot="title" class="step_title">
<p>{{ item.nodeName }}{{ dict.getLabel('nodeType', item.nodeType) }}</p>
<div class="peraoBtn">
<el-button type="text" :disabled="index==0" class="iconfont iconMoveUp"
@click="form.processNodeList[index] = form.processNodeList.splice(index-1, 1,form.processNodeList[index])[0]">
上移
</el-button>
<el-button type="text" :disabled="index==(form.processNodeList.length-1)" class="iconfont iconMoveDown"
@click="form.processNodeList[index] = form.processNodeList.splice(index+1, 1,form.processNodeList[index])[0]">
下移
</el-button>
<el-button type="text" class="iconfont iconEdit" @click="addAppStep(2,item,index)">
编辑
</el-button>
<el-button type="text" class="iconfont iconDelete" @click="deleteInfo(index)">
删除
</el-button>
</div>
</div>
<div slot="description" class="step_desc">
<div class="desc_style">
<p>
选人方式<span>{{ dict.getLabel('candidateApproverType', item.candidateApproverType) }}</span>
</p>
</div>
<div class="desc_person" v-if="item.scopeCandidates==1||item.candidateApproverType==1">
<p class="desc_p">指定人员</p>
<div class="desc_div">
<el-tag type="info" closable v-for="(value,i) in item.candidateList" :key="i"
@close="item.candidateList.splice(i,1)">
{{ value.name }}
</el-tag>
<el-button v-if="item.candidateList.length>0" type="text" @click="item.candidateList=[]">清空
</el-button>
</div>
</div>
<ai-wechat-selecter slot="append" :instance="instance" :props="{id:'wxUserId',label:'name'}"
v-model="item.candidateList" v-if="item.candidateApproverType==1">
<el-button size="mini" type="primary">选择指定人员</el-button>
</ai-wechat-selecter>
</div>
</el-step>
</el-steps>
</template>
</ai-card>
<el-dialog :title="titleType" class="editStyle" :visible.sync="isAddStep" width="575px" height="380px"
:close-on-click-modal="false">
<el-form :model="nodeObj" label-width="120px" ref="addForm" :rules="addRules">
<el-form-item label="审批步骤名称:" prop="nodeName">
<el-input size="small" v-model="nodeObj.nodeName" placeholder="如部门主管审批限10个字" :maxLength="10"
clearable></el-input>
</el-form-item>
<el-form-item label="审批方式:" prop="nodeType">
<el-radio-group v-model="nodeObj.nodeType">
<section style="position: relative;top: 10px;margin-bottom: 30px;">
<el-radio :label="2">或签
<el-popover
placement="top-start"
width="200"
trigger="click"
content="或签是指该节点指定多名负责人审批时,其中任何一人完成审批即可。适合一个事项只需要某个岗位任何一人审批即可的业务场景。">
<el-button class="el-icon-warning" slot="reference"
style="padding:0;height:14px;border:0;"></el-button>
</el-popover>
</el-radio>
<el-radio :label="3">抄送
<el-popover
placement="top-start"
width="200"
trigger="click"
content="抄送是指一个事项审批完成后,抄送给需要知晓的单位或个人,被抄送的对象可以查阅该事项内容,无需审批。适合一个事项无需对方审批,但审批完成后需要通知对方知晓的业务场景。">
<el-button class="el-icon-warning" slot="reference"
style="padding:0;height:14px;border:0;"></el-button>
</el-popover>
</el-radio>
</section>
</el-radio-group>
</el-form-item>
</el-form>
<div slot="footer" style="text-align: center;">
<el-button style="width: 92px;" size="small" @click="isAddStep = false">取消</el-button>
<el-button style="width: 92px;" size="small" type="primary" @click="saveAddProgress('addForm')">确认
</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import {mapState} from "vuex";
export default {
name: "processApproval",
inject: ['config'],
props: {
instance: Function,
dict: Object,
approvalSteps: String
},
data() {
return {
form: {
processNodeList: [],
},
areaId: "",
isAddStep: false,
isSelectImg: false,
isSelectUnit: false,
isSelectPerson: false,
nodeObj: {
candidateApproverType: '1',
candidateList: [],
nodeIndex: '',
nodeName: '',
nodeType: '',
scopeCandidates: ''
},
indexType: '',
titleType: '',
bomIndex: '',
}
},
computed: {
addRules() {
return {
nodeName: [
{required: true, message: '请输入审批节点名称', trigger: 'change'}
],
nodeType: [
{required: true, message: '请选择审批方式', trigger: 'change'}
],
candidateApproverType: [
{required: true, message: '请选择选人方式', trigger: 'change'}
],
scopeCandidates: [
{required: true, message: '请选择选人范围', trigger: 'change'}
]
}
},
...mapState(['user'])
},
methods: {
handleProcessApproval() {
return Promise.resolve(this.form)
},
/**
*删除
* */
deleteInfo(index) {
this.$confirm("是否删除").then(() => {
this.form.processNodeList.splice(index, 1)
})
},
/**
* 添加流程
* @param index
* @param item
* @param i
*/
addAppStep(index, item, i) {
this.isAddStep = true;
this.bomIndex = i;
this.indexType = index;
if (index == 2) {
this.titleType = '编辑审批步骤';
item.nodeType = item.nodeType * 1;
item.candidateApproverType = item.candidateApproverType * 1;
item.scopeCandidates = item.scopeCandidates * 1;
this.nodeObj = JSON.parse(JSON.stringify(item));
} else {
this.titleType = '添加审批步骤';
if (this.form.processNodeList.length > 0) {
this.init();
}
}
},
// 确定添加审批步骤
saveAddProgress(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
if (this.nodeObj.scopeCandidates == 0) this.nodeObj.candidateList = [];
if (this.indexType == 1) {
this.form.processNodeList.push(JSON.parse(JSON.stringify(this.nodeObj)));
} else {
this.form.processNodeList.splice(this.bomIndex, 1, JSON.parse(JSON.stringify(this.nodeObj)));
}
this.$refs[formName].resetFields();
this.isAddStep = false;
}
})
},
init() {
this.nodeObj = {
candidateApproverType: '1',
candidateList: [],
nodeIndex: '',
nodeName: '',
nodeType: '',
scopeCandidates: ''
};
this.$refs['addForm'].resetFields();
},
},
created() {
this.areaId = this.user.info.areaId.substring(0, 6) + '000000'
if (this.config.detailObj?.id) {
Object.keys(this.form).map(e => this.form[e] = this.config.detailObj[e])
}
}
}
</script>
<style lang="scss" scoped>
.process-approval {
.rightBtn {
font-size: 14px;
color: #5088FF;
user-select: none;
cursor: pointer;
}
.step_title {
font-weight: 700;
height: 32px;
line-height: 32px;
display: flex;
padding: 0 8px;
justify-content: space-between;
color: #333;
p {
font-size: 14px;
}
div {
span {
margin-left: 16px;
font-size: 12px;
cursor: pointer;
}
}
}
.step_desc {
font-size: 14px;
padding: 8px;
color: #999;
margin-bottom: 20px;
.desc_style {
display: flex;
margin-bottom: 16px;
p {
margin-right: 80px;
}
span {
color: #333;
}
}
.desc_person {
display: flex;
margin-bottom: 12px;
.desc_p {
position: relative;
top: 4px;
width: 70px;
}
.desc_div {
flex: 1;
}
.el-tag {
margin-right: 8px;
margin-bottom: 8px;
}
}
}
.add_btn {
position: absolute;
bottom: 0;
left: 0;
height: 64px;
line-height: 64px;
background: #F3F6F9;
width: 100%;
text-align: center;
.el-button {
width: 92px;
}
}
.select_per {
width: 640px;
height: 400px;
box-sizing: border-box;
display: flex;
justify-content: space-between;
align-items: center;
margin: auto;
.add_item {
width: 310px;
height: 400px;
background: rgba(252, 252, 252, 1);
border-radius: 2px;
border: 1px solid rgba(208, 212, 220, 1);
position: relative;
overflow: auto;
.add_top {
width: 100%;
height: 40px;
background: rgba(245, 245, 245, 1);
border-bottom: 1px solid rgba(208, 212, 220, 1);
padding: 0 8px;
box-sizing: border-box;
display: flex;
justify-content: space-between;
align-items: center;
}
.tree_list {
width: 100%;
height: 360px;
overflow: auto;
}
.add_buttom {
position: absolute;
left: 0;
bottom: 0;
font-size: 12px;
width: 310px;
height: 32px;
line-height: 32px;
z-index: 10000;
background: rgba(245, 246, 247, 1);
color: rgba(51, 51, 51, 1);
box-shadow: 0px 1px 0px 0px rgba(216, 220, 227, 1);
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
}
.add_tag {
width: 310px;
height: 360px;
overflow-y: auto;
.el-tag {
margin: 8px;
}
}
}
}
.icon {
width: 48px;
height: 48px;
border: 1px solid #ddd;
border-radius: 4px;
margin-right: 16px;
margin-bottom: 16px;
cursor: pointer;
}
.icon_style {
display: flex;
flex-wrap: wrap;
.icon:hover {
border-color: #5088FF;
}
.icon_color {
border-color: #5088FF;
}
}
.dia_per_content {
width: 640px;
height: 400px;
box-sizing: border-box;
display: flex;
justify-content: space-between;
align-items: center;
margin: auto;
.add_item {
width: 310px;
height: 400px;
background: rgba(252, 252, 252, 1);
border-radius: 2px;
border: 1px solid rgba(208, 212, 220, 1);
position: relative;
overflow: auto;
.add_top {
width: 100%;
height: 40px;
background: rgba(245, 245, 245, 1);
border-bottom: 1px solid rgba(208, 212, 220, 1);
padding: 0 8px;
box-sizing: border-box;
display: flex;
justify-content: space-between;
align-items: center;
}
.tree_list {
width: 100%;
height: 360px;
overflow: auto;
}
.add_buttom {
position: absolute;
left: 0;
bottom: 0;
font-size: 12px;
width: 310px;
height: 32px;
line-height: 32px;
z-index: 10000;
background: rgba(245, 246, 247, 1);
color: rgba(51, 51, 51, 1);
box-shadow: 0px 1px 0px 0px rgba(216, 220, 227, 1);
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
}
.add_tag {
width: 310px;
height: 360px;
overflow-y: auto;
.el-tag {
margin: 8px;
}
}
}
}
.peraoBtn {
.el-button--text {
color: #333;
font-size: 12px;
}
}
::v-deep .el-step__icon.is-text {
border: 2px solid #2266FF;
background: #2266FF;
color: #FFFFFF;
}
::v-deep .el-step__line {
background-color: #D0D4DC;
}
}
</style>

View File

@@ -0,0 +1,365 @@
<template>
<section class="personal-signature">
<ai-list v-if="!showPhonePage">
<ai-title slot="title" title="个人签名" :isShowBottomBorder="false"/>
<template #custom>
<div class="signaturePane">
<div class="signatureCard" v-for="(op,i) in signatures" :key="i">
<div class="default" v-if="op.isDefault==1">默认</div>
<div class="body">
<el-image :src="`data:image/png;base64,${op.signSealData}`"/>
</div>
<div class="footer">
<el-button type="text" :disabled="op.isDefault==1" @click.stop="handleSetDefault(op.id)">设为默认</el-button>
<hr/>
<el-button type="text" :disabled="op.isDefault==1||op.signType>0" @click.stop="handleDelete(op.id)">删除
</el-button>
</div>
</div>
<div class="signatureCard add" @click="dialog=true">
<ai-icon icon="iconAdd" size="32px"/>
<span>点击添加签名</span>
</div>
</div>
</template>
</ai-list>
<ai-dialog :visible.sync="dialog" v-bind="dialogConf" @onConfirm="handleSubmit"
@closed="form={},drawPlaceholder=true,qrCode=null,showQRCode=false,getSignatures()">
<ai-drawer v-if="hasAuthed" :seal.sync="sealData" ref="aiDrawer">
<template #tools>
<el-popover trigger="manual" v-model="showQRCode">
<el-image :src="qrCode"/>
<div class="writeInPhone" slot="reference" @click.stop="showQR">
<ai-icon icon="iconEwm"/>
<span>手机签名</span>
</div>
</el-popover>
</template>
</ai-drawer>
<el-form size="small" :model="form" ref="authForm" :rules="rules" class="authZone" v-else label-suffix=""
label-width="100px">
<el-alert type="warning" title="第一次添加个人签名,需先进行实名认证" show-icon :closable="false"/>
<el-form-item label="姓名" prop="personName">
<el-input v-model="form.personName" clearable placeholder="姓名"/>
</el-form-item>
<el-form-item label="身份证号" prop="idNumber">
<el-input v-model="form.idNumber" clearable placeholder="身份证号"/>
</el-form-item>
<el-form-item label="手机号码" prop="signPhone">
<el-input v-model="form.signPhone" clearable placeholder="手机号码"/>
</el-form-item>
</el-form>
</ai-dialog>
<draw-in-phone v-if="showPhonePage"/>
</section>
</template>
<script>
import {mapState} from "vuex";
import DrawInPhone from "./drawInPhone";
export default {
name: "AppPersonalSignature",
label: "个人签名",
components: {DrawInPhone},
provide() {
return {
signature: this
}
},
props: {
instance: Function,
dict: Object,
permissions: Function
},
computed: {
...mapState(['user']),
hasAuthed() {
return this.signatures.length > 0
},
dialogConf() {
return this.hasAuthed ? {
title: "手写签名",
width: '720px'
} : {
title: "实名认证",
width: '520px'
}
},
rules() {
return {
personName: [{required: true, message: "请填写姓名"}],
signPhone: [
{required: true, message: "请填写手机号码"},
{pattern: /^1[3456789]\d{9}$/, message: "手机号码格式有误"}
],
idNumber: [
{required: true, message: "请填写身份证号码"},
{validator: (r, v, cb) => cb(this.idCardNoUtil.checkIdCardNo(v) ? undefined : "身份证号码格式有误")}
],
}
}
},
data() {
return {
signatures: [],
dialog: false,
form: {},
sealData: null,
qrCode: null,
showQRCode: false,
showPhonePage: false,
loading: false,
}
},
created() {
if (this.$route.query.userId && this.$route.hash == "#phone") {
this.showPhonePage = true
} else {
this.getSignatures()
}
},
methods: {
getSignatures() {
this.instance.post("/app/syssignaccount/list", null, {
params: {
size: 999
}
}).then(res => {
if (res?.data) {
this.signatures = res.data.records
}
})
},
handleSubmit() {
if (this.loading) return
if (this.hasAuthed && this.$refs['aiDrawer'].drawPlaceholder) return this.$message.error("请签名")
this.loading = true
if (this.hasAuthed) {
let sealData = this.sealData?.replace(/data:image\/png;base64,/, '')
sealData && this.instance({
url: '/app/syssignaccount/upload-sealdata',
headers: {"Content-Type": "application/json"},
method: 'post',
params: {userId: this.user.info.id},
data: sealData
}).then(res => {
this.loading = false
if (res?.code == 0) {
this.dialog = false
this.$message.success("添加成功!")
this.getSignatures()
}
}).catch(() => {
this.loading = false
})
} else {
this.$refs.authForm.validate(v => {
if (v) {
this.instance.post("/app/syssignaccount/register", {
signPhone: this.form.signPhone,
signType: 1,
userType: 0,
registerInfo: {...this.form},
style: {personTemplateType: 'RECTANGLE', sealColor: 'RED'}
}).then(res => {
this.loading = false
if (res?.code == 0) {
this.dialog = false
this.$message.success("认证成功!")
this.getSignatures()
}
}).catch(() => {
this.loading = false
})
}
})
}
},
handleSetDefault(id) {
this.$confirm("是否设置该签名为默认签名?").then(() => {
this.instance.post("/app/syssignaccount/default", null, {params: {id, listType: 0}}).then(res => {
if (res?.code == 0) {
this.$message.success("设置成功!")
this.getSignatures()
}
}).catch(() => 0)
})
},
handleDelete(ids) {
this.$confirm("是否删除该签名?").then(() => {
this.instance.post("/app/syssignaccount/delete", null, {params: {ids}}).then(res => {
if (res?.code == 0) {
this.$message.success("删除成功!")
this.getSignatures()
}
}).catch(() => 0)
})
},
showQR() {
if (!this.qrCode) {
let url = `${location.href}?userId=${this.user.info.id}#phone`
this.instance.post("/app/syssignaccount/draw-qrcode", null, {
params: {url}
}).then(res => {
if (res?.data) {
this.showQRCode = true
this.qrCode = res.data
}
})
} else {
this.showQRCode = !this.showQRCode
}
}
}
}
</script>
<style lang="scss" scoped>
.personal-signature {
height: 100%;
background: #f3f6f9;
overflow: auto;
::v-deep .signaturePane {
display: flex;
gap: 16px;
flex-wrap: wrap;
padding: 16px;
.signatureCard {
width: 290px;
height: 258px;
background: #FFFFFF;
border-radius: 4px;
position: relative;
display: flex;
flex-direction: column;
overflow: hidden;
&.add {
justify-content: center;
align-items: center;
color: #666666;
cursor: pointer;
.AiIcon {
width: 32px;
height: 32px;
font-size: 32px;
}
& > span {
font-size: 12px;
line-height: 16px;
}
}
.default {
position: absolute;
width: 56px;
height: 24px;
background: #3573FF;
border-radius: 0 0 4px 0;
top: 0;
left: 0;
text-align: center;
line-height: 24px;
font-size: 12px;
color: #FFF;
}
.body {
min-height: 0;
flex: 1;
display: flex;
justify-content: center;
align-items: center;
padding: 25px;
pointer-events: none;
.el-image {
width: 100%;
height: 100%
}
}
.footer {
flex-shrink: 0;
height: 40px;
background: rgba(#30426F, .5);
display: flex;
align-items: center;
padding: 8px 0;
box-sizing: border-box;
hr {
height: 100%;
border-color: rgba(#fff, .5);
}
& > .el-button {
flex: 1;
color: #fff;
&[disabled] {
color: rgba(#fff, .5);
}
}
}
}
}
::v-deep .writeInPhone {
position: absolute;
width: 100px;
height: 32px;
background: rgba(#000, .5);
border-radius: 16px;
display: flex;
align-items: center;
justify-content: center;
gap: 4px;
color: rgba(#fff, .6);
cursor: pointer;
left: 16px;
top: 16px;
.AiIcon {
width: auto;
height: auto;
}
&:hover {
color: #fff;
}
}
::v-deep .ai-dialog__wrapper {
.ai-dialog__content--wrapper {
padding-right: 0 !important;
}
.el-dialog__body {
padding: 24px 0;
}
.authZone {
padding: 0 16px 24px;
width: 100%;
box-sizing: border-box;
display: flex;
flex-direction: column;
gap: 24px;
.el-alert {
border: 1px solid #FF8822;
}
.el-form-item {
margin-bottom: 0;
}
}
}
}
</style>

View File

@@ -0,0 +1,110 @@
<template>
<section class="drawInPhone" @touchmove.prevent>
<div class="endPage" v-if="finished">操作结束请关闭页面</div>
<ai-drawer :seal.sync="sealData" placeholder="请签名" :width="device.width" :height="device.height">
<template #tools>
<div class="writeInPhone" slot="reference" @click.stop="handleSubmit">
<ai-icon icon="iconPublish"/>
<span>提交</span>
</div>
</template>
</ai-drawer>
</section>
</template>
<script>
export default {
name: "drawInPhone",
inject: ['signature'],
data() {
return {
sealData: null,
device: {width: 0, height: 0},
finished: false
}
},
created() {
this.device.width = document.body.clientWidth
this.device.height = document.body.clientHeight
window.onresize = () => {
this.device.width = document.body.clientWidth
this.device.height = document.body.clientHeight
}
},
methods: {
handleSubmit() {
let sealData = this.sealData?.replace(/data:image\/png;base64,/, ''),
{userId} = this.$route.query
if (!userId) return alert("缺少必要参数")
sealData && this.signature.instance({
url: '/app/syssignaccount/upload-sealdata',
headers: {"Content-Type": "application/json"},
method: 'post',
params: {userId},
data: sealData,
withoutToken: true
}).then(res => {
if (res?.code == 0) {
alert("添加成功!")
this.finished = true
}
})
},
}
}
</script>
<style lang="scss" scoped>
.drawInPhone {
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
z-index: 20210205932;
.endPage {
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
z-index: 20210205933;
background: rgba(#000, .8);
color: #999;
display: flex;
justify-content: center;
align-items: center;
font-size: 32px;
}
.AiDrawer {
margin: 0;
}
.writeInPhone {
position: absolute;
width: 72px;
height: 32px;
background: rgba(#000, .5);
border-radius: 16px;
display: flex;
align-items: center;
justify-content: center;
gap: 4px;
color: rgba(#fff, .6);
cursor: pointer;
left: 16px;
top: 16px;
.AiIcon {
width: auto;
height: auto;
}
&:hover {
color: #fff;
}
}
}
</style>