卢龙web端功能迁移
This commit is contained in:
79
project/lulong/Announce/AppAnnounce/AppAnnounce.vue
Normal file
79
project/lulong/Announce/AppAnnounce/AppAnnounce.vue
Normal file
@@ -0,0 +1,79 @@
|
||||
<template>
|
||||
<div class="AppAnnounce">
|
||||
<!-- <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: 'AppAnnounce',
|
||||
label: '群发居民群',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
component: 'List',
|
||||
params: {},
|
||||
include: []
|
||||
}
|
||||
},
|
||||
|
||||
components: {
|
||||
Add,
|
||||
List,
|
||||
Detail
|
||||
},
|
||||
|
||||
mounted () {
|
||||
if (this.$route.params.id) {
|
||||
this.component = 'Detail'
|
||||
this.params = {
|
||||
id: this.$route.params.id
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
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">
|
||||
.AppAnnounce {
|
||||
height: 100%;
|
||||
background: #F3F6F9;
|
||||
overflow: auto;
|
||||
}
|
||||
</style>
|
||||
988
project/lulong/Announce/AppAnnounce/components/Add.vue
Normal file
988
project/lulong/Announce/AppAnnounce/components/Add.vue
Normal file
@@ -0,0 +1,988 @@
|
||||
<template>
|
||||
<ai-detail class="AppAnnounceAdd">
|
||||
<template slot="title">
|
||||
<ai-title :title="id ? '编辑群发居民群' : '添加群发居民群'" isShowBack isShowBottomBorder @onBackClick="cancel(false)">
|
||||
</ai-title>
|
||||
</template>
|
||||
<template slot="content">
|
||||
<div class="AppAnnounceDetail-container">
|
||||
<el-form ref="form" class="left" :model="form" label-width="110px" label-position="right">
|
||||
<ai-card title="基本信息">
|
||||
<template #content>
|
||||
<div class="ai-form">
|
||||
<el-form-item label="任务名称" prop="taskTitle" style="width: 100%;" :rules="[{ required: true, message: '请输入任务名称', trigger: 'blur' }]">
|
||||
<el-input size="small" placeholder="请输入任务名称" v-model="form.taskTitle" :maxlength="15" show-word-limit></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="发送范围" style="width: 100%;" prop="sendScope" :rules="[{ required: true, message: '请选择发送范围', trigger: 'change' }]">
|
||||
<el-radio-group v-model="form.sendScope" @change="onScopeChange">
|
||||
<!-- <el-radio label="0">全部居民群</el-radio> -->
|
||||
<el-radio label="1">按部门选择</el-radio>
|
||||
<!-- <el-radio label="2">按网格选择</el-radio> -->
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="选择群主" v-if="form.sendScope !== '0'" prop="wxGroupsName" style="width: 100%;" :rules="[{ required: true, message: '请选择选择群主', trigger: 'change' }]" >
|
||||
<ai-picker
|
||||
:instance="instance"
|
||||
multiple
|
||||
:dialogTitle="form.sendScope === '2' ? '选择网格' : '选择部门'"
|
||||
:ops="{label: form.sendScope === '2' ? 'girdName' : 'name'}"
|
||||
:pageTitle="form.sendScope === '2' ? '网格' : '部门'"
|
||||
:action="form.sendScope === '1' ? `/app/wxcp/wxdepartment/departList` : '/app/appgirdinfo/girdList'"
|
||||
v-model="form.filterCriteria"
|
||||
@pick="onPick"
|
||||
@change="onSelcetChange">
|
||||
<div class="AppAnnounceDetail-select">
|
||||
<el-input size="small" class="AppAnnounceDetail-select__input" placeholder="请选择..." disabled v-model="form.wxGroupsName"></el-input>
|
||||
<div class="select-left" v-if="form.wxGroups && form.wxGroups.length">
|
||||
<span v-for="(item, index) in form.wxGroups" :key="index" v-if="index < 9">{{ item.groupOwnerName }}</span>
|
||||
<em v-if="form.wxGroups.length > 9">等{{ form.wxGroups.length }}个</em>
|
||||
</div>
|
||||
<i v-else>请选择</i>
|
||||
<div class="select-right">{{ form.filterCriteria.length ? '重新选择' : '选择' }}</div>
|
||||
</div>
|
||||
</ai-picker>
|
||||
<div class="tips">
|
||||
<p>消息预计送达居民群数:</p>
|
||||
<span>{{ groupLen }}</span>
|
||||
<el-tooltip
|
||||
placement="top"
|
||||
content="将由指定群主发送给TA作为群主的所有的群,由于企业微信限制,当超过1000个时将只发送到最近活跃的1000个群">
|
||||
<i class="iconfont iconModal_Warning"></i>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="发送内容" prop="content" style="width: 100%;" :rules="[{ required: true, message: '请输入发送内容', trigger: 'blur' }]">
|
||||
<el-input size="small" type="textarea" :rows="6" maxlength="1300" show-word-limit placeholder="请输入文本内容..." v-model="form.content"></el-input>
|
||||
<div class="add">
|
||||
<div class="fileList" v-if="fileList && fileList.length">
|
||||
<div class="add-item" v-for="(item, index) in fileList" :key="index">
|
||||
<div class="left">
|
||||
<img :src="mapIcon(item.msgType)"/>
|
||||
<span>{{ item.mpTitle || item.name || item.linkTitle }}</span>
|
||||
</div>
|
||||
<i @click="removeFile(index)">删除</i>
|
||||
</div>
|
||||
</div>
|
||||
<el-popover
|
||||
placement="top"
|
||||
width="340"
|
||||
offset="0"
|
||||
trigger="hover">
|
||||
<div class="add-item" slot="reference" style="width: max-content;">
|
||||
<img src="https://cdn.cunwuyun.cn/dvcp/announce/add.png"/>
|
||||
<span style="color: #2266FF; font-size: 12px;">添加附件类型</span>
|
||||
</div>
|
||||
<div class="AppAnnounceDetail-content-wrapper">
|
||||
<el-upload
|
||||
ref="upload"
|
||||
multiple
|
||||
:file-list="fileList"
|
||||
:show-file-list="false"
|
||||
:before-upload="v => handleChange(v, 10, '.jpg,.png,.jpeg')"
|
||||
:limit="9"
|
||||
action="/app/wxcp/upload/uploadFile"
|
||||
accept=".jpg,.png,.jpeg"
|
||||
:on-exceed="onExceed"
|
||||
:http-request="v => submitUpload(v, '1')">
|
||||
<div class="content-item" trigger>
|
||||
<img src="https://cdn.cunwuyun.cn/dvcp/announce/big-img.png"/>
|
||||
<p>图片</p>
|
||||
</div>
|
||||
</el-upload>
|
||||
<el-upload
|
||||
ref="upload"
|
||||
multiple
|
||||
:file-list="fileList"
|
||||
:show-file-list="false"
|
||||
:before-upload="v => handleChange(v, 10, '.mp4')"
|
||||
:limit="9"
|
||||
action="/app/wxcp/upload/uploadFile"
|
||||
accept=".mp4"
|
||||
:on-exceed="onExceed"
|
||||
:http-request="v => submitUpload(v, '2')">
|
||||
<div class="content-item" trigger>
|
||||
<img src="https://cdn.cunwuyun.cn/dvcp/announce/big-video.png"/>
|
||||
<p>视频</p>
|
||||
</div>
|
||||
</el-upload>
|
||||
<el-upload
|
||||
ref="upload"
|
||||
multiple
|
||||
:file-list="fileList"
|
||||
:show-file-list="false"
|
||||
:before-upload="v => handleChange(v, 20, '.zip,.rar,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.pdf,.txt')"
|
||||
:limit="9"
|
||||
:on-exceed="onExceed"
|
||||
action="/app/wxcp/upload/uploadFile"
|
||||
accept=".zip,.rar,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.pdf,.txt"
|
||||
:http-request="v => submitUpload(v, '3')">
|
||||
<div class="content-item" trigger>
|
||||
<img src="https://cdn.cunwuyun.cn/dvcp/announce/folder.png"/>
|
||||
<p>文件</p>
|
||||
</div>
|
||||
</el-upload>
|
||||
<div class="content-item" @click="isShowAddLink = true">
|
||||
<img src="https://cdn.cunwuyun.cn/dvcp/announce/site.png"/>
|
||||
<p>网页</p>
|
||||
</div>
|
||||
<div class="content-item" @click="isShowAddMiniapp = true">
|
||||
<img src="https://cdn.cunwuyun.cn/dvcp/announce/miniapp.png"/>
|
||||
<p>小程序</p>
|
||||
</div>
|
||||
</div>
|
||||
</el-popover>
|
||||
<!-- <div class="add-material add-item" @click="$refs.ChooseMaterial.open()">
|
||||
<img src="https://cdn.cunwuyun.cn/dvcp/announce/add.png"/>
|
||||
<span style="color: #2266FF; font-size: 12px;">从素材库选择</span>
|
||||
</div> -->
|
||||
</div>
|
||||
<div class="tips">
|
||||
<em>从本地上传,图片最大支持10MB,支持JPG,PNG格式;视频最大支持10MB,支持MP4格式;文件最大支持20MB</em>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="标签" style="width: 100%;" prop="markTag">
|
||||
<el-checkbox-group v-model="form.markTag">
|
||||
<el-checkbox
|
||||
v-for="(item, index) in dict.getDict('mstTag')"
|
||||
:key="index"
|
||||
:label="item.dictValue">
|
||||
{{ item.dictName }}
|
||||
</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="结束时间" style="width: 100%;" prop="taskEndTime" :rules="[{ required: true, message: '请选择结束时间', trigger: 'change' }]">
|
||||
<el-date-picker
|
||||
style="width: 100%;"
|
||||
v-model="form.taskEndTime"
|
||||
type="datetime"
|
||||
size="small"
|
||||
:picker-options="pickerOptions"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
placeholder="请选择结束时间">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
<el-form-item label="宣发审批" prop="enableExamine" style="width: 100%;" :rules="[{ required: true, message: '请输入任务名称', trigger: 'blur' }]">
|
||||
<el-switch
|
||||
v-model="form.enableExamine"
|
||||
active-value="1"
|
||||
inactive-value="0"
|
||||
active-text="开启后,创建的群发任务需要审批人进行审批">
|
||||
</el-switch>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="form.enableExamine === '1'" label="审批人员" prop="examines" style="width: 100%;" :rules="[{ required: true, message: '请选择审批人员', trigger: 'change' }]">
|
||||
<ai-user-selecter :instance="instance" v-model="form.examines" @change="onUserChange">
|
||||
<div class="AppAnnounceDetail-select">
|
||||
<el-input class="AppAnnounceDetail-select__input" size="small" placeholder="请选择..." v-model="form.examinesName"></el-input>
|
||||
<div class="select-left" v-if="form.examines && form.examines.length">
|
||||
<span v-for="(item, index) in form.examines" :key="index">{{ item.name }}</span>
|
||||
</div>
|
||||
<i v-if="!form.examines.length">请选择</i>
|
||||
<div class="select-right">{{ form.examines.length ? '重新选择' : '选择' }}</div>
|
||||
</div>
|
||||
</ai-user-selecter>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</template>
|
||||
</ai-card>
|
||||
</el-form>
|
||||
<div class="right">
|
||||
<Phone :avatar="user.info.avatar" @close="isShowPhone = false" :isShowClose="false" :content="form.content" :fileList="fileList"></Phone>
|
||||
</div>
|
||||
<ai-dialog
|
||||
:visible.sync="isShowAddLink"
|
||||
width="920px"
|
||||
title="链接消息"
|
||||
@close="onClose"
|
||||
@onConfirm="onLinkConfirm">
|
||||
<el-form ref="linkForm" :model="linkForm" label-width="110px" label-position="right">
|
||||
<div class="ai-form">
|
||||
<el-form-item label="标题" style="width: 100%;" prop="linkTitle" :rules="[{ required: true, message: '请输入标题', trigger: 'blur' }]">
|
||||
<el-input
|
||||
size="small"
|
||||
placeholder="请输入标题"
|
||||
maxlength="42"
|
||||
show-word-limit
|
||||
v-model="linkForm.linkTitle">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="链接" style="width: 100%;" prop="linkUrl" :rules="[{ required: true, message: '请输入链接', trigger: 'blur' }]">
|
||||
<el-input
|
||||
size="small"
|
||||
placeholder="请输入链接"
|
||||
maxlength="682"
|
||||
show-word-limit
|
||||
v-model="linkForm.linkUrl">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="描述" style="width: 100%;" prop="linkDesc">
|
||||
<el-input
|
||||
size="small"
|
||||
placeholder="请输入描述"
|
||||
maxlength="170"
|
||||
show-word-limit
|
||||
v-model="linkForm.linkDesc">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="封面图" prop="linkPicUrl" style="width: 100%;">
|
||||
<ai-uploader :instance="instance" v-model="linkForm.linkPicUrl" :limit="1"></ai-uploader>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-form>
|
||||
</ai-dialog>
|
||||
<ai-dialog
|
||||
:visible.sync="isShowAddMiniapp"
|
||||
width="920px"
|
||||
title="小程序消息"
|
||||
@close="onClose"
|
||||
@onConfirm="onMiniAppForm">
|
||||
<el-form ref="miniAppForm" :model="miniAppForm" label-width="130px" label-position="right">
|
||||
<div class="ai-form">
|
||||
<el-form-item label="小程序appid" style="width: 100%;" prop="mpAppid" :rules="[{ required: true, message: '小程序appid', trigger: 'blur' }]">
|
||||
<el-input
|
||||
size="small"
|
||||
placeholder="小程序appid"
|
||||
v-model="miniAppForm.mpAppid">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="小程序page路径" style="width: 100%;" prop="mpPage" :rules="[{ required: true, message: '请输入小程序page路径', trigger: 'blur' }]">
|
||||
<el-input
|
||||
size="small"
|
||||
placeholder="请输入小程序page路径"
|
||||
v-model="miniAppForm.mpPage">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="标题" style="width: 100%;" prop="mpTitle" :rules="[{ required: true, message: '请输入标题', trigger: 'blur' }]">
|
||||
<el-input
|
||||
size="small"
|
||||
placeholder="请输入标题"
|
||||
maxlength="20"
|
||||
show-word-limit
|
||||
v-model="miniAppForm.mpTitle">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="封面图" prop="media" style="width: 100%;" :rules="[{ required: true, message: '请上传封面图', trigger: 'change' }]">
|
||||
<ai-uploader url="/app/wxcp/upload/uploadFile?type=image" :instance="instance" isWechat v-model="miniAppForm.media" :limit="1"></ai-uploader>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-form>
|
||||
</ai-dialog>
|
||||
<ai-dialog
|
||||
:visible.sync="isShowDate"
|
||||
width="590px"
|
||||
title="定时发送"
|
||||
customFooter>
|
||||
<el-form ref="dateForm" :model="dateForm" label-width="130px" label-position="right">
|
||||
<div class="ai-form">
|
||||
<el-form-item label="定时发送时间" style="width: 100%;" prop="choiceTime" :rules="[{ required: true, message: '请选择定时发送时间', trigger: 'change' }]">
|
||||
<el-date-picker
|
||||
style="width: 100%;"
|
||||
v-model="dateForm.choiceTime"
|
||||
type="datetime"
|
||||
size="small"
|
||||
:picker-options="pickerOptions"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
placeholder="请选择定时发送时间">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-form>
|
||||
<div class="dialog-footer" slot="footer">
|
||||
<el-button @click="onClose">取消</el-button>
|
||||
<el-button @click="onDateForm" type="primary" :loading="isLoading2" style="width: 92px;">确认</el-button>
|
||||
</div>
|
||||
</ai-dialog>
|
||||
<!-- <ChooseMaterial ref="ChooseMaterial" :instance="instance" @change="onChooseChange"></ChooseMaterial> -->
|
||||
</div>
|
||||
</template>
|
||||
<template #footer>
|
||||
<el-button @click="cancel">取消</el-button>
|
||||
<el-button type="primary" @click="confirm(0)" :loading="isLoading1" style="width: 120px;">通知成员发送</el-button>
|
||||
<el-button type="primary" @click="confirm(1)">定时发送</el-button>
|
||||
</template>
|
||||
</ai-detail>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Phone from './Phone'
|
||||
import ChooseMaterial from './ChooseMaterial.vue'
|
||||
import { mapActions, mapState } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'Add',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
params: Object
|
||||
},
|
||||
|
||||
components: {
|
||||
Phone,
|
||||
ChooseMaterial
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
info: {},
|
||||
department: [],
|
||||
isShowChoose: false,
|
||||
isLoading1: false,
|
||||
isLoading2: false,
|
||||
fileList: [],
|
||||
isShowAddLink: false,
|
||||
isShowAddMiniapp: false,
|
||||
isShowDate: false,
|
||||
isLoading: false,
|
||||
linkForm: {
|
||||
linkPicUrl: [],
|
||||
linkDesc: '',
|
||||
linkTitle: '',
|
||||
linkUrl: ''
|
||||
},
|
||||
dateForm: {
|
||||
choiceTime: ''
|
||||
},
|
||||
miniAppForm: {
|
||||
mpAppid: '',
|
||||
mpPage: '',
|
||||
mpTitle: '',
|
||||
media: []
|
||||
},
|
||||
form: {
|
||||
content: '',
|
||||
choiceTime: '',
|
||||
contents: [],
|
||||
enableExamine: '0',
|
||||
taskEndTime: '',
|
||||
examines: [],
|
||||
wxGroups: [],
|
||||
markTag: [],
|
||||
wxGroupsName: '',
|
||||
sendScope: '1',
|
||||
sendType: 0,
|
||||
name: '',
|
||||
filterCriteria: [],
|
||||
taskTitle: '',
|
||||
examinesName: ''
|
||||
},
|
||||
girdNames: '',
|
||||
id: '',
|
||||
tagsList: [],
|
||||
pickerOptions: {
|
||||
disabledDate: e => {
|
||||
return e.getTime() < (Date.now() - 60 * 1000 * 60 * 24)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['user']),
|
||||
|
||||
groupLen() {
|
||||
let i = 0
|
||||
if(this.form.wxGroups && this.form.wxGroups.length) {
|
||||
this.form.wxGroups.forEach(v => {
|
||||
i = i + v.groupIds.split(',').length
|
||||
})
|
||||
}
|
||||
return i
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
if (this.params && this.params.id) {
|
||||
this.id = this.params.id
|
||||
this.getInfo(this.params.id)
|
||||
this.dict.load('mstTag')
|
||||
} else {
|
||||
this.getWxGroups()
|
||||
this.dict.load('mstTag')
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
...mapActions(['initOpenData', 'transCanvas']),
|
||||
|
||||
onChooseChange (e) {
|
||||
this.form.content = e.filter(v => v.msgType === '0').map(v => v.content).join(' ')
|
||||
|
||||
this.fileList = this.fileList.concat(e.filter(v => v.msgType !== '0'))
|
||||
},
|
||||
|
||||
getInfo(id) {
|
||||
this.instance.post(`/app/appmasssendingtask/queryDetailById?id=${id}`).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.form = {
|
||||
...this.form,
|
||||
...res.data,
|
||||
wxGroupsName: '1',
|
||||
filterCriteria: res.data.filterCriteria.split(','),
|
||||
markTag: res.data.markTag.split(',')
|
||||
}
|
||||
|
||||
if (res.data.girdNames) {
|
||||
this.girdNames = res.data.girdNames.split(',')
|
||||
}
|
||||
|
||||
this.dateForm.choiceTime = ''
|
||||
|
||||
if (res.data.examines && res.data.examines.length) {
|
||||
this.form.examines = res.data.examines.map(v => {
|
||||
return {
|
||||
...v,
|
||||
wxOpenUserId: v.examineUserId,
|
||||
id: v.examineUserId,
|
||||
name: v.examineUserName
|
||||
}
|
||||
})
|
||||
this.form.examinesName = '1'
|
||||
}
|
||||
|
||||
|
||||
const content = res.data.contents.filter(v => v.msgType === '0')
|
||||
|
||||
if (content.length) {
|
||||
this.$set(this.form, 'content', content[0].content)
|
||||
}
|
||||
|
||||
this.fileList = res.data.contents.filter(v => v.msgType !== '0').map(v => {
|
||||
return {
|
||||
...v,
|
||||
...v.sysFile
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
onUserChange(e) {
|
||||
if (e.length) {
|
||||
this.form.examinesName = '1'
|
||||
} else {
|
||||
this.form.wxGroupsName = ''
|
||||
}
|
||||
},
|
||||
|
||||
onScopeChange(e) {
|
||||
this.form.filterCriteria = []
|
||||
this.form.wxGroups = []
|
||||
this.girdNames = ''
|
||||
|
||||
if (e === '0') {
|
||||
this.getWxGroups()
|
||||
} else {
|
||||
this.form.filterCriteria = []
|
||||
}
|
||||
},
|
||||
|
||||
onPick(e) {
|
||||
if (this.form.sendScope === '2' && e.length) {
|
||||
this.girdNames = e.map(v => v.girdName)
|
||||
}
|
||||
},
|
||||
|
||||
onSelcetChange(e) {
|
||||
if (e.length) {
|
||||
this.form.wxGroupsName = '1'
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.getWxGroups()
|
||||
})
|
||||
} else {
|
||||
this.form.wxGroupsName = ''
|
||||
this.form.wxGroups = []
|
||||
}
|
||||
},
|
||||
|
||||
getWxGroups() {
|
||||
this.instance.post(`/app/appmasssendingtask/queryWxGroups?sendScope=${this.form.sendScope}`, {
|
||||
filterCriteria: this.form.filterCriteria.join(',')
|
||||
}).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.form.wxGroups = res.data
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
onLinkConfirm() {
|
||||
this.$refs.linkForm.validate((valid) => {
|
||||
if (valid) {
|
||||
this.fileList.push({
|
||||
...this.linkForm,
|
||||
linkPicUrl: this.linkForm.linkPicUrl.length ? this.linkForm.linkPicUrl[0].url : '',
|
||||
msgType: '4'
|
||||
})
|
||||
|
||||
this.isShowAddLink = false
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
onMiniAppForm() {
|
||||
this.$refs.miniAppForm.validate((valid) => {
|
||||
if (valid) {
|
||||
this.fileList.push({
|
||||
...this.miniAppForm,
|
||||
msgType: '5',
|
||||
...this.miniAppForm.media[0],
|
||||
mediaId: this.miniAppForm.media[0].media.mediaId,
|
||||
sysFileId: this.miniAppForm.media[0].id
|
||||
})
|
||||
|
||||
this.isShowAddMiniapp = false
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
onClose() {
|
||||
this.linkForm.linkPicUrl = []
|
||||
this.linkForm.linkDesc = ''
|
||||
this.linkForm.linkTitle = ''
|
||||
this.linkForm.linkUrl = ''
|
||||
this.miniAppForm.mpAppid = ''
|
||||
this.miniAppForm.mpPage = ''
|
||||
this.miniAppForm.mpTitle = ''
|
||||
this.dateForm.choiceTime = ''
|
||||
|
||||
this.isShowDate = false
|
||||
},
|
||||
|
||||
removeFile(index) {
|
||||
this.fileList.splice(index, 1)
|
||||
},
|
||||
|
||||
mapIcon(type) {
|
||||
return {
|
||||
1: 'https://cdn.cunwuyun.cn/dvcp/announce/img.png',
|
||||
2: 'https://cdn.cunwuyun.cn/dvcp/announce/video.png',
|
||||
3: 'https://cdn.cunwuyun.cn/dvcp/announce/folder.png',
|
||||
4: 'https://cdn.cunwuyun.cn/dvcp/announce/site.png',
|
||||
5: 'https://cdn.cunwuyun.cn/dvcp/announce/miniapp.png'
|
||||
}[type]
|
||||
},
|
||||
|
||||
onBeforeUpload(event) {
|
||||
return this.onOverSize(event)
|
||||
},
|
||||
|
||||
getExtension(name) {
|
||||
return name.substring(name.lastIndexOf('.'))
|
||||
},
|
||||
|
||||
handleChange(e, size, accept) {
|
||||
const isLt10M = e.size / 1024 / 1024 < size
|
||||
const suffixName = this.getExtension(e.name)
|
||||
const suffixNameList = accept.split(',')
|
||||
|
||||
if (suffixNameList.indexOf(`${suffixName.toLowerCase()}`) === -1) {
|
||||
this.$message.error(`不支持该格式`)
|
||||
return false
|
||||
}
|
||||
|
||||
if (!isLt10M) {
|
||||
this.$message.error(`大小不超过${10}MB!`)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
},
|
||||
|
||||
onExceed() {
|
||||
this.$message.error(`最多上传9个附件`)
|
||||
},
|
||||
|
||||
submitUpload(file, type) {
|
||||
const fileType = {
|
||||
'1': 'image',
|
||||
'2': 'video',
|
||||
'3': 'file'
|
||||
}[type]
|
||||
let formData = new FormData()
|
||||
formData.append('file', file.file)
|
||||
formData.append('type', fileType)
|
||||
let loading = this.$loading()
|
||||
this.instance.post(`/app/wxcp/upload/uploadFile`, formData, {
|
||||
withCredentials: false
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.fileList.push({
|
||||
...res.data.file,
|
||||
media: res.data.media,
|
||||
msgType: type,
|
||||
sysFileId: res.data.file.id,
|
||||
imgPicUrl: res.data.file.url,
|
||||
mediaId: res.data.media.mediaId
|
||||
})
|
||||
|
||||
this.$message.success('上传成功')
|
||||
}
|
||||
}).finally(() => loading.close())
|
||||
},
|
||||
|
||||
onDateForm() {
|
||||
this.$refs.dateForm.validate((valid) => {
|
||||
if (valid) {
|
||||
if (new Date(this.dateForm.choiceTime).getTime() < Date.now()) {
|
||||
return this.$message.error('定时发送时间不得早于当前时间')
|
||||
}
|
||||
|
||||
if (this.params.sendChannel === '1' && new Date(this.dateForm.choiceTime).getTime() > new Date(this.form.taskEndTime).getTime()) {
|
||||
return this.$message.error('定时发送时间不得晚于结束时间')
|
||||
}
|
||||
|
||||
this.confirm(1)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
confirm(sendType) {
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (valid) {
|
||||
if (!this.form.wxGroups.length) {
|
||||
return this.$message.error('居民群数量不能为0')
|
||||
}
|
||||
|
||||
if (this.params.sendChannel === '1' && new Date(this.form.taskEndTime).getTime() < Date.now()) {
|
||||
return this.$message.error('结束时间不得早于当前时间')
|
||||
}
|
||||
|
||||
if (sendType === 1 && !this.dateForm.choiceTime) {
|
||||
this.isShowDate = true
|
||||
return false
|
||||
}
|
||||
|
||||
const contents = [
|
||||
{
|
||||
content: this.form.content,
|
||||
msgType: '0'
|
||||
},
|
||||
...this.fileList
|
||||
]
|
||||
|
||||
if (sendType === 0) {
|
||||
this.isLoading1 = true
|
||||
} else {
|
||||
this.isLoading2 = true
|
||||
}
|
||||
this.instance.post(`/app/appmasssendingtask/addOrUpdate`, {
|
||||
...this.form,
|
||||
id: this.params.id,
|
||||
wxGroups: this.form.wxGroups,
|
||||
contents,
|
||||
sendType,
|
||||
markTag: this.form.markTag.join(','),
|
||||
sendChannel: this.params.sendChannel,
|
||||
choiceTime: this.dateForm.choiceTime,
|
||||
filterCriteria: this.form.filterCriteria.join(','),
|
||||
examines: this.form.examines.length ? this.form.examines.map(v => {
|
||||
return {
|
||||
...v,
|
||||
examineUserId: v.id,
|
||||
examineUserName: v.name
|
||||
}
|
||||
}) : []
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('提交成功')
|
||||
setTimeout(() => {
|
||||
this.cancel(true)
|
||||
}, 600)
|
||||
} else {
|
||||
this.isLoading1 = false
|
||||
this.isLoading2 = false
|
||||
}
|
||||
|
||||
}).catch(() => {
|
||||
this.isLoading1 = false
|
||||
this.isLoading2 = false
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
selectDept() {
|
||||
return this.$message.error(`您未在系统中关联‘主部门’,请联系管理员处理`)
|
||||
},
|
||||
|
||||
cancel(isRefresh) {
|
||||
this.$emit('change', {
|
||||
type: 'list',
|
||||
isRefresh: !!isRefresh
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.el-tooltip__popper.is-dark {
|
||||
max-width: 240px;
|
||||
}
|
||||
.AppAnnounceDetail-content-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.content-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
line-height: 1;
|
||||
margin-right: 4px;
|
||||
text-align: center;
|
||||
background: #F9F9F9;
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
p {
|
||||
color: #222;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.AppAnnounceAdd {
|
||||
.ai-detail__content {
|
||||
.ai-detail__content--wrapper {
|
||||
position: relative;
|
||||
max-width: 100%;
|
||||
margin: 0;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.ai-form {
|
||||
textarea {
|
||||
border-radius: 4px 4px 0 0!important;
|
||||
}
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.add {
|
||||
display: flex;
|
||||
position: relative;
|
||||
flex-direction: column;
|
||||
padding: 14px 16px;
|
||||
background: #F9F9F9;
|
||||
border-radius: 0px 0px 4px 4px;
|
||||
border: 1px solid #D0D4DC;
|
||||
border-top: none;
|
||||
|
||||
.add-material {
|
||||
position: absolute;
|
||||
bottom: 14px;
|
||||
left: 16px;
|
||||
transform: translateX(120%);
|
||||
}
|
||||
|
||||
.add-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
line-height: 1;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin-right: 2px;
|
||||
}
|
||||
|
||||
span {
|
||||
color: #222;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.fileList {
|
||||
margin-bottom: 12px;
|
||||
|
||||
.add-item {
|
||||
justify-content: space-between;
|
||||
margin-bottom: 8px;
|
||||
|
||||
.left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
i {
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
font-style: normal;
|
||||
color: red;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.AppAnnounceDetail-container {
|
||||
display: flex;
|
||||
position: relative;
|
||||
height: 100%;
|
||||
padding: 0 20px;
|
||||
overflow: auto;
|
||||
overflow: overlay;
|
||||
|
||||
.left {
|
||||
flex: 1;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.right {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.AppAnnounceDetail-select {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-height: 32px;
|
||||
line-height: 1;
|
||||
background: #F5F5F5;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #D0D4DC;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||
|
||||
&:hover {
|
||||
border-color: #26f;
|
||||
}
|
||||
|
||||
& > i {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
line-height: 32px;
|
||||
padding: 0 12px;
|
||||
color: #888888;
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
border-right: 1px solid #D0D4DC;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.AppAnnounceDetail-select__input {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: -1;
|
||||
opacity: 0;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.select-right {
|
||||
height: 100%;
|
||||
padding: 0 12px;
|
||||
color: #222222;
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
transition: all ease 0.3s;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
.select-left {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
flex: 1;
|
||||
padding: 5px 0 0px 12px;
|
||||
border-right: 1px solid #D0D4DC;
|
||||
border-radius: 4px 0 0 4px;
|
||||
background: #fff;
|
||||
|
||||
em {
|
||||
height: 22px;
|
||||
line-height: 22px;
|
||||
margin: 0 4px 5px 0;
|
||||
color: #222222;
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
span {
|
||||
height: 22px;
|
||||
line-height: 22px;
|
||||
margin: 0 4px 5px 0;
|
||||
padding: 0 8px;
|
||||
font-size: 12px;
|
||||
color: #222222;
|
||||
background: #F3F4F7;
|
||||
border-radius: 2px;
|
||||
border: 1px solid #D0D4DC;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tips {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 14px;
|
||||
color: #222222;
|
||||
|
||||
span {
|
||||
margin: 0 3px;
|
||||
color: #2266FF;
|
||||
}
|
||||
|
||||
i {
|
||||
color: #8899bb;
|
||||
}
|
||||
|
||||
em {
|
||||
line-height: 20px;
|
||||
margin-top: 8px;
|
||||
color: #888888;
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
}
|
||||
}
|
||||
.select-div {
|
||||
width: 100%;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #ddd;
|
||||
padding: 0 15px;
|
||||
box-sizing: border-box;
|
||||
font-size: 14px;
|
||||
color: #999;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,221 @@
|
||||
<template>
|
||||
<div id="ChooseMaterial">
|
||||
<ai-dialog
|
||||
:visible.sync="isShow"
|
||||
width="890px"
|
||||
@onConfirm="onConfirm"
|
||||
title="选择素材">
|
||||
<div class="AppMaterialLibrary-title">
|
||||
<span
|
||||
v-for="(item, index) in typeList"
|
||||
:key="index"
|
||||
:class="[currIndex === index ? 'active' : '']" @click="currIndex = index, search.current = 1, getList()">
|
||||
{{ item }}
|
||||
</span>
|
||||
</div>
|
||||
<ai-search-bar class="search-bar">
|
||||
<template #left>
|
||||
</template>
|
||||
<template slot="right">
|
||||
<el-input
|
||||
v-model="search.title"
|
||||
size="small"
|
||||
v-throttle="() => { search.current = 1, getList() }"
|
||||
placeholder="请输入标题、话术内容、添加人"
|
||||
clearable
|
||||
@clear="search.current = 1, search.title = '', getList()"
|
||||
suffix-icon="iconfont iconSearch">
|
||||
</el-input>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table
|
||||
v-if="isShow"
|
||||
:tableData="tableData"
|
||||
:col-configs="colConfigs"
|
||||
:total="total"
|
||||
style="margin-top: 6px; width: 100%;"
|
||||
:current.sync="search.current"
|
||||
:size.sync="search.size"
|
||||
@selection-change="onSelectChange"
|
||||
@getList="getList">
|
||||
</ai-table>
|
||||
</ai-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ChooseMaterial',
|
||||
|
||||
props: {
|
||||
instance: Function
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
search: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
title: '',
|
||||
},
|
||||
ids: [],
|
||||
isShow: false,
|
||||
id: '',
|
||||
typeList: ['话术', '图片', '小程序', '文件', '视频', '网页'],
|
||||
currIndex: 0,
|
||||
tableData: [],
|
||||
total: 0,
|
||||
value: []
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
mpTitle () {
|
||||
return {
|
||||
'0': '话术标题',
|
||||
'1': '图片名称',
|
||||
'2': '小程序标题',
|
||||
'3': '文件名称',
|
||||
'4': '视频名称',
|
||||
'5': '网页名称'
|
||||
}[this.currIndex]
|
||||
},
|
||||
|
||||
colConfigs () {
|
||||
if (this.currIndex === 0) {
|
||||
return [
|
||||
{ type: 'selection' },
|
||||
{ prop: 'title', label: this.mpTitle },
|
||||
{ prop: 'content', label: '话术内容', align: 'center' },
|
||||
{ prop: 'createUserName', label: '添加人', align: 'center' },
|
||||
{ prop: 'createTime', label: '添加时间', align: 'center' }
|
||||
]
|
||||
}
|
||||
|
||||
if (this.currIndex === 2) {
|
||||
return [
|
||||
{ type: 'selection' },
|
||||
{ prop: 'mpTitle', label: this.mpTitle },
|
||||
{ prop: 'mpAppid', label: '小程序APPID', align: 'center' },
|
||||
{ prop: 'createUserName', label: '添加人', align: 'center' },
|
||||
{ prop: 'createTime', label: '添加时间', align: 'center' }
|
||||
]
|
||||
}
|
||||
|
||||
if (this.currIndex === 5) {
|
||||
return [
|
||||
{ type: 'selection' },
|
||||
{ prop: 'linkTitle', label: this.mpTitle },
|
||||
{ prop: 'linkUrl', label: '外链网页', align: 'center' },
|
||||
{ prop: 'createUserName', label: '添加人', align: 'center' },
|
||||
{ prop: 'createTime', label: '添加时间', align: 'center' }
|
||||
]
|
||||
}
|
||||
|
||||
return [
|
||||
{ type: 'selection' },
|
||||
{ prop: 'title', label: this.mpTitle },
|
||||
{ prop: 'fileSizeStr', label: '文件大小', align: 'center' },
|
||||
{ prop: 'createUserName', label: '添加人', align: 'center' },
|
||||
{ prop: 'createTime', label: '添加时间', align: 'center' }
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
created () {
|
||||
this.getList()
|
||||
},
|
||||
|
||||
methods: {
|
||||
getList() {
|
||||
this.instance.post(`/app/appmaterialinfo/listByMST`, null, {
|
||||
params: {
|
||||
...this.search,
|
||||
mstType: 0,
|
||||
type: this.currIndex
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.tableData = res.data.records
|
||||
this.total = res.data.total
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
onSelectChange (e) {
|
||||
this.value = e
|
||||
},
|
||||
|
||||
onConfirm () {
|
||||
if (!this.value.length) {
|
||||
return this.$message.error('请选择素材')
|
||||
}
|
||||
|
||||
if (this.value.length > 9) {
|
||||
return this.$message.error('素材不能超过9个')
|
||||
}
|
||||
|
||||
this.$emit('change', this.value)
|
||||
this.isShow = false
|
||||
},
|
||||
|
||||
open () {
|
||||
this.value = []
|
||||
this.isShow = true
|
||||
},
|
||||
|
||||
close () {
|
||||
this.isShow = false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
#ChooseMaterial {
|
||||
:deep( .ai-list__content--right-wrapper ) {
|
||||
padding: 0 20px!important;
|
||||
}
|
||||
|
||||
:deep( .el-dialog__header ) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
:deep( .el-dialog__body ) {
|
||||
padding-top: 0!important;
|
||||
}
|
||||
|
||||
.AppMaterialLibrary-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
border-bottom: 1px solid #eee;
|
||||
|
||||
span {
|
||||
height: 100%;
|
||||
line-height: 56px;
|
||||
margin-right: 32px;
|
||||
color: #888888;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
transition: all ease 0.3s;
|
||||
border-bottom: 3px solid transparent;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
|
||||
&:hover {
|
||||
color: #222;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
&.active {
|
||||
color: #222222;
|
||||
border-bottom: 3px solid #2266FF;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
783
project/lulong/Announce/AppAnnounce/components/Detail.vue
Normal file
783
project/lulong/Announce/AppAnnounce/components/Detail.vue
Normal file
@@ -0,0 +1,783 @@
|
||||
<template>
|
||||
<ai-detail class="AppAnnounceDetail">
|
||||
<template slot="title">
|
||||
<ai-title title="群发居民群详情" isShowBack isShowBottomBorder @onBackClick="cancel(false)">
|
||||
</ai-title>
|
||||
</template>
|
||||
<template slot="content">
|
||||
<ai-card title="基础信息">
|
||||
<template #right>
|
||||
<div class="right-tips" v-if="info.status === '4'">
|
||||
<el-tooltip
|
||||
placement="top"
|
||||
content="任务开始后,3天内15分钟更新1次,3天后访问页面时触发更新,1小时最多刷新1次">
|
||||
<i class="iconfont iconDetails"></i>
|
||||
</el-tooltip>
|
||||
<span>数据更新于{{ info.dataUpdateTime }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<template #content>
|
||||
<ai-wrapper>
|
||||
<ai-info-item label="任务名称" isLine :value="info.taskTitle"></ai-info-item>
|
||||
<ai-info-item label="任务状态" isLine>
|
||||
<span :style="{ color: dict.getColor('mstStatus', info.status) }">{{ dict.getLabel('mstStatus', info.status) }}</span>
|
||||
</ai-info-item>
|
||||
<ai-info-item label="创建人" isLine>
|
||||
<div class="user">
|
||||
<img src="https://cdn.cunwuyun.cn/dvcp/announce/user.png" />
|
||||
<span>{{ info.createUserName }}</span>
|
||||
(<span>{{ info.createUserDeptName }}</span>)
|
||||
</div>
|
||||
</ai-info-item>
|
||||
<ai-info-item label="审批人" isLine v-if="info.enableExamine === '1'">
|
||||
<div class="user-wrapper">
|
||||
<div class="user" v-for="(item, index) in info.examines" :key="index">
|
||||
<img src="https://cdn.cunwuyun.cn/dvcp/announce/user.png" />
|
||||
<span>{{ item.examineUserName }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</ai-info-item>
|
||||
<ai-info-item label="发送方式">
|
||||
<span>{{ info.sendChannel === '1' ? '通知员工转发' : '成员一键群发' }}</span>
|
||||
</ai-info-item>
|
||||
<ai-info-item label="标签" :value="info.markTag">
|
||||
</ai-info-item>
|
||||
<ai-info-item label="创建时间" :value="info.createTime"></ai-info-item>
|
||||
<ai-info-item label="群发时间" :value="info.choiceTime"></ai-info-item>
|
||||
<ai-info-item label="结束时间" :value="info.taskEndTime" v-if="info.sendChannel === '1'"></ai-info-item>
|
||||
<ai-info-item label="群发范围" isLine>
|
||||
<div class="text">
|
||||
<span>{{ info.sendScope === '0' ? '全部' : '按条件筛选的' }}</span>
|
||||
<i>{{ groups.length }}</i>
|
||||
<span>个居民群</span>
|
||||
<em @click="isShowGroups = true">详情</em>
|
||||
</div>
|
||||
</ai-info-item>
|
||||
<ai-info-item label="消息内容" isLine>
|
||||
<div class="msg">
|
||||
<p>{{ content }}</p>
|
||||
<div class="msg-bottom">
|
||||
<div class="left" v-if="fileList.length">
|
||||
<img :src="mapIcon(fileList[0].msgType)" />
|
||||
<span>{{ mapType(fileList[0].msgType) }}{{ fileList[0].mpTitle || fileList[0].name || fileList[0].linkTitle }} 等</span>
|
||||
<i>{{ fileList.length }}</i>
|
||||
<span>个附件</span>
|
||||
</div>
|
||||
<div class="left" v-else>
|
||||
<span>暂无附件</span>
|
||||
</div>
|
||||
<div class="right" @click="isShowPhone = true">预览消息</div>
|
||||
</div>
|
||||
</div>
|
||||
</ai-info-item>
|
||||
</ai-wrapper>
|
||||
</template>
|
||||
</ai-card>
|
||||
<ai-card>
|
||||
<template #title>
|
||||
<div class="AppAnnounceDetail-title">
|
||||
<span :class="[currIndex === 0 ? 'active' : '']" @click="currIndex = 0">成员统计</span>
|
||||
<span :class="[currIndex === 1 ? 'active' : '']" @click="currIndex = 1">居民群统计</span>
|
||||
</div>
|
||||
</template>
|
||||
<template #content>
|
||||
<div class="content-item" v-if="currIndex === 0">
|
||||
<div class="top">
|
||||
<div class="top-item">
|
||||
<div class="top-item__title">
|
||||
<h3>计划执行成员</h3>
|
||||
</div>
|
||||
<p>{{ memberInfo.planCount || 0 }}</p>
|
||||
</div>
|
||||
<div class="top-item">
|
||||
<div class="top-item__title">
|
||||
<h3>未执行成员</h3>
|
||||
</div>
|
||||
<p>{{ memberInfo.unExecutedCount || 0 }}</p>
|
||||
</div>
|
||||
<div class="top-item">
|
||||
<div class="top-item__title">
|
||||
<h3>已执行成员</h3>
|
||||
</div>
|
||||
<p>{{ memberInfo.executedCount || 0 }}</p>
|
||||
</div>
|
||||
<div class="top-item" v-if="info.sendChannel === '0'">
|
||||
<div class="top-item__title">
|
||||
<h3>无法执行成员</h3>
|
||||
<el-tooltip
|
||||
placement="top"
|
||||
content="由于员工不在可见范围、离职、客户群接收已达到上限等原因,无法执行群发任务的成员总数">
|
||||
<i class="iconfont iconDetails"></i>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<p>{{ memberInfo.cannotExecuteCount || 0 }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bottom">
|
||||
<div class="bottom-search">
|
||||
<div class="left">
|
||||
<el-radio-group v-model="search1.sendStatus" size="small" @change="search1.current = 1, getMemberInfo()">
|
||||
<el-radio-button size="small" label="0">未执行</el-radio-button>
|
||||
<el-radio-button size="small" label="1">已执行</el-radio-button>
|
||||
<el-radio-button size="small" label="2" v-if="info.sendChannel === '0'">无法执行</el-radio-button>
|
||||
</el-radio-group>
|
||||
<ai-picker
|
||||
dialogTitle="选择部门"
|
||||
action="/app/wxcp/wxdepartment/departList"
|
||||
:instance="instance"
|
||||
@pick="e => onUserChange(e, 'search1')" :multiple="false" v-model="user1">
|
||||
<div class="userSelcet">
|
||||
<span style="color: #606266;" v-if="search1.deptartId">{{ name1 }}</span>
|
||||
<span v-else>部门</span>
|
||||
<i class="el-icon-arrow-up" v-if="!search1.deptartId"></i>
|
||||
<i class="el-icon-circle-close" v-if="search1.deptartId" @click.stop="user1 = [], search1.deptartId = '', search1.current = 1, getMemberInfo()"></i>
|
||||
</div>
|
||||
</ai-picker>
|
||||
</div>
|
||||
<el-button :type="isDisabled ? '' : 'primary'" :disabled="isDisabled" @click="sendMsg(0)" v-if="info.status === '4'">{{ isDisabled ? min + '分钟后可再次提醒' : '提醒成员发送' }}</el-button>
|
||||
</div>
|
||||
<ai-table
|
||||
:tableData="tableData1"
|
||||
:col-configs="colConfigs1"
|
||||
:total="total1"
|
||||
border
|
||||
tableSize="small"
|
||||
:current.sync="search1.current"
|
||||
:size.sync="search1.size"
|
||||
@getList="getMemberInfo">
|
||||
<el-table-column slot="user" label="成员" align="left">
|
||||
<template slot-scope="{ row }">
|
||||
<div class="userinfo">
|
||||
<span>{{ row.groupOwnerName }}</span>
|
||||
<span style="color: #999">{{ row.mainDepartmentName }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content-item" v-if="currIndex === 1">
|
||||
<div class="top">
|
||||
<div class="top-item">
|
||||
<div class="top-item__title">
|
||||
<h3>计划送达居民群</h3>
|
||||
</div>
|
||||
<p>{{ groupInfo.planCount || 0 }}</p>
|
||||
</div>
|
||||
<div class="top-item">
|
||||
<div class="top-item__title">
|
||||
<h3>未送达居民群</h3>
|
||||
</div>
|
||||
<p>{{ groupInfo.unExecutedCount || 0 }}</p>
|
||||
</div>
|
||||
<div class="top-item">
|
||||
<div class="top-item__title">
|
||||
<h3>已送达居民群</h3>
|
||||
</div>
|
||||
<p>{{ groupInfo.executedCount || 0 }}</p>
|
||||
</div>
|
||||
<div class="top-item" v-if="info.sendChannel === '0'">
|
||||
<div class="top-item__title">
|
||||
<h3>无法送达居民群</h3>
|
||||
</div>
|
||||
<p>{{ groupInfo.cannotExecuteCount || 0 }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bottom">
|
||||
<div class="bottom-search">
|
||||
<div class="left">
|
||||
<el-radio-group v-model="search2.sendStatus" size="small" @change="search2.current = 1, getGroupInfo()">
|
||||
<el-radio-button size="small" label="0">未送达</el-radio-button>
|
||||
<el-radio-button size="small" label="1">已送达</el-radio-button>
|
||||
<el-radio-button size="small" label="2" v-if="info.sendChannel === '0'">无法送达</el-radio-button>
|
||||
</el-radio-group>
|
||||
<ai-picker
|
||||
dialogTitle="选择部门"
|
||||
action="/app/wxcp/wxdepartment/departList"
|
||||
:instance="instance"
|
||||
@pick="e => onUserChange(e, 'search2')" :multiple="false" v-model="user2">
|
||||
<div class="userSelcet">
|
||||
<span style="color: #606266;" v-if="search2.deptartId">{{ name2 }}</span>
|
||||
<span v-else>部门</span>
|
||||
<i class="el-icon-arrow-up" v-if="!search2.deptartId"></i>
|
||||
<i class="el-icon-circle-close" v-if="search2.deptartId" @click.stop="user1 = [], search2.deptartId = '', search2.current = 1, getGroupInfo()"></i>
|
||||
</div>
|
||||
</ai-picker>
|
||||
</div>
|
||||
<el-button :type="isDisabled ? '' : 'primary'" :disabled="isDisabled" @click="sendMsg(1)" v-if="info.status === '4'">{{ isDisabled ? min + '分钟后可再次提醒' : '提醒成员发送' }}</el-button>
|
||||
</div>
|
||||
<ai-table
|
||||
:tableData="tableData2"
|
||||
:col-configs="colConfigs2"
|
||||
:total="total2"
|
||||
border
|
||||
tableSize="small"
|
||||
:current.sync="search2.current"
|
||||
:size.sync="search2.size"
|
||||
@getList="getGroupInfo">
|
||||
<el-table-column slot="user" label="群主" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<div class="userinfo">
|
||||
<span>{{ row.groupOwnerName }}</span>
|
||||
<span style="color: #999">{{ row.mainDepartmentName }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</ai-card>
|
||||
<ai-dialog
|
||||
:visible.sync="isShowGroups"
|
||||
width="890px"
|
||||
title="群发范围"
|
||||
customFooter
|
||||
@onConfirm="isShowGroups = false">
|
||||
<ai-table
|
||||
:tableData="info.wxGroups"
|
||||
:col-configs="colConfigs3"
|
||||
border
|
||||
tableSize="small"
|
||||
:isShowPagination="false"
|
||||
@getList="() => {}">
|
||||
</ai-table>
|
||||
<div class="dialog-footer" slot="footer">
|
||||
<el-button @click="isShowGroups = false">关闭</el-button>
|
||||
</div>
|
||||
</ai-dialog>
|
||||
<div class="detail-phone" v-if="isShowPhone">
|
||||
<div class="mask"></div>
|
||||
<Phone :avatar="user.info.avatar" @close="isShowPhone = false" :isShowClose="true" :content="content" :fileList="fileList"></Phone>
|
||||
</div>
|
||||
</template>
|
||||
</ai-detail>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
import Phone from './Phone'
|
||||
export default {
|
||||
name: 'Detail',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
params: Object
|
||||
},
|
||||
|
||||
components: {
|
||||
Phone
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
total1: 0,
|
||||
isShowGroups: false,
|
||||
isShowPhone: false,
|
||||
total2: 0,
|
||||
user1: [],
|
||||
user2: [],
|
||||
name1: '',
|
||||
name2: '',
|
||||
radio1: '未执行',
|
||||
search1: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
deptartId: '',
|
||||
type: 0,
|
||||
sendStatus: '0'
|
||||
},
|
||||
search2: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
deptartId: '',
|
||||
type: 1,
|
||||
sendStatus: '0'
|
||||
},
|
||||
memberInfo: {},
|
||||
groupInfo: {},
|
||||
tableData1: [],
|
||||
fileList: [],
|
||||
tableData2: [],
|
||||
info: {},
|
||||
content: '',
|
||||
currIndex: 0,
|
||||
colConfigs3: [
|
||||
{ prop: 'groupOwnerName', label: '群主' },
|
||||
{ prop: 'groupNames', label: '群名称' }
|
||||
],
|
||||
colConfigs1: [
|
||||
{ slot: 'user', label: '成员' },
|
||||
{ prop: 'groupCount', label: '预计送达居民群', align: 'center' }
|
||||
],
|
||||
colConfigs2: [
|
||||
{ prop: 'groupName', label: '居民群' },
|
||||
{ prop: 'memberCount', label: '群人数', align: 'center' },
|
||||
{ slot: 'user', label: '群主', align: 'center' },
|
||||
],
|
||||
groups: [],
|
||||
timer: null,
|
||||
min: 60,
|
||||
isDisabled: false,
|
||||
rejecterId: ''
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['user'])
|
||||
},
|
||||
|
||||
created () {
|
||||
this.getInfo(this.params.id)
|
||||
this.getMemberInfo()
|
||||
this.getGroupInfo()
|
||||
},
|
||||
|
||||
destroyed () {
|
||||
clearInterval(this.timer)
|
||||
},
|
||||
|
||||
methods: {
|
||||
getMemberInfo () {
|
||||
this.instance.post(`/app/appmasssendingtask/detailStatistics`, null, {
|
||||
params: {
|
||||
...this.search1,
|
||||
taskId: this.params.id
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.tableData1 = res.data.executedList.records
|
||||
this.total1 = res.data.executedList.total
|
||||
this.memberInfo = res.data
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
onUserChange (e, search) {
|
||||
if (e.length) {
|
||||
search === 'search1' ? this.name1 = e[0].name : this.name2 = e[0].name
|
||||
this[search].deptartId = e[0].id
|
||||
} else {
|
||||
this[search].deptartId = ''
|
||||
search === 'search1' ? this.name1 = '' : this.name2 = ''
|
||||
}
|
||||
|
||||
this[search].current = 1
|
||||
if (search === 'search1') {
|
||||
this.getMemberInfo()
|
||||
} else {
|
||||
this.getGroupInfo()
|
||||
}
|
||||
},
|
||||
|
||||
sendMsg () {
|
||||
this.instance.post(`/app/appmasssendingtask/remindSend?id=${this.params.id}`).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.$message.success('提醒成功')
|
||||
this.getInfo(this.params.id)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
getGroupInfo () {
|
||||
this.instance.post(`/app/appmasssendingtask/detailStatistics`, null, {
|
||||
params: {
|
||||
...this.search2,
|
||||
taskId: this.params.id
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.tableData2 = res.data.executedList.records.map(v => {
|
||||
return {
|
||||
...v,
|
||||
groupName: v.groupName || '未命名群聊'
|
||||
}
|
||||
})
|
||||
this.total2 = res.data.executedList.total
|
||||
this.groupInfo = res.data
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
countdown () {
|
||||
this.timer = setInterval(() => {
|
||||
const nowTime = this.$moment(new Date())
|
||||
const min = nowTime.diff(this.info.remindTime, 'minute')
|
||||
this.min = (60 - min)
|
||||
|
||||
if (this.min <= 0) {
|
||||
this.isDisabled = false
|
||||
clearInterval(this.timer)
|
||||
} else {
|
||||
this.isDisabled = true
|
||||
}
|
||||
}, 1000)
|
||||
},
|
||||
|
||||
getInfo (id) {
|
||||
this.instance.post(`/app/appmasssendingtask/queryDetailById?id=${id}`).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.info = res.data
|
||||
if (res.data.status === '4' && res.data.remindTime) {
|
||||
this.countdown()
|
||||
}
|
||||
|
||||
const content = res.data.contents.filter(v => v.msgType === '0')
|
||||
|
||||
if (content.length) {
|
||||
this.content = content[0].content
|
||||
}
|
||||
|
||||
this.fileList = res.data.contents.filter(v => v.msgType !== '0').map(v => {
|
||||
return {
|
||||
...v,
|
||||
...v.sysFile
|
||||
}
|
||||
})
|
||||
|
||||
this.info.wxGroups = res.data.wxGroups.map(v => {
|
||||
this.groups.push(...v.groupIds.split(','))
|
||||
|
||||
return {
|
||||
...v,
|
||||
groupIds: v.groupIds.split(',')
|
||||
}
|
||||
})
|
||||
|
||||
if (res.data.examines && res.data.examines.length) {
|
||||
const user = res.data.examines.filter(v => v.examineStatus === '2')
|
||||
|
||||
if (user.length) {
|
||||
this.rejecterId = user[0].examineUserId
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
mapType (type) {
|
||||
return {
|
||||
1: '图片',
|
||||
2: '视频',
|
||||
3: '文件',
|
||||
4: '网站',
|
||||
5: '小程序'
|
||||
}[type]
|
||||
},
|
||||
|
||||
mapIcon (type) {
|
||||
return {
|
||||
1: 'https://cdn.cunwuyun.cn/dvcp/announce/img.png',
|
||||
2: 'https://cdn.cunwuyun.cn/dvcp/announce/video.png',
|
||||
3: 'https://cdn.cunwuyun.cn/dvcp/announce/folder.png',
|
||||
4: 'https://cdn.cunwuyun.cn/dvcp/announce/site.png',
|
||||
5: 'https://cdn.cunwuyun.cn/dvcp/announce/miniapp.png'
|
||||
}[type]
|
||||
},
|
||||
|
||||
cancel (isRefresh) {
|
||||
this.$emit('change', {
|
||||
type: 'list',
|
||||
isRefresh: !!isRefresh
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.AppAnnounceDetail {
|
||||
position: relative;
|
||||
.user-wrapper {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.detail-phone {
|
||||
position: fixed;
|
||||
left: 0%;
|
||||
top: 0%;
|
||||
z-index: 11;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.mask {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: 1;
|
||||
background: rgba($color: #000000, $alpha: 0.6);
|
||||
}
|
||||
|
||||
:deep( .phone-container ){
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
z-index: 11;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
}
|
||||
.userSelcet {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 215px;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
margin-left: 12px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #d0d4dc;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||
|
||||
&:hover {
|
||||
border-color: #26f;
|
||||
}
|
||||
|
||||
i {
|
||||
display: flex;
|
||||
position: relative;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 30px;
|
||||
height: 100%;
|
||||
line-height: 32px;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
color: #d0d4dc;
|
||||
transform: rotateZ(180deg);
|
||||
}
|
||||
|
||||
.el-icon-circle-close:hover {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
span {
|
||||
flex: 1;
|
||||
padding: 0 15px;
|
||||
font-size: 12px;
|
||||
color: $placeholderColor;
|
||||
}
|
||||
}
|
||||
|
||||
.userinfo {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
line-height: 1;
|
||||
|
||||
span:first-child {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
}
|
||||
.user {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
line-height: 1;
|
||||
margin-right: 8px;
|
||||
|
||||
img {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-right: 2px;
|
||||
}
|
||||
|
||||
span {
|
||||
position: relative;
|
||||
top: 2px;
|
||||
color: #222222;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.text {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
i {
|
||||
color: #2266FF;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
em {
|
||||
margin-left: 8px;
|
||||
color: #2266FF;
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
cursor: pointer;
|
||||
transition: all ease 0.3s;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.msg {
|
||||
background: #F9F9F9;
|
||||
border-radius: 2px;
|
||||
border: 1px solid #D0D4DC;
|
||||
|
||||
p {
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 1;
|
||||
-webkit-box-orient: vertical;
|
||||
line-height: 38px;
|
||||
padding: 0px 12px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.msg-bottom {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
height: 38px;
|
||||
padding: 0 16px;
|
||||
border-top: 1px solid #D0D4DC;
|
||||
|
||||
.left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
img {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
span {
|
||||
color: #222222;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
i {
|
||||
color: #2266FF;
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
}
|
||||
}
|
||||
|
||||
.right {
|
||||
color: #2266FF;
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:deep( .AppAnnounceDetail-title ){
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
span {
|
||||
height: 100%;
|
||||
line-height: 56px;
|
||||
margin-right: 32px;
|
||||
color: #888888;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
transition: all ease 0.3s;
|
||||
border-bottom: 3px solid transparent;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
|
||||
&:hover {
|
||||
color: #222;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
&.active {
|
||||
color: #222222;
|
||||
border-bottom: 3px solid #2266FF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.content-item {
|
||||
.top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 16px;
|
||||
|
||||
.top-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
flex: 1;
|
||||
height: 90px;
|
||||
margin-right: 16px;
|
||||
padding: 0 16px;
|
||||
background: #F9F9F9;
|
||||
border-radius: 2px;
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.top-item__title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 8px;
|
||||
|
||||
i {
|
||||
margin-left: 4px;
|
||||
color: #8899bb;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
h3 {
|
||||
color: #222222;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
p {
|
||||
color: #2266FF;
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bottom-search {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 16px;
|
||||
|
||||
.left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:deep( .right-tips ){
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
i {
|
||||
margin-right: 4px;
|
||||
color: #8899bb;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
span {
|
||||
color: #888888;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
432
project/lulong/Announce/AppAnnounce/components/List.vue
Normal file
432
project/lulong/Announce/AppAnnounce/components/List.vue
Normal file
@@ -0,0 +1,432 @@
|
||||
<template>
|
||||
<ai-list class="AppAnnounce">
|
||||
<template slot="title">
|
||||
<ai-title title="群发居民群" isShowBottomBorder>
|
||||
<template #sub>
|
||||
<span>管理员统一创建宣发任务,选择要发送的居民群后通知群主发送,群主确认后即可群发到居民群。群主向同一个居民群每天最多可群发10条消息。</span>
|
||||
</template>
|
||||
</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>
|
||||
<ai-select
|
||||
v-model="search.status"
|
||||
@change="search.current = 1, getList()"
|
||||
placeholder="任务状态"
|
||||
:selectList="dict.getDict('mstStatus')">
|
||||
</ai-select>
|
||||
<ai-select
|
||||
v-model="search.markTag"
|
||||
multiple
|
||||
collapse-tags
|
||||
@change="search.current = 1, getList()"
|
||||
placeholder="请选择标签"
|
||||
:selectList="dict.getDict('mstTag')">
|
||||
</ai-select>
|
||||
<el-date-picker
|
||||
v-model="search.startTime"
|
||||
type="date"
|
||||
size="small"
|
||||
value-format="yyyy-MM-dd"
|
||||
@change="search.current = 1, getList()"
|
||||
placeholder="选择群发开始日期">
|
||||
</el-date-picker>
|
||||
<el-date-picker
|
||||
v-model="search.endTime"
|
||||
type="date"
|
||||
size="small"
|
||||
value-format="yyyy-MM-dd"
|
||||
@change="search.current = 1, getList()"
|
||||
placeholder="选择群发结束日期">
|
||||
</el-date-picker>
|
||||
<ai-user-selecter :instance="instance" @change="onUserChange" :isMultiple="false" v-model="userList" :actions="{tree: `/api/wxcp/wxdepartment/listAll?wxMainDepartmentId=${user.info.wxMainDepartmentId}`}" >
|
||||
<div class="userSelcet">
|
||||
<span style="color: #606266;" v-if="search.createUserId">{{ name }}</span>
|
||||
<span v-else>创建人</span>
|
||||
<i class="el-icon-arrow-up" v-if="!search.createUserId"></i>
|
||||
<i class="el-icon-circle-close" v-if="search.createUserId" @click.stop="userList = [], search.createUserId = '', name = '', search.current = 1, getList()"></i>
|
||||
</div>
|
||||
</ai-user-selecter>
|
||||
</template>
|
||||
<template slot="right">
|
||||
<el-input
|
||||
v-model="search.taskTitle"
|
||||
size="small"
|
||||
v-throttle="() => { search.current = 1, getList() }"
|
||||
placeholder="请输入任务名称"
|
||||
clearable
|
||||
@clear="search.current = 1, search.taskTitle = '', 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; width: 100%;"
|
||||
:current.sync="search.current"
|
||||
:size.sync="search.size"
|
||||
@getList="getList">
|
||||
<el-table-column slot="user" width="140px" label="创建人" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<div class="userinfo">
|
||||
<span>{{ row.createUserName }}</span>
|
||||
<span style="color: #999">{{ row.createUserDeptName }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="options" width="140px" fixed="right" label="操作" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<div class="table-options">
|
||||
<el-button type="text" @click="remindExamine(row.id)" v-if="['0'].includes(row.status)">催办</el-button>
|
||||
<el-button type="text" @click="close(row.id)" v-if="['4'].includes(row.status)">关闭</el-button>
|
||||
<el-button type="text" @click="cancel(row.id)" v-if="['0'].includes(row.status)">撤回</el-button>
|
||||
<el-button type="text" @click="toDetail(row.id)">详情</el-button>
|
||||
<el-button type="text" @click="toAdd(row.id)" v-if="['1', '3'].includes(row.status)">编辑</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,
|
||||
status: '',
|
||||
createUserId: '',
|
||||
taskTitle: '',
|
||||
startTime: '',
|
||||
endTime: '',
|
||||
markTag: ''
|
||||
},
|
||||
currIndex: '1',
|
||||
name: '',
|
||||
isShow: false,
|
||||
userList: [],
|
||||
tableData: [],
|
||||
loading: false,
|
||||
total: 0,
|
||||
colConfigs: [
|
||||
{ prop: 'taskTitle', label: '任务名称' },
|
||||
{ prop: 'typeName', label: '群发类型', align: 'center' },
|
||||
{ slot: 'user', label: '创建人', openType: 'userName', align: 'center' },
|
||||
{ prop: 'choiceTime', label: '群发时间', align: 'center' },
|
||||
{ prop: 'taskEndTime', label: '群发结束时间', align: 'center' },
|
||||
{ prop: 'markTag', label: '标签', align: 'center' },
|
||||
{
|
||||
prop: 'status',
|
||||
align: 'center',
|
||||
label: '状态',
|
||||
render: (h, {row}) => {
|
||||
return h('span', {
|
||||
style: {
|
||||
color: this.dict.getColor('mstStatus', row.status)
|
||||
}
|
||||
}, this.dict.getLabel('mstStatus', row.status))
|
||||
}
|
||||
},
|
||||
{ prop: 'completionRate', label: '任务完成率', align: 'center', format: v => v ? v === '0.0' ? '0%' : `${v}%` : '-' }
|
||||
]
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(['user']),
|
||||
},
|
||||
|
||||
created () {
|
||||
this.dict.load('mstStatus', 'mstSendType', 'mstTag').then(() => {
|
||||
this.getList()
|
||||
})
|
||||
},
|
||||
|
||||
methods: {
|
||||
onUserChange (e) {
|
||||
if (e.length) {
|
||||
this.name = e[0].name
|
||||
this.search.createUserId = e[0].id
|
||||
} else {
|
||||
this.search.createUserId = ''
|
||||
this.name = ''
|
||||
}
|
||||
|
||||
this.search.current = 1
|
||||
this.getList()
|
||||
},
|
||||
|
||||
getList() {
|
||||
this.loading = true
|
||||
this.instance.post(`/app/appmasssendingtask/list`, null, {
|
||||
params: {
|
||||
...this.search,
|
||||
markTag: this.search.markTag ? this.search.markTag.join(',') : ''
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.tableData = res.data.records.map(v => {
|
||||
return {
|
||||
...v,
|
||||
typeName: '群发居民群'
|
||||
}
|
||||
})
|
||||
this.total = res.data.total
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.loading = false
|
||||
})
|
||||
} else {
|
||||
this.loading = false
|
||||
}
|
||||
}).catch(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
|
||||
remindExamine (id) {
|
||||
this.$confirm('确认再次通知任务审核人员?').then(() => {
|
||||
this.instance.post(`/app/appmasssendingtask/remindExamine?id=${id}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('催办成功!')
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
close (id) {
|
||||
this.$confirm('确认关闭该群发任务?').then(() => {
|
||||
this.instance.post(`/app/appmasssendingtask/closeTask?id=${id}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('关闭成功!')
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
cancel (id) {
|
||||
this.$confirm('确认撤回该群发任务?').then(() => {
|
||||
this.instance.post(`/app/appmasssendingtask/cancel?id=${id}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('撤回成功!')
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
remove(id) {
|
||||
this.$confirm('确定删除该数据?').then(() => {
|
||||
this.instance.post(`/app/appmasssendingtask/delete?ids=${id}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('删除成功!')
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
toAdd(id) {
|
||||
this.$emit('change', {
|
||||
type: 'Add',
|
||||
params: {
|
||||
id: id || '',
|
||||
sendChannel: 0
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
toDetail (id) {
|
||||
this.$emit('change', {
|
||||
type: 'Detail',
|
||||
params: {
|
||||
id
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.AppAnnounce {
|
||||
height: 100%;
|
||||
|
||||
.dialog {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: 111;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.mask {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: 1;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.dialog-wrapper {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
z-index: 2;
|
||||
width: 600px;
|
||||
height: 532px;
|
||||
padding: 40px 64px;
|
||||
box-sizing: border-box;
|
||||
background: #FFFFFF;
|
||||
border-radius: 4px;
|
||||
text-align: center;
|
||||
transform: translate(-50%, -50%);
|
||||
|
||||
& > img {
|
||||
position: absolute;
|
||||
right: 16px;
|
||||
top: 16px;
|
||||
z-index: 2;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin-bottom: 12px;
|
||||
font-size: 24px;
|
||||
color: #222;
|
||||
}
|
||||
|
||||
& > p {
|
||||
margin-bottom: 40px;
|
||||
font-size: 12px;
|
||||
color: #888888;
|
||||
}
|
||||
|
||||
.dialog-list {
|
||||
// display: flex;
|
||||
// justify-content: space-between;
|
||||
margin-bottom: 40px;
|
||||
|
||||
& > div {
|
||||
// flex: 1;
|
||||
width: 216px;
|
||||
margin-left: 120px;
|
||||
height: 280px;
|
||||
padding: 24px;
|
||||
background: #FFFFFF;
|
||||
border: 1px solid #D0D4DC;
|
||||
border-radius: 8px;
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
transition: all ease 0.3s;
|
||||
|
||||
&.active, &:hover {
|
||||
background: #F7FAFF;
|
||||
border: 1px solid #2266FF;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
p {
|
||||
line-height: 22px;
|
||||
font-size: 14px;
|
||||
color: #888;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin-bottom: 8px;
|
||||
font-size: 18px;
|
||||
color: #222;
|
||||
font-weight: 600;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
margin-right: 40px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.userinfo {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
line-height: 1;
|
||||
|
||||
span:first-child {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.userSelcet {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 215px;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #d0d4dc;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||
|
||||
&:hover {
|
||||
border-color: $placeholderColor;
|
||||
}
|
||||
|
||||
i {
|
||||
display: flex;
|
||||
position: relative;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 30px;
|
||||
height: 100%;
|
||||
line-height: 32px;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
color: #d0d4dc;
|
||||
transform: rotateZ(180deg);
|
||||
}
|
||||
|
||||
.el-icon-circle-close:hover {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
span {
|
||||
flex: 1;
|
||||
padding: 0 15px;
|
||||
font-size: 12px;
|
||||
color: $placeholderColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
344
project/lulong/Announce/AppAnnounce/components/Phone.vue
Normal file
344
project/lulong/Announce/AppAnnounce/components/Phone.vue
Normal file
@@ -0,0 +1,344 @@
|
||||
<template>
|
||||
<div class="phone-container">
|
||||
<img class="close" @click="$emit('close')" v-if="isShowClose" src="https://cdn.cunwuyun.cn/dvcp/announce/close.png" />
|
||||
<img class="phone" src="https://cdn.cunwuyun.cn/dvcp/announce/phone.png" />
|
||||
<img class="phone-wrapper" src="https://cdn.cunwuyun.cn/dvcp/announce/phone-wrapper.png" />
|
||||
<div class="right-content">
|
||||
<div class="msg-list">
|
||||
<div class="msg-item" v-if="content">
|
||||
<div class="msg-item__left">
|
||||
<img src="https://cdn.cunwuyun.cn/dvcp/announce/avatar.png" />
|
||||
</div>
|
||||
<div class="msg-item__right">
|
||||
<div class="msg-wrapper msg-text">
|
||||
<p>{{ content }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="msg-item" v-for="item in fileList" :key="item.id">
|
||||
<div class="msg-item__left">
|
||||
<img src="https://cdn.cunwuyun.cn/dvcp/announce/avatar.png" />
|
||||
</div>
|
||||
<div class="msg-item__right" :class="[['1', '2'].indexOf(item.msgType) !== -1 ? 'left-border' : '']">
|
||||
<div class="msg-wrapper msg-img" v-if="item.msgType === '1'">
|
||||
<img :src="item.imgPicUrl" />
|
||||
</div>
|
||||
<div class="msg-wrapper msg-video" v-if="item.msgType === '2'">
|
||||
<video controls :src="item.url || item.fileUrl"></video>
|
||||
</div>
|
||||
<div class="msg-wrapper msg-file" v-if="item.msgType === '3'">
|
||||
<div class="msg-left">
|
||||
<h2>{{ item.name || item.title }}</h2>
|
||||
<p>{{ item.fileSizeStr }}</p>
|
||||
</div>
|
||||
<img :src="mapIcon(item.name || item.fileUrl)" />
|
||||
</div>
|
||||
<div class="msg-wrapper msg-link" v-if="item.msgType === '4'">
|
||||
<h2>{{ item.linkTitle }}</h2>
|
||||
<div class="msg-right">
|
||||
<p>{{ item.linkDesc }}</p>
|
||||
<img :src="item.linkPicUrl || 'https://cdn.cunwuyun.cn/dvcp/announce/html.png'" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="msg-wrapper msg-miniapp" v-if="item.msgType === '5'">
|
||||
<h2>{{ item.mpTitle }}</h2>
|
||||
<img :src="item.url || item.pictureUrl" />
|
||||
<div class="msg-bottom">
|
||||
<i>小程序</i>
|
||||
<img src="https://cdn.cunwuyun.cn/dvcp/announce/miniapp.png">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: ['fileList', 'avatar', 'content', 'isShowClose'],
|
||||
|
||||
watch: {
|
||||
fileList (v) {
|
||||
if (v.length) {
|
||||
setTimeout(() => {
|
||||
document.querySelector('.right-content').scrollTo(0, 999999)
|
||||
}, 800)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
mapIcon (fileName) {
|
||||
if (['.zip', '.rar'].indexOf(this.getExtension(fileName)) !== -1) {
|
||||
return 'https://cdn.cunwuyun.cn/dvcp/announce/zip.png'
|
||||
}
|
||||
|
||||
if (['.doc', '.docx'].indexOf(this.getExtension(fileName)) !== -1) {
|
||||
return 'https://cdn.cunwuyun.cn/dvcp/announce/world.png'
|
||||
}
|
||||
|
||||
if (['.xls', '.xlsx'].indexOf(this.getExtension(fileName)) !== -1) {
|
||||
return 'https://cdn.cunwuyun.cn/dvcp/announce/xls.png'
|
||||
}
|
||||
|
||||
if (['.txt'].indexOf(this.getExtension(fileName)) !== -1) {
|
||||
return 'https://cdn.cunwuyun.cn/dvcp/announce/txt.png'
|
||||
}
|
||||
|
||||
if (['.pdf'].indexOf(this.getExtension(fileName)) !== -1) {
|
||||
return 'https://cdn.cunwuyun.cn/dvcp/announce/pdf.png'
|
||||
}
|
||||
|
||||
if (['.ppt', '.pptx'].indexOf(this.getExtension(fileName)) !== -1) {
|
||||
return 'https://cdn.cunwuyun.cn/dvcp/announce/ppt.png'
|
||||
}
|
||||
},
|
||||
|
||||
getExtension(name) {
|
||||
return name.substring(name.lastIndexOf('.'))
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.phone-container {
|
||||
width: 338px;
|
||||
height: 675px;
|
||||
padding: 80px 15px 100px 32px;
|
||||
|
||||
.phone {
|
||||
position: absolute;
|
||||
left: 13px;
|
||||
top: 4px;
|
||||
z-index: 1;
|
||||
width: 314px;
|
||||
height: 647px;
|
||||
}
|
||||
|
||||
.close {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: 111;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
cursor: pointer;
|
||||
transition: all ease 0.5s;
|
||||
transform: translate(100%, -50%);
|
||||
|
||||
&:hover {
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
|
||||
.phone-wrapper {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: 2;
|
||||
width: 338px;
|
||||
height: 675px;
|
||||
}
|
||||
|
||||
.right-content {
|
||||
position: relative;
|
||||
z-index: 11;
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
|
||||
.msg-item {
|
||||
display: flex;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.msg-item__left {
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
margin-right: 16px;
|
||||
border-radius: 4px;
|
||||
flex-shrink: 1;
|
||||
overflow: hidden;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.msg-item__right {
|
||||
position: relative;
|
||||
flex: 1;
|
||||
|
||||
&::after {
|
||||
position: absolute;
|
||||
top: 16px;
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-right: 6px solid #fff;
|
||||
border-left: 6px solid transparent;
|
||||
border-bottom: 6px solid transparent;
|
||||
border-top: 6px solid transparent;
|
||||
content: " ";
|
||||
transform: translate(-100%, 0%);
|
||||
}
|
||||
|
||||
&.left-border::after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.msg-img img {
|
||||
max-width: 206px;
|
||||
max-height: 200px;
|
||||
}
|
||||
|
||||
.msg-video video {
|
||||
max-width: 206px;
|
||||
max-height: 200px;
|
||||
}
|
||||
|
||||
.msg-text {
|
||||
max-width: 206px;
|
||||
width: max-content;
|
||||
line-height: 1.3;
|
||||
padding: 12px;
|
||||
background: #FFFFFF;
|
||||
border-radius: 5px;
|
||||
word-break: break-all;
|
||||
font-size: 14px;
|
||||
color: #222222;
|
||||
}
|
||||
|
||||
.msg-miniapp {
|
||||
width: 206px;
|
||||
padding: 0 12px;
|
||||
text-align: justify;
|
||||
font-size: 0;
|
||||
background: #FFFFFF;
|
||||
border-radius: 5px;
|
||||
font-size: 14px;
|
||||
color: #222222;
|
||||
|
||||
h2 {
|
||||
line-height: 1.2;
|
||||
padding: 8px 0;
|
||||
border-bottom: 1px solid #eee;
|
||||
color: #222222;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
& > img {
|
||||
width: 100%;
|
||||
height: 120px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.msg-bottom {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
line-height: 1;
|
||||
padding: 4px 0;
|
||||
border-top: 1px solid #eee;
|
||||
|
||||
i {
|
||||
margin-right: 4px;
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.msg-file {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 206px;
|
||||
padding: 12px;
|
||||
background: #FFFFFF;
|
||||
border-radius: 5px;
|
||||
|
||||
.msg-left {
|
||||
flex: 1;
|
||||
margin-right: 18px;
|
||||
|
||||
h2 {
|
||||
display: -webkit-box;
|
||||
flex: 1;
|
||||
line-height: 16px;
|
||||
margin-bottom: 4px;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 1;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
color: #222222;
|
||||
font-size: 14px;
|
||||
width: 120px;
|
||||
}
|
||||
|
||||
p {
|
||||
color: #888888;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.msg-link {
|
||||
width: 206px;
|
||||
padding: 12px;
|
||||
background: #FFFFFF;
|
||||
border-radius: 5px;
|
||||
|
||||
h2 {
|
||||
margin-bottom: 4px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
color: #222222;
|
||||
font-size: 14px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.msg-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
p {
|
||||
display: -webkit-box;
|
||||
flex: 1;
|
||||
line-height: 16px;
|
||||
margin-right: 10px;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 3;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
color: #888;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,924 @@
|
||||
<template>
|
||||
<ai-list class="AppAnnounceStatistics">
|
||||
<template slot="content">
|
||||
<div class="statistics-content">
|
||||
<ai-title title="宣发日历"></ai-title>
|
||||
<div class="flex-content">
|
||||
<div class="flex-left">
|
||||
<div class="date-header">
|
||||
<p>{{chooseYear}}年{{chooseMonth}}月</p>
|
||||
<div>
|
||||
<el-date-picker size="small"
|
||||
v-model="searchMonth"
|
||||
type="month" value-format="yyyy-MM"
|
||||
placeholder="选择日期" @change="searchMonthChange">
|
||||
</el-date-picker>
|
||||
</div>
|
||||
</div>
|
||||
<el-calendar v-model="calendarDate">
|
||||
<template
|
||||
slot="dateCell"
|
||||
slot-scope="{date, data}">
|
||||
<div class="flex-date">
|
||||
<span>{{Number(data.day.substring(8, 10))}}</span>
|
||||
<span class="tips" v-if="data.day.substring(5, 7) == chooseMonth && dateList[Number(data.day.substring(8, 10))] && dateList[Number(data.day.substring(8, 10))].taskList.length">{{dateList[Number(data.day.substring(8, 10))].taskList.length}}</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-calendar>
|
||||
</div>
|
||||
<div class="flex-right">
|
||||
<div class="title">{{chooseMonth}}月{{chooseDay}}日宣发内容</div>
|
||||
<div class="list-content" v-if="taskList.length">
|
||||
<el-timeline >
|
||||
<el-timeline-item v-for="(item, index) in taskList" :key="index">
|
||||
<el-card>
|
||||
<div class="flex-between">
|
||||
<p class="item-title">{{item.taskTitle}}</p>
|
||||
<span class="item-time" v-if="item.choiceTime">{{item.choiceTime.substring(10, 16)}}</span>
|
||||
</div>
|
||||
<div class="item-info item-created">
|
||||
<span class="label">创建人:</span>{{item.createUserName}}
|
||||
</div>
|
||||
<div class="item-info item-dept">
|
||||
<span class="label">创建部门:</span>{{item.createUserDeptName}}
|
||||
</div>
|
||||
<div class="flex-between">
|
||||
<!-- <div class="item-info">群发类型:<span>{{$dict.getLabel('mstSendType', item.sendType) || ''}}</span></div> -->
|
||||
<div class="item-info"><span class="label">群发类型:</span><span>群发居民群</span></div>
|
||||
<span class="item-btn" @click="$router.push({name: '357e228ba8e64008ace90d095a7a0dd7', params: { id: item.id }})">详情</span>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-timeline-item>
|
||||
</el-timeline>
|
||||
|
||||
</div>
|
||||
<ai-empty v-if="!taskList.length" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="statistics-content">
|
||||
<div class="flex-between mar-b16">
|
||||
<ai-title title="宣发效果"></ai-title>
|
||||
<div class="right-search">
|
||||
<div class="time-select" :class="effectType == index ? 'active' : ''" v-for="(item, index) in dateTypeList" :key="index" @click="changeEffectType(index)">{{item}}</div>
|
||||
<ai-picker :instance="instance" @pick="e => onUserChange(e)" :multiple="false" dialogTitle="选择部门" action="/app/wxcp/wxdepartment/departList">
|
||||
<div class="time-select">
|
||||
<span class="dept-name" style="color:#999;" v-if="deptList && !deptList.length">宣发部门</span>
|
||||
<span class="dept-name" v-else>{{deptList[0].name}}</span>
|
||||
<i class="el-icon-arrow-down"></i>
|
||||
</div>
|
||||
</ai-picker>
|
||||
</div>
|
||||
</div>
|
||||
<div class="line-content">
|
||||
<div class="flex1">
|
||||
<div class="header">
|
||||
<p>累计创建宣发任务数</p>
|
||||
<h2>{{effectData.createCount}}</h2>
|
||||
</div>
|
||||
<div class="chart-content">
|
||||
<div class="chart-title">宣发任务数</div>
|
||||
<div class="chart-box" id="createChart"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex1">
|
||||
<div class="header">
|
||||
<p>累计执行宣发次数</p>
|
||||
<h2>{{effectData.executeCount}}</h2>
|
||||
</div>
|
||||
<div class="chart-content">
|
||||
<div class="chart-title">宣发次数</div>
|
||||
<div class="chart-box" id="executeChart"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex1 mar-r0">
|
||||
<div class="header">
|
||||
<p>累计触达人次</p>
|
||||
<h2>{{effectData.receiveCount}}</h2>
|
||||
</div>
|
||||
<div class="chart-content">
|
||||
<div class="chart-title">触达人次</div>
|
||||
<div class="chart-box" id="receiveChart"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bottom">
|
||||
<ai-card title="宣发分类数" style="flex: 1; margin-right: 20px;">
|
||||
<template #content>
|
||||
<div id="chart1" style="width: 100%; height: 300px;"></div>
|
||||
</template>
|
||||
</ai-card>
|
||||
<ai-card title="宣发分类占比" style="width: 600px">
|
||||
<template #content>
|
||||
<div id="chart2" style="width: 100%; height: 300px;"></div>
|
||||
</template>
|
||||
</ai-card>
|
||||
</div>
|
||||
<div class="statistics-content">
|
||||
<div class="flex-between mar-b16">
|
||||
<ai-title title="宣发明细"></ai-title>
|
||||
<div class="right-search">
|
||||
<div class="time-select" :class="departType == index ? 'active' : ''" v-for="(item, index) in dateTypeList" :key="index" @click="changeDepartType(index)">{{item}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="departBarChart" v-if="isDepartData"></div>
|
||||
<ai-empty v-if="!isDepartData"></ai-empty>
|
||||
</div>
|
||||
|
||||
<ai-dialog :visible.sync="dialogDate" title="选择时间" width="500px" customFooter>
|
||||
<el-date-picker v-model="timeList" size="small" type="daterange" value-format="yyyy-MM-dd"
|
||||
range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期">
|
||||
</el-date-picker>
|
||||
<el-button slot="footer" @click="selectDete" type="primary">确认</el-button>
|
||||
</ai-dialog>
|
||||
</template>
|
||||
</ai-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as echarts from "echarts";
|
||||
import { mapActions, mapState } from 'vuex';
|
||||
export default {
|
||||
name: 'AppAnnounceStatistics',
|
||||
label: '协同宣发统计',
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
permissions: Function
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
calendarDate: new Date(),
|
||||
dateList: {},
|
||||
chooseYear: '',
|
||||
chooseMonth: '',
|
||||
chooseDay: '',
|
||||
searchMonth: '',
|
||||
taskList: [],
|
||||
effectType: 0, // 宣发效果类型 0:近七天、1:近30天、2:近一年、3:自定义
|
||||
effectData: {},
|
||||
createChart: null,
|
||||
executeChart: null,
|
||||
receiveChart: null,
|
||||
departType: 0, // 宣发明细类型 0:近七天、1:近30天、2:近一年、3:自定义
|
||||
dateTypeList: ['近7天', '近30天', '近1年', '自定义'],
|
||||
departData: {},
|
||||
departBarChart: null,
|
||||
dialogDate: false,
|
||||
timeListEffect: '',
|
||||
timeListDepart: '',
|
||||
timeList: '',
|
||||
isEffectTimeSelect: false,
|
||||
deptList: [],
|
||||
selectDeptName: '',
|
||||
isDepartData: true,
|
||||
departBarData: [],
|
||||
type: '',
|
||||
date: '',
|
||||
search: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
type: '0'
|
||||
},
|
||||
chart1: null,
|
||||
chart2: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(['user']),
|
||||
},
|
||||
watch: {
|
||||
calendarDate: function() {
|
||||
var year = '' , month = '', date = ''
|
||||
if(this.calendarDate.length == 9) { // 月份选择器触发
|
||||
year = this.calendarDate.substring(0, 4)
|
||||
month = this.calendarDate.substring(5, 7)
|
||||
date = this.calendarDate.substring(8, 10)
|
||||
}else { // 日历点击
|
||||
year = this.calendarDate.getFullYear();
|
||||
month = this.calendarDate.getMonth() + 1;
|
||||
date = this.calendarDate.getDate()
|
||||
if (month >= 1 && month <= 9) {
|
||||
month = "0" + month;
|
||||
}
|
||||
|
||||
if(this.chooseMonth != month) { // 日历点击不同月
|
||||
this.searchMonth = ''
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
this.chooseDay = date
|
||||
|
||||
if(this.chooseMonth != month || this.chooseYear != year) { // 不同年/不同月重新请求日历列表
|
||||
this.getCalendarList(year, month)
|
||||
} else {
|
||||
this.getTaskList(date)
|
||||
}
|
||||
|
||||
this.chooseMonth = month
|
||||
this.chooseYear = year
|
||||
|
||||
}
|
||||
},
|
||||
created() {
|
||||
var year = this.calendarDate.getFullYear();
|
||||
var month = this.calendarDate.getMonth() + 1;
|
||||
var date = this.calendarDate.getDate()
|
||||
if (month >= 1 && month <= 9) {
|
||||
month = "0" + month;
|
||||
}
|
||||
this.chooseMonth = month
|
||||
this.chooseYear = year
|
||||
this.chooseDay = date
|
||||
this.getCalendarList(year, month)
|
||||
this.getEffect()
|
||||
this.getDepart()
|
||||
this.dict.load('mstSendType')
|
||||
},
|
||||
|
||||
mounted () {
|
||||
this.$nextTick(() => {
|
||||
this.chart1 = echarts.init(document.querySelector('#chart1'))
|
||||
this.chart2 = echarts.init(document.querySelector('#chart2'))
|
||||
window.addEventListener('resize', this.onResize)
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
...mapActions(['initOpenData', 'transCanvas']),
|
||||
onUserChange (e) {
|
||||
this.deptList = e
|
||||
this.getEffect()
|
||||
},
|
||||
selectDete() {
|
||||
if(!this.timeList || !this.timeList.length) {
|
||||
return this.$message.error('请选择自定义时间');
|
||||
}
|
||||
|
||||
if(this.isEffectTimeSelect) { //宣发效果
|
||||
this.timeListEffect = this.timeList
|
||||
this.effectType = 3
|
||||
this.getEffect()
|
||||
} else { //宣发明细
|
||||
this.timeListDepart = this.timeList
|
||||
this.departType = 3
|
||||
this.getDepart()
|
||||
}
|
||||
|
||||
this.dialogDate = false
|
||||
},
|
||||
searchMonthChange() {
|
||||
this.calendarDate = this.searchMonth + '-1'
|
||||
},
|
||||
getCalendarList(year, month){
|
||||
this.instance.post(`/app/appmasssendingtask/statisticsCalendar?yyyyMM=${year}${month}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.dateList = res.data
|
||||
this.getTaskList(this.chooseDay)
|
||||
}
|
||||
})
|
||||
},
|
||||
getTaskList(day) {
|
||||
this.taskList = this.dateList[day].taskList
|
||||
},
|
||||
changeEffectType(type) {
|
||||
if(this.effectType != 3) {
|
||||
this.timeList = []
|
||||
}else {
|
||||
this.timeList = this.timeListEffect
|
||||
}
|
||||
if(type == 3) {
|
||||
this.isEffectTimeSelect = true
|
||||
this.dialogDate = true
|
||||
}else {
|
||||
this.effectType = type
|
||||
this.getEffect()
|
||||
}
|
||||
},
|
||||
getEffect() {
|
||||
var startTime = this.timeListEffect[0] || '' , endTime = this.timeListEffect[1] || '', departId = ''
|
||||
if(this.deptList && this.deptList.length) {
|
||||
departId = this.deptList[0].id
|
||||
}
|
||||
this.instance.post(`/app/appmasssendingtask/statisticsEffect?type=${this.effectType}&startTime=${startTime}&endTime=${endTime}&departId=${departId}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.effectData = res.data
|
||||
var xData = [], createData = [], executeData = [], receiveData = []
|
||||
res.data.trend.map(e => {
|
||||
if(this.effectType == 0 || this.effectType == 1) {
|
||||
e.ymd = e.ymd.substring(5, 10)
|
||||
}
|
||||
xData.push(e.ymd)
|
||||
createData.push(e.createCount)
|
||||
executeData.push(e.executeCount)
|
||||
receiveData.push(e.receiveCount)
|
||||
})
|
||||
|
||||
this.setLineChart(xData, createData, 'createChart', ['#2891FF'])
|
||||
this.setLineChart(xData, executeData, 'executeChart', ['#FFB865'])
|
||||
this.setLineChart(xData, receiveData, 'receiveChart', ['#26D52B'])
|
||||
this.initChart1(res.data.tagTrend)
|
||||
this.initChart2(res.data.tagDistribution)
|
||||
}
|
||||
})
|
||||
},
|
||||
setLineChart(xData, yData, id, colorList) {
|
||||
this[id] = echarts.init(document.querySelector(`#${id}`))
|
||||
var option = {
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: xData
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value'
|
||||
},
|
||||
grid: {
|
||||
left: '10px',
|
||||
right: '28px',
|
||||
bottom: '14px',
|
||||
top: '30px',
|
||||
containLabel: true
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis'
|
||||
},
|
||||
legend: {
|
||||
type: "plain"
|
||||
},
|
||||
color: colorList,
|
||||
series: [
|
||||
{
|
||||
data: yData,
|
||||
type: 'line'
|
||||
}
|
||||
]
|
||||
}
|
||||
this[id].setOption(option)
|
||||
},
|
||||
changeDepartType(type) {
|
||||
if(this.departType != 3) {
|
||||
this.timeList = []
|
||||
}else {
|
||||
this.timeList = this.timeListDepart
|
||||
}
|
||||
if(type == 3) {
|
||||
this.isEffectTimeSelect = false
|
||||
this.dialogDate = true
|
||||
}else {
|
||||
this.departType = type
|
||||
this.getDepart()
|
||||
}
|
||||
},
|
||||
getDepart() {
|
||||
var startTime = this.timeListDepart[0] || '' , endTime = this.timeListDepart[1] || ''
|
||||
this.instance.post(`/app/appmasssendingtask/statisticsDepart?type=${this.departType}&startTime=${startTime}&endTime=${endTime}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
if(res.data && res.data.length) {
|
||||
this.isDepartData = true
|
||||
var xData = [], yData = []
|
||||
res.data.map((item) => {
|
||||
this.departBarData.push(item)
|
||||
xData.push(item.deptName)
|
||||
yData.push(item.taskCount)
|
||||
})
|
||||
this.setBarChart(xData, yData)
|
||||
}else {
|
||||
this.isDepartData = false
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
setBarChart(xData, yData) {
|
||||
this.departBarChart = echarts.init(document.querySelector(`#departBarChart`))
|
||||
var option = {
|
||||
color: ['#2891FF'],
|
||||
grid: {
|
||||
top: '10%',
|
||||
left: '2%',
|
||||
right: '2%',
|
||||
bottom: 90,
|
||||
containLabel: true
|
||||
},
|
||||
// toolbox: {
|
||||
// feature: {
|
||||
// dataZoom: {
|
||||
// yAxisIndex: false
|
||||
// },
|
||||
// saveAsImage: {
|
||||
// pixelRatio: 2
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'shadow'
|
||||
},
|
||||
formatter: (data) => {
|
||||
var index = data[0].dataIndex
|
||||
return `<ww-open-data type="departmentName" openid="${this.departBarData[index].deptId}"></ww-open-data><br/>宣发任务数:${data[0].value}`
|
||||
}
|
||||
},
|
||||
dataZoom: [
|
||||
{
|
||||
type: 'inside'
|
||||
},
|
||||
{
|
||||
type: 'slider'
|
||||
}
|
||||
],
|
||||
xAxis: {
|
||||
data: xData,
|
||||
silent: false,
|
||||
splitLine: {
|
||||
show: false
|
||||
},
|
||||
splitArea: {
|
||||
show: false
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
splitArea: {
|
||||
show: false
|
||||
}
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: 'bar',
|
||||
data: yData,
|
||||
barWidth: 20,
|
||||
barGap: '250%',
|
||||
large: true
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
// {
|
||||
// tooltip: {
|
||||
// trigger: 'axis',
|
||||
// axisPointer: {
|
||||
// type: 'shadow'
|
||||
// }
|
||||
// },
|
||||
// grid: {
|
||||
// top: '10%',
|
||||
// left: '2%',
|
||||
// right: '2%',
|
||||
// bottom: '2%',
|
||||
// containLabel: true
|
||||
// },
|
||||
// color: ['#2891FF'],
|
||||
// xAxis: {
|
||||
// type: 'category',
|
||||
// data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
|
||||
// },
|
||||
// yAxis: {
|
||||
// type: 'value'
|
||||
// },
|
||||
// series: [
|
||||
// {
|
||||
// data: [120, 200, 150, 80, 70, 110, 130],
|
||||
// type: 'bar',
|
||||
// barWidth: 20,
|
||||
// barGap: '250%',
|
||||
// }
|
||||
// ]
|
||||
// };
|
||||
this.departBarChart.setOption(option)
|
||||
},
|
||||
|
||||
initChart1 (data) {
|
||||
const x = Object.keys(data)
|
||||
const tags = data[x[0]].map(v => v.tag)
|
||||
const a = tags.map(v => {
|
||||
return {
|
||||
name: v,
|
||||
type: 'line',
|
||||
data: x.map(e => {
|
||||
return data[e].filter(i => i.tag === v)[0].c
|
||||
})
|
||||
}
|
||||
})
|
||||
let option = {
|
||||
tooltip: {
|
||||
trigger: 'axis'
|
||||
},
|
||||
legend: {
|
||||
type: "plain"
|
||||
},
|
||||
grid: {
|
||||
left: '10px',
|
||||
right: '28px',
|
||||
bottom: '14px',
|
||||
top: '30px',
|
||||
containLabel: true
|
||||
},
|
||||
dataZoom: [
|
||||
{
|
||||
type: 'inside',
|
||||
start: 0,
|
||||
end: 7,
|
||||
minValueSpan: 7
|
||||
},
|
||||
{
|
||||
start: 0,
|
||||
end: 7
|
||||
}
|
||||
],
|
||||
// color: ['#2266FF', '#22AA99', '#F8B425', '#29ABF7', '#49DFCB'],
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
axisLabel: {
|
||||
align: 'center',
|
||||
padding: [2, 0, 0, 0],
|
||||
interval: 0,
|
||||
fontSize: 14,
|
||||
color: '#666666'
|
||||
},
|
||||
boundaryGap: false,
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: '#E1E5EF'
|
||||
}
|
||||
},
|
||||
data: x
|
||||
},
|
||||
yAxis: {
|
||||
axisTick: {
|
||||
length: 0,
|
||||
show: false
|
||||
},
|
||||
splitLine: {
|
||||
show: true,
|
||||
lineStyle:{
|
||||
color: ['#E1E5EF'],
|
||||
width: 1,
|
||||
type: 'solid'
|
||||
}
|
||||
},
|
||||
nameTextStyle: {
|
||||
color: '#666666',
|
||||
align: 'left'
|
||||
},
|
||||
axisLine: {
|
||||
show: false
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#666666'
|
||||
},
|
||||
type: 'value'
|
||||
},
|
||||
series: tags.map(v => {
|
||||
return {
|
||||
name: v,
|
||||
type: 'line',
|
||||
data: x.map(e => {
|
||||
return data[e].filter(i => i.tag === v)[0].c
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
this.chart1.setOption(option)
|
||||
},
|
||||
|
||||
initChart2 (data) {
|
||||
let option = {
|
||||
grid: {
|
||||
left: '1%',
|
||||
right: '0%',
|
||||
bottom: '2%',
|
||||
top: '0px',
|
||||
containLabel: true
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
axisPointer: {
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
left: 'center',
|
||||
top: '0px',
|
||||
textStyle: {
|
||||
}
|
||||
},
|
||||
// color: ['#2266FF', '#22AA99', '#F8B425', '#29ABF7', '#49DFCB'],
|
||||
series: [
|
||||
{
|
||||
type: 'pie',
|
||||
radius: '50%',
|
||||
data: data.map(v => {
|
||||
return {
|
||||
value: v.c,
|
||||
name: v.tag
|
||||
}
|
||||
}),
|
||||
label: {
|
||||
normal: {
|
||||
textStyle: {
|
||||
fontSize: '12'
|
||||
},
|
||||
formatter: '{b}: {@2012} ({d}%)'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
this.chart2.setOption(option)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.AppAnnounceStatistics {
|
||||
height: 100%;
|
||||
.flex-between{
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.bottom {
|
||||
display: flex;
|
||||
}
|
||||
.mar-b16{
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.mar-r0{
|
||||
margin-right: 0!important;
|
||||
}
|
||||
.statistics-content{
|
||||
padding: 0 24px 24px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0px 4px 6px -2px rgba(15,15,21,0.1500);
|
||||
border-radius: 4px;
|
||||
margin-bottom: 20px;
|
||||
.flex-content{
|
||||
width: 100%;
|
||||
display: flex;
|
||||
margin-top: 16px;
|
||||
.flex-left{
|
||||
width: 50%;
|
||||
.date-header{
|
||||
padding: 12px 16px;
|
||||
border: 1px solid #eee;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
p{
|
||||
line-height: 32px;
|
||||
}
|
||||
}
|
||||
.flex-date{
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.tips{
|
||||
display: inline-block;
|
||||
padding: 0 4px;
|
||||
height: 16px;
|
||||
line-height: 16px;
|
||||
border-radius: 8px;
|
||||
background: #2891FF;
|
||||
font-size: 12px;
|
||||
font-family: ArialMT;
|
||||
color: #FFF;
|
||||
margin-top: 8px;
|
||||
}
|
||||
}
|
||||
.flex-right{
|
||||
width: 50%;
|
||||
margin-left: 16px;
|
||||
border: 1px solid #eee;
|
||||
.title{
|
||||
line-height: 56px;
|
||||
border-bottom: 1px solid #EEE;
|
||||
padding-left: 16px;
|
||||
font-size: 16px;
|
||||
font-family: MicrosoftYaHeiSemibold;
|
||||
color: #333;
|
||||
}
|
||||
.list-content{
|
||||
padding: 16px;
|
||||
height: 339px;
|
||||
box-sizing: border-box;
|
||||
overflow-y: scroll;
|
||||
background-color: #F9F9F9;
|
||||
box-sizing: border-box;
|
||||
.item-title{
|
||||
width: calc(100% - 100px);
|
||||
word-break: break-all;
|
||||
margin-bottom: 8px;
|
||||
font-size: 16px;
|
||||
font-family: MicrosoftYaHeiSemibold;
|
||||
color: #222;
|
||||
line-height: 24px;
|
||||
}
|
||||
.item-time{
|
||||
width: 100px;
|
||||
text-align: right;
|
||||
font-size: 16px;
|
||||
font-family: ArialMT;
|
||||
color: #888;
|
||||
line-height: 24px;
|
||||
}
|
||||
.item-info{
|
||||
display: inline-block;
|
||||
font-size: 14px;
|
||||
font-family: MicrosoftYaHei;
|
||||
color: #222;
|
||||
line-height: 22px;
|
||||
span{
|
||||
display: inline-block;
|
||||
color: #222;
|
||||
word-break: break-all;
|
||||
// vertical-align: text-top;
|
||||
}
|
||||
.label{
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
.item-created{
|
||||
width: 152px;
|
||||
margin-bottom: 4px;
|
||||
.label{
|
||||
width: 56px;
|
||||
}
|
||||
.name{
|
||||
width: calc(100% - 56px);
|
||||
}
|
||||
}
|
||||
.item-dept{
|
||||
width: calc(100% - 152px);
|
||||
.label{
|
||||
width: 70px;
|
||||
}
|
||||
.name{
|
||||
width: calc(100% - 70px);
|
||||
}
|
||||
}
|
||||
.item-btn{
|
||||
color: #26f;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.right-search{
|
||||
margin-top: 10px;
|
||||
div{
|
||||
display: inline-block;
|
||||
}
|
||||
.time-select{
|
||||
font-size: 14px;
|
||||
font-family: MicrosoftYaHei;
|
||||
color: #222;
|
||||
line-height: 22px;
|
||||
padding: 6px 12px;
|
||||
border-radius: 2px;
|
||||
border: 1px solid #D0D4DC;
|
||||
margin-right: 8px;
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
.dept-name{
|
||||
display: inline-block;
|
||||
width: 200px;
|
||||
height: 22px;
|
||||
overflow:hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
vertical-align: bottom;
|
||||
}
|
||||
.el-icon-arrow-down{
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
.active{
|
||||
border: 1px solid #26f;
|
||||
color: #26f;
|
||||
}
|
||||
}
|
||||
.line-content{
|
||||
display: flex;
|
||||
.flex1{
|
||||
flex: 1;
|
||||
margin-right: 16px;
|
||||
.header{
|
||||
padding: 16px;
|
||||
width: 100%;
|
||||
height: 90px;
|
||||
background: #F9F9F9;
|
||||
border-radius: 2px;
|
||||
box-sizing: border-box;
|
||||
margin-bottom: 16px;
|
||||
p{
|
||||
font-size: 14px;
|
||||
font-family: MicrosoftYaHeiSemibold;
|
||||
color: #222;
|
||||
line-height: 22px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
h2{
|
||||
font-size: 24px;
|
||||
font-family: DINAlternate-Bold, DINAlternate;
|
||||
font-weight: bold;
|
||||
color: #26F;
|
||||
line-height: 32px;
|
||||
}
|
||||
}
|
||||
.chart-content{
|
||||
width: 100%;
|
||||
padding: 16px;
|
||||
background: #F9F9F9;
|
||||
border-radius: 2px;
|
||||
box-sizing: border-box;
|
||||
.chart-title{
|
||||
font-size: 16px;
|
||||
font-family: MicrosoftYaHeiSemibold;
|
||||
color: #333;
|
||||
line-height: 24px;
|
||||
}
|
||||
.chart-box{
|
||||
width: 100%;
|
||||
height: 280px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#departBarChart{
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
:deep( .el-calendar-table:not(.is-range) td.next),
|
||||
:deep( .el-calendar-table:not(.is-range) td.prev ){
|
||||
color: #ccc;
|
||||
}
|
||||
:deep( .el-calendar-table .el-calendar-day){
|
||||
height: 48px;
|
||||
line-height: 32px;
|
||||
padding-left: 12px;
|
||||
font-size: 14px;
|
||||
font-family: ArialMT;
|
||||
}
|
||||
.el-calendar-table:not(.is-range) td .current{
|
||||
color: #888;
|
||||
}
|
||||
:deep( .el-calendar__header){
|
||||
display: none;
|
||||
}
|
||||
:deep( .el-calendar__body){
|
||||
padding: 0;
|
||||
}
|
||||
:deep( .el-calendar-table thead th:nth-of-type(1)){
|
||||
border-left: 1px solid #eee;
|
||||
}
|
||||
:deep( .el-calendar-table thead th:nth-of-type(7)){
|
||||
border-right: 1px solid #eee;
|
||||
}
|
||||
:deep( .el-calendar-table tr td:first-child ){
|
||||
border-left: 1px solid #eee;
|
||||
}
|
||||
:deep( .el-calendar-table tr:first-child td ){
|
||||
border-top: 1px solid #eee;
|
||||
}
|
||||
:deep( .el-calendar-table td ){
|
||||
border-bottom: 1px solid #eee;
|
||||
border-right: 1px solid #eee;
|
||||
}
|
||||
:deep( .el-timeline-item__timestamp.is-top){
|
||||
margin-bottom: 0;
|
||||
padding-top: 0;
|
||||
}
|
||||
:deep( .el-timeline-item__node){
|
||||
background-color: #26F;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
left: 1px;
|
||||
}
|
||||
:deep( .el-card){
|
||||
border: none;
|
||||
}
|
||||
:deep( .el-card__body){
|
||||
padding: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
:deep( .ai-list__content ){
|
||||
padding: 0!important;
|
||||
|
||||
.ai-list__content--right-wrapper {
|
||||
background: transparent!important;
|
||||
box-shadow: none!important;
|
||||
margin: 0!important;
|
||||
padding: 0 0 0!important;
|
||||
}
|
||||
}
|
||||
|
||||
:deep( .AiPicker){
|
||||
display: inline-block;
|
||||
}
|
||||
</style>
|
||||
76
project/lulong/AppHelp/AppHelp.vue
Normal file
76
project/lulong/AppHelp/AppHelp.vue
Normal file
@@ -0,0 +1,76 @@
|
||||
<template>
|
||||
<div class="AppHelp">
|
||||
<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 List from './components/List'
|
||||
import Add from './components/Add'
|
||||
import GagList from './components/GagList'
|
||||
|
||||
export default {
|
||||
name: 'AppHelp',
|
||||
label: '邻里互助',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
component: 'List',
|
||||
params: {},
|
||||
include: []
|
||||
}
|
||||
},
|
||||
|
||||
components: {
|
||||
Add,
|
||||
List,
|
||||
Detail,
|
||||
GagList
|
||||
},
|
||||
|
||||
methods: {
|
||||
onChange (data) {
|
||||
if (data.type === 'GagList') {
|
||||
this.component = 'GagList'
|
||||
}
|
||||
|
||||
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">
|
||||
.AppHelp {
|
||||
height: 100%;
|
||||
background: #F3F6F9;
|
||||
overflow: auto;
|
||||
}
|
||||
</style>
|
||||
177
project/lulong/AppHelp/components/Add.vue
Normal file
177
project/lulong/AppHelp/components/Add.vue
Normal file
@@ -0,0 +1,177 @@
|
||||
<template>
|
||||
<ai-detail class="content-add">
|
||||
<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 class="ai-form" :model="form" label-width="120px" ref="form">
|
||||
<el-form-item label="发布单位" prop="publishDepartName" style="width: 100%;" :rules="[{ required: true, message: '请选择单位', trigger: 'change' }]">
|
||||
<ai-picker :instance="instance" multiple @pick="e => onUserChange(e)" dialogTitle="选择部门" action="/app/wxcp/wxdepartment/departList">
|
||||
<div class="time-select">
|
||||
<span class="dept-name" style="color:#999;" v-if="!form.publishDepartName">选择部门</span>
|
||||
<span class="dept-name" v-else>{{form.publishDepartName}}</span>
|
||||
<i class="el-icon-arrow-down"></i>
|
||||
</div>
|
||||
</ai-picker>
|
||||
</el-form-item>
|
||||
<el-form-item prop="visibleAreaId" style="width: 100%;" label="发布地区" :rules="[{required: true, message: '请选择地区', trigger: 'change'}]">
|
||||
<ai-area-select clearable @fullname="v => form.visibleAreaName = v" always-show :instance="instance" v-model="form.visibleAreaId" :disabled-level="disabledLevel"></ai-area-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="发布内容" prop="content" style="width: 100%;" :rules="[{required: true, message: '请输入发布内容', trigger: 'change'}]">
|
||||
<!-- <ai-editor v-model="form.content" :instance="instance"/> -->
|
||||
<el-input type="textarea" placeholder="请输入内容" v-model="form.content" rows="8" maxlength="500" :show-word-limit="true"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="图片" prop="files" style="width: 100%;">
|
||||
<ai-uploader
|
||||
:instance="instance"
|
||||
v-model="form.files"
|
||||
isShowTip
|
||||
:limit="9">
|
||||
</ai-uploader>
|
||||
</el-form-item>
|
||||
<el-form-item prop="themeId" style="width: 100%;" label="关联话题">
|
||||
<ai-select v-model="form.themeId" :selectList="talkList" placeholder="请选择关联话题" />
|
||||
</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: {},
|
||||
form: {
|
||||
themeId: '',
|
||||
content: '',
|
||||
areaId: '',
|
||||
visibleAreaName: '',
|
||||
files: [],
|
||||
areaName: '',
|
||||
publishDepartName: '',
|
||||
publishDepartIdList: [],
|
||||
},
|
||||
id: '',
|
||||
department: [],
|
||||
talkList: [],
|
||||
isFlag: false
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['user'])
|
||||
},
|
||||
|
||||
created () {
|
||||
if (this.params && this.params.id) {
|
||||
this.id = this.params.id
|
||||
this.getInfo(this.params.id)
|
||||
}
|
||||
this.form.visibleAreaId =this.user.info.areaId
|
||||
this.form.visibleAreaName =this.user.info.areaName
|
||||
this.disabledLevel = this.user.info.areaList.length
|
||||
this.getTalkList()
|
||||
},
|
||||
|
||||
methods: {
|
||||
getInfo (id) {
|
||||
this.instance.post(`/app/appneighborhoodassistance/queryDetailById?id=${id}`).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.form = res.data
|
||||
this.form.publishDepartIdList = this.form.publishDepartId.split(',')
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
confirm () {
|
||||
if(this.isFlag) return
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (valid) {
|
||||
this.isFlag = true
|
||||
this.instance.post(`/app/appneighborhoodassistance/addOrUpdate`, {
|
||||
...this.form,
|
||||
publishDepartId: this.form.publishDepartIdList.join(',')
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('提交成功')
|
||||
setTimeout(() => {
|
||||
this.cancel(true)
|
||||
}, 600)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
cancel (isRefresh) {
|
||||
this.$emit('change', {
|
||||
type: 'List',
|
||||
isRefresh: !!isRefresh
|
||||
})
|
||||
},
|
||||
|
||||
onChange (e) {
|
||||
if (e.length) {
|
||||
this.form.publishDepartIdList = e.map(v => v.id)
|
||||
this.form.publishDepartName = e.map(v => v.name).join(',')
|
||||
} else {
|
||||
this.form.publishDepartIdList = ''
|
||||
this.form.publishDepartName = ''
|
||||
}
|
||||
},
|
||||
|
||||
onUserChange (e) {
|
||||
this.deptList = e
|
||||
this.onChange(e)
|
||||
},
|
||||
|
||||
getTalkList() {
|
||||
this.instance.post(`/app/appneighborhoodassistancetheme/list?size=100`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.talkList = []
|
||||
res.data.records.map((item) => {
|
||||
this.talkList.push({
|
||||
dictName: item.title,
|
||||
dictValue: item.id
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.time-select {
|
||||
padding: 0 16px;
|
||||
height: 36px;
|
||||
line-height: 36px;
|
||||
border: 1px solid #d0d4dc;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
cursor: pointer;
|
||||
.el-icon-arrow-down {
|
||||
line-height: 36px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
294
project/lulong/AppHelp/components/Detail.vue
Normal file
294
project/lulong/AppHelp/components/Detail.vue
Normal file
@@ -0,0 +1,294 @@
|
||||
<template>
|
||||
<ai-detail class="detail">
|
||||
<template slot="title">
|
||||
<ai-title title="帖子详情" isShowBack isShowBottomBorder @onBackClick="cancel(false)">
|
||||
</ai-title>
|
||||
</template>
|
||||
<template slot="content">
|
||||
<ai-card title="帖子信息">
|
||||
<template #content>
|
||||
<div class="talk-info">
|
||||
<div class="user">
|
||||
<img :src="info.createUserAvatar" alt="">
|
||||
<div class="info">
|
||||
<h2>{{info.createUserName}}</h2>
|
||||
<div class="time-flex">
|
||||
<span class="area-name">{{info.publishDepartName}}</span>
|
||||
<span>{{info.createTime}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content">
|
||||
<span v-if="info.themeId">#【{{info.themeInfo.title}}】</span>{{info.content}}
|
||||
</div>
|
||||
<ai-uploader :instance="instance" disabled v-model="info.files">
|
||||
</ai-uploader>
|
||||
</div>
|
||||
</template>
|
||||
</ai-card>
|
||||
<ai-card title="评论信息">
|
||||
<template #content>
|
||||
<div class="comment-list" v-if="commontList.length">
|
||||
<div class="title">评论</div>
|
||||
<div class="item" v-for="(item, index) in commontList" :key="index">
|
||||
<div class="user">
|
||||
<img :src="item.createUserAvatar" alt="">
|
||||
<div class="info-flex">
|
||||
<h2>{{item.createUserName}}</h2>
|
||||
<span>{{item.createTime}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content-flex">
|
||||
<p>{{item.content}}</p>
|
||||
<div @click="delCommontOrReply('评论', item.id)">删除</div>
|
||||
</div>
|
||||
<div class="reply-list" v-if="item.replyList && item.replyList.length && item.isShowReply">
|
||||
<div class="reply-item" v-for="(reply, indexs) in item.replyList" :key="indexs">
|
||||
<div class="reply-user">
|
||||
<img :src="item.createUserAvatar" alt="">
|
||||
<div class="reply-name">
|
||||
<span>{{reply.createUserName}}</span>回复<span>{{item.createUserName}}</span>
|
||||
</div>
|
||||
<span class="reply-time">{{reply.createTime}}</span>
|
||||
</div>
|
||||
<div class="content-flex">
|
||||
<p>{{reply.content}}</p>
|
||||
<div @click="delCommontOrReply('回复', reply.id)">删除</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="reply-more" @click="item.isShowReply = !item.isShowReply" :class="[item.isShowReply ? 'active' : '']">
|
||||
<span class="line"></span>{{item.isShowReply ? '收起' : `展开${item.replyList.length}条回复`}}
|
||||
<i class="el-icon-arrow-down"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ai-empty v-else>暂无评论</ai-empty>
|
||||
</template>
|
||||
</ai-card>
|
||||
</template>
|
||||
</ai-detail>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Detail',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
params: Object
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
commontList: [],
|
||||
info: {},
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
getAvatar(row){
|
||||
return row.avatar||row.photo||'https://cdn.cunwuyun.cn/dvcp/h5/defaultAvatar.png'
|
||||
}
|
||||
},
|
||||
|
||||
created () {
|
||||
this.getInfo()
|
||||
this.getList()
|
||||
},
|
||||
|
||||
methods: {
|
||||
getList() {
|
||||
this.instance.post(`/app/appneighborhoodassistance/commontList?id=${this.params.id}&size=100`).then(res => {
|
||||
if (res.code == 0) {
|
||||
res.data.records.map((item) => {
|
||||
item.isShowReply = false
|
||||
})
|
||||
this.commontList = res.data.records
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
getInfo () {
|
||||
this.instance.post(`/app/appneighborhoodassistance/queryDetailById?id=${this.params.id}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
if (res.data) {
|
||||
this.info = res.data
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
cancel () {
|
||||
this.$emit('change', {
|
||||
type: 'List',
|
||||
isRefresh: true
|
||||
})
|
||||
},
|
||||
|
||||
delCommontOrReply(text, id) {
|
||||
this.$confirm(`确定删除该${text}?`).then(() => {
|
||||
this.instance.post(`/app/appneighborhoodassistance/delComment?id=${id}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('删除成功!')
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.detail {
|
||||
.talk-info {
|
||||
.user {
|
||||
display: flex;
|
||||
margin-bottom: 8px;
|
||||
img {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
margin-right: 16px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
.info {
|
||||
width: calc(100% - 76px);
|
||||
h2 {
|
||||
font-size: 20px;
|
||||
line-height: 30px;
|
||||
font-weight: 400;
|
||||
}
|
||||
.time-flex {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
color: #999;
|
||||
font-size: 14px;
|
||||
line-height: 30px;
|
||||
.area-name {
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.content {
|
||||
font-size: 16px;
|
||||
line-height: 32px;
|
||||
word-break: break-all;
|
||||
span {
|
||||
color: #26f;
|
||||
}
|
||||
}
|
||||
}
|
||||
.comment-list {
|
||||
.title {
|
||||
color: #333;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
line-height: 40px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.item {
|
||||
border-bottom: 1px solid #ddd;
|
||||
padding-bottom: 16px;
|
||||
.user {
|
||||
display: flex;
|
||||
margin-bottom: 8px;
|
||||
img {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
margin-right: 16px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
.info-flex {
|
||||
width: calc(100% - 76px);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
line-height: 60px;
|
||||
h2 {
|
||||
font-size: 20px;
|
||||
font-weight: 400;
|
||||
}
|
||||
span {
|
||||
color: #999;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.content-flex {
|
||||
display: flex;
|
||||
font-size: 16px;
|
||||
line-height: 30px;
|
||||
margin-bottom: 8px;
|
||||
padding-left: 76px;
|
||||
p {
|
||||
width: calc(100% - 50px);
|
||||
word-break: break-all;
|
||||
}
|
||||
div {
|
||||
color: #26f;
|
||||
width: 50px;
|
||||
text-align: right;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
.reply-list {
|
||||
padding-left: 100px;
|
||||
.reply-item {
|
||||
margin-bottom: 8px;
|
||||
.reply-user {
|
||||
font-size: 14px;
|
||||
img {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-radius: 50%;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.reply-name {
|
||||
display: inline-block;
|
||||
color: #333;
|
||||
width: 300px;
|
||||
span {
|
||||
display: inline-block;
|
||||
color: #666;
|
||||
margin: 0 8px;
|
||||
}
|
||||
}
|
||||
.reply-time {
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
.content-flex {
|
||||
font-size: 14px;
|
||||
line-height: 24px;
|
||||
padding-left: 58px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.reply-more {
|
||||
font-size: 14px;
|
||||
line-height: 28px;
|
||||
color: #333;
|
||||
.line {
|
||||
display: inline-block;
|
||||
width: 120px;
|
||||
border-top: 1px solid #eee;
|
||||
vertical-align: middle;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.el-icon-arrow-down {
|
||||
transition: all ease 0.5s;
|
||||
transform: rotate(0);
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
&.active .el-icon-arrow-down {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
109
project/lulong/AppHelp/components/GagList.vue
Normal file
109
project/lulong/AppHelp/components/GagList.vue
Normal file
@@ -0,0 +1,109 @@
|
||||
<template>
|
||||
<ai-list class="notice">
|
||||
<template slot="title">
|
||||
<ai-title title="禁言列表" isShowBack isShowBottomBorder @onBackClick="cancel"></ai-title>
|
||||
</template>
|
||||
<template slot="content">
|
||||
<ai-search-bar>
|
||||
<template #left>
|
||||
</template>
|
||||
<template #right>
|
||||
<el-input
|
||||
v-model="search.userName"
|
||||
class="search-input"
|
||||
size="small"
|
||||
v-throttle="() => {search.current = 1, getList()}"
|
||||
placeholder="请输入用户昵称"
|
||||
clearable
|
||||
@clear="search.current = 1, search.userName = '', getList()"
|
||||
suffix-icon="iconfont iconSearch">
|
||||
</el-input>
|
||||
</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="options" width="100px" fixed="right" label="操作" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<div class="table-options">
|
||||
<el-button type="text" @click="remove(row.userId)">解除禁言</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</template>
|
||||
</ai-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'GagList',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
search: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
userName: ''
|
||||
},
|
||||
total: 0,
|
||||
colConfigs: [
|
||||
{ prop: 'userName', label: '用户昵称', align: 'left' },
|
||||
{ prop: 'areaName', label: '所属地区', align: 'center' },
|
||||
{ prop: 'createTime', label: '被禁言时间', align: 'center' }
|
||||
],
|
||||
tableData: []
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
this.getList()
|
||||
},
|
||||
|
||||
methods: {
|
||||
getList() {
|
||||
this.instance.post(`/app/appneighborhoodassistance/blacklist`, null, {
|
||||
params: {
|
||||
...this.search
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.tableData = res.data.records
|
||||
this.total = res.data.total
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
remove (id) {
|
||||
this.$confirm('确定对该用户解除禁言?').then(() => {
|
||||
this.instance.post(`/app/appneighborhoodassistance/addBlacklist?userId=${id}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('解除成功!')
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
cancel () {
|
||||
this.$emit('change', {
|
||||
type: 'List',
|
||||
isRefresh: true
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
||||
181
project/lulong/AppHelp/components/List.vue
Normal file
181
project/lulong/AppHelp/components/List.vue
Normal file
@@ -0,0 +1,181 @@
|
||||
<template>
|
||||
<ai-list class="notice">
|
||||
<template slot="title">
|
||||
<ai-title title="邻里互助" isShowBottomBorder isShowArea :hideLevel="hideLevel-1" v-model="search.areaId" @change="changeArea">
|
||||
<template #rightBtn>
|
||||
<el-button size="small" type="primary" @click="toGagList">禁言名单</el-button>
|
||||
</template>
|
||||
</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>
|
||||
<el-date-picker
|
||||
v-model="dateList"
|
||||
@change="search.current = 1,getList()"
|
||||
type="daterange"
|
||||
size="small"
|
||||
value-format="yyyy-MM-dd"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期">
|
||||
</el-date-picker>
|
||||
</template>
|
||||
<template #right>
|
||||
<el-input
|
||||
v-model="search.createUserName"
|
||||
class="search-input"
|
||||
size="small"
|
||||
v-throttle="() => {search.current = 1, getList()}"
|
||||
placeholder="请输入发帖人"
|
||||
clearable
|
||||
@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: 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="toDetail(row.id)">详情</el-button>
|
||||
<el-button type="text" @click="remove(row.id)">删除</el-button>
|
||||
<el-button type="text" @click="gag(row.createUserId, row.blacklist)">{{ row.blacklist ? '解除禁言' : '禁言' }}</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,
|
||||
createUserName: '',
|
||||
areaId: ''
|
||||
},
|
||||
total: 0,
|
||||
colConfigs: [
|
||||
{ prop: 'content', label: '内容', align: 'left' },
|
||||
{ prop: 'createUserName', label: '发帖人', align: 'center', width: '120' },
|
||||
{ prop: 'createUserAreaName', label: '所属地区', align: 'center' },
|
||||
{ prop: 'createTime', label: '创建时间', align: 'center' },
|
||||
{ prop: 'commentCount', label: '评论数', align: 'center', width: '120' },
|
||||
{ prop: 'appreciateCount', label: '点赞数', align: 'center', width: '120' },
|
||||
{ prop: 'sharedCount', label: '分享数', align: 'center', width: '120' },
|
||||
{ prop: 'blacklist', label: '状态', align: 'center', format: v => v ? '禁言' : '正常' },
|
||||
{ slot: 'options'},
|
||||
],
|
||||
tableData: [],
|
||||
dateList: [],
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(['user']),
|
||||
hideLevel() {
|
||||
return this.user.info.areaList?.length || 0
|
||||
},
|
||||
},
|
||||
|
||||
created() {
|
||||
this.search.areaId = this.user.info.areaId
|
||||
this.getList()
|
||||
},
|
||||
|
||||
methods: {
|
||||
getList() {
|
||||
this.instance.post(`/app/appneighborhoodassistance/list`, null, {
|
||||
params: {
|
||||
...this.search,
|
||||
createUserAreaId: this.search.areaId,
|
||||
beginDate: this.dateList[0] || '',
|
||||
endDate: this.dateList[1] || '',
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.tableData = res.data.records
|
||||
this.total = res.data.total
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
changeArea () {
|
||||
this.search.current = 1
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.getList()
|
||||
})
|
||||
},
|
||||
|
||||
toGagList () {
|
||||
this.$emit('change', {
|
||||
type: 'GagList'
|
||||
})
|
||||
},
|
||||
|
||||
gag (id, status) {
|
||||
this.$confirm(`确定${status ? '解除禁言' : '禁言'}该用户?`).then(() => {
|
||||
this.instance.post(`/app/appneighborhoodassistance/addBlacklist?userId=${id}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success(`${status ? '解除禁言' : '禁言'}成功!`)
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
remove (id) {
|
||||
this.$confirm('确定删除该帖子?').then(() => {
|
||||
this.instance.post(`/app/appneighborhoodassistance/delete?id=${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>
|
||||
652
project/lulong/AppIntegralStatistics/AppIntegralStatistics.vue
Normal file
652
project/lulong/AppIntegralStatistics/AppIntegralStatistics.vue
Normal file
@@ -0,0 +1,652 @@
|
||||
<template>
|
||||
<section class="AppIntegralStatistics">
|
||||
<ai-detail list>
|
||||
<ai-title slot="title" title="总体统计">
|
||||
<template #rightBtn>
|
||||
<el-row type="flex" align="middle">
|
||||
<span class="shortcut" v-for="(item,i) in timeCheck" :key="i" :class="{active:type==i}"
|
||||
@click="timeChange(i)" v-text="item"/>
|
||||
<el-cascader ref="cascader1" v-model="girdArr" :options="girdOptions" placeholder="所属网格" size="small"
|
||||
:props="defaultProps" :show-all-levels="false" @change="gridChange" clearable/>
|
||||
</el-row>
|
||||
</template>
|
||||
</ai-title>
|
||||
<template #content>
|
||||
<div class="card_list">
|
||||
<div class="card">
|
||||
<h2>积分余额汇总
|
||||
<el-tooltip
|
||||
placement="right"
|
||||
style="width: 16px;"
|
||||
content="截止目前所有居民剩余可用积分余额的总和">
|
||||
<i class="el-icon-warning-outline"></i>
|
||||
</el-tooltip>
|
||||
</h2>
|
||||
<p class="color1">{{ data.nowIntegral || 0 }}</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h2>发放积分</h2>
|
||||
<p class="color1">{{ data.addIntegral || 0 }}</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h2>消耗积分</h2>
|
||||
<p class="color1">{{ Math.abs(data.reduceIntegral) || 0 }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<el-row type="flex" class="mar-t20 gap-20">
|
||||
<div class="chartBox fill">
|
||||
<b>个人积分排行</b>
|
||||
<div>
|
||||
<div id="chart1" style="height: 300px; width: 100%;"
|
||||
v-show="userSortListX.length && userSortListY.length"></div>
|
||||
<ai-empty v-if="!userSortListX.length && !userSortListY.length" style="height: 200px; width: 100%;"
|
||||
id="empty"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="chartBox fill">
|
||||
<b>网格积分排行</b>
|
||||
<div>
|
||||
<div id="chart2" style="height: 300px; width: 100%;" v-show="girdSortListX.length && girdSortListY.length"/>
|
||||
<ai-empty v-show="!girdSortListX.length && !girdSortListY.length" style="height: 200px; width: 100%;"
|
||||
id="empty"/>
|
||||
</div>
|
||||
</div>
|
||||
</el-row>
|
||||
<el-row type="flex" class="mar-t20 gap-20">
|
||||
<div class="chartBox fill" v-for="item in sta" :key="item.id">
|
||||
<div flex>
|
||||
<b class="fill" v-text="item.label"/>
|
||||
<div class="color-primary" v-text="`总次数:${item.total}`"/>
|
||||
</div>
|
||||
<div class="chart" :id="item.id" v-show="item.sta.length>0"/>
|
||||
<ai-empty v-if="item.sta.length==0" style="height: 200px; width: 100%;"/>
|
||||
</div>
|
||||
</el-row>
|
||||
<ai-card class="mar-t20" title="积分明细">
|
||||
<template #content>
|
||||
<ai-search-bar>
|
||||
<template #left>
|
||||
<el-cascader ref="cascader2" v-model="girdIdArr" :options="girdOptions" placeholder="所属网格"
|
||||
size="small"
|
||||
:props="defaultProps" :show-all-levels="false" clearable
|
||||
@change="gridChangeOpt"></el-cascader>
|
||||
<ai-select v-model="search.integralType" placeholder="请选择类型" @change="current=1, getTableData()"
|
||||
:selectList="dict.getDict('integralType')"/>
|
||||
<el-date-picker v-model="time" size="small" type="daterange" value-format="yyyy-MM-dd"
|
||||
range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期"
|
||||
@change="onChange">
|
||||
</el-date-picker>
|
||||
</template>
|
||||
<template #right>
|
||||
<el-input size="small" placeholder="请输入姓名" v-model="search.userName" clearable
|
||||
@clear="current = 1, search.userName = '', getTableData()" suffix-icon="iconfont iconSearch"
|
||||
v-throttle="() => {(current = 1), getTableData();}"/>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table :tableData="tableData" :total="total" :current.sync="current" :size.sync="size"
|
||||
@getList="getTableData" :col-configs="colConfigs" :dict="dict">
|
||||
<el-table-column slot="eventDesc" label='事件' align="center" width="400px" show-overflow-tooltip>
|
||||
<template slot-scope="{ row }">
|
||||
<span>{{ row.integralRuleName || row.eventDesc }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="changeIntegral" label="变动积分" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<span>{{ row.integralCalcType == 0 ? '-' : '+' }}{{ row.changeIntegral }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="options" label="操作" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<el-button type="text" @click="open(row.id)">详情</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</template>
|
||||
</ai-card>
|
||||
</template>
|
||||
</ai-detail>
|
||||
<el-dialog title="详情" :visible.sync="dialog" customFooter width="700">
|
||||
<ai-detail>
|
||||
<template #content>
|
||||
<ai-wrapper>
|
||||
<ai-info-item label="姓名" :value="details.integralUserName"/>
|
||||
<ai-info-item label="所属网格" :value="details.girdName"/>
|
||||
<ai-info-item label="事件" isLine :value="details.eventDesc">
|
||||
<span v-if="details.integralRuleId">{{ details.integralRuleName }}</span>
|
||||
<span v-else>{{ details.eventDesc }}</span>
|
||||
</ai-info-item>
|
||||
<ai-info-item label="时间" isLine :value="details.createTime"/>
|
||||
<ai-info-item label="积分变动">
|
||||
{{ details.integralCalcType == 0 ? '-' : '+' }}{{ details.changeIntegral }}
|
||||
</ai-info-item>
|
||||
<ai-info-item label="积分余额" :value="details.nowIntegral"/>
|
||||
<ai-info-item label="凭证" isLine v-if="fileDownLoad.length">
|
||||
<ai-file-list :fileList="fileDownLoad" style="width: 200px;" :fileOps="{name: 'name'}"></ai-file-list>
|
||||
</ai-info-item>
|
||||
</ai-wrapper>
|
||||
</template>
|
||||
</ai-detail>
|
||||
<span slot="footer" class="dialog-footer" center>
|
||||
<el-button @click="dialog = false" style="width: 92px">关闭</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
<ai-dialog :visible.sync="dialogDate" title="选择时间" width="500px" customFooter>
|
||||
<el-date-picker v-model="timeList" size="small" type="daterange" value-format="yyyy-MM-dd"
|
||||
range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期">
|
||||
</el-date-picker>
|
||||
<el-button slot="footer" @click="selectDete" type="primary">确认</el-button>
|
||||
</ai-dialog>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapState} from "vuex"
|
||||
import * as echarts from 'echarts';
|
||||
import dayjs from 'dayjs'
|
||||
import AiDetail from "dui/packages/layout/AiDetail.vue";
|
||||
import AiTitle from "dui/packages/basic/AiTitle.vue";
|
||||
|
||||
export default {
|
||||
name: "AppIntegralStatistics",
|
||||
components: {AiTitle, AiDetail},
|
||||
label: "积分统计",
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
permissions: Function,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
myChart1: null,
|
||||
myChart2: null,
|
||||
tableData: [],
|
||||
search: {
|
||||
current: 1,
|
||||
userName: '',
|
||||
girdId: '',
|
||||
integralType: '',
|
||||
startTime: '',
|
||||
endTime: '',
|
||||
},
|
||||
girdIdArr: [],
|
||||
total: 0,
|
||||
size: 10,
|
||||
current: 1,
|
||||
girdList: [],
|
||||
time: [],
|
||||
timeCheck: ['昨日', '近7天', '近30天', '自定义'],
|
||||
dialog: false,
|
||||
dialogDate: false,
|
||||
timeList: [],
|
||||
type: '1',
|
||||
startTime: '',
|
||||
endTime: '',
|
||||
data: {},
|
||||
girdId: '',
|
||||
girdArr: [],
|
||||
girdOptions: [],
|
||||
defaultProps: {
|
||||
label: 'girdName',
|
||||
value: 'id',
|
||||
children: 'children',
|
||||
checkStrictly: true,
|
||||
},
|
||||
details: {},
|
||||
fileDownLoad: [],
|
||||
userSortListX: [],
|
||||
userSortListY: [],
|
||||
girdSortListX: [],
|
||||
girdSortListY: [],
|
||||
sta: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(['user']),
|
||||
colConfigs() {
|
||||
return [
|
||||
{prop: "integralUserName", label: '姓名', align: "left", width: "200px"},
|
||||
{prop: "girdName", label: '所属网格', align: "center", width: "180px"},
|
||||
{slot: "eventDesc"},
|
||||
{prop: "integralType", label: '类型', align: "center", dict: "integralType"},
|
||||
{slot: "changeIntegral", label: '积分变动', align: "center",},
|
||||
{prop: "nowIntegral", label: '剩余积分', align: "center",},
|
||||
{prop: "createTime", label: '时间', align: "center",},
|
||||
{slot: "options"}
|
||||
]
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.time = [dayjs().subtract(1, 'week').format('YYYY-MM-DD'), dayjs().format('YYYY-MM-DD')]
|
||||
this.$dict.load('epidemicDangerousAreaLevel', 'integralType', 'integralRuleEvent', 'integralRuleEventType').then(() => {
|
||||
this.getGridList()
|
||||
this.search.startTime = this.time?.[0]
|
||||
this.search.endTime = this.time?.[1]
|
||||
this.getTableData()
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
// 统计接口
|
||||
getStatistics() {
|
||||
return Promise.all([
|
||||
this.instance.post('/app/appintegraluser/allAppletUserIntegral', null, {
|
||||
params: {
|
||||
type: this.type,
|
||||
girdId: this.girdId,
|
||||
startTime: this.startTime,
|
||||
endTime: this.endTime,
|
||||
}
|
||||
}).then(res => {
|
||||
if (res?.data) {
|
||||
return this.data = res.data
|
||||
}
|
||||
}),
|
||||
this.instance.post("/app/appwechatsigninfo/userSignAndIntegralApplyAndIntegralExchangeSort", null, {
|
||||
params: {
|
||||
type: this.type,
|
||||
girdId: this.girdId,
|
||||
startTime: this.startTime,
|
||||
endTime: this.endTime,
|
||||
}
|
||||
}).then(res => {
|
||||
if (res?.data) {
|
||||
const {
|
||||
signCountList = [], integralApplyCountList = [], integralExchangeCountList = [],
|
||||
signCount = 0, integralExchangeCount = 0, integralApplyCount = 0
|
||||
} = res.data
|
||||
return this.sta = [
|
||||
{label: "签到次数统计", id: 'signCount', sta: signCountList, total: signCount},
|
||||
{label: "积分申请次数统计", id: 'integralApplyCount', sta: integralApplyCountList, total: integralApplyCount},
|
||||
{label: "积分兑换次数统计", id: 'integralExchangeCount', sta: integralExchangeCountList, total: integralExchangeCount}
|
||||
]
|
||||
}
|
||||
}).then(() => this.sta.map(this.renderChart))
|
||||
])
|
||||
},
|
||||
// 人员、网格排行
|
||||
getRanking() {
|
||||
return this.instance.post('/app/appintegraluser/userAndGirdIntegralSortByApplet', null, {
|
||||
params: {
|
||||
type: this.type,
|
||||
girdId: this.girdId,
|
||||
startTime: this.startTime,
|
||||
endTime: this.endTime
|
||||
}
|
||||
}).then((res) => {
|
||||
if (res?.data) {
|
||||
this.userSortListX = res.data.userSortList.map(e => e.userName).reverse()
|
||||
this.userSortListY = res.data.userSortList.map(e => e.changeIntegral).reverse()
|
||||
this.girdSortListX = res.data.girdSortList.map(e => e.girdName).reverse()
|
||||
this.girdSortListY = res.data.girdSortList.map(e => e.changeIntegral).reverse()
|
||||
return 1;
|
||||
}
|
||||
}).then(() => {
|
||||
this.getColEcherts1(this.userSortListX, this.userSortListY)
|
||||
this.getColEcherts2(this.girdSortListX, this.girdSortListY)
|
||||
})
|
||||
},
|
||||
// 积分明细
|
||||
getTableData() {
|
||||
this.instance.post('/app/appintegraluser/girdIntegralDetailByApplet', null, {
|
||||
params: {
|
||||
...this.search,
|
||||
current: this.current,
|
||||
size: this.size,
|
||||
total: this.total,
|
||||
}
|
||||
}).then(res => {
|
||||
if (res?.data) {
|
||||
this.tableData = res.data.records
|
||||
this.total = res.data.total
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
gridChangeOpt(val) {
|
||||
this.girdIdArr = val
|
||||
this.search.girdId = val?.[val.length - 1]
|
||||
this.$refs.cascader2.dropDownVisible = false;
|
||||
this.getTableData()
|
||||
},
|
||||
|
||||
getColEcherts1(xData, yData) {
|
||||
let chartDom1 = document.getElementById('chart1');
|
||||
chartDom1.style.width = (window.innerWidth - 435) / 2 + "px";
|
||||
this.myChart1 = echarts.init(chartDom1);
|
||||
this.myChart1.setOption({
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'shadow'
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
left: '16px',
|
||||
right: '28px',
|
||||
bottom: '14px',
|
||||
top: '16px',
|
||||
containLabel: true
|
||||
},
|
||||
xAxis: {
|
||||
type: 'value',
|
||||
boundaryGap: [0, 0.01],
|
||||
},
|
||||
yAxis: {
|
||||
type: 'category',
|
||||
data: xData,
|
||||
axisTick: {
|
||||
show: false,
|
||||
},
|
||||
axisLine: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
series: [
|
||||
{
|
||||
data: yData,
|
||||
type: 'bar',
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: "#5087ec",
|
||||
label: {
|
||||
show: true, //开启显示
|
||||
position: 'right', //在上方显示
|
||||
textStyle: {
|
||||
fontSize: 13,
|
||||
color: '#666'
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
barWidth: 10,
|
||||
barGap: '20%',
|
||||
}
|
||||
]
|
||||
}, true);
|
||||
},
|
||||
getColEcherts2(xData, yData) {
|
||||
let chartDom2 = document.getElementById('chart2');
|
||||
chartDom2.style.width = (window.innerWidth - 435) / 2 + "px";
|
||||
this.myChart2 = echarts.init(chartDom2);
|
||||
this.myChart2.setOption({
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'shadow'
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
left: '16px',
|
||||
right: '28px',
|
||||
bottom: '14px',
|
||||
top: '16px',
|
||||
containLabel: true
|
||||
},
|
||||
xAxis: {
|
||||
type: 'value',
|
||||
boundaryGap: [0, 0.01],
|
||||
},
|
||||
yAxis: {
|
||||
type: 'category',
|
||||
data: xData,
|
||||
axisTick: {
|
||||
show: false,
|
||||
},
|
||||
axisLine: {
|
||||
show: false,
|
||||
},
|
||||
triggerEvent: true,
|
||||
//设置文本过长超出隐藏...表示
|
||||
axisLabel: {
|
||||
margin: 8,
|
||||
formatter: function (params) {
|
||||
var val = ""
|
||||
if (params.length > 8) {
|
||||
val = params.substr(0, 8) + '...'
|
||||
return val
|
||||
} else {
|
||||
return params;
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
series: [
|
||||
{
|
||||
data: yData,
|
||||
type: 'bar',
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: "#5087ec",
|
||||
label: {
|
||||
show: true, //开启显示
|
||||
position: 'right', //在右方显示
|
||||
textStyle: {
|
||||
fontSize: 13,
|
||||
color: '#666'
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
barWidth: 10,
|
||||
barGap: '20%',
|
||||
}
|
||||
]
|
||||
}, true);
|
||||
},
|
||||
onResize() {
|
||||
this.myChart1?.resize()
|
||||
this.myChart2?.resize()
|
||||
this.sta.map(e => e.chart?.resize())
|
||||
},
|
||||
gridChange(val) {
|
||||
this.girdArr = val
|
||||
this.girdId = val?.[val.length - 1]
|
||||
this.$refs.cascader1.dropDownVisible = false;
|
||||
this.getStatistics()
|
||||
this.getRanking()
|
||||
},
|
||||
// 所有网格
|
||||
getGridList() {
|
||||
this.instance.post(`/app/appgirdinfo/listAll3`).then((res) => {
|
||||
if (res?.code == 0) {
|
||||
this.girdOptions = this.toTree(res.data)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 转树形结构
|
||||
toTree(data) {
|
||||
let result = [];
|
||||
if (!Array.isArray(data)) {
|
||||
return result
|
||||
}
|
||||
let map = {};
|
||||
data.forEach(item => {
|
||||
map[item.id] = item;
|
||||
});
|
||||
data.forEach(item => {
|
||||
let parent = map[item.parentGirdId];
|
||||
if (parent) {
|
||||
(parent.children || (parent.children = [])).push(item);
|
||||
} else {
|
||||
result.push(item);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
},
|
||||
|
||||
timeChange(index) {
|
||||
this.type = index
|
||||
if (index == 3) {
|
||||
this.dialogDate = true
|
||||
} else {
|
||||
this.getStatistics()
|
||||
this.getRanking()
|
||||
}
|
||||
},
|
||||
|
||||
open(id) {
|
||||
this.dialog = true
|
||||
this.getDetail(id)
|
||||
},
|
||||
|
||||
onChange(val) {
|
||||
this.search.startTime = val?.[0]
|
||||
this.search.endTime = val?.[1]
|
||||
this.getTableData()
|
||||
},
|
||||
|
||||
getDetail(id) {
|
||||
this.instance.post(`/app/appintegraldetail/queryDetailById?id=${id}`).then(res => {
|
||||
if (res?.data) {
|
||||
this.details = res.data
|
||||
if (res.data.enclosure) {
|
||||
let str = res.data.enclosure.split('/')
|
||||
this.fileDownLoad = [{
|
||||
url: res.data.enclosure,
|
||||
name: str?.[str.length - 1]
|
||||
}]
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
selectDete() {
|
||||
if (!this.timeList || !this.timeList.length) {
|
||||
return this.$message.error('请选择自定义时间');
|
||||
}
|
||||
this.startTime = this.timeList?.[0]
|
||||
this.endTime = this.timeList?.[1]
|
||||
this.dialogDate = false
|
||||
this.getStatistics()
|
||||
this.getRanking()
|
||||
},
|
||||
renderChart(item = {}) {
|
||||
if (!item.chart) {
|
||||
const el = document.getElementById(item.id)
|
||||
el.style.width = (window.innerWidth - 435) / 3 + "px";
|
||||
item.chart = echarts.init(el)
|
||||
}
|
||||
item.chart.setOption({
|
||||
xAxis: {minInterval: 1},
|
||||
tooltip: {},
|
||||
legend: {},
|
||||
yAxis: {type: 'category', axisLabel: {fontSize: 8}},
|
||||
dataset: {dimensions: ['username', 'count', 'integral'], source: item.sta},
|
||||
series: [
|
||||
{name: "次数", barWidth: 10, barGap: '20%', type: 'bar'},
|
||||
{name: "积分", barWidth: 10, barGap: '20%', type: 'bar'}
|
||||
]
|
||||
}, true)
|
||||
}
|
||||
},
|
||||
filters: {
|
||||
formatTime(num) {
|
||||
if (num > 0) {
|
||||
return '+' + num
|
||||
} else {
|
||||
return num
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
window.addEventListener('resize', this.onResize)
|
||||
this.getRanking()
|
||||
this.getStatistics()
|
||||
},
|
||||
destroyed() {
|
||||
window.removeEventListener('resize', this.onResize)
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.AppIntegralStatistics {
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
|
||||
.shortcut {
|
||||
display: inline-block;
|
||||
width: 70px;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
border-radius: 2px;
|
||||
border: 1px solid #D0D4DC;
|
||||
margin-right: 8px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
|
||||
&.active {
|
||||
color: #2266FF;
|
||||
border: 1px solid #2266FF;
|
||||
}
|
||||
}
|
||||
|
||||
.chartBox {
|
||||
background: #F9F9F9;
|
||||
box-shadow: 0px 4px 6px -2px rgba(15, 15, 21, 0.1500);
|
||||
border-radius: 4px;
|
||||
padding: 16px;
|
||||
box-sizing: border-box;
|
||||
|
||||
.chart {
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
}
|
||||
}
|
||||
|
||||
.card_list {
|
||||
display: flex;
|
||||
|
||||
.card {
|
||||
flex: 1;
|
||||
height: 96px;
|
||||
background: #F9F9F9;
|
||||
border-radius: 2px;
|
||||
margin-right: 20px;
|
||||
padding: 16px 24px;
|
||||
box-sizing: border-box;
|
||||
|
||||
h2 {
|
||||
color: #888888;
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: 8px;
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.color1 {
|
||||
color: #2891FF;
|
||||
}
|
||||
|
||||
.color2 {
|
||||
color: #22AA99;
|
||||
}
|
||||
|
||||
.color3 {
|
||||
color: #F8B425;
|
||||
}
|
||||
}
|
||||
|
||||
.card:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
:deep( .el-dialog__footer ) {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
:deep( .el-dialog__header ) {
|
||||
border-bottom: 1px solid #DDD;
|
||||
}
|
||||
|
||||
:deep( .ai-detail ) {
|
||||
background: #FFF;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
68
project/lulong/AppIntegratingAudit/AppIntegratingAudit.vue
Normal file
68
project/lulong/AppIntegratingAudit/AppIntegratingAudit.vue
Normal file
@@ -0,0 +1,68 @@
|
||||
<template>
|
||||
<div class="AppHelp">
|
||||
<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 List from './components/List'
|
||||
|
||||
export default {
|
||||
name: 'AppIntegratingAudit',
|
||||
label: '积分审核',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
component: 'List',
|
||||
params: {},
|
||||
include: []
|
||||
}
|
||||
},
|
||||
|
||||
components: {
|
||||
List,
|
||||
Detail
|
||||
},
|
||||
|
||||
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">
|
||||
.AppHelp {
|
||||
height: 100%;
|
||||
background: #F3F6F9;
|
||||
overflow: auto;
|
||||
}
|
||||
</style>
|
||||
270
project/lulong/AppIntegratingAudit/components/Detail.vue
Normal file
270
project/lulong/AppIntegratingAudit/components/Detail.vue
Normal file
@@ -0,0 +1,270 @@
|
||||
<template>
|
||||
<ai-detail class="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="info.status === '0'">审核</el-button>
|
||||
</template>
|
||||
</ai-title>
|
||||
</template>
|
||||
<template slot="content">
|
||||
<ai-card title="基本信息">
|
||||
<template #content>
|
||||
<ai-wrapper>
|
||||
<ai-info-item label="事件类型" isLine :value="info.applyItemName"></ai-info-item>
|
||||
<ai-info-item label="申请人" :value="info.integralUserName"></ai-info-item>
|
||||
<ai-info-item label="手机号" :value="info.phone"></ai-info-item>
|
||||
<ai-info-item label="所属地区" :value="info.areaName"></ai-info-item>
|
||||
<ai-info-item label="所属网格" :value="info.girdName"></ai-info-item>
|
||||
<ai-info-item label="审核时间" v-if="info.status === '1'" :value="info.auditTime"></ai-info-item>
|
||||
<ai-info-item label="申请时间" v-if="info.status === '0'" :value="info.createTime"></ai-info-item>
|
||||
<ai-info-item label="状态">
|
||||
<span>{{ dict.getLabel('appIntegralApplyEventStatus', info.status) }}</span>
|
||||
<span v-if="info.status === '1'" style="margin-left: 10px; color: green">积分+{{ info.applyIntegral }}</span>
|
||||
</ai-info-item>
|
||||
<ai-info-item label="审批意见" v-if="info.status === '2'" isLine>
|
||||
<span style="color: red;">{{ info.auditDesc }}</span>
|
||||
</ai-info-item>
|
||||
</ai-wrapper>
|
||||
</template>
|
||||
</ai-card>
|
||||
<ai-card title="事件信息">
|
||||
<template #right>
|
||||
<el-button size="small" type="primary" @click="showEvent" v-if="info.status === '0'">编辑</el-button>
|
||||
</template>
|
||||
<template #content>
|
||||
<ai-wrapper>
|
||||
<ai-info-item label="积分值" isLine :value="info.applyIntegral"></ai-info-item>
|
||||
<ai-info-item label="事件描述" isLine :value="info.content"></ai-info-item>
|
||||
<ai-info-item label="图片" isLine v-if="info.images && info.images.length">
|
||||
<div class="files">
|
||||
<!-- <div class="file-item" v-for="(item, index) in info.images" :key="index" v-viewer="{movable: true}">
|
||||
<img :src="item.url">
|
||||
</div> -->
|
||||
<ai-uploader
|
||||
:instance="instance"
|
||||
fileType="img"
|
||||
acceptType=".jpg,.png,.jpeg,.JPG,.PNG,.JPEG"
|
||||
v-model="info.images"
|
||||
:limit="9" :disabled="true">
|
||||
</ai-uploader>
|
||||
</div>
|
||||
</ai-info-item>
|
||||
<ai-info-item label="视频" isLine v-if="info.videos && info.videos.length">
|
||||
<div class="files">
|
||||
<div class="file-item" v-for="(item, index) in info.videos" :key="index">
|
||||
<video controls :src="item.url"></video>
|
||||
</div>
|
||||
</div>
|
||||
</ai-info-item>
|
||||
</ai-wrapper>
|
||||
</template>
|
||||
</ai-card>
|
||||
<ai-dialog
|
||||
:visible.sync="isShow"
|
||||
@onConfirm="onConfirm"
|
||||
@close="onClose"
|
||||
width="890px"
|
||||
title="审核">
|
||||
<el-form class="ai-form" :model="form" label-width="120px" ref="form">
|
||||
<el-form-item label="是否通过" prop="auditStatus" style="width: 100%;" :rules="[{required: true, message: '请选择是否通过', trigger: 'change'}]">
|
||||
<el-radio-group v-model="form.auditStatus">
|
||||
<el-radio label="0">否</el-radio>
|
||||
<el-radio label="1">是</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item prop="auditDesc" v-if="form.auditStatus === '0'" label="审批意见" style="width: 100%" :rules="[{required: true, message: '请输入审批意见', trigger: 'blur'}]">
|
||||
<el-input size="small" type="textarea" :rows="5" v-model="form.auditDesc" clearable placeholder="请输入审批意见"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</ai-dialog>
|
||||
|
||||
<ai-dialog
|
||||
:visible.sync="isShowEvent"
|
||||
@onConfirm="onEventConfirm"
|
||||
@close="onClose"
|
||||
width="890px"
|
||||
title="编辑">
|
||||
<el-form class="ai-form" :model="eventForm" label-width="120px" ref="eventForm">
|
||||
<el-form-item label="积分值" prop="applyIntegral" :rules="[{required: true, message: '请输入积分值', trigger: 'change'}]">
|
||||
<el-input-number style="width: 200px;" size="small" :precision="2" type="input" v-model="eventForm.applyIntegral" clearable placeholder="请输入积分值" :min="0"></el-input-number>
|
||||
</el-form-item>
|
||||
<el-form-item prop="content" label="事件描述" style="width: 100%" :rules="[{required: true, message: '请输入事件描述', trigger: 'blur'}]">
|
||||
<el-input size="small" type="textarea" :rows="5" :maxlength="300" show-word-limit v-model="eventForm.content" clearable placeholder="请输入事件描述"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item style="width: 100%" label="图片">
|
||||
<ai-uploader
|
||||
:instance="instance"
|
||||
fileType="img"
|
||||
acceptType=".jpg,.png,.jpeg"
|
||||
v-model="eventForm.images"
|
||||
:limit="9">
|
||||
</ai-uploader>
|
||||
</el-form-item>
|
||||
<el-form-item style="width: 100%" label="视频">
|
||||
<ai-uploader
|
||||
:instance="instance"
|
||||
fileType="file"
|
||||
acceptType=".mp4,.MOV"
|
||||
v-model="eventForm.videos"
|
||||
:limit="9">
|
||||
</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: {},
|
||||
form: {
|
||||
auditDesc: '',
|
||||
auditStatus: ''
|
||||
},
|
||||
eventForm: {
|
||||
files: null,
|
||||
images: [],
|
||||
videos: [],
|
||||
content: '',
|
||||
applyIntegral: ''
|
||||
},
|
||||
isShowEvent: false,
|
||||
isShow: false
|
||||
}
|
||||
},
|
||||
|
||||
created () {
|
||||
this.getInfo()
|
||||
},
|
||||
|
||||
methods: {
|
||||
getInfo () {
|
||||
this.instance.post(`/app/appintegraluserapply/queryDetailById?id=${this.params.id}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
if (res.data) {
|
||||
this.info = {
|
||||
...res.data,
|
||||
files: res.data.files.map(v => {
|
||||
return {
|
||||
...v,
|
||||
postfix: v.postfix.toLowerCase()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (res.data.status === '0') {
|
||||
this.eventForm.files = res.data.files
|
||||
this.eventForm.content = res.data.content
|
||||
this.eventForm.applyIntegral = res.data.applyIntegral
|
||||
}
|
||||
this.info.images = res.data.files.filter(e => (['jpeg', 'jpg', 'png', 'JPG', 'JPEG', 'PNG'].includes(e.postfix.split('.')[1])))
|
||||
this.info.videos = res.data.files.filter(e => (['mp4', 'MP4', 'MOV'].includes(e.postfix.split('.')[1])))
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
showEvent () {
|
||||
this.eventForm.files = null
|
||||
this.eventForm.content = this.info.content
|
||||
this.eventForm.applyIntegral = this.info.applyIntegral
|
||||
this.eventForm.images = this.info.images
|
||||
this.eventForm.videos = this.info.videos
|
||||
this.isShowEvent = true
|
||||
},
|
||||
|
||||
onClose () {
|
||||
this.form.auditDesc = ''
|
||||
this.form.auditStatus = ''
|
||||
},
|
||||
|
||||
onEventConfirm () {
|
||||
if ((this.eventForm.images.length + this.eventForm.videos.length) > 9) {
|
||||
return this.$message.error('图片和视频不得超过9个')
|
||||
} else {
|
||||
this.eventForm.files = [...this.eventForm.images,...this.eventForm.videos]
|
||||
}
|
||||
this.$refs.eventForm.validate((valid) => {
|
||||
if (valid) {
|
||||
this.instance.post(`/app/appintegraluserapply/updateByGirdMember`, {
|
||||
...this.eventForm,
|
||||
id: this.params.id,
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('编辑成功!')
|
||||
this.isShowEvent = false
|
||||
this.getInfo()
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
onConfirm () {
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (valid) {
|
||||
this.instance.post(`/app/appintegraluserapply/auditById`, {
|
||||
...this.form,
|
||||
id: this.params.id
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('审核成功!')
|
||||
this.isShow = false
|
||||
this.getInfo()
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
cancel () {
|
||||
this.$emit('change', {
|
||||
type: 'List',
|
||||
isRefresh: true
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.detail {
|
||||
.files {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
.file-item {
|
||||
width: 118px;
|
||||
height: 118px;
|
||||
margin: 0 20px 20px 0;
|
||||
|
||||
img, video {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
img {
|
||||
cursor: pointer;
|
||||
transition: all ease 0.3s;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
293
project/lulong/AppIntegratingAudit/components/List.vue
Normal file
293
project/lulong/AppIntegratingAudit/components/List.vue
Normal file
@@ -0,0 +1,293 @@
|
||||
<template>
|
||||
<ai-list class="AppIntegratingAudit">
|
||||
<template slot="title">
|
||||
<ai-title title="积分审核" isShowBottomBorder v-model="search.areaId" isShowArea :hideLevel="hideLevel - 1" @change="changeArea">
|
||||
</ai-title>
|
||||
</template>
|
||||
<template slot="content">
|
||||
<ai-search-bar class="search-bar">
|
||||
<template #left>
|
||||
<ai-select
|
||||
v-model="search.applyItemId"
|
||||
@change="(search.current = 1), getList()"
|
||||
placeholder="请选择事件/类型"
|
||||
:selectList="dictList">
|
||||
</ai-select>
|
||||
<el-date-picker
|
||||
v-model="search.createTimeStart"
|
||||
type="date"
|
||||
size="small"
|
||||
value-format="yyyy-MM-dd"
|
||||
placeholder="选择开始日期"
|
||||
@change="search.current = 1, getList()">
|
||||
</el-date-picker>
|
||||
<el-date-picker
|
||||
v-model="search.createTimeEnd"
|
||||
type="date"
|
||||
size="small"
|
||||
value-format="yyyy-MM-dd"
|
||||
placeholder="选择结束日期"
|
||||
@change="search.current = 1, getList()">
|
||||
</el-date-picker>
|
||||
<ai-picker
|
||||
:instance="instance"
|
||||
:multiple="false"
|
||||
dialogTitle="选择网格"
|
||||
:ops="{ label: 'girdName' }"
|
||||
pageTitle="网格"
|
||||
action="/app/appgirdinfo/girdList"
|
||||
v-model="userList"
|
||||
@pick="onGridChange">
|
||||
<div class="userSelcet">
|
||||
<span style="color: #606266;" v-if="search.girdId">{{ search.girdName }}</span>
|
||||
<span v-else>请选择网格</span>
|
||||
<i class="el-icon-arrow-up" v-if="!search.girdId"></i>
|
||||
<i class="el-icon-circle-close" v-if="search.girdId" @click.stop="userList = [], search.girdId = '', search.girdName = '', search.current = 1, getList()"></i>
|
||||
</div>
|
||||
</ai-picker>
|
||||
<ai-select
|
||||
v-model="search.status"
|
||||
@change="(search.current = 1), getList()"
|
||||
placeholder="请选择状态"
|
||||
:selectList="$dict.getDict('appIntegralApplyEventStatus')">
|
||||
</ai-select>
|
||||
</template>
|
||||
<template #right>
|
||||
<el-input
|
||||
v-model="search.createUserName"
|
||||
class="search-input"
|
||||
size="small"
|
||||
v-throttle="() => {search.current = 1, getList()}"
|
||||
placeholder="请输入申请人、审批人"
|
||||
clearable
|
||||
@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: 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="toDetail(row.id)">详情</el-button>
|
||||
<!-- <el-button type="text" @click="remove(row.id)">删除</el-button> -->
|
||||
<el-button type="text" @click="push(row.id)" v-if="row.status === '1' && row.pushStatus === '0'">推送精选</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</template>
|
||||
</ai-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { MessageBox } from 'element-ui'
|
||||
import { mapState } from 'vuex'
|
||||
export default {
|
||||
name: 'List',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
search: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
areaId: '',
|
||||
applyItemId: '',
|
||||
girdId: '',
|
||||
createTimeStart: '',
|
||||
createTimeEnd: '',
|
||||
girdName: ''
|
||||
},
|
||||
userList: [],
|
||||
dictList: [],
|
||||
total: 10,
|
||||
colConfigs: [
|
||||
{ prop: 'applyItemName', label: '事件类型', align: 'left' },
|
||||
{ prop: 'integralUserName', label: '申请人', align: 'center' },
|
||||
{ prop: 'areaName', label: '所属地区', align: 'center' },
|
||||
{ prop: 'girdName', label: '所属网格', align: 'center' },
|
||||
{ prop: 'createTime', label: '申请时间', align: 'center' },
|
||||
{ prop: 'status', label: '状态', align: 'center', format: v => this.dict.getLabel('appIntegralApplyEventStatus', v) },
|
||||
{ prop: 'auditUserName', label: '审批人', align: 'center' },
|
||||
{ prop: 'pushStatus', label: '推送精选', align: 'center', format: v => this.dict.getLabel('appIntegralApplyEventPushStatus', v) }
|
||||
],
|
||||
tableData: [],
|
||||
dateList: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(['user']),
|
||||
|
||||
hideLevel () {
|
||||
return this.user.info.areaList?.length || 0
|
||||
}
|
||||
},
|
||||
|
||||
created () {
|
||||
this.search.areaId = this.user.info.areaId
|
||||
this.$dict.load('appIntegralApplyEventStatus', 'appIntegralApplyEventPushStatus').then(() => {
|
||||
this.getList()
|
||||
this.getRulesList()
|
||||
})
|
||||
},
|
||||
|
||||
methods: {
|
||||
getRulesList () {
|
||||
this.instance.post(`/app/appintegralrule/listByAppletFD?current=1&size=3000`).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.dictList = res.data.records.map(v => {
|
||||
return {
|
||||
dictName: v.ruleName,
|
||||
dictValue: v.id
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
onGridChange (e) {
|
||||
if (e.length) {
|
||||
this.search.girdId = e[0].id
|
||||
this.search.girdName = e[0].girdName
|
||||
this.search.current = 1
|
||||
this.getList()
|
||||
}
|
||||
},
|
||||
|
||||
getList () {
|
||||
this.instance.post(`/app/appintegraluserapply/list`, null, {
|
||||
params: {
|
||||
...this.search
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.tableData = res.data.records
|
||||
this.total = res.data.total
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
changeArea () {
|
||||
this.search.current = 1
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.getList()
|
||||
})
|
||||
},
|
||||
|
||||
push (id) {
|
||||
MessageBox.confirm('是否将精选内容对全体居民公开,选则否将只对本村/社区居民公开。', '推送精选', {
|
||||
distinguishCancelAndClose: true,
|
||||
confirmButtonText: '是',
|
||||
type: 'warning',
|
||||
closeOnClickModal: false,
|
||||
center: true,
|
||||
customClass: 'AiConfirm',
|
||||
cancelButtonText: '否'
|
||||
}).then(() => {
|
||||
this.instance.post(`/app/appintegraluserapply/pushById?id=${id}&status=1`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.getList()
|
||||
this.$message.success('推送成功')
|
||||
}
|
||||
})
|
||||
}).catch((e) => {
|
||||
e === 'cancel' && this.instance.post(`/app/appintegraluserapply/pushById?id=${id}&status=0`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.getList()
|
||||
this.$message.success('推送成功')
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
remove (id) {
|
||||
this.$confirm('确定删除该帖子?').then((e) => {
|
||||
this.instance.post(`/app/appintegraluserapply/delete?id=${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>
|
||||
.AppIntegratingAudit {
|
||||
.userSelcet {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 215px;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #d0d4dc;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||
|
||||
&:hover {
|
||||
border-color: $placeholderColor;
|
||||
}
|
||||
|
||||
i {
|
||||
display: flex;
|
||||
position: relative;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 30px;
|
||||
height: 100%;
|
||||
line-height: 32px;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
color: #d0d4dc;
|
||||
transform: rotateZ(180deg);
|
||||
}
|
||||
|
||||
.el-icon-circle-close:hover {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
span {
|
||||
flex: 1;
|
||||
padding: 0 15px;
|
||||
font-size: 12px;
|
||||
color: $placeholderColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
63
project/lulong/AppIntegratingPublic/AppIntegratingPublic.vue
Normal file
63
project/lulong/AppIntegratingPublic/AppIntegratingPublic.vue
Normal file
@@ -0,0 +1,63 @@
|
||||
<template>
|
||||
<div class="AppHelp">
|
||||
<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: 'AppIntegratingPublic',
|
||||
label: '积分公示',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
component: 'List',
|
||||
params: {},
|
||||
include: []
|
||||
}
|
||||
},
|
||||
|
||||
components: {
|
||||
Add,
|
||||
List
|
||||
},
|
||||
|
||||
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">
|
||||
.AppHelp {
|
||||
height: 100%;
|
||||
background: #F3F6F9;
|
||||
overflow: auto;
|
||||
}
|
||||
</style>
|
||||
138
project/lulong/AppIntegratingPublic/components/Add.vue
Normal file
138
project/lulong/AppIntegratingPublic/components/Add.vue
Normal file
@@ -0,0 +1,138 @@
|
||||
<template>
|
||||
<ai-detail class="content-add">
|
||||
<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 class="ai-form" :model="form" label-width="120px" ref="form">
|
||||
<el-form-item label="所属网格" prop="girdId" style="width: 100%;" :rules="[{ required: true, message: '请选择所属网格', trigger: 'change' }]">
|
||||
<ai-picker :ops="{label: 'girdName'}" :instance="instance" v-model="form.girdId" @pick="e => onUserChange(e)" dialogTitle="选择所属网格" action="/app/appgirdinfo/girdList">
|
||||
<div class="time-select">
|
||||
<span class="dept-name" style="color:#999;" v-if="!form.girdName">选择所属网格</span>
|
||||
<span class="dept-name" v-else>{{ form.girdName }}</span>
|
||||
<i class="el-icon-arrow-down"></i>
|
||||
</div>
|
||||
</ai-picker>
|
||||
</el-form-item>
|
||||
<el-form-item label="一类" prop="classOne" style="width: 100%;" :rules="[{required: true, message: '请输入一类', trigger: 'change'}]">
|
||||
<el-input placeholder="请输入一类" size="small" v-model="form.classOne"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="二类" prop="classTwo" style="width: 100%;" :rules="[{required: true, message: '请输入二类', trigger: 'change'}]">
|
||||
<el-input placeholder="请输入二类" size="small" v-model="form.classTwo"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="三类" prop="classThree" style="width: 100%;" :rules="[{required: true, message: '请输入三类', trigger: 'change'}]">
|
||||
<el-input placeholder="请输入三类" size="small" v-model="form.classThree"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="分值" prop="integral" style="width: 100%;" :rules="[{required: true, message: '请输入分值', trigger: 'change'}]">
|
||||
<el-input-number v-model="form.integral" :min="0"></el-input-number>
|
||||
</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 {
|
||||
form: {
|
||||
classOne: '',
|
||||
classThree: '',
|
||||
classTwo: '',
|
||||
girdId: '',
|
||||
girdName: '',
|
||||
integral: ''
|
||||
},
|
||||
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/appintegralpublicityinfo/queryDetailById?id=${id}`).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.form = {
|
||||
...res.data,
|
||||
girdId: [res.data.girdId]
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
confirm () {
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (valid) {
|
||||
this.isFlag = true
|
||||
this.instance.post(`/app/appintegralpublicityinfo/addOrUpdate`, {
|
||||
...this.form,
|
||||
girdId: this.form.girdId[0]
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('提交成功')
|
||||
setTimeout(() => {
|
||||
this.cancel(true)
|
||||
}, 600)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
cancel (isRefresh) {
|
||||
this.$emit('change', {
|
||||
type: 'List',
|
||||
isRefresh: !!isRefresh
|
||||
})
|
||||
},
|
||||
|
||||
onUserChange (e) {
|
||||
if (e.length) {
|
||||
this.form.girdName = e[0].girdName
|
||||
} else {
|
||||
this.form.girdId = []
|
||||
this.form.girdName = ''
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.time-select {
|
||||
padding: 0 16px;
|
||||
height: 36px;
|
||||
line-height: 36px;
|
||||
border: 1px solid #d0d4dc;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
cursor: pointer;
|
||||
.el-icon-arrow-down {
|
||||
line-height: 36px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
192
project/lulong/AppIntegratingPublic/components/List.vue
Normal file
192
project/lulong/AppIntegratingPublic/components/List.vue
Normal file
@@ -0,0 +1,192 @@
|
||||
<template>
|
||||
<ai-list class="notice">
|
||||
<template slot="title">
|
||||
<ai-title title="积分公示" isShowBottomBorder>
|
||||
</ai-title>
|
||||
</template>
|
||||
<template slot="content">
|
||||
<ai-search-bar class="search-bar">
|
||||
<template #left>
|
||||
<ai-picker
|
||||
:ops="{label: 'girdName'}"
|
||||
dialogTitle="选择所属网格"
|
||||
action="/app/appgirdinfo/girdList"
|
||||
:instance="instance"
|
||||
@change="search.current = 1, getList()"
|
||||
@pick="onGirdChange"
|
||||
v-model="search.girdId">
|
||||
<div class="userSelcet">
|
||||
<span style="color: #606266;" v-if="search.girdId.length">{{ search.girdName }}</span>
|
||||
<span v-else>请选择网格</span>
|
||||
<i class="el-icon-arrow-up" v-if="!search.girdId.length"></i>
|
||||
<i class="el-icon-circle-close" v-if="search.girdId.length" @click.stop="search.girdId = [], search.girdName, search.current = 1, getList()"></i>
|
||||
</div>
|
||||
</ai-picker>
|
||||
<el-button size="small" type="primary" icon="iconfont iconAdd" @click="toAdd('')">添加</el-button>
|
||||
<ai-import
|
||||
:instance="instance"
|
||||
:dict="dict"
|
||||
type="appintegralpublicityinfo" name="积分公示"
|
||||
@success="search.current = 1, getList()">
|
||||
</ai-import>
|
||||
</template>
|
||||
<template #right>
|
||||
</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="options" width="120px" fixed="right" label="操作" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<div class="table-options">
|
||||
<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,
|
||||
girdId: [],
|
||||
girdName: ''
|
||||
},
|
||||
total: 0,
|
||||
colConfigs: [
|
||||
{ prop: 'girdName', label: '所属网格', align: 'left' },
|
||||
{ prop: 'classOne', label: '一类', align: 'center' },
|
||||
{ prop: 'classTwo', label: '二类', align: 'center' },
|
||||
{ prop: 'classThree', label: '三类', align: 'center' },
|
||||
{ prop: 'integral', label: '分值', align: 'center' },
|
||||
{ slot: 'options'},
|
||||
],
|
||||
tableData: []
|
||||
}
|
||||
},
|
||||
|
||||
created () {
|
||||
this.getList()
|
||||
},
|
||||
|
||||
methods: {
|
||||
onGirdChange (e) {
|
||||
if (e.length) {
|
||||
this.search.girdName = e[0].girdName
|
||||
}
|
||||
|
||||
this.search.current = 1
|
||||
this.getList()
|
||||
},
|
||||
|
||||
getList() {
|
||||
this.instance.post(`/app/appintegralpublicityinfo/list`, null, {
|
||||
params: {
|
||||
...this.search,
|
||||
girdName: '',
|
||||
girdId: this.search.girdId.length ? this.search.girdId[0] : ''
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.tableData = res.data.records
|
||||
this.total = res.data.total
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
remove (id) {
|
||||
this.$confirm('确定删除该数据?').then(() => {
|
||||
this.instance.post(`/app/appintegralpublicityinfo/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>
|
||||
.notice .userSelcet {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 215px;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #d0d4dc;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||
|
||||
&:hover {
|
||||
border-color: $placeholderColor;
|
||||
}
|
||||
|
||||
i {
|
||||
display: flex;
|
||||
position: relative;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 30px;
|
||||
height: 100%;
|
||||
line-height: 32px;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
color: #d0d4dc;
|
||||
transform: rotateZ(180deg);
|
||||
}
|
||||
|
||||
.el-icon-circle-close:hover {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
span {
|
||||
flex: 1;
|
||||
padding: 0 15px;
|
||||
font-size: 12px;
|
||||
color: $placeholderColor;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
43
project/lulong/AppIntegratingRules/AppIntegratingRules.vue
Normal file
43
project/lulong/AppIntegratingRules/AppIntegratingRules.vue
Normal file
@@ -0,0 +1,43 @@
|
||||
<template>
|
||||
<div class="AppHelp">
|
||||
<keep-alive :include="['List']">
|
||||
<component ref="component" :is="component" :params="params" :instance="instance" :dict="dict"></component>
|
||||
</keep-alive>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import List from './components/List'
|
||||
export default {
|
||||
name: 'AppIntegratingRules',
|
||||
label: '积分规则',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
component: 'List',
|
||||
params: {},
|
||||
include: []
|
||||
}
|
||||
},
|
||||
|
||||
components: {
|
||||
List
|
||||
},
|
||||
|
||||
methods: {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.AppHelp {
|
||||
height: 100%;
|
||||
background: #F3F6F9;
|
||||
overflow: auto;
|
||||
}
|
||||
</style>
|
||||
611
project/lulong/AppIntegratingRules/components/List.vue
Normal file
611
project/lulong/AppIntegratingRules/components/List.vue
Normal file
@@ -0,0 +1,611 @@
|
||||
<template>
|
||||
<ai-list class="gridScoreRules">
|
||||
<ai-title
|
||||
slot="title"
|
||||
title="积分规则"
|
||||
isShowBottomBorder>
|
||||
</ai-title>
|
||||
<template slot="content">
|
||||
<ai-search-bar>
|
||||
<template #left>
|
||||
<el-button type="primary" icon="iconfont iconAdd" @click="dialog = true"> 添加</el-button>
|
||||
<el-cascader size="small" v-model="systemRuleIdList" :options="rulesOps" placeholder="请选择事件/类型" clearable :props="rulesProps"
|
||||
@change="handleTypeSearch" ref="eventTypeSearch"/>
|
||||
<ai-select v-model="search.status" @change="(page.current = 1), getList()" placeholder="请选择状态" :selectList="$dict.getDict('integralRuleStatus')">
|
||||
</ai-select>
|
||||
<ai-picker
|
||||
:instance="instance"
|
||||
dialogTitle="选择网格"
|
||||
:ops="{label: 'girdName', id: 'girdCode'}"
|
||||
pageTitle="网格"
|
||||
:action="'/app/appgirdinfo/girdList?idType=1'"
|
||||
v-model="searchGirdList"
|
||||
@pick="onGirdChange">
|
||||
<div class="userSelcet">
|
||||
<span style="color: #606266;" v-if="search.girdCode">{{ girdName }}</span>
|
||||
<span v-else>有效地区</span>
|
||||
<i class="el-icon-arrow-up" v-if="!search.girdCode"></i>
|
||||
<i class="el-icon-circle-close" v-if="search.girdCode" @click.stop="searchGirdList = [], search.girdCode = '', name = '', search.current = 1, getList()"></i>
|
||||
</div>
|
||||
</ai-picker>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table
|
||||
:tableData="tableData"
|
||||
:col-configs="colConfigs"
|
||||
:total="page.total"
|
||||
:dict="dict"
|
||||
:current.sync="page.current"
|
||||
:size.sync="page.size"
|
||||
@getList="getList()">
|
||||
<el-table-column slot="integral" label="分值" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<span>{{ row.integral > 0 ? "+" : "" }}{{ row.integral }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="options" label="操作" align="center" fixed="right" width="160">
|
||||
<template slot-scope="{ row }">
|
||||
<div class="table-options">
|
||||
<el-button type="text" @click="changeStatus(row.id, 0)" v-if="row.status == 1">停用</el-button>
|
||||
<el-button type="text" @click="changeStatus(row.id, 1)" v-else>启用</el-button>
|
||||
<el-button type="text" @click="toEdit(row)">编辑</el-button>
|
||||
<el-button type="text" @click="remove(row.id)">删除</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
<ai-dialog :title="dialogTitle" :visible.sync="dialog" @onConfirm="onConfirm" @close="closed" width="900px">
|
||||
<div class="form_div" v-if="dialog">
|
||||
<el-form ref="DialogForm" :model="form" :rules="formRules" size="small" label-suffix=":" label-width="150px">
|
||||
<el-form-item label="事件类型" prop="systemRuleId">
|
||||
<el-cascader v-model="form.systemRuleId" ref="cascaderArr" :props="etOps" clearable placeholder="请选择" @change="handleTypeForm" :options="rulesOps"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="自定义事件" prop="ruleName" v-if="form.systemRuleId !== '17'">
|
||||
<ai-select v-model="form.ruleName" @change="change" placeholder="请选择自定义事件" :selectList="dict.getDict('appIntegralApplyEventType')">
|
||||
</ai-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="规则">
|
||||
<div>常规</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="周期范围" prop="scoringCycle">
|
||||
<ai-select v-model="form.scoringCycle" :selectList="dict.getDict('integralRuleScoringCycle')" />
|
||||
</el-form-item>
|
||||
<el-form-item label="奖励次数">
|
||||
<el-input type="number" placeholder="请输入,周期范围内,不填写表示不限制" v-model.number="form.numberLimit" clearable />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="积分分值" prop="integral">
|
||||
<el-input placeholder="请输入" v-model="form.integral" clearable/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="有效地区" prop="girdName" required>
|
||||
<ai-picker
|
||||
:instance="instance"
|
||||
dialogTitle="选择网格"
|
||||
:ops="{label: 'girdName', id: 'girdCode'}"
|
||||
pageTitle="网格"
|
||||
:action="'/app/appgirdinfo/girdList?idType=1'"
|
||||
v-model="form.girdCode"
|
||||
@pick="onPick">
|
||||
<div class="AppAnnounceDetail-select">
|
||||
<el-input size="small" class="AppAnnounceDetail-select__input" placeholder="请选择..." disabled v-model="form.girdName"></el-input>
|
||||
<div class="select-left" v-if="girdList.length">
|
||||
<span v-for="(item, index) in girdList" :key="index">{{ item.girdName }}</span>
|
||||
</div>
|
||||
<i v-if="!girdList.length">请选择</i>
|
||||
<div class="select-right">{{ girdList.length ? '重新选择' : '选择' }}</div>
|
||||
</div>
|
||||
</ai-picker>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</ai-dialog>
|
||||
</template>
|
||||
</ai-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "gridScoreRules",
|
||||
label: "积分规则",
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
permissions: Function,
|
||||
},
|
||||
data() {
|
||||
var validcode = (rule, value, callback) => {
|
||||
if (value) {
|
||||
if (value != 0) {
|
||||
if (!/^(([1-9]{1}\d*)|(0{1}))(\.\d{1,2})?$/.test(value)) {
|
||||
callback(new Error('请输入积分分值,只可输入正数、最多保留两位小数'))
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
} else {
|
||||
callback(new Error('请输入有效的积分分值'));
|
||||
}
|
||||
} else {
|
||||
callback(new Error('请输入积分分值'));
|
||||
}
|
||||
}
|
||||
return {
|
||||
girdList: [],
|
||||
girdName: '',
|
||||
search: {
|
||||
status: "",
|
||||
systemRuleId: "",
|
||||
ruleName: "",
|
||||
girdCode: ''
|
||||
},
|
||||
searchGirdList: [],
|
||||
systemRuleIdList: [],
|
||||
page: {current: 1, size: 10, total: 0},
|
||||
colConfigs: [
|
||||
{
|
||||
prop: "parentRuleName",
|
||||
label: "类型",
|
||||
dict: "integralRuleEventType",
|
||||
},
|
||||
{prop: "ruleName", label: "事件", dict: "integralRuleEvent", align: "center"},
|
||||
{prop: "ruleType", label: "规则", dict: "integralRuleRuleType", align: "center"},
|
||||
{
|
||||
prop: "scoringCycle",
|
||||
label: "周期范围",
|
||||
align: "center",
|
||||
dict: "integralRuleScoringCycle",
|
||||
render: (h, {row}) => {
|
||||
return h(
|
||||
"span",
|
||||
{},
|
||||
row.numberLimit.length
|
||||
? $dict.getLabel("integralRuleScoringCycle", row.scoringCycle)
|
||||
: $dict.getLabel("integralRuleScoringCycle", row.scoringCycle) +
|
||||
row.numberLimit +
|
||||
"次"
|
||||
);
|
||||
},
|
||||
},
|
||||
{slot: "integral", label: "积分分值", align: "center"},
|
||||
{
|
||||
prop: "validRangeData",
|
||||
label: "有效地区",
|
||||
align: "center",
|
||||
format: v => JSON.parse(v).girdName
|
||||
},
|
||||
{
|
||||
prop: "status",
|
||||
label: "状态",
|
||||
align: "center",
|
||||
dict: "integralRuleStatus",
|
||||
},
|
||||
{slot: "options", label: "操作", align: "center"},
|
||||
],
|
||||
tableData: [],
|
||||
dialog: false,
|
||||
form: {
|
||||
ruleType: "0",
|
||||
systemRuleId: "",
|
||||
ruleName: "",
|
||||
scoringCycle: "",
|
||||
numberLimit: "",
|
||||
integral: "",
|
||||
validRangeType: "1",
|
||||
validRangeData: "",
|
||||
girdName: '',
|
||||
girdCode: []
|
||||
},
|
||||
formRules: {
|
||||
systemRuleId: [
|
||||
{required: true, message: "请选择事件/类型", trigger: "change"},
|
||||
],
|
||||
ruleName: [
|
||||
{required: true, message: "请选择自定义事件", trigger: "change"},
|
||||
],
|
||||
scoringCycle: [
|
||||
{required: true, message: "请选择周期范围", trigger: "change"},
|
||||
],
|
||||
integral: [{required: true, validator: validcode, trigger: "blur"},],
|
||||
girdName: [
|
||||
{required: true, message: "请选择网格", trigger: "change"},
|
||||
],
|
||||
},
|
||||
rulesOps: [],
|
||||
rulesProps: {
|
||||
label: "ruleName",
|
||||
value: "id",
|
||||
checkStrictly: true,
|
||||
},
|
||||
radio: 0,
|
||||
treeObj: {
|
||||
treeList: [],
|
||||
defaultProps: {
|
||||
label: "girdName",
|
||||
value: "id",
|
||||
children: 'children',
|
||||
isLeaf: 'leaf'
|
||||
},
|
||||
},
|
||||
treeSelected: {},
|
||||
girdInfoList: [],
|
||||
rulueType: "0",
|
||||
girdNameList: [],
|
||||
list: [],
|
||||
isOneAndTen: false,
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.form.areaId = this.$store.state.user.info.areaId
|
||||
this.$dict.load("integralRuleStatus", "integralRuleRuleType", "integralRuleScoringCycle",
|
||||
"integralRuleEvent", "integralRuleEventType", 'appIntegralApplyEventType').then(() => {
|
||||
this.getList();
|
||||
this.getRulesList();
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
onGirdChange (e) {
|
||||
if (e.length) {
|
||||
this.girdName = e[0].girdName
|
||||
this.search.girdCode = e[0].girdCode
|
||||
} else {
|
||||
this.girdName = ''
|
||||
}
|
||||
|
||||
this.searchGirdList = e
|
||||
|
||||
this.page.current = 1
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.getList()
|
||||
})
|
||||
},
|
||||
onPick (e) {
|
||||
if (e.length) {
|
||||
this.form.girdName = e[0].girdName
|
||||
} else {
|
||||
this.form.girdName = ''
|
||||
this.form.girdCode = []
|
||||
}
|
||||
|
||||
this.girdList = e
|
||||
},
|
||||
|
||||
getList() {
|
||||
this.instance
|
||||
.post(`/app/appintegralrule/listByAppletFD`, null, {
|
||||
params: {
|
||||
...this.search,
|
||||
...this.page,
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
if (res?.data) {
|
||||
this.tableData = res.data.records;
|
||||
this.page.total = res.data.total;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
change (e) {
|
||||
},
|
||||
closed () {
|
||||
this.form.ruleType = '0'
|
||||
this.form.systemRuleId = ''
|
||||
this.form.ruleName = ''
|
||||
this.form.scoringCycle = ''
|
||||
this.form.numberLimit = ''
|
||||
this.form.integral = ''
|
||||
this.form.validRangeType = '1'
|
||||
this.form.validRangeData = ''
|
||||
this.form.girdName = ''
|
||||
this.form.girdCode = []
|
||||
this.girdList = []
|
||||
},
|
||||
toEdit(row) {
|
||||
this.form = {...row}
|
||||
if (this.form?.validRangeData) {
|
||||
this.form.girdName = JSON.parse(this.form.validRangeData).girdName
|
||||
this.form.girdCode = [JSON.parse(this.form.validRangeData).girdCode]
|
||||
this.girdList = [JSON.parse(this.form.validRangeData)]
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
this.dialog = true;
|
||||
});
|
||||
},
|
||||
remove(id) {
|
||||
this.$confirm("删除后不可恢复,是否要删除该规则?", {
|
||||
type: "error",
|
||||
}).then(() => {
|
||||
this.instance
|
||||
.post(`/app/appintegralrule/delete?ids=${id}`)
|
||||
.then((res) => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success("删除成功!");
|
||||
this.getList();
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
changeStatus(id, status) {
|
||||
let text = status == 1 ? "启用" : "停用";
|
||||
this.$confirm(`确定${text}该条规则?`).then(() => {
|
||||
this.instance
|
||||
.post(`/app/appintegralrule/enableStatus?id=${id}`)
|
||||
.then((res) => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success(`${text}成功!`);
|
||||
this.getList();
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
onConfirm() {
|
||||
this.$refs.DialogForm.validate((valid) => {
|
||||
if (valid) {
|
||||
let formData = this.$copy(this.form);
|
||||
// formData.ladderRule = JSON.stringify(formData.ladderRule)
|
||||
formData.integral = formData.integral || 0;
|
||||
this.instance
|
||||
.post(`/app/appintegralrule/addOrUpdate`, {
|
||||
...formData,
|
||||
appCodeType: '2',
|
||||
girdCode: '',
|
||||
validRangeData: JSON.stringify({
|
||||
id: this.girdList[0].id,
|
||||
girdName: this.girdList[0].girdName,
|
||||
girdCode: this.girdList[0].girdCode
|
||||
})
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success(
|
||||
`${this.isEdit ? "编辑成功" : "添加成功"}`
|
||||
);
|
||||
this.dialog = false;
|
||||
this.getList();
|
||||
this.closed();
|
||||
this.girdInfoList = []
|
||||
this.girdNameList = []
|
||||
}
|
||||
});
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
},
|
||||
handleTypeSearch(v) {
|
||||
this.systemRuleIdList = v
|
||||
this.search.systemRuleId = v?.[v.length - 1];
|
||||
this.search.ruleName = this.$refs.eventTypeSearch.getCheckedNodes()[0]?.label
|
||||
this.page.current = 1;
|
||||
this.$refs.eventTypeSearch.dropDownVisible = false;
|
||||
this.getList();
|
||||
},
|
||||
handleTypeForm(v) {
|
||||
if (this.dialog) {
|
||||
if(v[1] == '17') {
|
||||
this.form.scoringCycle = '0'
|
||||
this.form.numberLimit = '1'
|
||||
this.isOneAndTen = true
|
||||
} else {
|
||||
this.form.scoringCycle = ''
|
||||
this.form.numberLimit = ''
|
||||
this.isOneAndTen = false
|
||||
}
|
||||
this.form.systemRuleId = v?.[v.length - 1];
|
||||
}
|
||||
},
|
||||
handleDelete(i) {
|
||||
this.$confirm("是否要删除该规则?")
|
||||
.then(() => {
|
||||
this.form.ladderRule.splice(i, 1);
|
||||
})
|
||||
.catch(() => 0);
|
||||
},
|
||||
checkIntegral(v) {
|
||||
return /\.\d{2,}$/.test(v) ? Math.abs(v).toFixed(1) : Math.abs(v);
|
||||
},
|
||||
getRulesList() {
|
||||
this.instance
|
||||
.post(`/app/appintegralsystemrule/listByAppletFD?current=1&size=3000`)
|
||||
.then((res) => {
|
||||
if (res?.data) {
|
||||
this.rulesOps = this.toTree(res.data.records)
|
||||
this.rulesOps.push({
|
||||
ruleName: "积分申请",
|
||||
id: "积分申请",
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
// 转树形结构
|
||||
toTree(data) {
|
||||
let result = [];
|
||||
if (!Array.isArray(data)) {
|
||||
return result;
|
||||
}
|
||||
let map = {};
|
||||
data.forEach((item) => {
|
||||
map[item.id] = item;
|
||||
});
|
||||
data.forEach((item) => {
|
||||
let parent = map[item.parentRuleId];
|
||||
if (parent) {
|
||||
(parent.children || (parent.children = [])).push(item);
|
||||
} else {
|
||||
result.push(item);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isEdit() {
|
||||
return !!this.form.id;
|
||||
},
|
||||
dialogTitle() {
|
||||
return this.isEdit ? "编辑积分规则" : "添加积分规则";
|
||||
},
|
||||
etOps() {
|
||||
return {
|
||||
value: "id",
|
||||
label: "ruleName",
|
||||
};
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.gridScoreRules {
|
||||
height: 100%;
|
||||
background: #f3f6f9;
|
||||
|
||||
.userSelcet {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 215px;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #d0d4dc;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||
|
||||
&:hover {
|
||||
border-color: $placeholderColor;
|
||||
}
|
||||
|
||||
i {
|
||||
display: flex;
|
||||
position: relative;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 30px;
|
||||
height: 100%;
|
||||
line-height: 32px;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
color: #d0d4dc;
|
||||
transform: rotateZ(180deg);
|
||||
}
|
||||
|
||||
.el-icon-circle-close:hover {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
span {
|
||||
flex: 1;
|
||||
padding: 0 15px;
|
||||
font-size: 12px;
|
||||
color: $placeholderColor;
|
||||
}
|
||||
}
|
||||
|
||||
:deep( .ai-list__content--right ){
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
// :deep( .searchRightZone ){
|
||||
// display: flex;
|
||||
// }
|
||||
|
||||
.AppAnnounceDetail-select {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-height: 32px;
|
||||
line-height: 1;
|
||||
background: #F5F5F5;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #D0D4DC;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||
|
||||
&:hover {
|
||||
border-color: #26f;
|
||||
}
|
||||
|
||||
& > i {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
line-height: 32px;
|
||||
padding: 0 12px;
|
||||
color: #888888;
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
border-right: 1px solid #D0D4DC;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.AppAnnounceDetail-select__input {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: -1;
|
||||
opacity: 0;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.select-right {
|
||||
height: 100%;
|
||||
padding: 0 12px;
|
||||
color: #222222;
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
transition: all ease 0.3s;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
.select-left {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
flex: 1;
|
||||
padding: 5px 0 0px 12px;
|
||||
border-right: 1px solid #D0D4DC;
|
||||
border-radius: 4px 0 0 4px;
|
||||
background: #fff;
|
||||
|
||||
em {
|
||||
height: 22px;
|
||||
line-height: 22px;
|
||||
margin: 0 4px 5px 0;
|
||||
color: #222222;
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
span {
|
||||
height: 22px;
|
||||
line-height: 22px;
|
||||
margin: 0 4px 5px 0;
|
||||
padding: 0 8px;
|
||||
font-size: 12px;
|
||||
color: #222222;
|
||||
background: #F3F4F7;
|
||||
border-radius: 2px;
|
||||
border: 1px solid #D0D4DC;
|
||||
}
|
||||
}
|
||||
}
|
||||
:deep( .ai-dialog ){
|
||||
.el-cascader {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.tableInput {
|
||||
& > input {
|
||||
text-align: center;
|
||||
border: none;
|
||||
background: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,106 @@
|
||||
<template>
|
||||
<ai-list v-if="!isShowDetail">
|
||||
<template slot="title">
|
||||
<ai-title title="积分超市" :isShowBottomBorder="false">
|
||||
</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 :ref="String(i)" v-if="currIndex == i" :is="tab.comp" @change="onChange" lazy :instance="instance" :dict="dict" :permissions="permissions"/>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</template>
|
||||
</ai-list>
|
||||
<AddGoods v-else-if="componentName === 'AddGoods'" :params="params" :instance="instance" :dict="dict" @change="onChange"></AddGoods>
|
||||
<AddStore v-else-if="componentName === 'AddStore'" :params="params" :instance="instance" :dict="dict" @change="onChange"></AddStore>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AddGoods from './components/addGoods'
|
||||
import AddStore from './components/AddStore'
|
||||
import StoreList from './components/StoreList'
|
||||
import GoodsList from './components/GoodsList'
|
||||
import { mapState } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'AppIntegratingSupermarket',
|
||||
label: '积分超市',
|
||||
|
||||
components: {
|
||||
GoodsList,
|
||||
StoreList,
|
||||
AddGoods,
|
||||
AddStore
|
||||
},
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
permissions: Function
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['user']),
|
||||
|
||||
tabs () {
|
||||
const tabList = [
|
||||
{label: '商品信息', name: 'GoodsList', comp: GoodsList, permission: ''},
|
||||
{label: '店铺管理', name: 'StoreList', comp: StoreList, permission: ''}
|
||||
].filter(item => {
|
||||
return true
|
||||
})
|
||||
|
||||
return tabList
|
||||
}
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
activeName: 'GoodsList',
|
||||
currIndex: '0',
|
||||
componentName: '',
|
||||
params: {},
|
||||
isShowDetail: false
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
onAreaChange () {
|
||||
if (this.currIndex === '0') {
|
||||
this.$nextTick(() => {
|
||||
this.$refs[this.currIndex][0].getList()
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
onChange (data) {
|
||||
if (data.type === 'GoodsList') {
|
||||
this.componentName = 'GoodsList'
|
||||
this.isShowDetail = false
|
||||
this.params = data.params
|
||||
}
|
||||
if (data.type === 'StoreList') {
|
||||
this.componentName = 'StoreList'
|
||||
this.isShowDetail = false
|
||||
this.params = data.params
|
||||
}
|
||||
|
||||
if (data.type === 'AddGoods') {
|
||||
this.componentName = 'AddGoods'
|
||||
this.isShowDetail = true
|
||||
this.params = data.params
|
||||
}
|
||||
|
||||
if (data.type === 'AddStore') {
|
||||
this.componentName = 'AddStore'
|
||||
this.isShowDetail = true
|
||||
this.params = data.params
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
||||
512
project/lulong/AppIntegratingSupermarket/components/AddStore.vue
Normal file
512
project/lulong/AppIntegratingSupermarket/components/AddStore.vue
Normal file
@@ -0,0 +1,512 @@
|
||||
<template>
|
||||
<ai-detail class="appgoods">
|
||||
<template slot="title">
|
||||
<ai-title :title="id ? '编辑店铺' : '添加店铺'" isShowBack isShowBottomBorder @onBackClick="cancel(false)">
|
||||
</ai-title>
|
||||
</template>
|
||||
<template slot="content">
|
||||
<ai-card title="基本信息">
|
||||
<template #content>
|
||||
<el-form class="ai-form" :model="form" label-width="120px" ref="form">
|
||||
<el-form-item style="width: 100%" label="店铺名称" prop="title" :rules="[{required: true, message: '请输入店铺名称', trigger: 'blur'}]">
|
||||
<el-input type="input" size="small" v-model="form.title" clearable placeholder="请输入店铺名称" :maxlength="50" show-word-limit></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item style="width: 100%" label="店铺类型" prop="type" :rules="[{required: true, message: '请选择店铺类型', trigger: 'change'}]">
|
||||
<ai-select
|
||||
v-model="form.type"
|
||||
placeholder="请选择店铺类型"
|
||||
:selectList="dict.getDict('integralSSType')">
|
||||
</ai-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="可见范围" label-width="120px" prop="serviceType" :rules="[{required: true, message: '请选择可见范围', trigger: 'change'}]">
|
||||
<el-radio-group v-model="form.serviceType" @change="form.girdList = [], girdList = [], form.visibleNames = ''">
|
||||
<el-radio label="0">不限</el-radio>
|
||||
<el-radio label="1">仅指定网格可见</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="选择网格" v-if="form.serviceType === '1'" style="width: 100%;" label-width="120px" prop="visibleNames" :rules="[{ required: true, message: '请选择网格', trigger: 'change' }]">
|
||||
<ai-picker
|
||||
:instance="instance"
|
||||
multiple
|
||||
dialogTitle="选择网格"
|
||||
:ops="{label: 'girdName', id: 'girdCode'}"
|
||||
pageTitle="网格"
|
||||
:action="'/app/appgirdinfo/girdList?idType=1'"
|
||||
v-model="form.girdList"
|
||||
@pick="onPick"
|
||||
@change="onSelcetChange">
|
||||
<div class="AppAnnounceDetail-select">
|
||||
<el-input size="small" class="AppAnnounceDetail-select__input" placeholder="请选择..." disabled v-model="form.visibleNames"></el-input>
|
||||
<div class="select-left" v-if="form.girdList.length">
|
||||
<span v-for="(item, index) in girdList" :key="index" v-if="index < 9">{{ item.girdName }}</span>
|
||||
<em v-if="girdList.length > 9">等{{ girdList.length }}个</em>
|
||||
</div>
|
||||
<i v-if="!form.girdList.length">请选择</i>
|
||||
<div class="select-right">{{ form.girdList.length ? '重新选择' : '选择' }}</div>
|
||||
</div>
|
||||
</ai-picker>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
</ai-card>
|
||||
<ai-card title="商品列表">
|
||||
<template #right>
|
||||
<el-button type="primary" icon="iconfont iconAdd" @click="showList">选择商品</el-button>
|
||||
</template>
|
||||
<template #content>
|
||||
<ai-table
|
||||
:tableData="form.goodsList"
|
||||
:isShowPagination="false"
|
||||
:col-configs="chooseColConfigs"
|
||||
@getList="() => {}">
|
||||
<el-table-column
|
||||
label="商品"
|
||||
slot="goods"
|
||||
align="left"
|
||||
width="300">
|
||||
<template v-slot="{ row }">
|
||||
<div class="goods">
|
||||
<ai-uploader
|
||||
:disabled="true"
|
||||
:instance="instance"
|
||||
:value="[{url: row.goods.picUrl}]"
|
||||
:limit="1">
|
||||
</ai-uploader>
|
||||
<p>{{ row.goods.title }}</p>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
label="兑换所需积分"
|
||||
slot="integralPrice"
|
||||
align="center"
|
||||
width="140">
|
||||
<template v-slot="{ row }">
|
||||
<el-input-number style="width: 120px;" :precision="2" size="small" type="input" v-model="row.integralPrice" :min="0" placeholder="请输入"></el-input-number>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
label="兑换后补差价金额"
|
||||
slot="payMoney"
|
||||
align="center"
|
||||
width="150">
|
||||
<template v-slot="{ row }">
|
||||
<el-input-number style="width: 120px;" :precision="2" size="small" type="input" v-if="row.goods.type !== '0'" :min="0" v-model="row.payMoney" clearable placeholder="请输入"></el-input-number>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
label="库存"
|
||||
slot="stock"
|
||||
align="center"
|
||||
width="140">
|
||||
<template v-slot="{ row }">
|
||||
<el-input-number style="width: 120px;" :precision="0" size="small" type="input" v-model="row.stock" :min="0" clearable placeholder="请输入"></el-input-number>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" slot="options" align="center" width="180" fixed="right">
|
||||
<template v-slot="{ row, $index }">
|
||||
<div class="table-options">
|
||||
<el-button v-if="row.id" type="text" :title="row.status === '0' ? '上架' : '下架'" @click="changeStatus(row.status, $index)">{{ row.status === '0' ? '上架' : '下架' }}</el-button>
|
||||
<el-button type="text" title="删除" @click="remove($index)">删除</el-button>
|
||||
<el-button type="text" title="复制链接" v-if="row.goods.type === '1'" @click="copy(row.goods.jdUrl)">复制链接</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</template>
|
||||
</ai-card>
|
||||
<ai-dialog
|
||||
title="选择商品"
|
||||
:visible.sync="isShow"
|
||||
:destroyOnClose="true"
|
||||
@confirm="onConfirm"
|
||||
width="1080px">
|
||||
<ai-search-bar>
|
||||
<template slot="left">
|
||||
<ai-select
|
||||
v-model="search.type"
|
||||
@change="(search.current = 1), getList()"
|
||||
placeholder="请选择商品类型"
|
||||
:selectList="dict.getDict('integralSGType')">
|
||||
</ai-select>
|
||||
<ai-select
|
||||
v-model="search.status"
|
||||
@change="(search.current = 1), getList()"
|
||||
placeholder="请选择状态"
|
||||
:selectList="dict.getDict('integralSGStatus')">
|
||||
</ai-select>
|
||||
</template>
|
||||
<template slot="right">
|
||||
<el-input
|
||||
v-model="search.title"
|
||||
class="search-input"
|
||||
size="small"
|
||||
v-throttle="() => {search.current = 1, getList()}"
|
||||
placeholder="请输入商品名称/商品类型说明"
|
||||
clearable
|
||||
@clear="search.current = 1, search.title = '', getList()"
|
||||
suffix-icon="iconfont iconSearch">
|
||||
</el-input>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table
|
||||
ref="aiTable"
|
||||
style="margin-top: 8px;"
|
||||
:tableData="tableData"
|
||||
:col-configs="colConfigs"
|
||||
:total="total"
|
||||
:current.sync="search.current"
|
||||
:size.sync="search.size"
|
||||
@selection-change="handleSelectionChange"
|
||||
@getList="getList">
|
||||
<el-table-column
|
||||
label="商品"
|
||||
slot="goods"
|
||||
align="left"
|
||||
width="300">
|
||||
<template v-slot="{ row }">
|
||||
<div class="goods">
|
||||
<ai-uploader
|
||||
:disabled="true"
|
||||
:instance="instance"
|
||||
:value="[{url: row.picUrl}]"
|
||||
:limit="1">
|
||||
</ai-uploader>
|
||||
<p>{{ row.title }}</p>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</ai-dialog>
|
||||
</template>
|
||||
<template #footer>
|
||||
<el-button @click="cancel">取消</el-button>
|
||||
<el-button type="primary" @click="confirm">提交</el-button>
|
||||
</template>
|
||||
</ai-detail>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'AddStore',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
params: Object
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
isShow: false,
|
||||
form: {
|
||||
title: '',
|
||||
type: '',
|
||||
serviceType: '0',
|
||||
visibleNames: '',
|
||||
girdList: [],
|
||||
goodsList: []
|
||||
},
|
||||
girdList: [],
|
||||
id: '',
|
||||
search: {
|
||||
type: '',
|
||||
title: '',
|
||||
current: 1,
|
||||
status: '',
|
||||
size: 10
|
||||
},
|
||||
total: 0,
|
||||
tableData: [],
|
||||
chooseColConfigs: [
|
||||
{ slot: 'goods' },
|
||||
{ prop: 'goods', label: '商品类型', align: 'center', format: v => this.dict.getLabel('integralSGType', v.type) },
|
||||
{ prop: 'typeExplain', label: '商品类型说明'},
|
||||
{ slot: 'integralPrice' },
|
||||
{ slot: 'payMoney' },
|
||||
// { prop: 'goods', label: '商品链接', align: 'center', format: v => v.jdUrl },
|
||||
{ slot: 'stock' },
|
||||
{ prop: 'status', width: 90, label: '状态', align: 'center', format: v => this.dict.getLabel('integralSGStatus', v) || '已上架' }
|
||||
],
|
||||
colConfigs: [
|
||||
{ type: 'selection', label: '', align: 'left' },
|
||||
{ prop: 'serialNumber', label: '商品ID', align: 'center' },
|
||||
{ slot: 'goods', align: 'center' },
|
||||
{ prop: 'type', label: '商品类型', align: 'center', format: v => this.dict.getLabel('integralSGType', v) },
|
||||
{ prop: 'typeExplain', label: '商品类型说明'},
|
||||
{ prop: 'onlineTime', label: '上架时间', align: 'center' },
|
||||
{ prop: 'status', width: 90, label: '状态', align: 'center', format: v => this.dict.getLabel('integralSGStatus', v) }
|
||||
],
|
||||
chooseList: []
|
||||
}
|
||||
},
|
||||
|
||||
created () {
|
||||
this.dict.load('integralSGType', 'integralSGStatus').then(() => {
|
||||
this.getList()
|
||||
})
|
||||
|
||||
if (this.params && this.params.id) {
|
||||
this.id = this.params.id
|
||||
this.getInfo(this.params.id)
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
getList () {
|
||||
this.instance.post(`/app/appintegralsupermarketgoods/list`, null, {
|
||||
params: {
|
||||
...this.search
|
||||
}
|
||||
}).then((res) => {
|
||||
if (res.code == 0) {
|
||||
this.tableData = res.data.records
|
||||
this.total = res.data.total
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
copy (url) {
|
||||
let oInput = document.createElement('input')
|
||||
oInput.value = url
|
||||
document.body.appendChild(oInput)
|
||||
oInput.select()
|
||||
document.execCommand('Copy')
|
||||
this.$message({
|
||||
message: '已复制',
|
||||
type: 'success'
|
||||
})
|
||||
oInput.remove()
|
||||
},
|
||||
|
||||
changeStatus (status, index) {
|
||||
this.$confirm(`确定${status === '0' ? '上架' : '下架'}该商品?`).then(() => {
|
||||
this.$set(this.form.goodsList[index], 'status', status === '0' ? '1' : '0')
|
||||
this.$message.success(`${status === '0' ? '上架' : '下架'}成功`)
|
||||
})
|
||||
},
|
||||
|
||||
handleSelectionChange (e) {
|
||||
this.chooseList = e
|
||||
},
|
||||
|
||||
remove (index) {
|
||||
this.$confirm('确定删除该商品吗?').then(() => {
|
||||
this.form.goodsList.splice(index, 1)
|
||||
this.$message.success('删除成功!')
|
||||
})
|
||||
},
|
||||
|
||||
showList () {
|
||||
this.isShow = true
|
||||
|
||||
// this.$nextTick(() => {
|
||||
// if (this.form.goodsList.length) {
|
||||
// this.form.goodsList.map(v => v.goods).forEach(v => {
|
||||
// if (this.tableData.filter(e => e.id === v.id).length) {
|
||||
// this.$refs.aiTable.toggleRowSelection(this.tableData.filter(e => e.id === v.id)[0], true)
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
// })
|
||||
},
|
||||
|
||||
onConfirm () {
|
||||
this.isShow = false
|
||||
let list = this.chooseList.filter(v => {
|
||||
return this.form.goodsList.map(e => e.goodsId).indexOf(v.id) === -1
|
||||
}).map(v => {
|
||||
return {
|
||||
goods: {
|
||||
...v
|
||||
},
|
||||
goodsId: v.id,
|
||||
integralPrice: undefined,
|
||||
payMoney: undefined,
|
||||
stock: undefined,
|
||||
status: v.status
|
||||
}
|
||||
})
|
||||
|
||||
this.form.goodsList = [
|
||||
...this.form.goodsList ,
|
||||
...list
|
||||
]
|
||||
},
|
||||
|
||||
getInfo (id) {
|
||||
this.instance.post(`/app/appintegralsupermarketshop/queryDetailById?id=${id}`).then(res => {
|
||||
if (res.code === 0) {
|
||||
res.data.goodsList.map((item) => {
|
||||
item.typeExplain = item.goods.typeExplain
|
||||
})
|
||||
this.form = {
|
||||
...res.data,
|
||||
visibleNames: '1',
|
||||
girdList: res.data.serviceType === '1' ? res.data.visibleConfig.map(v => v.visibleId) : []
|
||||
}
|
||||
|
||||
this.girdList = res.data.visibleConfig.map(v => {
|
||||
return {
|
||||
girdCode: v.visibleId,
|
||||
girdName: v.visibleName
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
onPick (e) {
|
||||
this.girdList = e
|
||||
},
|
||||
|
||||
onSelcetChange (e) {
|
||||
if (e.length) {
|
||||
this.form.visibleNames = '1'
|
||||
} else {
|
||||
this.form.visibleNames = ''
|
||||
this.form.girdList = []
|
||||
}
|
||||
},
|
||||
|
||||
confirm () {
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (valid) {
|
||||
if (!this.form.goodsList.length) {
|
||||
return this.$message.error('请选择商品')
|
||||
}
|
||||
|
||||
for (let i = 0; i < this.form.goodsList.length; i++) {
|
||||
// if (!this.form.goodsList[i].integralPrice) {
|
||||
// return this.$message.error('请输入兑换所需积分')
|
||||
// }
|
||||
// if (!this.form.goodsList[i].payMoney && this.form.goodsList[i].goods.type === '1') {
|
||||
// return this.$message.error('请输入兑换后补差价金额')
|
||||
// }
|
||||
if (!this.form.goodsList[i].stock) {
|
||||
return this.$message.error('请输入库存')
|
||||
}
|
||||
}
|
||||
|
||||
this.instance.post(`/app/appintegralsupermarketshop/addOrUpdate`, {
|
||||
...this.form,
|
||||
id: this.params.id || '',
|
||||
visibleConfig: this.form.serviceType === '1' ? this.girdList.map(v => {
|
||||
return {
|
||||
visibleId: v.girdCode,
|
||||
visibleName: v.girdName
|
||||
}
|
||||
}) : []
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('提交成功')
|
||||
setTimeout(() => {
|
||||
this.cancel(true)
|
||||
}, 600)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
cancel (isRefresh) {
|
||||
this.$emit('change', {
|
||||
type: 'GoodsList',
|
||||
isRefresh: !!isRefresh
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.appgoods {
|
||||
.goods {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 250px;
|
||||
height: 120px;
|
||||
}
|
||||
.AppAnnounceDetail-select {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-height: 32px;
|
||||
line-height: 1;
|
||||
background: #F5F5F5;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #D0D4DC;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||
|
||||
&:hover {
|
||||
border-color: #26f;
|
||||
}
|
||||
|
||||
& > i {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
line-height: 32px;
|
||||
padding: 0 12px;
|
||||
color: #888888;
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
border-right: 1px solid #D0D4DC;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.AppAnnounceDetail-select__input {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: -1;
|
||||
opacity: 0;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.select-right {
|
||||
height: 100%;
|
||||
padding: 0 12px;
|
||||
color: #222222;
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
transition: all ease 0.3s;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
.select-left {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
flex: 1;
|
||||
padding: 5px 0 0px 12px;
|
||||
border-right: 1px solid #D0D4DC;
|
||||
border-radius: 4px 0 0 4px;
|
||||
background: #fff;
|
||||
|
||||
em {
|
||||
height: 22px;
|
||||
line-height: 22px;
|
||||
margin: 0 4px 5px 0;
|
||||
color: #222222;
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
span {
|
||||
height: 22px;
|
||||
line-height: 22px;
|
||||
margin: 0 4px 5px 0;
|
||||
padding: 0 8px;
|
||||
font-size: 12px;
|
||||
color: #222222;
|
||||
background: #F3F4F7;
|
||||
border-radius: 2px;
|
||||
border: 1px solid #D0D4DC;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,229 @@
|
||||
<template>
|
||||
<ai-list isTabs class="GoodsList">
|
||||
<template slot="content">
|
||||
<ai-search-bar>
|
||||
<template slot="left">
|
||||
<el-button type="primary" icon="iconfont iconAdd" @click="toAdd('')">添加</el-button>
|
||||
<ai-select
|
||||
v-model="search.type"
|
||||
@change="(search.current = 1), getList()"
|
||||
placeholder="请选择商品类型"
|
||||
:selectList="dict.getDict('integralSGType')">
|
||||
</ai-select>
|
||||
<ai-select
|
||||
v-model="search.status"
|
||||
@change="(search.current = 1), getList()"
|
||||
placeholder="请选择类型"
|
||||
:selectList="dict.getDict('integralSGStatus')">
|
||||
</ai-select>
|
||||
</template>
|
||||
<template slot="right">
|
||||
<el-input
|
||||
v-model="search.title"
|
||||
class="search-input"
|
||||
size="small"
|
||||
v-throttle="() => {search.current = 1, getList()}"
|
||||
placeholder="请输入商品名称"
|
||||
clearable
|
||||
@clear="search.current = 1, search.title = '', getList()"
|
||||
suffix-icon="iconfont iconSearch">
|
||||
</el-input>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table
|
||||
style="margin-top: 8px;"
|
||||
:tableData="tableData"
|
||||
:col-configs="colConfigs"
|
||||
:total="total"
|
||||
:current.sync="search.current"
|
||||
:size.sync="search.size"
|
||||
@getList="getList">
|
||||
<el-table-column
|
||||
label="商品"
|
||||
slot="goods"
|
||||
align="left"
|
||||
width="450">
|
||||
<template v-slot="{ row }">
|
||||
<div class="goods">
|
||||
<!-- <ai-uploader class="upload"
|
||||
:disabled="true"
|
||||
:instance="instance"
|
||||
:value="[{url: row.picUrl}]"
|
||||
:limit="1">
|
||||
<span class="type" :class="`type`+row.type">{{$dict.getLabel('integralSGType', row.type)}}</span>
|
||||
</ai-uploader> -->
|
||||
<div class="img-content">
|
||||
<img :src="row.picUrl" alt="" v-viewer>
|
||||
<!-- <span class="type type0" v-if="row.type === '0'">积分兑换</span>
|
||||
<span class="type type1" v-else>京东低价商品</span> -->
|
||||
<span class="type" :class="`type${row.typeText}`">{{dict.getLabel('integralSGTypeText', row.typeText)}}</span>
|
||||
</div>
|
||||
|
||||
<p>{{ row.title }}</p>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" slot="options" align="center" width="210" fixed="right">
|
||||
<template v-slot="{ row }">
|
||||
<div class="table-options">
|
||||
<el-button type="text" title="编辑" @click="toAdd(row.id)">编辑</el-button>
|
||||
<el-button type="text" :title="row.status === '0' ? '上架' : '下架'" @click="changeStatus(row)">{{ row.status === '0' ? '上架' : '下架' }}</el-button>
|
||||
<el-button type="text" title="删除" @click="remove(row.id)">删除</el-button>
|
||||
<el-button type="text" title="复制链接" v-if="row.type === '1'" @click="copy(row.jdUrl)">复制链接</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</template>
|
||||
</ai-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Viewer from 'v-viewer'
|
||||
import Vue from 'vue'
|
||||
Vue.use(Viewer)
|
||||
export default {
|
||||
name: 'GoodsList',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
permissions: Function
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
search: {
|
||||
type: '',
|
||||
title: '',
|
||||
current: 1,
|
||||
status: '',
|
||||
size: 10,
|
||||
},
|
||||
total: 0,
|
||||
tableData: [],
|
||||
colConfigs: [
|
||||
{ prop: 'serialNumber', label: '商品ID', align: 'left' },
|
||||
{ slot: 'goods', align: 'center' },
|
||||
{ prop: 'type', label: '商品类型', align: 'center', format: v => this.dict.getLabel('integralSGType', v) },
|
||||
{ prop: 'onlineTime', label: '上架时间', align: 'center' },
|
||||
{ prop: 'status', label: '状态', align: 'center', format: v => this.dict.getLabel('integralSGStatus', v) }
|
||||
],
|
||||
userList: []
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
},
|
||||
|
||||
created () {
|
||||
this.dict.load('integralSGType', 'integralSGStatus', 'integralSGTypeText').then(() => {
|
||||
this.getList()
|
||||
})
|
||||
},
|
||||
|
||||
methods: {
|
||||
getList () {
|
||||
this.instance.post(`/app/appintegralsupermarketgoods/list`, null, {
|
||||
params: {
|
||||
...this.search
|
||||
}
|
||||
}).then((res) => {
|
||||
if (res.code == 0) {
|
||||
res.data.records.map((item) => {
|
||||
item.typeText = item.type == 0 ? 0 : 1
|
||||
})
|
||||
this.tableData = res.data.records
|
||||
this.total = res.data.total
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
onAreaChange () {
|
||||
this.search.current = 1
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.getTableData()
|
||||
})
|
||||
},
|
||||
|
||||
toAdd (id) {
|
||||
this.$emit('change', {
|
||||
type: 'AddGoods',
|
||||
params: {
|
||||
id: id || ''
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
copy (url) {
|
||||
let oInput = document.createElement('input')
|
||||
oInput.value = url
|
||||
document.body.appendChild(oInput)
|
||||
oInput.select()
|
||||
document.execCommand('Copy')
|
||||
this.$message({
|
||||
message: '已复制',
|
||||
type: 'success'
|
||||
})
|
||||
oInput.remove()
|
||||
},
|
||||
|
||||
remove (id) {
|
||||
this.$confirm('确定删除该商品吗?').then(() => {
|
||||
this.instance.post(`/app/appintegralsupermarketgoods/delete?id=${id}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('删除成功!')
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
changeStatus (row) {
|
||||
this.$confirm(`确定${row.status === '0' ? '上架' : '下架'}该商品?`).then(() => {
|
||||
this.instance.post(`/app/appintegralsupermarketgoods/online?id=${row.id}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success(`${row.status === '0' ? '上架' : '下架'}成功`)
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.GoodsList {
|
||||
.goods {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.img-content {
|
||||
position: relative;
|
||||
margin-right: 8px;
|
||||
img {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
.type {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 120px;
|
||||
text-align: center;
|
||||
color: #fff;
|
||||
z-index: 999;
|
||||
font-size: 12px;
|
||||
}
|
||||
.type1 {
|
||||
background-color: #E64E39;
|
||||
}
|
||||
.type0 {
|
||||
background-color: #FF6900;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,227 @@
|
||||
<template>
|
||||
<ai-list isTabs class="order_management">
|
||||
<template slot="content">
|
||||
<ai-search-bar>
|
||||
<template slot="left">
|
||||
<el-button type="primary" icon="iconfont iconAdd" @click="toAdd('')">添加</el-button>
|
||||
<ai-select
|
||||
v-model="search.type"
|
||||
@change="(search.current = 1), getList()"
|
||||
placeholder="请选择店铺类型"
|
||||
:selectList="dict.getDict('integralSSType')">
|
||||
</ai-select>
|
||||
<ai-select
|
||||
v-model="search.status"
|
||||
@change="(search.current = 1), getList()"
|
||||
placeholder="请选择状态"
|
||||
:selectList="dict.getDict('integralSSStatus')">
|
||||
</ai-select>
|
||||
<ai-picker
|
||||
:instance="instance"
|
||||
:multiple="false"
|
||||
dialogTitle="请选择服务地区"
|
||||
:ops="{ label: 'girdName' }"
|
||||
pageTitle="网格"
|
||||
action="/app/appgirdinfo/girdList"
|
||||
v-model="userList"
|
||||
@pick="onGridChange">
|
||||
<div class="userSelcet">
|
||||
<span style="color: #606266;" v-if="search.visibleId">{{ search.girdName }}</span>
|
||||
<span v-else>请选择服务地区</span>
|
||||
<i class="el-icon-arrow-up" v-if="!search.visibleId"></i>
|
||||
<i class="el-icon-circle-close" v-if="search.visibleId" @click.stop="search.visibleId = '', search.girdName = '', search.current = 1, getList()"></i>
|
||||
</div>
|
||||
</ai-picker>
|
||||
</template>
|
||||
<template slot="right">
|
||||
<el-input
|
||||
v-model="search.title"
|
||||
class="search-input"
|
||||
size="small"
|
||||
v-throttle="() => {search.current = 1, getList()}"
|
||||
placeholder="请输入店铺名称"
|
||||
clearable
|
||||
@clear="search.current = 1, search.title = '', getList()"
|
||||
suffix-icon="iconfont iconSearch">
|
||||
</el-input>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table
|
||||
style="margin-top: 8px;"
|
||||
:tableData="tableData"
|
||||
:col-configs="colConfigs"
|
||||
:total="total"
|
||||
:current.sync="search.current"
|
||||
:size.sync="search.size"
|
||||
@getList="getList">
|
||||
<el-table-column label="网格店铺服务网格" slot="grid" align="center">
|
||||
<template v-slot="{ row }">
|
||||
<span>{{ row.type === '0' ? (row.visibleNames ? row.visibleNames : row.serviceType === '0' ? '不限' : '-') : '-' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="居民店铺服务地区" slot="area" align="center">
|
||||
<template v-slot="{ row }">
|
||||
<span>{{ row.type === '1' ? (row.visibleNames ? row.visibleNames : row.serviceType === '0' ? '不限' : '-') : '-' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" slot="options" align="center" width="160" fixed="right">
|
||||
<template v-slot="{ row }">
|
||||
<div class="table-options">
|
||||
<el-button type="text" title="编辑" @click="toAdd(row.id)">编辑</el-button>
|
||||
<el-button type="text" :title="row.status === '0' ? '启用' : '停用'" @click="changeStatus(row)">{{ row.status === '0' ? '启用' : '停用' }}</el-button>
|
||||
<el-button type="text" title="删除" @click="remove(row.id)">删除</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</template>
|
||||
</ai-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'GoodsList',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
permissions: Function
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
search: {
|
||||
type: '',
|
||||
title: '',
|
||||
current: 1,
|
||||
status: '',
|
||||
size: 10,
|
||||
visibleId: '',
|
||||
girdName: ''
|
||||
},
|
||||
total: 0,
|
||||
tableData: [],
|
||||
shopList: [],
|
||||
colConfigs: [
|
||||
{ prop: 'serialNumber', label: '店铺ID', align: 'left' },
|
||||
{ prop: 'title', label: '店铺名称', align: 'center' },
|
||||
{ prop: 'type', label: '店铺类型', align: 'center', format: v => this.dict.getLabel('integralSSType', v) },
|
||||
{ slot: 'grid', label: '网格店铺服务网格', align: 'center' },
|
||||
{ slot: 'area', label: '居民店铺服务地区', align: 'center' },
|
||||
{ prop: 'goodsCount', label: '店铺商品数', align: 'center' },
|
||||
{ prop: 'status', label: '状态', align: 'center', format: v => this.dict.getLabel('integralSSStatus', v) }
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
},
|
||||
|
||||
created () {
|
||||
this.dict.load('integralSSType', 'integralSSStatus', 'integralSSSType').then(() => {
|
||||
this.getList()
|
||||
})
|
||||
},
|
||||
|
||||
methods: {
|
||||
onGridChange (e) {
|
||||
if (e.length) {
|
||||
this.search.visibleId = e[0].girdCode
|
||||
this.search.girdName = e[0].girdName
|
||||
this.search.current = 1
|
||||
this.getList()
|
||||
}
|
||||
},
|
||||
getList () {
|
||||
this.instance.post(`/app/appintegralsupermarketshop/list`, null, {
|
||||
params: {
|
||||
...this.search
|
||||
}
|
||||
}).then((res) => {
|
||||
if (res.code == 0) {
|
||||
this.tableData = res.data.records
|
||||
this.total = res.data.total
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
toAdd (id) {
|
||||
this.$emit('change', {
|
||||
type: 'AddStore',
|
||||
params: {
|
||||
id: id || ''
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
remove (id) {
|
||||
this.$confirm('确定删除该商品吗?').then(() => {
|
||||
this.instance.post(`/app/appintegralsupermarketshop/delete?id=${id}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('删除成功!')
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
changeStatus (row) {
|
||||
this.$confirm(`确定${row.status === '0' ? '启用' : '停用'}该商铺?`).then(() => {
|
||||
this.instance.post(`/app/appintegralsupermarketshop/enable?id=${row.id}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success(`${row.status === '0' ? '启用' : '停用'}成功`)
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.order_management {
|
||||
.userSelcet {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 215px;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #d0d4dc;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||
|
||||
&:hover {
|
||||
border-color: $placeholderColor;
|
||||
}
|
||||
|
||||
i {
|
||||
display: flex;
|
||||
position: relative;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 30px;
|
||||
height: 100%;
|
||||
line-height: 32px;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
color: #d0d4dc;
|
||||
transform: rotateZ(180deg);
|
||||
}
|
||||
|
||||
.el-icon-circle-close:hover {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
span {
|
||||
flex: 1;
|
||||
padding: 0 15px;
|
||||
font-size: 12px;
|
||||
color: $placeholderColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
237
project/lulong/AppIntegratingSupermarket/components/addGoods.vue
Normal file
237
project/lulong/AppIntegratingSupermarket/components/addGoods.vue
Normal file
@@ -0,0 +1,237 @@
|
||||
<template>
|
||||
<ai-detail class="appgoods">
|
||||
<template slot="title">
|
||||
<ai-title :title="id ? '编辑商品' : '添加商品'" isShowBack isShowBottomBorder @onBackClick="cancel(false)">
|
||||
</ai-title>
|
||||
</template>
|
||||
<template slot="content">
|
||||
<ai-card title="基本信息">
|
||||
<template #content>
|
||||
<el-form class="ai-form" :model="form" label-width="120px" ref="form">
|
||||
<el-form-item style="width: 100%" label="商品名称" prop="title" :rules="[{required: true, message: '请输入商品名称', trigger: 'blur'}]">
|
||||
<el-input type="input" size="small" v-model="form.title" clearable placeholder="请输入商品名称" :maxlength="50" show-word-limit></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item style="width: 100%" label="商品类型" prop="type" :rules="[{required: true, message: '请选择商品类型', trigger: 'change'}]">
|
||||
<ai-select
|
||||
v-model="form.type"
|
||||
placeholder="请选择商品类型"
|
||||
:selectList="dict.getDict('integralSGType')"
|
||||
@change="onChange">
|
||||
</ai-select>
|
||||
</el-form-item>
|
||||
<el-form-item style="width: 100%" label="商品类型说明" prop="typeExplain">
|
||||
<el-input type="input" size="small" v-model="form.typeExplain" clearable placeholder="请输入商品类型说明" maxlength="50" show-word-limit></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item style="width: 100%" label="商品图片" prop="picUrl" :rules="[{required: true, message: '请选择商品图片', trigger: 'change'}]">
|
||||
<ai-uploader
|
||||
:instance="instance"
|
||||
isShowTip
|
||||
isCrop
|
||||
:cropOps="{
|
||||
fixedNumber: [1, 1]
|
||||
}"
|
||||
v-model="form.picUrl"
|
||||
:limit="1">
|
||||
<template slot="tips">
|
||||
<p>建议尺寸:400*400,支持上传jpg/png格式图片,最多上传一张,单个图片大小不超过10M</p>
|
||||
</template>
|
||||
</ai-uploader>
|
||||
</el-form-item>
|
||||
<el-form-item label="零售价格" prop="retailPrice" :rules="[{required: true, message: '请输入零售价格', trigger: 'change'}]">
|
||||
<el-input-number style="width: 200px;" size="small" :precision="2" type="input" v-model="form.retailPrice" clearable placeholder="请输入零售价格" :min="0"></el-input-number>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="form.type === '2'" label="小程序appid" prop="jdAppid" :rules="[{required: true, message: '请输入京东小程序appid', trigger: 'blur'}]">
|
||||
<el-input type="input" size="small" v-model="form.jdAppid" clearable placeholder="请输入京东小程序appid"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="form.type === '2'" style="width: 100%" label="小程序路径" prop="jdUrl" :rules="[{required: true, message: '请输入小程序路径', trigger: 'blur'}]">
|
||||
<el-input type="input" size="small" v-model="form.jdUrl" clearable placeholder="请输入小程序路径"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="form.type === '1'" label="商品链接" prop="jdUrl" :rules="[{required: true, message: '请输入商品链接', trigger: 'blur'}]">
|
||||
<el-input type="input" size="small" v-model="form.jdUrl" clearable placeholder="请输入商品链接"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item style="width: 100%" label="商品描述" prop="description">
|
||||
<el-input type="textarea" :rows="4" size="small" v-model="form.description" clearable 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">提交</el-button>
|
||||
</template>
|
||||
</ai-detail>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Add',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
params: Object
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
form: {
|
||||
typeExplain: '',
|
||||
title: '',
|
||||
description: '',
|
||||
type: '',
|
||||
jdUrl: '',
|
||||
jdAppid: 'wx91d27dbf599dff74',
|
||||
retailPrice: undefined,
|
||||
picUrl: []
|
||||
},
|
||||
girdList: [],
|
||||
cropOps: {
|
||||
width: '800px',
|
||||
height: '800px'
|
||||
},
|
||||
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/appintegralsupermarketgoods/queryDetailById?id=${id}`).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.form = res.data
|
||||
this.form.picUrl = [{
|
||||
url: res.data.picUrl
|
||||
}]
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
onChange () {
|
||||
if (this.form.type === '2') {
|
||||
this.form.jdUrl = 'pages/gold/item/pages/detail/index?sku=60626768856&sourceType=wx-zhongwei&ea_ptag=17078.27.755'
|
||||
} else {
|
||||
this.form.jdUrl = ''
|
||||
}
|
||||
},
|
||||
|
||||
confirm () {
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (valid) {
|
||||
this.instance.post(`/app/appintegralsupermarketgoods/addOrUpdate`, {
|
||||
...this.form,
|
||||
picUrl: this.form.picUrl[0].url,
|
||||
id: this.params.id || ''
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('提交成功')
|
||||
setTimeout(() => {
|
||||
this.cancel(true)
|
||||
}, 600)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
cancel (isRefresh) {
|
||||
this.$emit('change', {
|
||||
type: 'GoodsList',
|
||||
isRefresh: !!isRefresh
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.appgoods {
|
||||
.AppAnnounceDetail-select {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-height: 32px;
|
||||
line-height: 1;
|
||||
background: #F5F5F5;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #D0D4DC;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||
|
||||
&:hover {
|
||||
border-color: #26f;
|
||||
}
|
||||
|
||||
& > i {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
line-height: 32px;
|
||||
padding: 0 12px;
|
||||
color: #888888;
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
border-right: 1px solid #D0D4DC;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.AppAnnounceDetail-select__input {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: -1;
|
||||
opacity: 0;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.select-right {
|
||||
height: 100%;
|
||||
padding: 0 12px;
|
||||
color: #222222;
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
transition: all ease 0.3s;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
.select-left {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
flex: 1;
|
||||
padding: 5px 0 0px 12px;
|
||||
border-right: 1px solid #D0D4DC;
|
||||
border-radius: 4px 0 0 4px;
|
||||
background: #fff;
|
||||
|
||||
em {
|
||||
height: 22px;
|
||||
line-height: 22px;
|
||||
margin: 0 4px 5px 0;
|
||||
color: #222222;
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
span {
|
||||
height: 22px;
|
||||
line-height: 22px;
|
||||
margin: 0 4px 5px 0;
|
||||
padding: 0 8px;
|
||||
font-size: 12px;
|
||||
color: #222222;
|
||||
background: #F3F4F7;
|
||||
border-radius: 2px;
|
||||
border: 1px solid #D0D4DC;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
70
project/lulong/AppIntegratingTask/AppIntegratingTask.vue
Normal file
70
project/lulong/AppIntegratingTask/AppIntegratingTask.vue
Normal file
@@ -0,0 +1,70 @@
|
||||
<template>
|
||||
<div class="AppHelp">
|
||||
<keep-alive :include="['List']">
|
||||
<component ref="component" :is="component" @change="onChange" :params="params" :instance="instance" :dict="dict"></component>
|
||||
</keep-alive>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Add from './components/Add'
|
||||
import List from './components/List'
|
||||
import Detail from './components/Detail'
|
||||
|
||||
export default {
|
||||
name: 'AppIntegratingTask',
|
||||
label: '积分任务',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
component: 'List',
|
||||
params: {},
|
||||
include: []
|
||||
}
|
||||
},
|
||||
|
||||
components: {
|
||||
Add,
|
||||
List,
|
||||
Detail
|
||||
},
|
||||
|
||||
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">
|
||||
.AppHelp {
|
||||
height: 100%;
|
||||
background: #F3F6F9;
|
||||
overflow: auto;
|
||||
}
|
||||
</style>
|
||||
433
project/lulong/AppIntegratingTask/components/Add.vue
Normal file
433
project/lulong/AppIntegratingTask/components/Add.vue
Normal file
@@ -0,0 +1,433 @@
|
||||
<template>
|
||||
<ai-detail class="activitiesAdd">
|
||||
<ai-title slot="title" :title="id? '编辑活动':'创建活动'" isShowBottomBorder isShowBack @onBackClick="cancel(true)"/>
|
||||
<template slot="content">
|
||||
<ai-card title="基本信息">
|
||||
<template #content>
|
||||
<el-form class="ai-form" ref="form" :model="form" :rules="formRules" size="small" label-width="120px">
|
||||
|
||||
<el-form-item label="活动名称" prop="title" style="width: 100%">
|
||||
<el-input v-model="form.title" placeholder="请输入" show-word-limit maxlength="64"></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="活动说明" style="width: 100%">
|
||||
<el-input type="textarea" :rows="5" v-model="form.detail" placeholder="请输入" show-word-limit maxlength="500"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="活动图片" prop="files">
|
||||
<ai-uploader
|
||||
:instance="instance"
|
||||
v-model="form.files"
|
||||
:limit="9">
|
||||
</ai-uploader>
|
||||
</el-form-item>
|
||||
<el-form-item prop="areaId" style="width: 100%;" label="活动地区" :rules="[{required: true, message: '请选择地区', trigger: 'change'}]">
|
||||
<ai-area-select
|
||||
clearable
|
||||
@fullname="v => form.areaName = v"
|
||||
:disabled-level="$store.state.user.info.areaList.length"
|
||||
always-show
|
||||
:instance="instance"
|
||||
v-model="form.areaId">
|
||||
</ai-area-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="活动地点" style="width: 100%;" prop="address" :rules="[{required: true, message: '请选择活动地点', trigger: 'change'}]">
|
||||
<el-input v-model="form.address" disabled>
|
||||
<template slot="append">
|
||||
<el-button @click="showMap = true">选择位置</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="积分类型" prop="type" style="width: 100%" :rules="[{required: true, message: '请选择积分类型', trigger: 'change'}]">
|
||||
<el-radio-group v-model="form.type" @change="$refs.form.clearValidate()">
|
||||
<el-radio label="0">打卡得积分</el-radio>
|
||||
<el-radio label="1">报名得积分</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="打卡范围" prop="clockRange" style="width: 100%" v-if="form.type === '0'">
|
||||
<el-input type="number" v-model="form.clockRange" placeholder="请输入" >
|
||||
<template slot="append">米</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="form.type === '0' ? '进场打卡时间' : '报名时间'" prop="intoTime">
|
||||
<el-date-picker style="width: 100%" v-model="form.intoTime" type="datetimerange" start-placeholder="开始日期" :picker-options="timeOption"
|
||||
end-placeholder="结束日期" value-format="yyyy-MM-dd HH:mm:ss" ></el-date-picker>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item v-if="form.type === '0'" label="进场得积分" prop="intoIntegral">
|
||||
<el-input v-model="form.intoIntegral" type="number" placeholder="请输入" style="width: 100%">
|
||||
<template slot="append">积分</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item v-if="form.type === '0'" :label="form.type === '0' ? '离场打卡时间' : '离场时间'" prop="exitTime">
|
||||
<el-date-picker style="width: 100%" v-model="form.exitTime" type="datetimerange" start-placeholder="开始日期" :picker-options="timeOption"
|
||||
end-placeholder="结束日期" value-format="yyyy-MM-dd HH:mm:ss">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item v-if="form.type === '0'" label="离场得积分" prop="exitIntegral">
|
||||
<el-input v-model="form.exitIntegral" type="number" placeholder="请输入" style="width: 100%">
|
||||
<template slot="append">积分</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="form.type === '1'" label="报名得积分" prop="enrollIntegral" :rules="[{required: true, message: '请选择报名得积分', trigger: 'blur'}]">
|
||||
<el-input v-model="form.enrollIntegral" type="number" placeholder="请输入" style="width: 100%">
|
||||
<template slot="append">积分</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<ai-dialog title="地图" :visible.sync="showMap" @opened="initMap" :destroyOnclose="false" width="800px" class="mapDialog" @onConfirm="selectMap">
|
||||
<div id="map"></div>
|
||||
<el-form label-width="80px" style="padding: 10px 20px 0 20px;">
|
||||
<el-row type="flex" justify="space-between">
|
||||
<el-form-item label="经度">
|
||||
<el-input disabled size="small" v-model="placeDetail.lng"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="纬度">
|
||||
<el-input disabled size="small" v-model="placeDetail.lat"></el-input>
|
||||
</el-form-item>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<el-input id="searchPlaceInput" size="medium" class="searchPlaceInput" clearable v-model="searchPlace" autocomplete="on" @change="placeSearch.search(searchPlace)" placeholder="请输入关键字">
|
||||
<el-button type="primary" slot="append" @click="placeSearch.search(searchPlace)">搜索</el-button>
|
||||
</el-input>
|
||||
<div id="searchPlaceOutput" />
|
||||
</ai-dialog>
|
||||
</template>
|
||||
</ai-card>
|
||||
</template>
|
||||
<template #footer>
|
||||
<el-button class="delete-btn footer-btn" @click="cancel(false)">取消</el-button>
|
||||
<el-button class="footer-btn" type="primary" @click="confirm()">保存</el-button>
|
||||
</template>
|
||||
</ai-detail>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AMapLoader from '@amap/amap-jsapi-loader'
|
||||
export default {
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
params: Object,
|
||||
},
|
||||
|
||||
data() {
|
||||
var validLocation = (rule, value, callback) => {
|
||||
if(!this.form.lat || !this.form.lng) {
|
||||
return callback(new Error('请标绘地理位置'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
return {
|
||||
form: {
|
||||
title: '',
|
||||
detail: '',
|
||||
lng: '',
|
||||
lat: '',
|
||||
type: '0',
|
||||
areaId: '',
|
||||
enrollIntegral: '',
|
||||
files: [],
|
||||
address: '',
|
||||
clockRange: '',
|
||||
intoTime: [],
|
||||
intoBegintime: '',
|
||||
intoEndtime: '',
|
||||
intoIntegral: '',
|
||||
exitTime: [],
|
||||
exitBegintime: '',
|
||||
exitEndtime: '',
|
||||
exitIntegral: '',
|
||||
},
|
||||
formRules: {
|
||||
title: [{required: true, message: "请输入活动名称", trigger: "blur"}],
|
||||
location: [{required: true, validator: validLocation, trigger: "blur"}],
|
||||
clockRange: [{required: true, message: "请输入打卡范围", trigger: "blur"}],
|
||||
intoTime: [{required: true, message: "请选择进场打卡时间", trigger: "blur"}],
|
||||
intoIntegral: [{required: true, message: "请输入进场得积分", trigger: "blur"}],
|
||||
exitTime: [{required: true, message: "请选择离场打卡时间", trigger: "blur"}]
|
||||
},
|
||||
id: '',
|
||||
isEdit: false,
|
||||
info: {},
|
||||
mapDetail: null,
|
||||
map: null,
|
||||
placeSearch: null,
|
||||
placeDetail: {
|
||||
lng: '',
|
||||
lat: '',
|
||||
address: ''
|
||||
},
|
||||
lng: '',
|
||||
lat: '',
|
||||
showMap: false,
|
||||
searchPlace: '',
|
||||
timeOption: {
|
||||
disabledDate(date) {
|
||||
return date.getTime() < Date.now() - 24 * 60 * 60 * 1000
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.form.areaId = this.$store.state.user.info.areaId
|
||||
this.$dict.load('tfx_activityStatus')
|
||||
if(this.params && this.params.id) {
|
||||
this.id = this.params.id
|
||||
this.getDetail()
|
||||
setTimeout(() => {
|
||||
},500)
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
'form.intoTime': {
|
||||
handler(val) {
|
||||
if(val) {
|
||||
this.form.intoBegintime = val[0]
|
||||
this.form.intoEndtime = val[1]
|
||||
}
|
||||
}
|
||||
},
|
||||
'form.exitTime': {
|
||||
handler(val) {
|
||||
if(val) {
|
||||
this.form.exitBegintime = val[0]
|
||||
this.form.exitEndtime = val[1]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
mounted () {
|
||||
this.$nextTick(() => {
|
||||
this.instance.post("/app/appdvcpconfig/getCorpLocation").then(res => {
|
||||
if (res.code == 0) {
|
||||
this.lng = res.data.lng
|
||||
this.lat = res.data.lat
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
methods: {
|
||||
selectMap() {
|
||||
this.form.lng = this.placeDetail.lng
|
||||
this.form.lat = this.placeDetail.lat
|
||||
this.form.address = this.placeDetail.address
|
||||
this.showMap = false
|
||||
},
|
||||
initMap() {
|
||||
if (this.map) return
|
||||
AMapLoader.load({
|
||||
key: '54a02a43d9828a8f9cd4f26fe281e74e',
|
||||
version: '2.0',
|
||||
plugins: ['AMap.PlaceSearch', 'AMap.AutoComplete', 'AMap.Geocoder'],
|
||||
}).then((AMap) => {
|
||||
this.map = new AMap.Map('map', {
|
||||
resizeEnable: true,
|
||||
zooms: [6, 20],
|
||||
center: this.form.lng ? [this.form.lng, this.form.lat] : [this.lng, this.lat],
|
||||
zoom: 11,
|
||||
})
|
||||
this.placeSearch = new AMap.PlaceSearch({ map: this.map })
|
||||
new AMap.AutoComplete({
|
||||
input: 'searchPlaceInput',
|
||||
output: 'searchPlaceOutput',
|
||||
}).on('select', (e) => {
|
||||
if (e?.poi) {
|
||||
this.placeSearch.setCity(e.poi.adcode)
|
||||
this.movePosition(e.poi.location)
|
||||
}
|
||||
})
|
||||
this.map.on('click', (e) => {
|
||||
new AMap.Geocoder().getAddress(e.lnglat, (sta, res) => {
|
||||
if (res?.regeocode) {
|
||||
this.placeDetail = {
|
||||
lng: e.lnglat?.lng,
|
||||
lat: e.lnglat?.lat,
|
||||
address: res.regeocode.formattedAddress,
|
||||
}
|
||||
}
|
||||
})
|
||||
this.movePosition(e.lnglat)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
movePosition(center) {
|
||||
if (this.map) {
|
||||
this.map.clearMap()
|
||||
this.map.panTo(center)
|
||||
this.map.add([
|
||||
new AMap.Marker({
|
||||
position: center,
|
||||
clickable: true,
|
||||
}),
|
||||
])
|
||||
this.map.setFitView()
|
||||
}
|
||||
},
|
||||
cancel (isRefresh) {
|
||||
this.$emit('change', {
|
||||
type: 'List',
|
||||
isRefresh: !!isRefresh
|
||||
})
|
||||
},
|
||||
|
||||
getMap(lng,lat,address) {
|
||||
AMapLoader.load({
|
||||
key: '54a02a43d9828a8f9cd4f26fe281e74e',
|
||||
version: '2.0',
|
||||
plugins: ['AMap.PlaceSearch', 'AMap.AutoComplete', 'AMap.Geocoder'],
|
||||
}).then((AMap) => {
|
||||
this.mapDetail = new AMap.Map(document.getElementById("mapDetail"), {
|
||||
resizeEnable: true,
|
||||
zooms: [6, 20],
|
||||
zoom: 11,
|
||||
center:[lng,lat],
|
||||
})
|
||||
let marker = new AMap.Marker({
|
||||
position: new AMap.LngLat(lng,lat),
|
||||
title: address
|
||||
})
|
||||
this.mapDetail.add(marker);
|
||||
})
|
||||
},
|
||||
|
||||
update() {
|
||||
this.isEdit = true
|
||||
this.getDetail()
|
||||
},
|
||||
|
||||
getDetail() {
|
||||
this.instance.post(`/app/appintegraltask/queryDetailById`,null, {
|
||||
params: {id:this.id}
|
||||
}).then((res) => {
|
||||
if(res?.data) {
|
||||
this.form = res.data
|
||||
this.form.intoTime = [res.data.intoBegintime,res.data.intoEndtime]
|
||||
this.form.exitTime = [res.data.exitBegintime,res.data.exitEndtime]
|
||||
this.info = res.data
|
||||
this.placeDetail.lng = res.data.lng
|
||||
this.placeDetail.lat = res.data.lat
|
||||
this.getMap(this.info.lng,this.info.lat,this.info.address)
|
||||
}
|
||||
})
|
||||
},
|
||||
selectCandidate(v) {
|
||||
this.form.candidateUsers = v
|
||||
},
|
||||
selectVote(e) {
|
||||
this.form.voteUsers = e
|
||||
},
|
||||
|
||||
handleAreaSelect(v) {
|
||||
this.form.areaName = v?.[0]?.label
|
||||
},
|
||||
|
||||
confirm() {
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (valid) {
|
||||
if(new Date(this.form.intoBegintime).getTime() <= Date.now()){
|
||||
return this.$message.error('进场打卡开始时间不能小于当前时间')
|
||||
}
|
||||
let intoEnd = new Date(this.form.intoEndtime).getTime()
|
||||
let exitBegin = new Date(this.form.exitBegintime).getTime()
|
||||
if(exitBegin <= intoEnd) {
|
||||
return this.$message.error('离场的开始时间不能小于且等于进场的结束时间')
|
||||
}
|
||||
this.instance.post(`/app/appintegraltask/addOrUpdate`,{
|
||||
...this.form
|
||||
}).then(res => {
|
||||
if(res.code == 0) {
|
||||
this.$message.success(this.id ? '编辑成功' : '新增成功')
|
||||
this.cancel(true)
|
||||
}
|
||||
}).catch(err => {
|
||||
console.log(err);
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scope>
|
||||
.activitiesAdd {
|
||||
height: 100%;
|
||||
|
||||
:deep( .amap-logo ){
|
||||
display: none!important;
|
||||
}
|
||||
:deep( .amap-copyright ){
|
||||
display: none!important;
|
||||
}
|
||||
|
||||
:deep( .el-date-editor .el-input ){
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.tips {
|
||||
width: 100%;
|
||||
border: 1px solid #f82;
|
||||
background-color: #fff3e9;
|
||||
color: #f82;
|
||||
padding: 8px 16px;
|
||||
box-sizing: border-box;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 32px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.amap-container {
|
||||
height: 380px;
|
||||
}
|
||||
}
|
||||
|
||||
.mapDialog {
|
||||
.el-dialog__body {
|
||||
padding: 0;
|
||||
.ai-dialog__content {
|
||||
padding: 0;
|
||||
}
|
||||
.ai-dialog__content--wrapper {
|
||||
padding: 0 !important;
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
#map {
|
||||
width: 100%;
|
||||
height: 420px;
|
||||
}
|
||||
|
||||
.searchPlaceInput {
|
||||
position: absolute;
|
||||
width: 250px;
|
||||
top: 30px;
|
||||
left: 25px;
|
||||
}
|
||||
|
||||
#searchPlaceOutput {
|
||||
position: absolute;
|
||||
width: 250px;
|
||||
left: 25px;
|
||||
height: initial;
|
||||
top: 80px;
|
||||
background: white;
|
||||
z-index: 250;
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
|
||||
.auto-item {
|
||||
text-align: left;
|
||||
font-size: 14px;
|
||||
padding: 8px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
192
project/lulong/AppIntegratingTask/components/Detail.vue
Normal file
192
project/lulong/AppIntegratingTask/components/Detail.vue
Normal file
@@ -0,0 +1,192 @@
|
||||
<template>
|
||||
<ai-detail class="activitiesAdd">
|
||||
<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.title"></ai-info-item>
|
||||
<ai-info-item label="创建人" :value="info.createUserName"></ai-info-item>
|
||||
<ai-info-item label="活动说明" isLine :value="info.detail"></ai-info-item>
|
||||
<ai-info-item label="活动图片" isLine>
|
||||
<ai-uploader
|
||||
disabled
|
||||
:instance="instance"
|
||||
:value="info.files">
|
||||
</ai-uploader>
|
||||
</ai-info-item>
|
||||
<ai-info-item label="活动地区" isLine :value="info.areaName"></ai-info-item>
|
||||
<ai-info-item label="活动地点" :value="info.address"></ai-info-item>
|
||||
<ai-info-item label="地图位置" isLine><div id="mapDetail"></div></ai-info-item>
|
||||
<ai-info-item label="积分类型" isLine :value="info.type === '0' ? '打卡得积分' : '报名得积分'"></ai-info-item>
|
||||
<ai-info-item label="活动状态">
|
||||
{{ dict.getLabel('fdIntegralTaskStatus',info.status) }}
|
||||
</ai-info-item>
|
||||
<ai-info-item v-if="info.type === '0'" label="打卡范围">{{ info.clockRange }}米</ai-info-item>
|
||||
<ai-info-item :label="info.type === '0' ? '进场打卡时间' : '报名时间'">{{ info.intoBegintime }}至{{ info.intoEndtime}}</ai-info-item>
|
||||
<ai-info-item v-if="info.type === '0'" label="进场得积分">{{ info.intoIntegral || 0 }}分</ai-info-item>
|
||||
<ai-info-item v-if="info.type === '0'" :label="info.type === '0' ? '离场打卡时间' : '离场时间'">{{ info.exitBegintime }}至{{ info.exitEndtime}}</ai-info-item>
|
||||
<ai-info-item v-if="info.type === '0'" label="离场得积分">{{ info.exitIntegral || 0 }}分</ai-info-item>
|
||||
<ai-info-item v-if="info.type === '1'" label="报名得积分">{{ info.enrollIntegral || 0 }}分</ai-info-item>
|
||||
</ai-wrapper>
|
||||
</template>
|
||||
</ai-card>
|
||||
<ai-card title="打卡记录" v-if="info.type === '0'">
|
||||
<template #content>
|
||||
<ai-wrapper>
|
||||
<ai-info-item label="参与人数" :value="search1.total"></ai-info-item>
|
||||
</ai-wrapper>
|
||||
<ai-table
|
||||
:tableData="tableData1"
|
||||
:col-configs="colConfigs1"
|
||||
:total="search1.total"
|
||||
:current.sync="search1.current"
|
||||
:size.sync="search1.size"
|
||||
@getList="getList1">
|
||||
</ai-table>
|
||||
</template>
|
||||
</ai-card>
|
||||
<ai-card title="报名记录" v-if="info.type === '1'">
|
||||
<template #content>
|
||||
<ai-wrapper>
|
||||
<ai-info-item label="参与人数" :value="search1.total"></ai-info-item>
|
||||
</ai-wrapper>
|
||||
<ai-table
|
||||
:tableData="tableData1"
|
||||
:col-configs="colConfigs2"
|
||||
:total="search1.total"
|
||||
:current.sync="search1.current"
|
||||
:size.sync="search1.size"
|
||||
@getList="getList1">
|
||||
</ai-table>
|
||||
</template>
|
||||
</ai-card>
|
||||
</template>
|
||||
</ai-detail>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AMapLoader from '@amap/amap-jsapi-loader'
|
||||
export default {
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
params: Object,
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
id: '',
|
||||
info: {},
|
||||
mapDetail: null,
|
||||
map: null,
|
||||
search1: {
|
||||
total: 0,
|
||||
current: 1,
|
||||
size: 10
|
||||
},
|
||||
tableData1: [],
|
||||
colConfigs1: [
|
||||
{prop: 'realName', label: '姓名', align: 'center' },
|
||||
{prop: 'phone', label: '联系方式', align: 'center' },
|
||||
{prop: 'areaName', label: '所属地区', align: 'center' },
|
||||
{prop: 'intoClockTime', label: '进场打卡时间', align: 'center' },
|
||||
{prop: 'exitClockTime', label: '离场打卡时间', align: 'center' }
|
||||
],
|
||||
colConfigs2: [
|
||||
{prop: 'realName', label: '姓名', align: 'center' },
|
||||
{prop: 'phone', label: '联系方式', align: 'center' },
|
||||
{prop: 'areaName', label: '所属地区', align: 'center' },
|
||||
{prop: 'enrollClockTime', label: '报名时间', align: 'center' }
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
created () {
|
||||
this.id = this.params.id
|
||||
this.$dict.load('tfx_activityStatus').then(() => {
|
||||
this.getDetail()
|
||||
})
|
||||
|
||||
this.getList1()
|
||||
},
|
||||
|
||||
methods: {
|
||||
cancel (isRefresh) {
|
||||
this.$emit('change', {
|
||||
type: 'List',
|
||||
isRefresh: !!isRefresh
|
||||
})
|
||||
},
|
||||
|
||||
getList1 () {
|
||||
this.instance.post(`/app/appintegraltask/clockList?taskId=${this.params.id}`,null, {
|
||||
params: {
|
||||
...this.search1,
|
||||
}
|
||||
}).then(res=> {
|
||||
if(res?.data) {
|
||||
this.tableData1 = res.data.records
|
||||
this.search1.total = res.data.total
|
||||
}
|
||||
})
|
||||
},
|
||||
getMap(lng,lat,address) {
|
||||
AMapLoader.load({
|
||||
key: '54a02a43d9828a8f9cd4f26fe281e74e',
|
||||
version: '2.0',
|
||||
plugins: ['AMap.PlaceSearch', 'AMap.AutoComplete', 'AMap.Geocoder'],
|
||||
}).then((AMap) => {
|
||||
this.mapDetail = new AMap.Map(document.getElementById("mapDetail"), {
|
||||
resizeEnable: true,
|
||||
zooms: [6, 20],
|
||||
zoom: 11,
|
||||
center:[lng,lat],
|
||||
})
|
||||
let marker = new AMap.Marker({
|
||||
position: new AMap.LngLat(lng,lat),
|
||||
title: address
|
||||
})
|
||||
this.mapDetail.add(marker);
|
||||
})
|
||||
},
|
||||
|
||||
update() {
|
||||
this.isEdit = true
|
||||
this.getDetail()
|
||||
},
|
||||
|
||||
getDetail() {
|
||||
this.instance.post(`/app/appintegraltask/queryDetailById?id=${this.params.id}`).then((res) => {
|
||||
if(res.data) {
|
||||
this.info = res.data
|
||||
this.getMap(this.info.lng, this.info.lat, this.info.address)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scope>
|
||||
.activitiesAdd {
|
||||
height: 100%;
|
||||
|
||||
:deep( .amap-logo ){
|
||||
display: none!important;
|
||||
}
|
||||
:deep( .amap-copyright ){
|
||||
display: none!important;
|
||||
}
|
||||
|
||||
:deep( .el-date-editor .el-input ){
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.amap-container {
|
||||
height: 380px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
223
project/lulong/AppIntegratingTask/components/List.vue
Normal file
223
project/lulong/AppIntegratingTask/components/List.vue
Normal file
@@ -0,0 +1,223 @@
|
||||
<template>
|
||||
<ai-list class="activitiesList">
|
||||
<ai-title
|
||||
slot="title"
|
||||
title="活动管理"
|
||||
isShowBottomBorder
|
||||
isShowArea
|
||||
:hideLevel="$store.state.user.info.areaList.length - 1"
|
||||
v-model="search.areaId"
|
||||
:instance="instance"
|
||||
@change="search.current = 1, getList()">
|
||||
</ai-title>
|
||||
<template #content>
|
||||
<ai-search-bar bottomBorder>
|
||||
<template #left>
|
||||
<el-button size="small" type="primary" icon="iconfont iconAdd" @click="toAdd('')" >创建活动</el-button>
|
||||
<el-date-picker
|
||||
v-model="search.beginDate"
|
||||
type="date"
|
||||
size="small"
|
||||
value-format="yyyy-MM-dd"
|
||||
placeholder="选择开始日期"
|
||||
@change="search.current = 1, getList()">
|
||||
</el-date-picker>
|
||||
<el-date-picker
|
||||
v-model="search.endDate"
|
||||
type="date"
|
||||
size="small"
|
||||
value-format="yyyy-MM-dd"
|
||||
placeholder="选择结束日期"
|
||||
@change="search.current = 1, getList()">
|
||||
</el-date-picker>
|
||||
<ai-select
|
||||
v-model="search.status"
|
||||
clearable
|
||||
placeholder="活动状态"
|
||||
:selectList="dict.getDict('fdIntegralTaskStatus')"
|
||||
@change="search.current = 1, getList()">
|
||||
</ai-select>
|
||||
</template>
|
||||
<template #right>
|
||||
<el-input
|
||||
v-model="search.title"
|
||||
size="small"
|
||||
placeholder="活动名称/创建人"
|
||||
clearable
|
||||
v-throttle="() => {getList()}"
|
||||
@clear="search.title = '', getList()"
|
||||
suffix-icon="iconfont iconSearch">
|
||||
</el-input>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table
|
||||
:tableData="tableData"
|
||||
:total="search.total"
|
||||
:current.sync="search.current"
|
||||
:size.sync="search.size"
|
||||
@getList="getList"
|
||||
:col-configs="colConfigs"
|
||||
:dict="dict">
|
||||
<el-table-column slot="qrcode" width="200px" label="二维码" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<div class="qrcode">
|
||||
<el-button type="text" @click="qrcode(row.qrCode, row.id)">{{ row.qrCode ? '预览' : '生成' }}</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="options" label="操作" fixed="right" align="center" width="120px">
|
||||
<template slot-scope="{ row }">
|
||||
<div class="table-options">
|
||||
<el-button type="text" @click.native="toDetail(row.id)">详情</el-button>
|
||||
<el-button type="text" :disabled="row.status ==2" @click.native="stopBtn(row.id)">结束</el-button>
|
||||
<!-- <el-button type="text" @click.native="handleDelete(row.id)">删除</el-button> -->
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
<div class="qrCode" v-viewer="{movable: true}" v-show="false">
|
||||
<img :src="img">
|
||||
</div>
|
||||
</template>
|
||||
</ai-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
search: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
total: 0,
|
||||
title: '',
|
||||
areaId: '',
|
||||
status: '',
|
||||
beginDate: '',
|
||||
endDate: ''
|
||||
},
|
||||
tableData: [],
|
||||
img: '',
|
||||
isLoading: false,
|
||||
}
|
||||
},
|
||||
|
||||
created () {
|
||||
this.search.areaId = this.$store.state.user.info.areaId
|
||||
this.$dict.load('fdIntegralTaskStatus').then(()=> {
|
||||
this.getList()
|
||||
})
|
||||
},
|
||||
|
||||
computed: {
|
||||
colConfigs() {
|
||||
return [
|
||||
{ prop: "title", label: "活动名称", align: "left" },
|
||||
{ prop: "areaName", label: "活动地区", align: "center" },
|
||||
{ prop: "createUserName", label: "创建人", align: "center" },
|
||||
{
|
||||
prop: "intoBegintime",
|
||||
label: "开始结束时间",
|
||||
align: "center",
|
||||
width: "400px",
|
||||
render: (h, {row}) => h('p',
|
||||
{
|
||||
textAlign: 'center'
|
||||
},
|
||||
row.exitEndtime ? `${row.intoBegintime}至${row.exitEndtime}` : row.intoBegintime)
|
||||
},
|
||||
{ prop: "status", label: "活动状态", align: "center", dict:"fdIntegralTaskStatus" },
|
||||
{ slot: "qrcode" },
|
||||
{ slot: "options", },
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
getList() {
|
||||
this.instance.post(`/app/appintegraltask/list`,null, {
|
||||
params: {
|
||||
...this.search,
|
||||
}
|
||||
}).then(res=> {
|
||||
if(res?.data) {
|
||||
this.tableData = res.data.records
|
||||
this.search.total = res.data.total
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
toDetail (id) {
|
||||
this.$emit('change', {
|
||||
type: 'Detail',
|
||||
params: {
|
||||
id: id || '',
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
toAdd(id) {
|
||||
this.$emit('change', {
|
||||
type: 'Add',
|
||||
params: {
|
||||
id: id || '',
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
qrcode (qrcode, id) {
|
||||
if (!qrcode) {
|
||||
this.isLoading = true
|
||||
this.instance.post(`/app/appintegraltask/generateQrCode?id=${id}&width=400&height=400`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('二维码生成成功!')
|
||||
this.getList()
|
||||
}
|
||||
this.isLoading = false
|
||||
})
|
||||
} else {
|
||||
this.img = qrcode
|
||||
this.$nextTick(() => {
|
||||
setTimeout(() => {
|
||||
const viewer = this.$el.querySelector('.qrCode').$viewer
|
||||
viewer.view()
|
||||
}, 600)
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
handleDelete (id) {
|
||||
this.$confirm('确定删除该活动?').then(() => {
|
||||
this.instance.post(`/app/appintegraltask/delete?ids=${id}`).then(res=>{
|
||||
if(res.code == 0) {
|
||||
this.$message.success('删除成功!')
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
stopBtn (id) {
|
||||
this.$confirm('确定要结束该活动吗?').then(() => {
|
||||
this.instance.post(`/app/appintegraltask/stop?id=${id}`).then(res=>{
|
||||
if(res.code == 0) {
|
||||
this.$message.success('结束成功!')
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.activitiesList {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
69
project/lulong/AppResidentInfo/AppResidentInfo.vue
Normal file
69
project/lulong/AppResidentInfo/AppResidentInfo.vue
Normal file
@@ -0,0 +1,69 @@
|
||||
<template>
|
||||
<div class="AppHelp">
|
||||
<keep-alive :include="['List']">
|
||||
<component ref="component" :permissions="permissions" :is="component" @change="onChange" :params="params" :instance="instance" :dict="dict"></component>
|
||||
</keep-alive>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Add from './components/Add'
|
||||
import List from './components/List'
|
||||
import Detail from './components/Detail'
|
||||
|
||||
export default {
|
||||
name: 'AppResidentInfo',
|
||||
label: '积分账户',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
permissions: Function
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
component: 'List',
|
||||
params: {},
|
||||
include: []
|
||||
}
|
||||
},
|
||||
|
||||
components: {
|
||||
Add,
|
||||
List,
|
||||
Detail
|
||||
},
|
||||
|
||||
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(() => {
|
||||
this.$refs.component.getList()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.AppHelp {
|
||||
height: 100%;
|
||||
background: #F3F6F9;
|
||||
overflow: auto;
|
||||
}
|
||||
</style>
|
||||
717
project/lulong/AppResidentInfo/components/Add.vue
Normal file
717
project/lulong/AppResidentInfo/components/Add.vue
Normal file
@@ -0,0 +1,717 @@
|
||||
<template>
|
||||
<ai-detail class="residentDetail">
|
||||
<ai-title slot="title" :title="pageTitle" isShowBack @onBackClick="back" isShowBottomBorder>
|
||||
<template v-if="params.type === 'Detail'" #rightBtn>
|
||||
<el-button icon="iconfont iconDelete" @click="handleDelete()">
|
||||
删除人员
|
||||
</el-button>
|
||||
</template>
|
||||
</ai-title>
|
||||
<template #content>
|
||||
<el-form class="content-right" :model="baseInfo" ref="ruleForm" :rules="rules" label-width="130px"
|
||||
label-position="right" size="small">
|
||||
<template v-if="params.type === 'Detail'">
|
||||
<ai-edit-card slot="" :title="baseInfo.name||'基本信息'" :show-btn="permissions('app_appresident_edit')"
|
||||
@save="saveFrom" @cancel="getDetail(baseInfo.id)">
|
||||
<template #edit>
|
||||
<el-row type="flex">
|
||||
<div class="fill">
|
||||
<el-form-item label="姓名:" prop="name">
|
||||
<el-input
|
||||
v-model="baseInfo.name"
|
||||
autocomplete="off"
|
||||
placeholder="请输入姓名"
|
||||
maxlength="20"
|
||||
:disabled="isEdit"
|
||||
show-word-limit/>
|
||||
</el-form-item>
|
||||
<el-form-item label="身份证号:" prop="idNumber">
|
||||
<el-input v-model="baseInfo.idNumber" placeholder="请输入身份证号" :maxlength="18" show-word-limit
|
||||
@change="idChange" :disabled="isEdit"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="性别:" prop="sex">
|
||||
<ai-select v-model="baseInfo.sex" :selectList="dict.getDict('sex')" :disabled="isEdit"/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<el-form-item label="个人照片:" prop="photo" class="fill">
|
||||
<ai-avatar :instance="instance" v-model="baseInfo.photo"/>
|
||||
</el-form-item>
|
||||
</el-row>
|
||||
<el-row type="flex">
|
||||
<div class="fill">
|
||||
<el-form-item label="出生日期:">
|
||||
<el-date-picker
|
||||
disabled
|
||||
:editable="false"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
format="yyyy-MM-dd"
|
||||
v-model="baseInfo.birthday"
|
||||
type="date"
|
||||
placeholder="选择日期"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="文化程度:" prop="education">
|
||||
<ai-select v-model="baseInfo.education" :selectList="dict.getDict('education')"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="政治面貌:" prop="politicsStatus">
|
||||
<ai-select v-model="baseInfo.politicsStatus" :selectList="dict.getDict('politicsStatus')"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="职业:" prop="job">
|
||||
<ai-select v-model="baseInfo.job" :selectList="dict.getDict('job')"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="宗教信仰:" prop="faithType">
|
||||
<ai-select v-model="baseInfo.faithType" :selectList="dict.getDict('faithType')"/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="fill">
|
||||
<el-form-item label="年龄:" prop="age">
|
||||
<el-input
|
||||
disabled
|
||||
v-model="baseInfo.age"
|
||||
autocomplete="off"
|
||||
size="small"
|
||||
placeholder="请输入年龄"
|
||||
type="number"
|
||||
@mousewheel.native.prevent
|
||||
/>
|
||||
<!-- <p v-else>{{baseInfo.age}}</p> -->
|
||||
</el-form-item>
|
||||
<el-form-item label="民族:" prop="nation">
|
||||
<ai-select v-model="baseInfo.nation" :selectList="dict.getDict('nation')"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="婚姻状况:" prop="maritalStatus">
|
||||
<ai-select v-model="baseInfo.maritalStatus" :selectList="dict.getDict('maritalStatus')"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="兵役状况:" prop="militaryStatus">
|
||||
<ai-select v-model="baseInfo.militaryStatus" :selectList="dict.getDict('militaryStatus')"/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-row>
|
||||
<el-form-item label="籍贯:" prop=" birthplaceAreaId">
|
||||
<ai-area-select
|
||||
clearable
|
||||
always-show
|
||||
:instance="instance"
|
||||
v-model="baseInfo.birthplaceAreaId"
|
||||
:areaLevel="3"
|
||||
/>
|
||||
</el-form-item>
|
||||
</template>
|
||||
<template>
|
||||
<ai-card title="基本信息">
|
||||
<ai-wrapper class="fill" slot="content">
|
||||
<ai-info-item label="性别" :value="dict.getLabel('sex', baseInfo.sex)"/>
|
||||
<ai-info-item label="身份证号">
|
||||
<ai-id mode="show" v-model="baseInfo.idNumber" right-btn class="line-center"/>
|
||||
</ai-info-item>
|
||||
<ai-info-item label="出生日期" :value="baseInfo.birthday"/>
|
||||
<ai-info-item label="年龄" :value="baseInfo.age"/>
|
||||
<ai-info-item label="籍贯" :value="baseInfo.birthplaceAreaName"/>
|
||||
<ai-info-item label="民族" :value="dict.getLabel('nation', baseInfo.nation)"/>
|
||||
<ai-info-item label="文化程度" :value="dict.getLabel('education', baseInfo.education)"/>
|
||||
<ai-info-item label="婚姻状况" :value="dict.getLabel('maritalStatus', baseInfo.maritalStatus)"/>
|
||||
<ai-info-item label="政治面貌" :value="dict.getLabel('politicsStatus', baseInfo.politicsStatus)"/>
|
||||
<ai-info-item label="兵役状况" :value="dict.getLabel('militaryStatus', baseInfo.militaryStatus)"/>
|
||||
<ai-info-item label="宗教信仰" :value="dict.getLabel('faithType', baseInfo.faithType)"/>
|
||||
<ai-info-item label="职业" :value="dict.getLabel('job', baseInfo.job)"/>
|
||||
</ai-wrapper>
|
||||
<ai-avatar v-model="baseInfo.photo" :editable="false"/>
|
||||
</ai-card>
|
||||
</template>
|
||||
</ai-edit-card>
|
||||
<ai-edit-card title="联络信息"
|
||||
@save="saveFrom" @cancel="getDetail(baseInfo.id)">
|
||||
<template #edit>
|
||||
<el-form-item label="联系方式:" prop="phone">
|
||||
<el-input v-model="baseInfo.phone" size="small" placeholder="请输入联系方式" :maxlength="11"
|
||||
show-word-limit/>
|
||||
</el-form-item>
|
||||
<el-form-item label="现住址:" prop="currentAreaId">
|
||||
<ai-area-select clearable always-show :instance="instance" :disabled-level="disabledLevel"
|
||||
v-model="baseInfo.currentAreaId" :valueLevel="4"/>
|
||||
<el-form-item>
|
||||
<el-input v-model="baseInfo.currentAddress" placeholder="详细地址" maxlength="30" show-word-limit
|
||||
clearable/>
|
||||
</el-form-item>
|
||||
</el-form-item>
|
||||
</template>
|
||||
<template>
|
||||
<ai-card title="联络信息" type="flex">
|
||||
<ai-wrapper slot="content">
|
||||
<ai-info-item label="联系方式" :value="baseInfo.phone"/>
|
||||
<ai-info-item label="现住址" isLine
|
||||
:value="[baseInfo.currentAreaName, baseInfo.currentAddress].join('')"/>
|
||||
</ai-wrapper>
|
||||
</ai-card>
|
||||
</template>
|
||||
</ai-edit-card>
|
||||
<ai-edit-card title="户籍信息"
|
||||
@save="saveFrom" @cancel="getDetail(baseInfo.id)">
|
||||
<template #edit>
|
||||
<el-row type="flex">
|
||||
<div class="fill">
|
||||
<el-form-item label="是否户主:" prop="householdName">
|
||||
<ai-select v-model="baseInfo.householdName" :selectList="dict.getDict('householdName')"
|
||||
@change="householdRelationChange"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="与户主关系:" prop="householdRelation" v-if="baseInfo.householdName==0">
|
||||
<ai-select v-model="baseInfo.householdRelation"
|
||||
:selectList="dict.getDict('householdRelation')"/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="fill">
|
||||
<el-form-item label="户主身份证号:" prop="householdIdNumber" v-if="baseInfo.householdName==0">
|
||||
<el-input v-model="baseInfo.householdIdNumber" placeholder="请输入户主身份证号" :maxlength="18"
|
||||
clearable/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-row>
|
||||
<el-form-item label="户籍地:" prop="householdAreaId">
|
||||
<ai-area-select clearable always-show :instance="instance" v-model="baseInfo.householdAreaId"/>
|
||||
<el-form-item v-if="baseInfo.householdAreaId">
|
||||
<el-input v-model="baseInfo.householdAddress" placeholder="详细地址" maxlength="30" show-word-limit
|
||||
clearable/>
|
||||
</el-form-item>
|
||||
</el-form-item>
|
||||
</template>
|
||||
<template>
|
||||
<ai-card title="户籍信息">
|
||||
<ai-wrapper slot="content">
|
||||
<ai-info-item label="是否户主" :value="dict.getLabel('householdName', baseInfo.householdName)"/>
|
||||
<template v-if="baseInfo.householdName==0">
|
||||
<ai-info-item label="与户主关系"
|
||||
:value="dict.getLabel('householdRelation', baseInfo.householdRelation)"/>
|
||||
<ai-info-item label="户主身份证号" :value="baseInfo.householdIdNumber"/>
|
||||
</template>
|
||||
<ai-info-item label="户籍地" isLine
|
||||
:value="[baseInfo.householdAreaName, baseInfo.householdAddress].join('')"/>
|
||||
</ai-wrapper>
|
||||
</ai-card>
|
||||
</template>
|
||||
</ai-edit-card>
|
||||
</template>
|
||||
<template v-else>
|
||||
<ai-card title="基本信息">
|
||||
<template #content>
|
||||
<el-row type="flex">
|
||||
<div class="fill">
|
||||
<el-form-item label="姓名:" prop="name">
|
||||
<el-input
|
||||
v-model="baseInfo.name"
|
||||
autocomplete="off"
|
||||
size="small"
|
||||
placeholder="请输入姓名"
|
||||
maxlength="20"
|
||||
show-word-limit/>
|
||||
</el-form-item>
|
||||
<el-form-item label="身份证号:" prop="idNumber">
|
||||
<el-input v-model="baseInfo.idNumber" placeholder="请输入身份证号" :maxlength="18" show-word-limit />
|
||||
</el-form-item>
|
||||
<el-form-item label="性别:" prop="sex">
|
||||
<ai-select v-model="baseInfo.sex" :selectList="dict.getDict('sex')"/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<el-form-item label="个人照片:" prop="photo" class="fill">
|
||||
<ai-avatar :instance="instance" v-model="baseInfo.photo"/>
|
||||
</el-form-item>
|
||||
</el-row>
|
||||
<el-row type="flex">
|
||||
<div class="fill">
|
||||
<el-form-item label="出生日期:">
|
||||
<el-date-picker
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
format="yyyy-MM-dd"
|
||||
v-model="baseInfo.birthday"
|
||||
type="date"
|
||||
placeholder="选择日期"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="文化程度:" prop="education">
|
||||
<ai-select v-model="baseInfo.education" :selectList="dict.getDict('education')"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="政治面貌:" prop="politicsStatus">
|
||||
<ai-select v-model="baseInfo.politicsStatus" :selectList="dict.getDict('politicsStatus')"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="职业:" prop="job">
|
||||
<ai-select v-model="baseInfo.job" :selectList="dict.getDict('job')"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="宗教信仰:" prop="faithType">
|
||||
<ai-select v-model="baseInfo.faithType" :selectList="dict.getDict('faithType')"/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="fill">
|
||||
<el-form-item label="年龄:" prop="age">
|
||||
<el-input
|
||||
v-model="baseInfo.age"
|
||||
size="small"
|
||||
placeholder="请输入年龄"
|
||||
type="number"
|
||||
/>
|
||||
<!-- <p v-else>{{baseInfo.age}}</p> -->
|
||||
</el-form-item>
|
||||
<el-form-item label="民族:" prop="nation">
|
||||
<ai-select v-model="baseInfo.nation" :selectList="dict.getDict('nation')"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="婚姻状况:" prop="maritalStatus">
|
||||
<ai-select v-model="baseInfo.maritalStatus" :selectList="dict.getDict('maritalStatus')"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="兵役状况:" prop="militaryStatus">
|
||||
<ai-select v-model="baseInfo.militaryStatus" :selectList="dict.getDict('militaryStatus')"/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-row>
|
||||
<el-form-item label="籍贯:" prop=" birthplaceAreaId">
|
||||
<ai-area-select
|
||||
clearable
|
||||
always-show
|
||||
:instance="instance"
|
||||
v-model="baseInfo.birthplaceAreaId"
|
||||
:areaLevel="3"
|
||||
/>
|
||||
</el-form-item>
|
||||
</template>
|
||||
</ai-card>
|
||||
<ai-card title="联络信息">
|
||||
<template #content>
|
||||
<el-form-item label="联系方式:" prop="phone">
|
||||
<el-input v-model="baseInfo.phone" size="small" placeholder="请输入联系方式" :maxlength="11"
|
||||
show-word-limit/>
|
||||
</el-form-item>
|
||||
<el-form-item label="现住址:" prop="currentAreaId">
|
||||
<ai-area-select clearable always-show :instance="instance" :disabled-level="disabledLevel"
|
||||
v-model="baseInfo.currentAreaId" :valueLevel="4"/>
|
||||
<el-form-item>
|
||||
<el-input v-model="baseInfo.currentAddress" placeholder="详细地址" maxlength="30" show-word-limit
|
||||
clearable/>
|
||||
</el-form-item>
|
||||
</el-form-item>
|
||||
<el-form-item label="所属网格" prop="girdName" required>
|
||||
<ai-picker
|
||||
:instance="instance"
|
||||
dialogTitle="选择所属网格"
|
||||
:ops="{label: 'girdName', id: 'id'}"
|
||||
pageTitle="所属网格"
|
||||
:action="'/app/appgirdinfo/girdList'"
|
||||
v-model="baseInfo.girdId"
|
||||
@pick="onPick">
|
||||
<div class="AppAnnounceDetail-select">
|
||||
<el-input size="small" class="AppAnnounceDetail-select__input" placeholder="请选择..." disabled v-model="baseInfo.girdName"></el-input>
|
||||
<div class="select-left" v-if="girdList.length">
|
||||
<span v-for="(item, index) in girdList" :key="index">{{ item.girdName }}</span>
|
||||
</div>
|
||||
<i v-if="!girdList.length">请选择网格</i>
|
||||
<div class="select-right">{{ girdList.length ? '重新选择' : '选择网格' }}</div>
|
||||
</div>
|
||||
</ai-picker>
|
||||
</el-form-item>
|
||||
</template>
|
||||
</ai-card>
|
||||
<ai-card title="户籍信息">
|
||||
<template #content>
|
||||
<el-row type="flex">
|
||||
<div class="fill">
|
||||
<el-form-item label="是否户主:" prop="isHousehold">
|
||||
<ai-select v-model="baseInfo.isHousehold" :selectList="dict.getDict('householdName')"
|
||||
@change="householdRelationChange"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="与户主关系:" prop="householdRelation" v-if="baseInfo.isHousehold==0">
|
||||
<ai-select v-model="baseInfo.householdRelation" :selectList="dict.getDict('householdRelation')"/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="fill">
|
||||
<el-form-item label="户主身份证号:" prop="householdIdNumber" v-if="baseInfo.isHousehold==0">
|
||||
<el-input v-model="baseInfo.householdIdNumber" placeholder="请输入户主身份证号" :maxlength="18"
|
||||
clearable/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-row>
|
||||
<el-form-item label="户籍地:" prop="householdAreaId">
|
||||
<ai-area-select clearable always-show :instance="instance" v-model="baseInfo.householdAreaId"/>
|
||||
<el-form-item v-if="baseInfo.householdAreaId">
|
||||
<el-input v-model="baseInfo.householdAddress" placeholder="详细地址" maxlength="30" show-word-limit
|
||||
clearable/>
|
||||
</el-form-item>
|
||||
</el-form-item>
|
||||
</template>
|
||||
</ai-card>
|
||||
</template>
|
||||
</el-form>
|
||||
</template>
|
||||
<template v-if="params.type !== 'Detail'" #footer>
|
||||
<el-button @click="back">取消</el-button>
|
||||
<el-button type="primary" @click="saveFrom()">保存</el-button>
|
||||
</template>
|
||||
</ai-detail>
|
||||
</template>
|
||||
<script>
|
||||
import {mapState} from "vuex";
|
||||
import {ID} from "dui/lib/js/utils";
|
||||
|
||||
export default {
|
||||
name: "Add",
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
permissions: Function,
|
||||
params: Object,
|
||||
name: {default: ""}
|
||||
},
|
||||
data() {
|
||||
let IdNumberPass = (rule, value, callback) => {
|
||||
if (value) {
|
||||
if (ID.check(value)) {
|
||||
callback();
|
||||
} else {
|
||||
callback(new Error("身份证号格式错误"));
|
||||
}
|
||||
} else {
|
||||
callback(new Error("请输入身份证号"));
|
||||
}
|
||||
};
|
||||
return {
|
||||
buildingCascader: true,
|
||||
houseCascader: true,
|
||||
navId: 0,
|
||||
girdList: [],
|
||||
baseInfo: {
|
||||
registerStatus: "",
|
||||
tips: [],
|
||||
age: "",
|
||||
girdName: '',
|
||||
girdId: [],
|
||||
birthplaceAreaId: "",
|
||||
currentAddress: "",
|
||||
currentAreaId: "",
|
||||
education: "",
|
||||
faithType: "",
|
||||
fileStatus: "",
|
||||
householdAddress: "",
|
||||
householdAreaId: "",
|
||||
householdIdNumber: "",
|
||||
isHousehold: "",
|
||||
householdRelation: "",
|
||||
id: "",
|
||||
idNumber: "",
|
||||
job: "",
|
||||
logoutDescription: "",
|
||||
logoutReason: "",
|
||||
logoutTime: "",
|
||||
logoutUserId: "",
|
||||
maritalStatus: "",
|
||||
militaryStatus: "",
|
||||
name: "",
|
||||
nation: "",
|
||||
phone: "",
|
||||
photo: "",
|
||||
politicsStatus: "",
|
||||
sex: "",
|
||||
tsrqInfos: []
|
||||
},
|
||||
family: [],
|
||||
familyInfo: {},
|
||||
writeInfo: {
|
||||
id: "",
|
||||
logoutReason: "",
|
||||
logoutDescription: "",
|
||||
fileStatus: "1"
|
||||
},
|
||||
rules: {
|
||||
name: [{required: true, message: "请输入姓名", trigger: "blur"}],
|
||||
idNumber: [
|
||||
{required: true, message: "请输入身份证号", trigger: "blur"}
|
||||
],
|
||||
sex: [{required: true, message: "请选择性别", trigger: "change"}],
|
||||
currentAreaId: [{message: "请选择现住址", required: true, trigger: "change"},
|
||||
{
|
||||
validator: (r, v, cb) => {
|
||||
if (/.+0{3}$/.test(v)) {
|
||||
cb("现住址必须选到村级")
|
||||
} else cb()
|
||||
}, trigger: "blur"
|
||||
}],
|
||||
currentAddress: [{message: "请选择现住址详细地址", required: true}],
|
||||
householdAreaId: [
|
||||
{
|
||||
validator: (r, v, cb) => {
|
||||
if (/.+0{3}$/.test(v) && v) {
|
||||
cb("户籍地必须选到村级")
|
||||
} else cb()
|
||||
}, trigger: "blur"
|
||||
}
|
||||
],
|
||||
phone: [
|
||||
{required: true, message: "请输入联系方式", trigger: "blur"}
|
||||
],
|
||||
girdName: [
|
||||
{required: true, message: "请选择网格", trigger: "change"}
|
||||
],
|
||||
isHousehold: [
|
||||
{required: true, message: "请选择是否户主", trigger: "change"}
|
||||
],
|
||||
householdRelation: [
|
||||
{required: true, message: "请选择与户主关系", trigger: "change"}
|
||||
],
|
||||
householdIdNumber: [
|
||||
{required: true, message: "请输入身份证号", trigger: "blur"}
|
||||
],
|
||||
householdAddress: [
|
||||
{required: true, message: "请选择户籍地详细地址", trigger: "blur"}
|
||||
]
|
||||
},
|
||||
imgUrl: "",
|
||||
fileList: [],
|
||||
disabledLevel: 0,
|
||||
currentTab: "0"
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState(["user"]),
|
||||
isEdit() {
|
||||
return this.params.type === 'Edit'
|
||||
},
|
||||
pageTitle() {
|
||||
return {
|
||||
Edit: '编辑居民信息',
|
||||
Add: '添加居民信息',
|
||||
Detail: '居民信息详情'
|
||||
}[this.params.type]
|
||||
},
|
||||
hasSpecial() {
|
||||
//是否有特殊人员信息
|
||||
return this.baseInfo.tsrqInfos?.length > 0
|
||||
},
|
||||
colConfigs() {
|
||||
return [
|
||||
{
|
||||
label: "与户主关系", align: 'center',
|
||||
render: (h, {row}) => h('p', this.dict.getLabel('householdRelation', row.householdRelation))
|
||||
},
|
||||
{label: "姓名", prop: "name"},
|
||||
{label: "性别", prop: "sex", dict: "sex", align: 'center'},
|
||||
{label: "年龄", prop: "age", align: 'center'},
|
||||
{label: "身份证号", render: (h, {row}) => h('p', ID.hideId(row.idNumber))},
|
||||
{slot: "options"}
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
back() {
|
||||
this.$emit('change', {
|
||||
type: 'List'
|
||||
})
|
||||
},
|
||||
onPick (e) {
|
||||
if (e.length) {
|
||||
this.baseInfo.girdName = e[0].girdName
|
||||
} else {
|
||||
this.baseInfo.girdName = ''
|
||||
this.baseInfo.girdId = []
|
||||
}
|
||||
|
||||
this.girdList = e
|
||||
},
|
||||
householdRelationChange() {
|
||||
this.baseInfo.householdIdNumber = "";
|
||||
this.baseInfo.householdRelation = "";
|
||||
},
|
||||
saveFrom(cb) {
|
||||
this.$refs.ruleForm.validate(v => {
|
||||
if (v) {
|
||||
this.saveFromFn().then(() => {
|
||||
if (cb) {
|
||||
cb()
|
||||
this.getDetail()
|
||||
} else {
|
||||
this.back()
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
familyInit() {
|
||||
Object.keys(this.writeInfo).forEach(e => {
|
||||
this.writeInfo[e] = "";
|
||||
});
|
||||
this.$refs.writeInfo.resetFields();
|
||||
},
|
||||
saveFromFn() {
|
||||
let {currentHouseList, householdHouseList, tips} = this.baseInfo
|
||||
return this.instance.post(`/app/appresidentapplet/addOrUpdate`, {
|
||||
residentType: this.$route.query.type,
|
||||
...this.baseInfo,
|
||||
currentHouseList: currentHouseList?.join("|"),
|
||||
householdHouseList: householdHouseList?.join("|"),
|
||||
tips: tips?.join("|"),
|
||||
girdId: this.baseInfo.girdId[0]
|
||||
}).then(res => {
|
||||
if (res?.code == 0) {
|
||||
this.$message.success("保存成功");
|
||||
}
|
||||
})
|
||||
},
|
||||
getDetail() {
|
||||
this.instance.post(`/app/appresidentapplet/queryDetailById?id=${this.params.id}`).then(res => {
|
||||
if (res?.data) {
|
||||
this.baseInfo = {
|
||||
...res.data,
|
||||
girdId: [res.data.girdId]
|
||||
};
|
||||
this.girdList = [{
|
||||
id: res.data.girdId,
|
||||
girdName: res.data.girdName
|
||||
}]
|
||||
}
|
||||
});
|
||||
},
|
||||
handleDelete() {
|
||||
this.$confirm("删掉档案后,\n" +
|
||||
`<span class="username">${this.baseInfo.name}</span>` +
|
||||
" 的历史相关信息可能无法追溯查看,是否确定删除该人员档案?", {
|
||||
title: "档案删除"
|
||||
}).then(() => {
|
||||
this.instance.post(`/app/appresidentapplet/delete?ids=${this.baseInfo.id}`).then(res => {
|
||||
if (res && res.code == 0) {
|
||||
this.$message.success("删除成功");
|
||||
this.$router.push({query: {}});
|
||||
}
|
||||
});
|
||||
}).catch(() => 0)
|
||||
},
|
||||
idChange(val) {
|
||||
if (val.length == 18) {
|
||||
this.IdCard(val);
|
||||
}
|
||||
},
|
||||
IdCard(UUserCard) {
|
||||
if (UUserCard) {
|
||||
const idCard = new ID(UUserCard)
|
||||
this.baseInfo.age = idCard.age
|
||||
this.baseInfo.sex = idCard.sex
|
||||
this.baseInfo.birthday = idCard.birthday
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$dict.load(['sex', 'education', 'politicsStatus', 'job', 'faithType', 'nation', 'maritalStatus', 'militaryStatus', 'householdName', 'householdRelation', ]).then(()=> {
|
||||
this.disabledLevel = this.user.info.areaMap[this.user.info.areaId].length;
|
||||
if (!this.params.id) {
|
||||
// this.baseInfo.householdAreaId = JSON.parse(JSON.stringify(this.user.info.areaId))
|
||||
this.baseInfo.currentAreaId = this.user.info.areaId
|
||||
} else {
|
||||
this.getDetail(this.params.id);
|
||||
}
|
||||
})
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.residentDetail {
|
||||
font-size: 14px;
|
||||
.AppAnnounceDetail-select {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-height: 32px;
|
||||
line-height: 1;
|
||||
background: #F5F5F5;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #D0D4DC;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||
|
||||
&:hover {
|
||||
border-color: #26f;
|
||||
}
|
||||
|
||||
& > i {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
line-height: 32px;
|
||||
padding: 0 12px;
|
||||
color: #888888;
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
border-right: 1px solid #D0D4DC;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.AppAnnounceDetail-select__input {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: -1;
|
||||
opacity: 0;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.select-right {
|
||||
height: 100%;
|
||||
padding: 0 12px;
|
||||
color: #222222;
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
transition: all ease 0.3s;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
.select-left {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
flex: 1;
|
||||
padding: 5px 0 0px 12px;
|
||||
border-right: 1px solid #D0D4DC;
|
||||
border-radius: 4px 0 0 4px;
|
||||
background: #fff;
|
||||
|
||||
em {
|
||||
height: 22px;
|
||||
line-height: 22px;
|
||||
margin: 0 4px 5px 0;
|
||||
color: #222222;
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
span {
|
||||
height: 22px;
|
||||
line-height: 22px;
|
||||
margin: 0 4px 5px 0;
|
||||
padding: 0 8px;
|
||||
font-size: 12px;
|
||||
color: #222222;
|
||||
background: #F3F4F7;
|
||||
border-radius: 2px;
|
||||
border: 1px solid #D0D4DC;
|
||||
}
|
||||
}
|
||||
}
|
||||
:deep( .AiID ){
|
||||
line-height: unset;
|
||||
|
||||
.el-button--text {
|
||||
padding: 0 8px;
|
||||
height: fit-content;
|
||||
}
|
||||
}
|
||||
|
||||
:deep( .el-form-item ){
|
||||
margin-bottom: 10px;
|
||||
|
||||
.el-form-item {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.el-cascader, .el-select, .el-date-editor {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
:deep( .el-form-item__error ){
|
||||
position: static;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
122
project/lulong/AppResidentInfo/components/Detail.vue
Normal file
122
project/lulong/AppResidentInfo/components/Detail.vue
Normal file
@@ -0,0 +1,122 @@
|
||||
<template>
|
||||
<ai-detail class="activitiesAdd">
|
||||
<template slot="title">
|
||||
<ai-title title="居民信息详情" isShowBack isShowBottomBorder @onBackClick="cancel(false)"></ai-title>
|
||||
</template>
|
||||
<template slot="content">
|
||||
<ai-card title="基本信息">
|
||||
<ai-wrapper class="fill" slot="content">
|
||||
<ai-info-item label="姓名" isLine :value="baseInfo.name"/>
|
||||
<ai-info-item label="照片">
|
||||
<ai-avatar v-model="baseInfo.photo" :editable="false"/>
|
||||
</ai-info-item>
|
||||
<ai-info-item label="性别" :value="dict.getLabel('sex', baseInfo.sex)"/>
|
||||
<ai-info-item label="身份证号" :value="baseInfo.idNumber">
|
||||
<!-- <ai-id mode="show" v-model="baseInfo.idNumber" right-btn class="line-center"/> -->
|
||||
</ai-info-item>
|
||||
<ai-info-item label="出生日期" :value="baseInfo.birthday"/>
|
||||
<ai-info-item label="年龄" :value="baseInfo.age"/>
|
||||
<ai-info-item label="籍贯" :value="baseInfo.birthplaceAreaName"/>
|
||||
<ai-info-item label="民族" :value="dict.getLabel('nation', baseInfo.nation)"/>
|
||||
<ai-info-item label="文化程度" :value="dict.getLabel('education', baseInfo.education)"/>
|
||||
<ai-info-item label="婚姻状况" :value="dict.getLabel('maritalStatus', baseInfo.maritalStatus)"/>
|
||||
<ai-info-item label="政治面貌" :value="dict.getLabel('politicsStatus', baseInfo.politicsStatus)"/>
|
||||
<ai-info-item label="兵役状况" :value="dict.getLabel('militaryStatus', baseInfo.militaryStatus)"/>
|
||||
<ai-info-item label="宗教信仰" :value="dict.getLabel('faithType', baseInfo.faithType)"/>
|
||||
<ai-info-item label="职业" :value="dict.getLabel('job', baseInfo.job)"/>
|
||||
</ai-wrapper>
|
||||
</ai-card>
|
||||
<ai-card title="联络信息" type="flex">
|
||||
<ai-wrapper slot="content">
|
||||
<ai-info-item label="联系方式" :value="baseInfo.phone"/>
|
||||
<ai-info-item label="现住址" isLine :value="[baseInfo.currentAreaName, baseInfo.currentAddress].join('')"/>
|
||||
<ai-info-item label="所属网格" :value="baseInfo.girdName"/>
|
||||
</ai-wrapper>
|
||||
</ai-card>
|
||||
<ai-card title="户籍信息">
|
||||
<ai-wrapper slot="content">
|
||||
<ai-info-item label="是否户主" :value="dict.getLabel('householdName', baseInfo.isHousehold)"/>
|
||||
<template v-if="baseInfo.isHousehold == 0">
|
||||
<ai-info-item label="与户主关系" :value="dict.getLabel('householdRelation', baseInfo.householdRelation)"/>
|
||||
<ai-info-item label="户主身份证号" :value="baseInfo.householdIdNumber"/>
|
||||
</template>
|
||||
<ai-info-item label="户籍地" isLine :value="[baseInfo.householdAreaName, baseInfo.householdAddress].join('')"></ai-info-item>
|
||||
</ai-wrapper>
|
||||
</ai-card>
|
||||
</template>
|
||||
</ai-detail>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ID } from 'dui/lib/js/utils'
|
||||
export default {
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
params: Object,
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
baseInfo: {},
|
||||
id: ''
|
||||
}
|
||||
},
|
||||
|
||||
created () {
|
||||
this.id = this.params.id
|
||||
|
||||
this.getDetail()
|
||||
},
|
||||
|
||||
methods: {
|
||||
cancel (isRefresh) {
|
||||
this.$emit('change', {
|
||||
type: 'List',
|
||||
isRefresh: !!isRefresh
|
||||
})
|
||||
},
|
||||
|
||||
IdCard (UUserCard) {
|
||||
if (UUserCard) {
|
||||
const idCard = new ID(UUserCard)
|
||||
this.baseInfo.age = idCard.age
|
||||
this.baseInfo.sex = idCard.sex
|
||||
this.baseInfo.birthday = idCard.birthday
|
||||
}
|
||||
},
|
||||
|
||||
getDetail() {
|
||||
this.instance.post(`/app/appresidentapplet/queryDetailById?id=${this.params.id}`).then(res => {
|
||||
if (res.data) {
|
||||
this.baseInfo = {
|
||||
...res.data
|
||||
}
|
||||
this.IdCard(res.data.idNumber)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scope>
|
||||
.activitiesAdd {
|
||||
height: 100%;
|
||||
|
||||
:deep( .amap-logo ){
|
||||
display: none!important;
|
||||
}
|
||||
:deep( .amap-copyright ){
|
||||
display: none!important;
|
||||
}
|
||||
|
||||
:deep( .el-date-editor .el-input ){
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.amap-container {
|
||||
height: 380px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
181
project/lulong/AppResidentInfo/components/List.vue
Normal file
181
project/lulong/AppResidentInfo/components/List.vue
Normal file
@@ -0,0 +1,181 @@
|
||||
<template>
|
||||
<ai-list class="activitiesList">
|
||||
<ai-title
|
||||
slot="title"
|
||||
title="居民信息"
|
||||
isShowBottomBorder
|
||||
isShowArea
|
||||
:hideLevel="$store.state.user.info.areaList.length - 1"
|
||||
v-model="search.areaId"
|
||||
:instance="instance"
|
||||
@change="search.current = 1, getList()">
|
||||
</ai-title>
|
||||
<template #content>
|
||||
<ai-search-bar bottomBorder>
|
||||
<template #left>
|
||||
<el-button type="primary" icon="iconfont iconAdd" @click="toAdd('')">添加</el-button>
|
||||
<ai-import
|
||||
:instance="instance"
|
||||
:dict="dict"
|
||||
type="appresidentapplet"
|
||||
name="居民信息"
|
||||
@success="search.current = 1, getList()">
|
||||
</ai-import>
|
||||
</template>
|
||||
<template #right>
|
||||
<el-input
|
||||
v-model="search.name"
|
||||
size="small"
|
||||
placeholder="姓名/身份证/联系方式"
|
||||
clearable
|
||||
v-throttle="() => {search.current = 1, getList()}"
|
||||
@clear="search.name = '', getList()"
|
||||
suffix-icon="iconfont iconSearch">
|
||||
</el-input>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table
|
||||
:tableData="tableData"
|
||||
:total="search.total"
|
||||
:current.sync="search.current"
|
||||
:size.sync="search.size"
|
||||
@getList="getList"
|
||||
:col-configs="colConfigs"
|
||||
:dict="dict">
|
||||
<el-table-column slot="options" label="操作" fixed="right" align="center" width="160px">
|
||||
<template slot-scope="{ row }">
|
||||
<div class="table-options">
|
||||
<el-button type="text" @click="toDetail(row.id)">详情</el-button>
|
||||
<el-button type="text" @click="toAdd(row.id)">编辑</el-button>
|
||||
<el-button type="text" @click="remove(row.id)">删除</el-button>
|
||||
<el-button type="text" @click="qrCode(row)">生成二维码</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
<ai-dialog :visible.sync="dialogCode" title="二维码" width="500px" customFooter>
|
||||
<div class="code-div">
|
||||
<img :src="codeImgUrl" alt="" class="code-img">
|
||||
</div>
|
||||
<el-button slot="footer" @click="dialogCode=false" type="primary">关闭</el-button>
|
||||
</ai-dialog>
|
||||
</template>
|
||||
</ai-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
search: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
total: 0,
|
||||
name: '',
|
||||
areaId: ''
|
||||
},
|
||||
tableData: [],
|
||||
dialogCode: false,
|
||||
codeImgUrl: ''
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
colConfigs() {
|
||||
return [
|
||||
{ label: "姓名", prop: "name", align: "left" },
|
||||
// { label: "性别", prop: "sex", dict: 'sex', align: "center" },
|
||||
{ prop: 'idNumber', label: '身份证号', align: 'center'},
|
||||
// format: v => v.substring(0, 10) + '****' + v.substring(14, 18)
|
||||
// { label: "年龄", prop: "age", align: "center"},
|
||||
{ label: "现住址", prop: "currentAreaName", align: "center" },
|
||||
{ label: "网格", prop: "girdName", align: "center" },
|
||||
{ label: "民族", prop: "nation", align: "center", dict: "nation" },
|
||||
{ label: "文化程度", prop: "education", align: "center", dict: "education" },
|
||||
{ label: "政治面貌", prop: "politicsStatus", align: "center", dict: "politicsStatus" },
|
||||
{ slot: "options", },
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
created () {
|
||||
this.search.areaId = this.$store.state.user.info.areaId
|
||||
this.$dict.load(['nation', 'education', 'politicsStatus']).then(()=> {
|
||||
this.getList()
|
||||
})
|
||||
},
|
||||
|
||||
methods: {
|
||||
getList() {
|
||||
this.instance.post(`/app/appresidentapplet/list`,null, {
|
||||
params: {
|
||||
...this.search,
|
||||
}
|
||||
}).then(res=> {
|
||||
if(res?.data) {
|
||||
this.tableData = res.data.records
|
||||
this.search.total = res.data.total
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
toDetail (id) {
|
||||
this.$emit('change', {
|
||||
type: 'Detail',
|
||||
params: {
|
||||
id: id || '',
|
||||
type: 'Detail'
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
toAdd(id) {
|
||||
this.$emit('change', {
|
||||
type: 'Add',
|
||||
params: {
|
||||
type: id ? 'Edit' : 'Add',
|
||||
id: id || ''
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
remove (id) {
|
||||
this.$confirm('确定删除该数据?').then(() => {
|
||||
this.instance.post(`/app/appresidentapplet/delete?ids=${id}`).then(res=>{
|
||||
if(res.code == 0) {
|
||||
this.$message.success('删除成功!')
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
qrCode(row) {
|
||||
this.instance.post(`/app/appresidentapplet/generateQrCode?id=${row.id}`).then(res=>{
|
||||
if(res.code == 0) {
|
||||
this.dialogCode = true
|
||||
this.codeImgUrl = res.data
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.activitiesList {
|
||||
height: 100%;
|
||||
.code-div {
|
||||
text-align: center;
|
||||
}
|
||||
.code-img {
|
||||
width: 300px;
|
||||
height: 300px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,64 @@
|
||||
<template>
|
||||
<div class="AppActivitiesManagement">
|
||||
<keep-alive :include="['List']">
|
||||
<component ref="component" :is="component" :permissions="permissions " @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: 'AppResidentIntegrating',
|
||||
label: '居民积分明细',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
permissions: Function
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
component: 'List',
|
||||
params: {},
|
||||
include: []
|
||||
}
|
||||
},
|
||||
|
||||
components: {
|
||||
List,
|
||||
Detail
|
||||
},
|
||||
|
||||
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">
|
||||
.AppActivitiesManagement {
|
||||
height: 100%;
|
||||
background: #F3F6F9;
|
||||
overflow: auto;
|
||||
}
|
||||
</style>
|
||||
181
project/lulong/AppResidentIntegrating/components/Detail.vue
Normal file
181
project/lulong/AppResidentIntegrating/components/Detail.vue
Normal file
@@ -0,0 +1,181 @@
|
||||
<template>
|
||||
<ai-detail>
|
||||
<template slot="title">
|
||||
<ai-title title="详情" isShowBack isShowBottomBorder @onBackClick="cancel(false)">
|
||||
</ai-title>
|
||||
</template>
|
||||
<template slot="content">
|
||||
<el-row style="margin-bottom: 16px;">
|
||||
<div class="card_list">
|
||||
<div class="card">
|
||||
<h2>姓名</h2>
|
||||
<p class="color1">{{ info.userName }}</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h2>积分余额</h2>
|
||||
<p class="color2">{{ info.integral || 0 }}</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h2>已用积分</h2>
|
||||
<p class="color3">{{ info.usedIntegral || 0 }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</el-row>
|
||||
<ai-card>
|
||||
<ai-title slot="title" title="余额变动明细"/>
|
||||
<template #content>
|
||||
<ai-search-bar>
|
||||
<template #left>
|
||||
<ai-select v-model="search.type" placeholder="请选择类型" @change="search.current = 1, getList()" :selectList="dict.getDict('integralType')"/>
|
||||
</template>
|
||||
<template #right>
|
||||
<ai-download
|
||||
:instance="instance"
|
||||
:url="`/app/appintegraluser/changeIntegralExport?id=${params.id}`"
|
||||
:params="search"
|
||||
fileName="余额变动明细"
|
||||
:disabled="tableData.length == 0">
|
||||
<el-button size="small">导出</el-button>
|
||||
</ai-download>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table :tableData="tableData" :total="total" :current.sync="search.current" :size.sync="search.size"
|
||||
@getList="getList" :col-configs="colConfigs" :dict="dict">
|
||||
<el-table-column slot="changeIntegral" label="变动积分" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<span>{{ row.integralCalcType == 0 ? '-' : '+' }}{{ row.changeIntegral }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="eventDesc" label='事件' align="center" show-overflow-tooltip>
|
||||
<template slot-scope="{ row }">
|
||||
<span>{{ row.eventDesc || row.eventName }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</template>
|
||||
</ai-card>
|
||||
</template>
|
||||
</ai-detail>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Detail',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
params: Object
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
info: {},
|
||||
id: '',
|
||||
search: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
type: ''
|
||||
},
|
||||
total: 0,
|
||||
tableData: []
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
colConfigs() {
|
||||
return [
|
||||
{prop: "doTime", label: '时间', align: "left", width: "200px"},
|
||||
{prop: "integralType", label: '类型', align: "center", dict: "integralType"},
|
||||
{slot: "changeIntegral"},
|
||||
{prop: "nowIntegral", label: '剩余积分', align: "center" },
|
||||
{slot: "eventDesc"},
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
created () {
|
||||
console.log(this.params)
|
||||
this.dict.load('integralType').then(() => {
|
||||
this.getInfo()
|
||||
this.getList()
|
||||
})
|
||||
},
|
||||
|
||||
methods: {
|
||||
getInfo (id) {
|
||||
this.instance.post(`/app/appintegraluser/girdDetail?id=${this.params.id}`).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.info = res.data
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
getList () {
|
||||
this.instance.post(`/app/appintegraluser/getChangeDetail`, null, {
|
||||
params: {
|
||||
...this.search,
|
||||
id: this.params.id
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.tableData = res.data.records
|
||||
this.total = res.data.total
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
cancel (isRefresh) {
|
||||
this.$emit('change', {
|
||||
type: 'List',
|
||||
isRefresh: !!isRefresh
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.card_list {
|
||||
display: flex;
|
||||
|
||||
.card {
|
||||
flex: 1;
|
||||
height: 96px;
|
||||
background: #FFFFFF;
|
||||
box-shadow: 0px 4px 6px -2px rgba(15, 15, 21, 0.1500);
|
||||
border-radius: 4px;
|
||||
margin-right: 20px;
|
||||
padding: 16px 24px;
|
||||
box-sizing: border-box;
|
||||
|
||||
h2 {
|
||||
color: #888888;
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: 8px;
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.color1 {
|
||||
color: #2891FF;
|
||||
}
|
||||
|
||||
.color2 {
|
||||
color: #22AA99;
|
||||
}
|
||||
|
||||
.color3 {
|
||||
color: #F8B425;
|
||||
}
|
||||
}
|
||||
|
||||
.card:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
278
project/lulong/AppResidentIntegrating/components/List.vue
Normal file
278
project/lulong/AppResidentIntegrating/components/List.vue
Normal file
@@ -0,0 +1,278 @@
|
||||
<template>
|
||||
<ai-list class="notice">
|
||||
<ai-title slot="title" title="居民积分" v-model="search.areaId" isShowBottomBorder isShowArea :hideLevel="hideLevel - 1" @change="search.current = 1, getList()"></ai-title>
|
||||
<template slot="content">
|
||||
<ai-search-bar class="search-bar">
|
||||
<template #left>
|
||||
<el-button type="primary" size="small" icon="iconfont iconAdd" @click="changeIntegral('',0)"> 批量调整积分</el-button>
|
||||
<ai-download
|
||||
:instance="instance"
|
||||
url="/app/appwechatuserqujing/export"
|
||||
:params="params"
|
||||
v-if="permissions('app_appwechatuserqujing_export')"
|
||||
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.idNumber"
|
||||
class="search-input"
|
||||
size="small"
|
||||
v-throttle="() => {search.current = 1, getList()}"
|
||||
placeholder="姓名/身份证/手机号"
|
||||
clearable
|
||||
@clear="search.current = 1, search.idNumber = '', getList()"
|
||||
suffix-icon="iconfont iconSearch">
|
||||
</el-input>
|
||||
</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="options" width="120px" fixed="right" label="操作" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<div class="table-options">
|
||||
<el-button type="text" @click="toDetail(row.integralUserId)">详情</el-button>
|
||||
<el-button type="text" @click="changeIntegral(row,1)">调整积分</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
<ai-dialog
|
||||
title="调整积分"
|
||||
:visible.sync="dialog"
|
||||
:destroyOnClose="true"
|
||||
width="720px"
|
||||
@onConfirm="onConfirm"
|
||||
@closed="form={},chooseUserList=[]">
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
|
||||
<el-form-item label="选择人员" prop="ids" v-if="!isEdit">
|
||||
<ai-person-select :instance="instance" keys="openId" customRightText :customClicker="true" :chooseUserList="chooseUserList"
|
||||
:url="`/app/appwechatuserqujing/listByFdAppletUser?areaId=${search.areaId}`" headerTitle="用户列表"
|
||||
:isMultiple="true" dialogTitle="选择" @selectPerson="selectPerson" class="aipersonselect">
|
||||
<template name="option" v-slot:option="{ item }">
|
||||
<span class="iconfont iconProlife">{{ item.realName }}</span>
|
||||
<!-- <ai-id mode="show" :show-eyes="false" :value="item.idNumber"/> -->
|
||||
<span>{{ item.phone }}</span>
|
||||
</template>
|
||||
</ai-person-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="调整说明" prop="eventDesc">
|
||||
<el-input v-model="form.eventDesc" placeholder="请输入..." type="textarea" :rows="4" show-word-limit
|
||||
maxlength="100"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="类型" prop="integralCalcType">
|
||||
<ai-select v-model="form.integralCalcType" :selectList="dict.getDict('integralCalcType')"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="积分" prop="integral">
|
||||
<el-input v-model.trim="form.integral" placeholder="请输入正数" size="small"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</ai-dialog>
|
||||
</template>
|
||||
</ai-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
export default {
|
||||
name: 'List',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
permissions: Function
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
search: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
idNumber: '',
|
||||
areaId: ''
|
||||
},
|
||||
form: {
|
||||
ids: [],
|
||||
eventDesc: "",
|
||||
enclosure: "",
|
||||
integralCalcType: "",
|
||||
integral: ''
|
||||
},
|
||||
dialog: false,
|
||||
chooseUserList: [],
|
||||
total: 0,
|
||||
isEdit: false,
|
||||
colConfigs: [
|
||||
{ prop: 'realName', label: '姓名', align: 'left', width: '200px' },
|
||||
{ prop: 'phone', label: '手机号', align: 'center' },
|
||||
{ prop: 'idNumber', label: '身份证号', align: 'center' },
|
||||
{ prop: 'areaName', label: '所属地区', align: 'center' },
|
||||
{ prop: 'girdName', label: '所属网格', align: 'center' },
|
||||
{ prop: 'integral', label: '剩余积分', align: 'center' },
|
||||
{ prop: 'usedIntegral', label: '已用积分', align: 'center' }
|
||||
],
|
||||
tableData: []
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['user']),
|
||||
|
||||
hideLevel () {
|
||||
return this.user.info.areaList.length || 0
|
||||
},
|
||||
|
||||
params () {
|
||||
return {
|
||||
...this.search,
|
||||
size: 1000
|
||||
}
|
||||
},
|
||||
|
||||
rules() {
|
||||
return {
|
||||
ids: [{required: true, message: '请选择人员', trigger: 'blur'}],
|
||||
eventDesc: [{required: true, message: '请输入调整说明', trigger: 'blur'}],
|
||||
integralCalcType: [{required: true, message: '请选择类型', trigger: 'blur'}],
|
||||
integral: [{required: true, message: '请输入积分', trigger: 'blur' },
|
||||
{pattern: /^([1-9]\d*|0)(\.\d{1,2})?$/, message: '请输入正数且最多只能保留两位小数'}],
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
this.search.areaId = this.user.info.areaId
|
||||
this.dict.load('integralCalcType').then(() => {
|
||||
this.getList()
|
||||
})
|
||||
},
|
||||
|
||||
methods: {
|
||||
getList () {
|
||||
this.instance.post(`/app/appwechatuserqujing/listByFdAppletUser`, null, {
|
||||
params: {
|
||||
...this.search,
|
||||
areaId: this.search.areaId
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.tableData = res.data.records
|
||||
this.total = res.data.total
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
selectPerson(val) {
|
||||
if (val) {
|
||||
this.personList = val
|
||||
this.form.ids = [...this.personList.map(e => e.openId)]
|
||||
} else {
|
||||
this.form.ids = this.chooseUserList.map(e => e.openId)
|
||||
}
|
||||
},
|
||||
|
||||
changeIntegral(row,type) {
|
||||
this.isEdit = false
|
||||
if(type==0) {
|
||||
this.dialog = true
|
||||
} else if(type ==1) {
|
||||
this.isEdit = true
|
||||
this.chooseUserList = [{
|
||||
openId: row.openId,
|
||||
name: row.realName
|
||||
}]
|
||||
this.form = {
|
||||
ids: this.chooseUserList.map(e => e.openId)
|
||||
}
|
||||
|
||||
this.dialog = true
|
||||
}
|
||||
},
|
||||
|
||||
changeTableSort(col) {
|
||||
if(col.prop === 'integral') { // 剩余积分
|
||||
this.search.sortFiled = 0
|
||||
if(col.order === 'ascending') {
|
||||
this.search.sortRule = true
|
||||
} else if(col.order === 'descending') {
|
||||
this.search.sortRule = false
|
||||
} else if(col.order === null) {
|
||||
this.search.sortRule = ''
|
||||
}
|
||||
} else if(col.prop === 'totalIntegral') { // 累计积分
|
||||
this.search.sortFiled = 1
|
||||
if(col.order === 'ascending') {
|
||||
this.search.sortRule = true
|
||||
} else if(col.order === 'descending') {
|
||||
this.search.sortRule = false
|
||||
} else if(col.order === null) {
|
||||
this.search.sortRule = ''
|
||||
}
|
||||
} else if(col.prop === 'usedIntegral') { // 已用积分
|
||||
this.search.sortFiled = 2
|
||||
if(col.order === 'ascending') {
|
||||
this.search.sortRule = true
|
||||
} else if(col.order === 'descending') {
|
||||
this.search.sortRule = false
|
||||
} else if(col.order === null) {
|
||||
this.search.sortRule = ''
|
||||
}
|
||||
}
|
||||
this.getList()
|
||||
},
|
||||
|
||||
onConfirm() {
|
||||
if(this.flag) return
|
||||
|
||||
if(this.form.file?.length) {
|
||||
this.form.enclosure = this.form.file[0].url
|
||||
}
|
||||
this.$refs.form.validate((valid)=> {
|
||||
if(valid) {
|
||||
this.flag = true
|
||||
this.instance.post(`/app/appintegraluser/changeIntegral`,{
|
||||
ids: this.form.ids,
|
||||
eventDesc: this.form.eventDesc,
|
||||
enclosure: this.form.enclosure, // 附件
|
||||
integralCalcType: this.form.integralCalcType,
|
||||
integral: this.form.integral,
|
||||
integralUserType: 3
|
||||
}).then(res => {
|
||||
if(res?.code == 0) {
|
||||
this.$message.success('调整积分成功')
|
||||
setTimeout(() =>{
|
||||
this.dialog = false
|
||||
this.getList()
|
||||
this.flag = false
|
||||
}, 600)
|
||||
} else {
|
||||
this.flag = false
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
},
|
||||
|
||||
toDetail(id) {
|
||||
this.$emit('change', {
|
||||
type: 'Detail',
|
||||
params: {
|
||||
id: id || ''
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
||||
Reference in New Issue
Block a user