Merge branch 'dev' into build
# Conflicts: # package.json # vue.config.js
This commit is contained in:
@@ -21,7 +21,7 @@
|
||||
<div class="title">
|
||||
<h4>事件汇总</h4>
|
||||
<div class="timecSelect">
|
||||
时间:<el-date-picker size="small" value-format="yyyy-MM-dd" @change="timeChange" v-model="timeList" type="daterange" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期"></el-date-picker>
|
||||
时间:<el-date-picker size="small" value-format="yyyy-MM-dd" @change="timeChange" v-model="timeList" type="daterange" range-separator="至" :start-placeholder="startPla" :end-placeholder="endPla"></el-date-picker>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bar_Box">
|
||||
@@ -39,17 +39,29 @@
|
||||
</template>
|
||||
<template #right>
|
||||
<ai-download :instance="instance" :url="`/app/appintegraluser/changeIntegralExport?id=${$route.query.id}`" :params="search" fileName="网格员余额变动明细"
|
||||
:disabled="tableData.length == 0">
|
||||
:disabled="tableData.length == 0">
|
||||
<el-button size="small">导出</el-button>
|
||||
</ai-download>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table :tableData="tableData" :total="search.total" :current.sync="search.current" :size.sync="search.size"
|
||||
<ai-table :tableData="tableData" :total="total" :current.sync="search.current" :size.sync="search.size"
|
||||
@getList="getIntegralChange" :col-configs="colConfigs" :dict="dict">
|
||||
|
||||
<el-table-column slot="eventDesc" label="事件" align="center">
|
||||
<el-table-column slot="changeIntegral" label="变动积分" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<span>{{ row.integralType == 3 ? row.integralRuleNamesearch : row.integralType == 0? row.eventDesc : '' }}</span>
|
||||
<span v-if="row.integralType == 3">{{ row.changeIntegral | formatTime }}</span>
|
||||
<span v-if="row.integralType == 0">{{ row.changeIntegral > 0 ? '+' : '-' }}{{ row.changeIntegral }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="integralType" label="类型" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<span v-if="row.integralType == 0">积分调整</span>
|
||||
<span v-else>{{ row.eventType }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="eventDesc" label='事件' align="center" width="400px" show-overflow-tooltip>
|
||||
<template slot-scope="{ row }">
|
||||
<span v-if="row.integralType == 0">{{ row.eventDesc }}</span>
|
||||
<span v-else>{{ row.eventName }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
@@ -59,6 +71,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import dayjs from "dayjs";
|
||||
import * as echarts from 'echarts';
|
||||
export default {
|
||||
name: "gridScoreDetail",
|
||||
@@ -72,8 +85,8 @@ export default {
|
||||
type: '',
|
||||
current: 1,
|
||||
size: 10,
|
||||
total: 0
|
||||
},
|
||||
total: 0,
|
||||
girdList: [],
|
||||
timeList: [],
|
||||
data: {},
|
||||
@@ -81,6 +94,8 @@ export default {
|
||||
endTime: '',
|
||||
xData: [],
|
||||
yData: [],
|
||||
startPla: '',
|
||||
endPla: ''
|
||||
}
|
||||
},
|
||||
props: {
|
||||
@@ -93,20 +108,24 @@ export default {
|
||||
colConfigs() {
|
||||
return [
|
||||
{ prop: "doTime", label: '时间', align: "left", width: "200px" },
|
||||
{ prop: "integralType", label: '类型', align: "center", width: "240px", dict:"integralType"},
|
||||
{ prop: "changeIntegral", label: '变动积分', align: "center",width: "200px",render: (h, { row }) => {
|
||||
return h('span', {}, `${row.integralCalcType == 1 ? '+' : '-'}${row.changeIntegral}`)
|
||||
}},
|
||||
{ slot: "integralType", label: '类型', align: "center", width: "240px", dict:"integralType"},
|
||||
{ slot: "changeIntegral"},
|
||||
{ prop: "nowIntegral", label: '剩余积分', align: "center",width: "200px" },
|
||||
{ slot: "eventDesc", label: '事件', align: "center", },
|
||||
{ slot: "eventDesc"},
|
||||
]
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$dict.load('integralType')
|
||||
this.getDetail()
|
||||
this.getIntegralChange()
|
||||
this.getEventSummary()
|
||||
this.$dict.load('integralType').then(() => {
|
||||
this.getDetail()
|
||||
this.getIntegralChange()
|
||||
this.getEventSummary()
|
||||
let nowTime = dayjs().format('YYYY-MM-DD')
|
||||
let timeAgo = dayjs().subtract(29, 'day').format('YYYY-MM-DD')
|
||||
this.startPla = timeAgo
|
||||
this.endPla = nowTime
|
||||
})
|
||||
|
||||
},
|
||||
methods: {
|
||||
// 详情
|
||||
@@ -122,7 +141,7 @@ export default {
|
||||
})
|
||||
},
|
||||
|
||||
// 事件汇总 暂定
|
||||
// 事件汇总
|
||||
getEventSummary() {
|
||||
this.instance.post(`/app/appintegraluser/eventSummary`,null,{
|
||||
params: {
|
||||
@@ -144,11 +163,13 @@ export default {
|
||||
this.instance.post(`/app/appintegraluser/getChangeDetail`, null, {
|
||||
params: {
|
||||
...this.search, //积分类型
|
||||
total: this.total,
|
||||
id: this.$route.query.id,
|
||||
}
|
||||
}).then(res => {
|
||||
if(res?.data) {
|
||||
this.tableData = res.data.records
|
||||
this.total = res.data.total
|
||||
}
|
||||
})
|
||||
},
|
||||
@@ -157,6 +178,7 @@ export default {
|
||||
if(this.timeList.length) {
|
||||
this.startTime = this.timeList[0]
|
||||
this.endTime = this.timeList[1]
|
||||
this.getEventSummary()
|
||||
}
|
||||
},
|
||||
|
||||
@@ -184,16 +206,12 @@ export default {
|
||||
data: xData,
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value'
|
||||
type: 'value',
|
||||
},
|
||||
series: [
|
||||
{
|
||||
data: yData,
|
||||
type: 'bar',
|
||||
showBackground: true,
|
||||
backgroundStyle: {
|
||||
color: 'rgba(180, 180, 180, 0.2)'
|
||||
},
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: "#5087ec",
|
||||
@@ -228,6 +246,16 @@ export default {
|
||||
|
||||
},
|
||||
|
||||
filters: {
|
||||
formatTime(num) {
|
||||
if(num > 0) {
|
||||
return '+' + num
|
||||
} else {
|
||||
return num
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.getColEcherts()
|
||||
},
|
||||
|
||||
@@ -4,40 +4,27 @@
|
||||
<template #content>
|
||||
<ai-search-bar>
|
||||
<template #left>
|
||||
<el-button type="primary" size="small" icon="iconfont iconAdd" @click="dialog = true">批量调整积分</el-button>
|
||||
<el-cascader ref="cascader1" clearable v-model="search.girdId" :options="girdOptions" placeholder="所属网格" size="small"
|
||||
<el-button type="primary" size="small" icon="iconfont iconAdd" @click="changeIntegral('',0)"> 批量调整积分</el-button>
|
||||
<el-cascader ref="cascader1" clearable v-model="girdIdList" :options="girdOptions" placeholder="所属网格" size="small"
|
||||
:props="defaultProps" :show-all-levels="false" @change="gridChange"></el-cascader>
|
||||
</template>
|
||||
<template #right>
|
||||
<el-input size="small" placeholder="请输入居民名称或真实姓名" v-model="search.userName" clearable
|
||||
<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();}"/>
|
||||
<ai-download :instance="instance" url="`/app/appintegraluser/girdIntegralExport" :params="search" fileName="网格员积分"
|
||||
<ai-download :instance="instance" url="/app/appintegraluser/girdIntegralExport" :params="search" fileName="网格员积分"
|
||||
:disabled="tableData.length == 0">
|
||||
<el-button size="small">导出</el-button>
|
||||
</ai-download>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table :tableData="tableData" :total="page.total" :current.sync="current" :size.sync="page.size"
|
||||
<ai-table :tableData="tableData" :total="total" :current.sync="current" :size.sync="size"
|
||||
@getList="getTableData()" :col-configs="colConfigs" :dict="dict" @sort-change="changeTableSort">
|
||||
<el-table-column slot="integral" label="积分余额" align="center" prop="integral" :sortable="'custom'">
|
||||
<template slot-scope="{ row }">
|
||||
<span>{{ row.integral }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="totalIntegral" label="累计积分" align="center" prop="totalIntegral" :sortable="'custom'">
|
||||
<template slot-scope="{ row }">
|
||||
<span>{{ row.totalIntegral }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="usedIntegral" label="已用积分" align="center" prop="usedIntegral" :sortable="'custom'">
|
||||
<template slot-scope="{ row }">
|
||||
<span>{{ row.usedIntegral }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
|
||||
<el-table-column slot="options" label="操作" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<el-button type="text" @click="dialog = true">调整积分</el-button>
|
||||
<el-button type="text" @click="changeIntegral(row,1)">调整积分</el-button>
|
||||
<el-button type="text" @click="toDetail(row.id)">详情</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -45,17 +32,17 @@
|
||||
</template>
|
||||
</ai-list>
|
||||
<ai-dialog
|
||||
title="添加积分调整"
|
||||
title="调整积分"
|
||||
:visible.sync="dialog"
|
||||
:destroyOnClose="true"
|
||||
width="720px"
|
||||
@onConfirm="onConfirm"
|
||||
@closed="form={}">
|
||||
@closed="form={},chooseUserList=[]">
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
|
||||
<el-form-item label="选择人员" prop="residentId">
|
||||
<ai-person-select :instance="instance" :customClicker="true"
|
||||
:url="'/app/appgirdmemberinfo/list?size=10'"
|
||||
:isMultiple="true" dialogTitle="选择" @selectPerson="selectPerson">
|
||||
<el-form-item label="选择人员" prop="ids">
|
||||
<ai-person-select :instance="instance" :customClicker="true" :chooseUserList="chooseUserList"
|
||||
url="/app/appgirdmemberinfo/list" headerTitle="网格员列表"
|
||||
:isMultiple="true" dialogTitle="选择" @selectPerson="selectPerson" class="aipersonselect">
|
||||
<template name="option" v-slot:option="{ item }">
|
||||
<span class="iconfont iconProlife">{{ item.name }}</span>
|
||||
<ai-id mode="show" :show-eyes="false" :value="item.idNumber"/>
|
||||
@@ -98,9 +85,13 @@ export default {
|
||||
girdId: '',
|
||||
current: 1,
|
||||
size: 10,
|
||||
sortFiled: '',
|
||||
sortRule: '',
|
||||
},
|
||||
girdIdList: [],
|
||||
tableData: [],
|
||||
page: {size: 10, total: 0},
|
||||
size: 10,
|
||||
total: 0,
|
||||
current: 1,
|
||||
girdList: [],
|
||||
form: {
|
||||
@@ -108,7 +99,7 @@ export default {
|
||||
eventDesc: "",
|
||||
enclosure: "", // 附件
|
||||
integralCalcType: "",
|
||||
integral: 0,
|
||||
integral: '',
|
||||
file: [],
|
||||
},
|
||||
personList: [],
|
||||
@@ -119,6 +110,8 @@ export default {
|
||||
value: 'id',
|
||||
checkStrictly: true,
|
||||
},
|
||||
chooseUserList: [],
|
||||
flag: false,
|
||||
}
|
||||
},
|
||||
created() {
|
||||
@@ -131,19 +124,20 @@ export default {
|
||||
colConfigs() {
|
||||
return [
|
||||
{ prop: "userName", label: '姓名', align: "left", },
|
||||
{ prop: "girdName", label: '所属网格', align: "center", },
|
||||
{ slot: "integral", label: '积分余额', align: "center", },
|
||||
{ slot: "totalIntegral", label: '累计积分', align: "center", },
|
||||
{ slot: "usedIntegral", label: '已用积分', align: "center", },
|
||||
{ prop: "girdName", label: '所属网格' },
|
||||
{ prop: "integral", label: '积分余额', align: "center", sortable: "custom" },
|
||||
{ prop: "totalIntegral", label: '累计积分', align: "center", sortable: "custom" },
|
||||
{ prop: "usedIntegral", label: '已用积分', align: "center", sortable: "custom" },
|
||||
{ slot: "options" },
|
||||
]
|
||||
},
|
||||
rules() {
|
||||
return {
|
||||
residentId: [{required: true, message: '请选择人员', trigger: 'blur'},],
|
||||
eventDesc: [{required: true, message: '请输入调整说明', trigger: 'blur'},],
|
||||
integralCalcType: [{required: true, message: '请选择类型', trigger: 'change'},],
|
||||
integral: [{required: true, validator: (r, v, cb) => v > 0 ? cb() : cb("请输入正数")}],
|
||||
ids: [{required: true, message: '请选择人员', trigger: 'blur'}],
|
||||
eventDesc: [{required: true, message: '请输入调整说明', trigger: 'blur'}],
|
||||
integralCalcType: [{required: true, message: '请选择类型', trigger: 'change'}],
|
||||
integral: [{required: true, message: '请输入积分', trigger: 'blur' },
|
||||
{pattern: /^([1-9]\d*|0)(\.\d{1,2})?$/, message: '请输入正数且最多只能保留两位小数'}],
|
||||
}
|
||||
},
|
||||
},
|
||||
@@ -151,29 +145,38 @@ export default {
|
||||
getTableData() {
|
||||
this.instance.post(`/app/appintegraluser/integralManager`,null,{
|
||||
params: {
|
||||
...this.page,
|
||||
...this.search,
|
||||
current: this.current,
|
||||
|
||||
size: this.size,
|
||||
total: this.total
|
||||
}
|
||||
}).then(res => {
|
||||
if(res?.data) {
|
||||
this.tableData = res.data.records
|
||||
this.page.total = res.data.total
|
||||
this.total = res.data.total
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
selectPerson(val) {
|
||||
this.personList = val
|
||||
this.form.ids = this.personList.map(e => e.id)
|
||||
// if (val) {
|
||||
// this.form.residentId = val.id
|
||||
// this.personList = [{...val}]
|
||||
// } else {
|
||||
// this.form.residentId = ""
|
||||
// this.personList = []
|
||||
// }
|
||||
if (val) {
|
||||
this.personList = val
|
||||
this.form.ids = [...this.personList.map(e => e.id)]
|
||||
} else {
|
||||
this.form.ids = this.chooseUserList.map(e => e.id)
|
||||
}
|
||||
},
|
||||
changeIntegral(row,type) {
|
||||
if(type==0) {
|
||||
this.dialog = true
|
||||
} else if(type ==1) {
|
||||
this.chooseUserList = [{
|
||||
id: row.userId,
|
||||
name: row.userName
|
||||
}]
|
||||
this.form.ids = this.chooseUserList.map(e => e.id)
|
||||
this.dialog = true
|
||||
}
|
||||
},
|
||||
getGridList() {
|
||||
this.instance.post(`/app/appgirdinfo/listAll3`).then((res) => {
|
||||
@@ -205,48 +208,74 @@ export default {
|
||||
},
|
||||
|
||||
gridChange(val) {
|
||||
this.girdIdList = val
|
||||
this.search.girdId = val?.[val.length - 1]
|
||||
this.$refs.cascader1.dropDownVisible = false;
|
||||
this.getTableData()
|
||||
},
|
||||
|
||||
changeTableSort(col) {
|
||||
// console.log(col);
|
||||
if(col.prop === 'integral') { // 剩余积分
|
||||
// col.order === 'ascending' &&
|
||||
// col.order === 'descending' &&
|
||||
// col.order === null &&
|
||||
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') { // 累计积分
|
||||
// col.order === 'ascending' &&
|
||||
// col.order === 'descending' &&
|
||||
// col.order === null &&
|
||||
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') { // 已用积分
|
||||
// col.order === 'ascending' &&
|
||||
// col.order === 'descending' &&
|
||||
// col.order === null &&
|
||||
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.getTableData()
|
||||
this.getTableData()
|
||||
},
|
||||
|
||||
onConfirm() {
|
||||
if(this.flag) return
|
||||
|
||||
if(this.form.file?.length) {
|
||||
this.form.enclosure = this.form.file[0].url
|
||||
}
|
||||
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,
|
||||
}).then(res => {
|
||||
if(res.code == 0) {
|
||||
this.$message.success('调整积分成功')
|
||||
setTimeout(() =>{
|
||||
this.getTableData()
|
||||
this.dialog = false
|
||||
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,
|
||||
}).then(res => {
|
||||
if(res?.code == 0) {
|
||||
this.$message.success('调整积分成功')
|
||||
setTimeout(() =>{
|
||||
this.dialog = false
|
||||
this.getTableData()
|
||||
this.flag = false
|
||||
}, 600)
|
||||
} else {
|
||||
this.flag = false
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
},
|
||||
|
||||
toDetail(id) {
|
||||
@@ -264,5 +293,69 @@ export default {
|
||||
<style lang="scss" scoped>
|
||||
.gridScoreManage {
|
||||
height: 100%;
|
||||
|
||||
::v-deep .ai-dialog .ai-dialog__content {
|
||||
max-height: 600px!important;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.userlist {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.userlist, .user {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.user {
|
||||
position: relative;
|
||||
width: 70px;
|
||||
text-align: center;
|
||||
|
||||
.remove-icon {
|
||||
position: absolute;
|
||||
right: 7px;
|
||||
top: -4px;
|
||||
line-height: 1;
|
||||
padding: 6px 0;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: crimson;
|
||||
}
|
||||
}
|
||||
|
||||
img, h2 {
|
||||
display: block;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
text-align: center;
|
||||
margin: 0 auto 4px;
|
||||
font-size: 14px;
|
||||
color: #fff;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
h2 {
|
||||
background-color: $primaryColor;
|
||||
}
|
||||
|
||||
span {
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
word-break: break-all;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .selectCont .pagination {
|
||||
width: 100%!important;
|
||||
background: pink;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
<template>
|
||||
<section class="gridScoreRules">
|
||||
<!-- v-if="permissions('app_appvillagerintegralrule_detail')" -->
|
||||
@@ -6,19 +5,21 @@
|
||||
<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="search.systemRuleId" :options="rulesOps" placeholder="请选择事件/类型" clearable :props="rulesProps" @change="handleTypeSearch" ref="eventTypeSearch"/>
|
||||
<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>
|
||||
</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()">
|
||||
<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 v-if="row.integralValueType == 1">
|
||||
{{row.integralStart > 0? "+" + row.integralStart : row.integralStart}}~{{row.integralEnd > 0 ? "+" + row.integralEnd : row.integralEnd}}
|
||||
</span>
|
||||
<span v-else>{{ row.integral > 0 ? "+" : "" }}{{ row.integral }}</span>
|
||||
<!-- <span v-if="row.integralValueType == 1">
|
||||
{{ row.integralStart > 0 ? "+" + row.integralStart : row.integralStart }}~{{ row.integralEnd > 0 ? "+" + row.integralEnd : row.integralEnd }}
|
||||
</span> -->
|
||||
<span>{{ row.integral > 0 ? "+" : "" }}{{ row.integral }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="options" label="操作" align="center" fixed="right" width="200">
|
||||
@@ -35,15 +36,14 @@
|
||||
</template>
|
||||
</ai-list>
|
||||
<!-- <ai-empty v-else>暂无应用权限</ai-empty> -->
|
||||
<ai-dialog :title="dialogTitle" :visible.sync="dialog" @onConfirm="onConfirm" @closed="closed" width="900px">
|
||||
<ai-dialog :title="dialogTitle" :visible.sync="dialog" @onConfirm="onConfirm" @closed="closed" width="900px" @open="beforeSelectTree">
|
||||
<div class="form_div">
|
||||
<el-form ref="DialogForm" :model="form" :rules="formRules" size="small" label-suffix=":" label-width="150px" >
|
||||
<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="自定义事件" v-if="form.systemRuleId == '自定义'">
|
||||
<el-input placeholder="请输入,周期范围内,不填写表示不限制" v-model="form.ruleName" clearable/>
|
||||
<el-form-item label="自定义事件" v-if="form.systemRuleId == '自定义'" prop="ruleName" :required="form.systemRuleId == '自定义'">
|
||||
<el-input placeholder="请输入,周期范围内,不填写表示不限制" v-model="form.ruleName" clearable maxlength="10" show-word-limit/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="规则">
|
||||
@@ -82,11 +82,11 @@
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="奖励次数">
|
||||
<el-input placeholder="请输入,周期范围内,不填写表示不限制" v-model.number="form.numberLimit" clearable/>
|
||||
<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-input placeholder="请输入" v-model="form.integral" clearable/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="有效范围" prop="validRangeType" required>
|
||||
@@ -96,21 +96,27 @@
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="生效网格" :prop="form.validRangeType == 1 ? 'validRangeData' : ''" :rules="[{ required: true, message: '请选择生效网格', trigger: 'change' }, ]" v-if="form.validRangeType == 1">
|
||||
<el-button type="text" @click="(showGrid = true), beforeSelectTree()" >{{ girdInfoList.length ? "已选择" : "请选择" }}</el-button>
|
||||
<el-form-item label="生效网格" :prop="form.validRangeType == 1 ? 'validRangeData' : ''"
|
||||
:rules="[{ required: true, message: '请选择生效网格', trigger: 'change' }, ]" v-if="form.validRangeType == 1">
|
||||
<ai-dialog-btn dialogTitle="选择网格" append-to-body @onConfirm="getCheckedTree" :customFooter="false" :text="girdInfoList.length ? '重新选择' : '请选择'">
|
||||
<div class="grid">
|
||||
<el-tree :data="treeObj.treeList" :props="treeObj.defaultProps" node-key="id" :expand-on-click-node="false">
|
||||
<template slot-scope="{data}">
|
||||
<el-row class="fill" type="flex" @click.native.stop="handleTreeChecked(data)">
|
||||
<div class="fill" v-text="data.girdName"/>
|
||||
<div class="iconfont iconSuccess color-primary mar-r8" v-if="data.checked"/>
|
||||
</el-row>
|
||||
</template>
|
||||
</el-tree>
|
||||
</div>
|
||||
</ai-dialog-btn>
|
||||
|
||||
<div v-if="girdInfoList.length">
|
||||
<span v-for="(e,index) in girdNameList" :key="index" class="mar-r8" v-text="e"/>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<ai-dialog title="选择网格" :visible.sync="showGrid" :customFooter="true" :destroyOnClose="true" border width="720px" append-to-body>
|
||||
<div class="grid">
|
||||
<el-tree :data="treeObj.treeList" :props="treeObj.defaultProps" node-key="id" ref="tree" :check-strictly="true" show-checkbox default-expand-all :default-checked-keys="currCheckedKeys" @check="onCheckChange">
|
||||
</el-tree>
|
||||
</div>
|
||||
<div class="dialog-footer" slot="footer">
|
||||
<el-button size="medium" @click="showGrid = false">取消</el-button>
|
||||
<el-button type="primary" size="medium" @click="getCheckedTree()">确认</el-button>
|
||||
</div>
|
||||
</ai-dialog>
|
||||
</ai-dialog>
|
||||
</section>
|
||||
</template>
|
||||
@@ -125,38 +131,54 @@ export default {
|
||||
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 {
|
||||
search: {
|
||||
status: "",
|
||||
systemRuleId: "",
|
||||
ruleName: ""
|
||||
},
|
||||
page: { current: 1, size: 10, total: 0 },
|
||||
systemRuleIdList: [],
|
||||
page: {current: 1, size: 10, total: 0},
|
||||
colConfigs: [
|
||||
{
|
||||
prop: "parentRuleName",
|
||||
label: "类型",
|
||||
dict: "integralRuleEventType",
|
||||
},
|
||||
{ prop: "ruleName", label: "事件", dict: "integralRuleEvent" },
|
||||
{ prop: "ruleType", label: "规则", dict: "integralRuleRuleType" },
|
||||
{prop: "ruleName", label: "事件", dict: "integralRuleEvent"},
|
||||
{prop: "ruleType", label: "规则", dict: "integralRuleRuleType"},
|
||||
{
|
||||
prop: "scoringCycle",
|
||||
label: "周期范围",
|
||||
dict: "integralRuleScoringCycle",
|
||||
render: (h, { row }) => {
|
||||
render: (h, {row}) => {
|
||||
return h(
|
||||
"span",
|
||||
{},
|
||||
row.numberLimit.length
|
||||
? $dict.getLabel("integralRuleScoringCycle", row.scoringCycle)
|
||||
: $dict.getLabel("integralRuleScoringCycle", row.scoringCycle) +
|
||||
"span",
|
||||
{},
|
||||
row.numberLimit.length
|
||||
? $dict.getLabel("integralRuleScoringCycle", row.scoringCycle)
|
||||
: $dict.getLabel("integralRuleScoringCycle", row.scoringCycle) +
|
||||
row.numberLimit +
|
||||
"次"
|
||||
);
|
||||
},
|
||||
},
|
||||
{ slot: "integral", label: "积分分值", align: "center" },
|
||||
{slot: "integral", label: "积分分值", align: "center"},
|
||||
{
|
||||
prop: "validRangeType",
|
||||
label: "有效范围",
|
||||
@@ -169,7 +191,7 @@ export default {
|
||||
width: 96,
|
||||
dict: "integralRuleStatus",
|
||||
},
|
||||
{ slot: "options", label: "操作", align: "center" },
|
||||
{slot: "options", label: "操作", align: "center"},
|
||||
],
|
||||
tableData: [],
|
||||
dialog: false,
|
||||
@@ -185,20 +207,17 @@ export default {
|
||||
},
|
||||
formRules: {
|
||||
systemRuleId: [
|
||||
{ required: true, message: "请选择事件/类型", trigger: "change" },
|
||||
{required: true, message: "请选择事件/类型", trigger: "change"},
|
||||
],
|
||||
ruleName: [
|
||||
{required: true, message: "请输入自定义事件", trigger: "change"},
|
||||
],
|
||||
scoringCycle: [
|
||||
{ required: true, message: "请选择周期范围", trigger: "change" },
|
||||
],
|
||||
integral: [
|
||||
{
|
||||
required: true,
|
||||
pattern: /^\d*[.\d]\d?$/,
|
||||
message: "请输入积分分值,最多保留一位小数",
|
||||
},
|
||||
{required: true, message: "请选择周期范围", trigger: "change"},
|
||||
],
|
||||
integral: [{required: true, validator: validcode, trigger: "blur"},],
|
||||
validRangeType: [
|
||||
{ required: true, message: "请选择有效范围", trigger: "change" },
|
||||
{required: true, message: "请选择有效范围", trigger: "change"},
|
||||
],
|
||||
},
|
||||
rulesOps: [],
|
||||
@@ -208,42 +227,44 @@ export default {
|
||||
checkStrictly: true,
|
||||
},
|
||||
radio: 0,
|
||||
showGrid: false,
|
||||
treeObj: {
|
||||
treeList: [],
|
||||
defaultProps: {
|
||||
label: "girdName",
|
||||
value: "id",
|
||||
children: 'children',
|
||||
isLeaf: 'leaf'
|
||||
},
|
||||
checkedKeys: [],
|
||||
},
|
||||
treeSelected: {},
|
||||
girdInfoList: [],
|
||||
currCheckedKeys: [],
|
||||
rulueType: "0",
|
||||
girdNameList: [],
|
||||
list: [],
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.$dict.load("integralRuleStatus","integralRuleRuleType","integralRuleScoringCycle","integralRuleEvent","integralRuleEventType").then(() => {
|
||||
this.getList();
|
||||
this.getRulesList();
|
||||
this.beforeSelectTree();
|
||||
});
|
||||
this.$dict.load("integralRuleStatus", "integralRuleRuleType", "integralRuleScoringCycle",
|
||||
"integralRuleEvent", "integralRuleEventType").then(() => {
|
||||
this.getList();
|
||||
this.getRulesList();
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
getList() {
|
||||
this.instance
|
||||
.post(`/app/appintegralrule/list`, null, {
|
||||
params: {
|
||||
...this.search,
|
||||
...this.page,
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
if (res?.data) {
|
||||
this.tableData = res.data.records;
|
||||
this.page.total = res.data.total;
|
||||
}
|
||||
});
|
||||
.post(`/app/appintegralrule/list`, null, {
|
||||
params: {
|
||||
...this.search,
|
||||
...this.page,
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
if (res?.data) {
|
||||
this.tableData = res.data.records;
|
||||
this.page.total = res.data.total;
|
||||
}
|
||||
});
|
||||
},
|
||||
closed() {
|
||||
this.form = {
|
||||
@@ -256,81 +277,73 @@ export default {
|
||||
validRangeType: "0",
|
||||
validRangeData: "",
|
||||
};
|
||||
this.girdInfoList = []
|
||||
this.treeSelected = {}
|
||||
},
|
||||
toEdit(row) {
|
||||
this.form = {...row}
|
||||
// let arr = this.form?.validRangeData?.split(",");
|
||||
// this.girdInfoList = arr.map(e=> {
|
||||
// return {
|
||||
// id: e,
|
||||
// checkType: true
|
||||
// }
|
||||
// })
|
||||
this.girdInfoList = this.form?.validRangeData?.split(",");
|
||||
if (this.form?.validRangeData) {
|
||||
this.girdInfoList = JSON.parse(this.form.validRangeData)
|
||||
this.girdNameList = this.girdInfoList.map(e => e.girdName)
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
this.dialog = true;
|
||||
});
|
||||
},
|
||||
remove(id) {
|
||||
this.$confirm("删除后不可恢复,是否要删除该事项?", {
|
||||
this.$confirm("删除后不可恢复,是否要删除该规则?", {
|
||||
type: "error",
|
||||
}).then(() => {
|
||||
this.instance
|
||||
.post(`/app/appintegralrule/delete?ids=${id}`)
|
||||
.then((res) => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success("删除成功!");
|
||||
this.getList();
|
||||
}
|
||||
});
|
||||
.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();
|
||||
}
|
||||
});
|
||||
.post(`/app/appintegralrule/enableStatus?id=${id}`)
|
||||
.then((res) => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success(`${text}成功!`);
|
||||
this.getList();
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
onReset() {
|
||||
this.page.current = 1;
|
||||
this.search.classification = "";
|
||||
this.search.integralType = "";
|
||||
this.search.ruleStatus = "";
|
||||
this.getList();
|
||||
},
|
||||
onConfirm() {
|
||||
// if(this.form.ruleType==1 && !this.form.ladderRule.length) {
|
||||
// return this.$message.error('请添加规则')
|
||||
// }
|
||||
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)
|
||||
.then((res) => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success(
|
||||
.post(`/app/appintegralrule/addOrUpdate`, formData)
|
||||
.then((res) => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success(
|
||||
`${this.isEdit ? "编辑成功" : "添加成功"}`
|
||||
);
|
||||
this.onReset();
|
||||
this.dialog = false;
|
||||
}
|
||||
});
|
||||
);
|
||||
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;
|
||||
@@ -344,26 +357,26 @@ export default {
|
||||
},
|
||||
handleDelete(i) {
|
||||
this.$confirm("是否要删除该规则?")
|
||||
.then(() => {
|
||||
this.form.ladderRule.splice(i, 1);
|
||||
})
|
||||
.catch(() => 0);
|
||||
.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/list?current=1&sizes=3000`)
|
||||
.then((res) => {
|
||||
if (res?.data) {
|
||||
this.rulesOps = this.toTree(res.data.records);
|
||||
this.rulesOps.push({
|
||||
ruleName: "自定义",
|
||||
id: "自定义",
|
||||
});
|
||||
}
|
||||
});
|
||||
.post(`/app/appintegralsystemrule/list?current=1&sizes=3000`)
|
||||
.then((res) => {
|
||||
if (res?.data) {
|
||||
this.rulesOps = this.toTree(res.data.records);
|
||||
this.rulesOps.push({
|
||||
ruleName: "自定义",
|
||||
id: "自定义",
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
// 转树形结构
|
||||
toTree(data) {
|
||||
@@ -385,84 +398,42 @@ export default {
|
||||
});
|
||||
return result;
|
||||
},
|
||||
|
||||
girdToTree(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;
|
||||
},
|
||||
|
||||
getCheckedTree() {
|
||||
if (!this.$refs.tree.getCheckedNodes().length) {
|
||||
const selected = Object.values(this.treeSelected)
|
||||
if (!selected.length) {
|
||||
return this.$message.error("请选择网格");
|
||||
}
|
||||
// console.log(this.girdInfoList, this.$refs.tree.getCheckedNodes());
|
||||
this.girdInfoList = this.$refs.tree.getCheckedNodes().map((item) => {
|
||||
return { ...item, checkType: true };
|
||||
|
||||
this.girdInfoList = selected.map((item) => {
|
||||
return {...item, checkType: true};
|
||||
});
|
||||
// this.$set(this.girdInfoList, this.currIndex, {
|
||||
// ...this.$refs.tree.getCheckedNodes(),
|
||||
// checkType: true
|
||||
// })
|
||||
this.form.validRangeData = this.$refs.tree
|
||||
.getCheckedNodes()
|
||||
.map((e) => e.id)
|
||||
.toString();
|
||||
this.showGrid = false;
|
||||
let validRangeData = selected.map((e) => ({id: e.id, girdName: e.girdName}))
|
||||
this.girdNameList = validRangeData.map(e => e.girdName)
|
||||
this.form.validRangeData = JSON.stringify(validRangeData)
|
||||
},
|
||||
|
||||
beforeSelectTree() {
|
||||
this.treeObj.checkedKeys = [];
|
||||
this.instance
|
||||
.post(`/app/appgirdinfo/listAll3`, null, null)
|
||||
.then((res) => {
|
||||
if (res.code == 0) {
|
||||
res.data.forEach((item)=>{
|
||||
const isChecked = this.girdInfoList.find((checkedId)=>{
|
||||
return item.id === checkedId
|
||||
})
|
||||
if(isChecked) item.checkType = true
|
||||
})
|
||||
console.log(res.data)
|
||||
|
||||
this.treeObj.treeList = this.girdToTree(res.data);
|
||||
this.girdInfoList.map((e) => {
|
||||
this.treeObj.checkedKeys.push(e.id);
|
||||
});
|
||||
this.$nextTick(() => {
|
||||
this.currCheckedKeys = this.girdInfoList;
|
||||
this.$nextTick(() => {
|
||||
this.$refs.tree?.getCheckedKeys(this.currCheckedKeys);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
onCheckChange(e) {
|
||||
// this.$nextTick(() => {
|
||||
// this.$refs.tree.getCheckedKeys().forEach(v => {
|
||||
// this.$refs.tree.setChecked(v, false)
|
||||
// })
|
||||
// this.$refs.tree.setChecked(e.id, true)
|
||||
// })
|
||||
// console.log(e);
|
||||
this.$refs.tree.setChecked(e.id, true);
|
||||
this.instance.post(`/app/appgirdinfo/listAll3`, null, null).then((res) => {
|
||||
if (res?.data) {
|
||||
this.list = res.data.map(e => ({...e, checked: !!this.girdInfoList.find(s => s.id == e.id)}))
|
||||
this.girdInfoList.map(e => this.treeSelected[e.id] = e)
|
||||
this.treeObj.treeList = this.$arr2tree(this.list, {parent: 'parentGirdId'})
|
||||
}
|
||||
});
|
||||
},
|
||||
handleTreeChecked(data) {
|
||||
this.list.forEach(v => {
|
||||
return {
|
||||
...v,
|
||||
checked: false
|
||||
}
|
||||
})
|
||||
data.checked = !data.checked
|
||||
if (data.checked) {
|
||||
this.treeSelected[data.id] = data
|
||||
} else {
|
||||
delete this.treeSelected[data.id]
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isEdit() {
|
||||
@@ -508,4 +479,4 @@ export default {
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<span v-for="(item,index) in timeCheck" :key="index" :class="type == index? 'active':''"
|
||||
@click="timeChange(index)">{{ item }}</span>
|
||||
</div>
|
||||
<el-cascader ref="cascader1" v-model="girdId" :options="girdOptions" placeholder="所属网格" size="small"
|
||||
<el-cascader ref="cascader1" v-model="girdArr" :options="girdOptions" placeholder="所属网格" size="small"
|
||||
:props="defaultProps" :show-all-levels="false" @change="gridChange" clearable></el-cascader>
|
||||
</div>
|
||||
</div>
|
||||
@@ -56,7 +56,7 @@
|
||||
<template #content>
|
||||
<ai-search-bar>
|
||||
<template #left>
|
||||
<el-cascader ref="cascader2" v-model="search.girdId" :options="girdOptions" placeholder="所属网格" size="small"
|
||||
<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')"/>
|
||||
@@ -70,11 +70,24 @@
|
||||
v-throttle="() => {(current = 1), getTableData();}" />
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table :tableData="tableData" :total="page.total" :current.sync="current" :size.sync="page.size"
|
||||
<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 v-if="row.integralRuleId">{{ row.integralRuleName }}</span>
|
||||
<span v-else>{{ row.eventDesc }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="integralType" label="类型" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<span v-if="row.integralRuleId">{{ row.eventType }}</span>
|
||||
<span v-else>{{ row.integralRuleName }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="changeIntegral" label="积分变动" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<span>{{ row.integralCalcType == 1 ? '+' : '-' }}{{ row.changeIntegral }}</span>
|
||||
<span v-if="row.integralType == 3">{{ row.changeIntegral | formatTime }}</span>
|
||||
<span v-if="row.integralType == 0">{{ row.changeIntegral > 0 ? '+' : '-' }}{{ row.changeIntegral }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="options" label="操作" align="center">
|
||||
@@ -92,18 +105,26 @@
|
||||
<ai-wrapper>
|
||||
<ai-info-item label="姓名" :value="details.integralUserName" />
|
||||
<ai-info-item label="所属网格" :value="details.girdName"/>
|
||||
<ai-info-item label="事件" isLine :value="details.eventDesc"/>
|
||||
<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="积分变动" v-if="details.integralType == 3">
|
||||
{{ details.changeIntegral | formatTime }}
|
||||
</ai-info-item>
|
||||
<ai-info-item label="积分变动" v-if="details.integralType == 0">
|
||||
{{ details.changeIntegral > 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="fileOps"></ai-file-list>
|
||||
<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">关闭</el-button>
|
||||
<el-button @click="dialog = false" style="width: 92px">关闭</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
|
||||
@@ -140,10 +161,9 @@ export default {
|
||||
startTime: '',
|
||||
endTime: '',
|
||||
},
|
||||
page: {
|
||||
size: 10,
|
||||
total: 0,
|
||||
},
|
||||
girdIdArr:[],
|
||||
total: 0,
|
||||
size: 10,
|
||||
current: 1,
|
||||
girdList: [],
|
||||
time: [],
|
||||
@@ -156,10 +176,12 @@ export default {
|
||||
endTime: '',
|
||||
data: {},
|
||||
girdId: '',
|
||||
girdArr: [],
|
||||
girdOptions: [],
|
||||
defaultProps: {
|
||||
label: 'girdName',
|
||||
value: 'id',
|
||||
children: 'children',
|
||||
checkStrictly: true,
|
||||
},
|
||||
details: {},
|
||||
@@ -168,9 +190,6 @@ export default {
|
||||
userSortListY: [],
|
||||
girdSortListX: [],
|
||||
girdSortListY: [],
|
||||
fileOps: {
|
||||
name: ''
|
||||
},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -179,8 +198,8 @@ export default {
|
||||
return [
|
||||
{ prop: "integralUserName", label: '姓名', align: "left", width: "200px" },
|
||||
{ prop: "girdName", label: '所属网格', align: "center", width: "180px" },
|
||||
{ prop: "eventDesc", label: '事件', align: "center",width: "200px" },
|
||||
{ prop: "integralType", label: '类型', align: "center",width: "200px", dict:"integralType" },
|
||||
{ slot: "eventDesc"},
|
||||
{ slot: "integralType", label: '类型' },
|
||||
{ slot: "changeIntegral", label: '积分变动', align: "center", },
|
||||
{ prop: "nowIntegral", label: '剩余积分', align: "center", },
|
||||
{ prop: "createTime", label: '时间', align: "center", },
|
||||
@@ -189,7 +208,7 @@ export default {
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$dict.load('epidemicDangerousAreaLevel','integralType').then(() => {
|
||||
this.$dict.load('epidemicDangerousAreaLevel','integralType','integralRuleEvent','integralRuleEventType').then(() => {
|
||||
this.getStatistics()
|
||||
this.getGridList()
|
||||
this.getRanking()
|
||||
@@ -237,19 +256,21 @@ export default {
|
||||
getTableData() {
|
||||
this.instance.post('/app/appintegraluser/girdIntegralDetail',null,{
|
||||
params: {
|
||||
...this.page,
|
||||
...this.search,
|
||||
current: this.current
|
||||
current: this.current,
|
||||
size: this.size,
|
||||
total: this.total,
|
||||
}
|
||||
}).then(res => {
|
||||
if(res?.data) {
|
||||
this.tableData = res.data.records
|
||||
this.page.total = res.data.total
|
||||
this.total = res.data.total
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
gridChangeOpt(val) {
|
||||
this.girdIdArr = val
|
||||
this.search.girdId = val?.[val.length - 1]
|
||||
this.$refs.cascader2.dropDownVisible = false;
|
||||
this.getTableData()
|
||||
@@ -390,6 +411,7 @@ export default {
|
||||
this.myChart2.resize()
|
||||
},
|
||||
gridChange(val) {
|
||||
this.girdArr = val
|
||||
this.girdId = val?.[val.length - 1]
|
||||
this.$refs.cascader1.dropDownVisible = false;
|
||||
this.getStatistics()
|
||||
@@ -398,7 +420,7 @@ export default {
|
||||
// 所有网格
|
||||
getGridList() {
|
||||
this.instance.post(`/app/appgirdinfo/listAll3`).then((res) => {
|
||||
if (res.code == 0) {
|
||||
if (res?.code == 0) {
|
||||
this.girdOptions = this.toTree(res.data)
|
||||
}
|
||||
})
|
||||
@@ -450,9 +472,11 @@ export default {
|
||||
if(res?.data) {
|
||||
this.details = res.data
|
||||
if(res.data.enclosure) {
|
||||
this.fileDownLoad = [{ url:res.data.enclosure }]
|
||||
let str = res.data.enclosure.split('/')
|
||||
this.fileOps.name = str?.[str.length - 1]
|
||||
this.fileDownLoad = [{
|
||||
url:res.data.enclosure,
|
||||
name: str?.[str.length - 1]
|
||||
}]
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -471,6 +495,16 @@ export default {
|
||||
|
||||
},
|
||||
|
||||
filters: {
|
||||
formatTime(num) {
|
||||
if(num > 0) {
|
||||
return '+' + num
|
||||
} else {
|
||||
return num
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.getColEcherts1()
|
||||
this.getColEcherts2()
|
||||
|
||||
@@ -103,10 +103,8 @@ export default {
|
||||
return [
|
||||
{prop: 'doTime', label: '时间', width: 200},
|
||||
{prop: "type", label: "类型", dict: "integralDetailType", align: 'center'},
|
||||
{
|
||||
prop: 'changeIntegral', align: 'center', label: '变动积分',
|
||||
render: (h, {row}) => h('p', `${row.integralCalcType == 1 ? '+' : '-'}${row.changeIntegral}`)
|
||||
},
|
||||
{prop: 'changeIntegral', align: 'center', label: '变动积分',render:
|
||||
(h, {row}) => h('p', `${row.integralCalcType == 1 ? '+' : '-'}${row.changeIntegral}`)},
|
||||
{prop: 'nowIntegral', align: 'center', label: '剩余积分'},
|
||||
{prop: 'eventDesc', label: '事件', width: 500}
|
||||
]
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
<template>
|
||||
<section class="AppResident">
|
||||
<ai-list v-if="!showDetail" isTabs>
|
||||
<ai-title slot="title" title="居民档案" :instance="instance" :hideLevel="hideLevel-1" isShowArea
|
||||
v-model="areaId"/>
|
||||
<ai-title slot="title" title="居民档案" :instance="instance" :hideLevel="hideLevel-1" :isShowArea="permissions('app_datastatistics')" v-model="areaId"/>
|
||||
<template #tabs>
|
||||
<el-tabs v-model="activeName">
|
||||
<el-tab-pane v-for="op in tabs" :key="op.value" :name="op.value" :label="op.label">
|
||||
@@ -67,14 +66,14 @@ export default {
|
||||
comp: ResidentList,
|
||||
detail: ResidentDetail
|
||||
})),
|
||||
{label: "居民统计", value: "3", comp: ResidentSta},
|
||||
{label: "居民统计", value: "3", comp: ResidentSta, permit: "app_datastatistics"},
|
||||
{label: "居民档案审核", value: "4", comp: auditList, detail: auditDetail, permit: "app_appresident_examine"}
|
||||
].filter(e => !e.permit || this.permissions(e.permit))
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.activeName = this.$route.query?.type
|
||||
this.areaId = this.$copy(this.user.info.areaId)
|
||||
this.areaId = this.permissions("app_datastatistics") ? this.$copy(this.user.info.areaId) : ""
|
||||
this.dict.load('residentType', "sex", "faithType", "fileStatus", "legality", "education", "maritalStatus",
|
||||
"politicsStatus", "householdName", "nation", "liveReason", "certificateType", "job", "militaryStatus",
|
||||
"householdRelation", "logoutReason", "nation", "registerStatus", "residentTipType", "liveCategory",
|
||||
|
||||
@@ -1,73 +1,71 @@
|
||||
<template>
|
||||
<div class="doc-circulation ailist-wrapper">
|
||||
<keep-alive :include="['List']">
|
||||
<component ref="component" :is="component" @change="onChange" :params="params" :instance="instance" :dict="dict"></component>
|
||||
<component ref="component" :is="component" @change="onChange" :params="params" v-bind="$props"/>
|
||||
</keep-alive>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import List from './components/List'
|
||||
import Add from './components/Add'
|
||||
import Detail from './components/Detail'
|
||||
import List from './components/List'
|
||||
import Add from './components/Add'
|
||||
import Detail from './components/Detail'
|
||||
|
||||
export default {
|
||||
name: 'AppVillageIntroduction',
|
||||
label: '本村简介',
|
||||
export default {
|
||||
name: 'AppVillageIntroduction',
|
||||
label: '本村简介',
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
menuName: {default: "本村简介"}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
component: 'List',
|
||||
params: {},
|
||||
include: []
|
||||
}
|
||||
},
|
||||
components: {
|
||||
Add,
|
||||
List,
|
||||
Detail
|
||||
},
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object
|
||||
},
|
||||
mounted() {
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
component: 'List',
|
||||
params: {},
|
||||
include: []
|
||||
methods: {
|
||||
onChange(data) {
|
||||
if (data.type === 'Add') {
|
||||
this.component = 'Add'
|
||||
this.params = data.params
|
||||
}
|
||||
},
|
||||
|
||||
components: {
|
||||
Add,
|
||||
List,
|
||||
Detail
|
||||
},
|
||||
if (data.type === 'Detail') {
|
||||
this.component = 'Detail'
|
||||
this.params = data.params
|
||||
}
|
||||
|
||||
mounted () {
|
||||
},
|
||||
if (data.type === 'list') {
|
||||
this.component = 'List'
|
||||
this.params = data.params
|
||||
|
||||
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()
|
||||
}
|
||||
})
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
if (data.isRefresh) {
|
||||
this.$refs.component.getList()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.doc-circulation {
|
||||
height: 100%;
|
||||
background: #F3F6F9;
|
||||
overflow: auto;
|
||||
}
|
||||
.doc-circulation {
|
||||
height: 100%;
|
||||
background: #F3F6F9;
|
||||
overflow: auto;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<ai-detail>
|
||||
<template slot="title">
|
||||
<ai-title :title="params.id ? '编辑本村简介' : '添加本村简介'" isShowBack isShowBottomBorder @onBackClick="cancel(false)">
|
||||
<ai-title :title="pageTitle" isShowBack isShowBottomBorder @onBackClick="cancel(false)">
|
||||
</ai-title>
|
||||
</template>
|
||||
<template slot="content">
|
||||
@@ -19,12 +19,12 @@
|
||||
</el-form-item>
|
||||
<el-form-item label="缩略图" prop="thumbUrl">
|
||||
<ai-uploader
|
||||
:instance="instance"
|
||||
isShowTip
|
||||
v-model="form.thumbUrl"
|
||||
:limit="1"
|
||||
:cropOps="cropOps"
|
||||
is-crop>
|
||||
:instance="instance"
|
||||
isShowTip
|
||||
v-model="form.thumbUrl"
|
||||
:limit="1"
|
||||
:cropOps="cropOps"
|
||||
is-crop>
|
||||
<template slot="tips">
|
||||
<p>最多上传1张图片,单个文件最大10MB,支持jpg、jpeg、png格式</p>
|
||||
<p>图片比例:1.6:1</p>
|
||||
@@ -43,89 +43,91 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
export default {
|
||||
name: 'Add',
|
||||
import {mapState} from 'vuex'
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
params: Object
|
||||
},
|
||||
export default {
|
||||
name: 'Add',
|
||||
|
||||
data () {
|
||||
return {
|
||||
info: {},
|
||||
form: {
|
||||
title: '',
|
||||
content: '',
|
||||
areaId: '',
|
||||
createUnitName: '',
|
||||
createUserName: '',
|
||||
status: '',
|
||||
thumbUrl: []
|
||||
},
|
||||
cropOps: {
|
||||
width: "336px",
|
||||
height: "210px"
|
||||
},
|
||||
id: ''
|
||||
}
|
||||
},
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
params: Object,
|
||||
menuName: String
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['user'])
|
||||
},
|
||||
|
||||
created () {
|
||||
this.form.areaId = this.user.info.areaId
|
||||
this.disabledLevel = this.user.info.areaList.length
|
||||
if (this.params && this.params.id) {
|
||||
this.id = this.params.id
|
||||
this.getInfo(this.params.id)
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
getInfo (id) {
|
||||
this.instance.post(`/app/appcountrysidetourism/queryDetailById?id=${id}`).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.form = res.data
|
||||
this.form.thumbUrl = res.data.thumbUrl ? JSON.parse(res.data.thumbUrl) : []
|
||||
}
|
||||
})
|
||||
data() {
|
||||
return {
|
||||
info: {},
|
||||
form: {
|
||||
title: '',
|
||||
content: '',
|
||||
areaId: '',
|
||||
createUnitName: '',
|
||||
createUserName: '',
|
||||
status: '',
|
||||
thumbUrl: []
|
||||
},
|
||||
|
||||
confirm () {
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (valid) {
|
||||
this.instance.post(`/app/appcountrysidetourism/addOrUpdate`, {
|
||||
...this.form,
|
||||
type: 0,
|
||||
createUserName: this.user.info.name,
|
||||
thumbUrl: this.form.thumbUrl.length ? JSON.stringify([{
|
||||
url: this.form.thumbUrl[0].url
|
||||
}]) : ''
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('提交成功')
|
||||
setTimeout(() => {
|
||||
this.cancel(true)
|
||||
}, 600)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
cropOps: {
|
||||
width: "336px",
|
||||
height: "210px"
|
||||
},
|
||||
id: ''
|
||||
}
|
||||
},
|
||||
|
||||
cancel (isRefresh) {
|
||||
this.$emit('change', {
|
||||
type: 'list',
|
||||
isRefresh: !!isRefresh
|
||||
})
|
||||
}
|
||||
computed: {
|
||||
...mapState(['user']),
|
||||
pageTitle: v => `${!!v.params.id ? '编辑' : '添加'}${v.menuName}`
|
||||
},
|
||||
created() {
|
||||
this.form.areaId = this.user.info.areaId
|
||||
this.disabledLevel = this.user.info.areaList.length
|
||||
if (this.params && this.params.id) {
|
||||
this.id = this.params.id
|
||||
this.getInfo(this.params.id)
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
getInfo(id) {
|
||||
this.instance.post(`/app/appcountrysidetourism/queryDetailById?id=${id}`).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.form = res.data
|
||||
this.form.thumbUrl = res.data.thumbUrl ? JSON.parse(res.data.thumbUrl) : []
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
confirm() {
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (valid) {
|
||||
this.instance.post(`/app/appcountrysidetourism/addOrUpdate`, {
|
||||
...this.form,
|
||||
type: 0,
|
||||
createUserName: this.user.info.name,
|
||||
thumbUrl: this.form.thumbUrl.length ? JSON.stringify([{
|
||||
url: this.form.thumbUrl[0].url
|
||||
}]) : ''
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('提交成功')
|
||||
setTimeout(() => {
|
||||
this.cancel(true)
|
||||
}, 600)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
cancel(isRefresh) {
|
||||
this.$emit('change', {
|
||||
type: 'list',
|
||||
isRefresh: !!isRefresh
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<ai-list class="notice">
|
||||
<template slot="title">
|
||||
<ai-title title="本村简介" isShowBottomBorder isShowArea v-model="search.areaId" :instance="instance" @change="search.current = 1, getList()"></ai-title>
|
||||
<ai-title :title="menuName" isShowBottomBorder isShowArea v-model="search.areaId" :instance="instance" @change="search.current = 1, getList()"></ai-title>
|
||||
</template>
|
||||
<template slot="content">
|
||||
<ai-search-bar class="search-bar">
|
||||
@@ -57,9 +57,9 @@
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object
|
||||
dict: Object,
|
||||
menuName:String
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
search: {
|
||||
|
||||
@@ -1,73 +1,74 @@
|
||||
<template>
|
||||
<div class="doc-circulation ailist-wrapper">
|
||||
<keep-alive :include="['List']">
|
||||
<component ref="component" :is="component" @change="onChange" :params="params" :instance="instance" :dict="dict"></component>
|
||||
<component ref="component" :is="component" @change="onChange" :params="params" v-bind="$props"/>
|
||||
</keep-alive>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import List from './components/List'
|
||||
import Add from './components/Add'
|
||||
import Detail from './components/Detail'
|
||||
import List from './components/List'
|
||||
import Add from './components/Add'
|
||||
import Detail from './components/Detail'
|
||||
|
||||
export default {
|
||||
name: 'AppVillageRegulations',
|
||||
label: '村规民约',
|
||||
export default {
|
||||
name: 'AppVillageRegulations',
|
||||
label: '村规民约',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object
|
||||
},
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
menuName: {default: "村规民约"}
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
component: 'List',
|
||||
params: {},
|
||||
include: []
|
||||
data() {
|
||||
return {
|
||||
component: 'List',
|
||||
params: {},
|
||||
include: []
|
||||
}
|
||||
},
|
||||
|
||||
components: {
|
||||
Add,
|
||||
List,
|
||||
Detail
|
||||
},
|
||||
|
||||
mounted() {
|
||||
},
|
||||
|
||||
methods: {
|
||||
onChange(data) {
|
||||
if (data.type === 'Add') {
|
||||
this.component = 'Add'
|
||||
this.params = data.params
|
||||
}
|
||||
},
|
||||
|
||||
components: {
|
||||
Add,
|
||||
List,
|
||||
Detail
|
||||
},
|
||||
if (data.type === 'Detail') {
|
||||
this.component = 'Detail'
|
||||
this.params = data.params
|
||||
}
|
||||
|
||||
mounted () {
|
||||
},
|
||||
if (data.type === 'list') {
|
||||
this.component = 'List'
|
||||
this.params = data.params
|
||||
|
||||
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()
|
||||
}
|
||||
})
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
if (data.isRefresh) {
|
||||
this.$refs.component.getList()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.doc-circulation {
|
||||
height: 100%;
|
||||
background: #F3F6F9;
|
||||
overflow: auto;
|
||||
}
|
||||
.doc-circulation {
|
||||
height: 100%;
|
||||
background: #F3F6F9;
|
||||
overflow: auto;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<ai-detail>
|
||||
<template slot="title">
|
||||
<ai-title :title="params.id ? '编辑村规民约' : '添加村规民约'" isShowBack isShowBottomBorder @onBackClick="cancel(false)">
|
||||
<ai-title :title="pageTitle" isShowBack isShowBottomBorder @onBackClick="cancel(false)">
|
||||
</ai-title>
|
||||
</template>
|
||||
<template slot="content">
|
||||
@@ -50,7 +50,8 @@
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
params: Object
|
||||
params: Object,
|
||||
menuName: String
|
||||
},
|
||||
|
||||
data () {
|
||||
@@ -74,7 +75,8 @@
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['user'])
|
||||
...mapState(['user']),
|
||||
pageTitle: v => `${!!v.params.id ? '编辑' : '添加'}${v.menuName}`
|
||||
},
|
||||
|
||||
created () {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<ai-list class="notice">
|
||||
<template slot="title">
|
||||
<ai-title title="村规民约" isShowBottomBorder isShowArea v-model="search.areaId" :instance="instance" @change="search.current = 1, getList()"></ai-title>
|
||||
<ai-title :title="menuName" isShowBottomBorder isShowArea v-model="search.areaId" :instance="instance" @change="search.current = 1, getList()"></ai-title>
|
||||
</template>
|
||||
<template slot="content">
|
||||
<ai-search-bar class="search-bar">
|
||||
@@ -10,25 +10,25 @@
|
||||
</template>
|
||||
<template #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">
|
||||
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
|
||||
:tableData="tableData"
|
||||
:col-configs="colConfigs"
|
||||
:total="total"
|
||||
style="margin-top: 6px;"
|
||||
:current.sync="search.current"
|
||||
:size.sync="search.size"
|
||||
@getList="getList">
|
||||
: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="tags" label="标签">
|
||||
<template slot-scope="{ row }">
|
||||
<div class="table-tags">
|
||||
@@ -51,101 +51,103 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
export default {
|
||||
name: 'List',
|
||||
import {mapState} from 'vuex'
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object
|
||||
export default {
|
||||
name: 'List',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
menuName: String
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
search: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
title: '',
|
||||
areaId: ''
|
||||
},
|
||||
currIndex: -1,
|
||||
areaList: [],
|
||||
total: 10,
|
||||
colConfigs: [
|
||||
{prop: 'title', label: '标题', align: 'left', width: '200px'},
|
||||
{prop: 'areaName', label: '地区', align: 'center'},
|
||||
{prop: 'status', label: '发布状态', align: 'center', formart: v => v === '1' ? '已发布' : '未发布'},
|
||||
{prop: 'createUserName', label: '发布人', align: 'center'},
|
||||
{prop: 'createDate', label: '发布时间', align: 'center'},
|
||||
{slot: 'options', label: '操作', align: 'center'}
|
||||
],
|
||||
areaName: '',
|
||||
unitName: '',
|
||||
tableData: []
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['user'])
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.search.areaId = this.user.info.areaId
|
||||
this.getList()
|
||||
},
|
||||
|
||||
methods: {
|
||||
getList() {
|
||||
this.instance.post(`/app/appcountrysidetourism/list`, null, {
|
||||
params: {
|
||||
type: 4,
|
||||
...this.search
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.tableData = res.data.records
|
||||
this.total = res.data.total
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
search: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
title: '',
|
||||
areaId: ''
|
||||
},
|
||||
currIndex: -1,
|
||||
areaList: [],
|
||||
total: 10,
|
||||
colConfigs: [
|
||||
{ prop: 'title', label: '标题', align: 'left', width: '200px' },
|
||||
{ prop: 'areaName', label: '地区', align: 'center' },
|
||||
{ prop: 'status', label: '发布状态', align: 'center', formart: v => v === '1' ? '已发布' : '未发布' },
|
||||
{ prop: 'createUserName', label: '发布人', align: 'center' },
|
||||
{ prop: 'createDate', label: '发布时间', align: 'center' },
|
||||
{ slot: 'options', label: '操作', align: 'center' }
|
||||
],
|
||||
areaName: '',
|
||||
unitName: '',
|
||||
tableData: []
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['user'])
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.search.areaId = this.user.info.areaId
|
||||
this.getList()
|
||||
},
|
||||
|
||||
methods: {
|
||||
getList() {
|
||||
this.instance.post(`/app/appcountrysidetourism/list`, null, {
|
||||
params: {
|
||||
type: 4,
|
||||
...this.search
|
||||
changeStatus(item) {
|
||||
let title = item.status == '1' ? '是否要取消发布?' : '是否要发布?';
|
||||
this.$confirm(title, {type: 'warning'}).then(() => {
|
||||
item.status = item.status == '1' ? '0' : '1'
|
||||
this.instance.post('/app/appcountrysidetourism/addOrUpdate', item).then(res => {
|
||||
if (res && res.code == 0) {
|
||||
title == '是否要发布?' ? this.$message.success('发布成功') : this.$message.success('取消发布成功')
|
||||
this.getList()
|
||||
}
|
||||
}).then(res => {
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
remove(id) {
|
||||
this.$confirm('确定删除该数据?').then(() => {
|
||||
this.instance.post(`/app/appcountrysidetourism/delete?ids=${id}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.tableData = res.data.records
|
||||
this.total = res.data.total
|
||||
this.$message.success('删除成功!')
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
},
|
||||
})
|
||||
},
|
||||
|
||||
changeStatus (item) {
|
||||
let title = item.status == '1' ? '是否要取消发布?' : '是否要发布?';
|
||||
this.$confirm(title, {type: 'warning'}).then(() => {
|
||||
item.status = item.status == '1' ? '0' : '1'
|
||||
this.instance.post('/app/appcountrysidetourism/addOrUpdate', item).then(res => {
|
||||
if (res && res.code == 0) {
|
||||
title == '是否要发布?' ? this.$message.success('发布成功') : this.$message.success('取消发布成功')
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
remove(id) {
|
||||
this.$confirm('确定删除该数据?').then(() => {
|
||||
this.instance.post(`/app/appcountrysidetourism/delete?ids=${id}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('删除成功!')
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
toAdd(id) {
|
||||
this.$emit('change', {
|
||||
type: 'Add',
|
||||
params: {
|
||||
id: id || ''
|
||||
}
|
||||
})
|
||||
}
|
||||
toAdd(id) {
|
||||
this.$emit('change', {
|
||||
type: 'Add',
|
||||
params: {
|
||||
id: id || ''
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.notice {
|
||||
}
|
||||
.notice {
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -37,13 +37,16 @@
|
||||
</el-button>
|
||||
</template>
|
||||
<template #right>
|
||||
<ai-download url="/app/apppreventionreturntopoverty/exportAcquisitionTable" :params="{...search,ids}"
|
||||
:instance="instance" fileName="导出名单" suffixName="zip">
|
||||
<el-button icon="iconfont iconExported">导出名单</el-button>
|
||||
</ai-download>
|
||||
<ai-import :instance="instance" name="监测对象" title="导入监测对象"
|
||||
suffixName="xlsx"
|
||||
url="/app/apppreventionreturntopoverty/downloadTemplate"
|
||||
importUrl="/app/apppreventionreturntopoverty/import"
|
||||
@onSuccess="page.current=1,getTableData()"/>
|
||||
<ai-download url="/app/apppreventionreturntopoverty/export" :params="{...search,ids}"
|
||||
:instance="instance" fileName="监测对象导出文件"/>
|
||||
<ai-download url="/app/apppreventionreturntopoverty/export" :params="{...search,ids}" :instance="instance" fileName="监测对象导出文件"/>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table :tableData="tableData" :total="page.total" :current.sync="page.current" :size.sync="page.size"
|
||||
@@ -105,7 +108,7 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
search: {status: '',houseType: '', objectType: '', riskType: '', birthStart: '', birthEnd:'',sex: '' },
|
||||
search: {status: '', houseType: '', objectType: '', riskType: '', birthStart: '', birthEnd: '', sex: '', isHousehold: 1},
|
||||
page: {current: 1, size: 10, total: 0},
|
||||
tableData: [],
|
||||
ids: [],
|
||||
|
||||
79
packages/wxwork/Announce/AppAnnounce/AppAnnounce.vue
Normal file
79
packages/wxwork/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>
|
||||
917
packages/wxwork/Announce/AppAnnounce/components/Add.vue
Normal file
917
packages/wxwork/Announce/AppAnnounce/components/Add.vue
Normal file
@@ -0,0 +1,917 @@
|
||||
<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.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-if="!form.wxGroups.length">请选择</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.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>
|
||||
<div class="tips">
|
||||
<em>从本地上传,图片最大支持10MB,支持JPG,PNG格式;视频最大支持10MB,支持MP4格式;文件最大支持20MB</em>
|
||||
</div>
|
||||
</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-wechat-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.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-wechat-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>
|
||||
</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 {mapActions, mapState} from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'Add',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
params: Object
|
||||
},
|
||||
|
||||
components: {
|
||||
Phone
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
info: {},
|
||||
department: [],
|
||||
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',
|
||||
examines: [],
|
||||
wxGroups: [],
|
||||
wxGroupsName: '',
|
||||
sendScope: '0',
|
||||
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
|
||||
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)
|
||||
} else {
|
||||
this.getWxGroups()
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
...mapActions(['initOpenData', 'transCanvas']),
|
||||
|
||||
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(',')
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
})
|
||||
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}`, null, {
|
||||
data: {
|
||||
filterCriteria: this.form.filterCriteria.join(',')
|
||||
},
|
||||
headers: {'Content-Type': 'application/json;charset=utf-8'},
|
||||
transformRequest: [function (data) {
|
||||
return data.filterCriteria
|
||||
}]
|
||||
}).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('定时发送时间不得早于当前时间')
|
||||
} else {
|
||||
this.confirm(1)
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
confirm(sendType) {
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (valid) {
|
||||
if (!this.form.wxGroups.length) {
|
||||
return this.$message.error('居民群数量不能为0')
|
||||
}
|
||||
|
||||
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,
|
||||
choiceTime: this.dateForm.choiceTime,
|
||||
filterCriteria: this.form.filterCriteria.join(','),
|
||||
examines: this.form.examines.length ? this.form.examines.map(v => {
|
||||
return {
|
||||
...v,
|
||||
examineUserId: v.id
|
||||
}
|
||||
}) : []
|
||||
}).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
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
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;
|
||||
flex-direction: column;
|
||||
padding: 14px 16px;
|
||||
background: #F9F9F9;
|
||||
border-radius: 0px 0px 4px 4px;
|
||||
border: 1px solid #D0D4DC;
|
||||
border-top: none;
|
||||
|
||||
.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
773
packages/wxwork/Announce/AppAnnounce/components/Detail.vue
Normal file
773
packages/wxwork/Announce/AppAnnounce/components/Detail.vue
Normal file
@@ -0,0 +1,773 @@
|
||||
<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.name }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</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="群发范围" 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">
|
||||
<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">无法执行</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">
|
||||
<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">无法送达</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="群发范围"
|
||||
@onConfirm="isShowGroups = false">
|
||||
<ai-table
|
||||
:tableData="info.wxGroups"
|
||||
:col-configs="colConfigs3"
|
||||
border
|
||||
tableSize="small"
|
||||
:isShowPagination="false"
|
||||
@getList="() => {}">
|
||||
</ai-table>
|
||||
</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: '群主', openType: 'userName' },
|
||||
{ prop: 'groupNames', label: '群名称' }
|
||||
],
|
||||
colConfigs1: [
|
||||
{ slot: 'user', label: '成员', openType: 'userName' },
|
||||
{ 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);
|
||||
}
|
||||
|
||||
::v-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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
::v-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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .right-tips {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
i {
|
||||
margin-right: 4px;
|
||||
color: #8899bb;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
span {
|
||||
color: #888888;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
295
packages/wxwork/Announce/AppAnnounce/components/List.vue
Normal file
295
packages/wxwork/Announce/AppAnnounce/components/List.vue
Normal file
@@ -0,0 +1,295 @@
|
||||
<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>
|
||||
<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-wechat-selecter :instance="instance" @change="onUserChange" :isMultiple="false" v-model="user">
|
||||
<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="user = [], search.createUserId = '', name = '', search.current = 1, getList()"></i>
|
||||
</div>
|
||||
</ai-wechat-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="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>
|
||||
export default {
|
||||
name: 'List',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
search: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
status: '',
|
||||
createUserId: '',
|
||||
taskTitle: '',
|
||||
startTime: '',
|
||||
endTime: ''
|
||||
},
|
||||
name: '',
|
||||
user: [],
|
||||
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: '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', formart: v => v ? v === '0.0' ? '0%' : `${v}%` : '-' }
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
created () {
|
||||
this.dict.load('mstStatus', 'mstSendType').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,
|
||||
}
|
||||
}).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()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
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
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
toDetail (id) {
|
||||
this.$emit('change', {
|
||||
type: 'Detail',
|
||||
params: {
|
||||
id
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.AppAnnounce {
|
||||
height: 100%;
|
||||
.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: #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;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
344
packages/wxwork/Announce/AppAnnounce/components/Phone.vue
Normal file
344
packages/wxwork/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"></video>
|
||||
</div>
|
||||
<div class="msg-wrapper msg-file" v-if="item.msgType === '3'">
|
||||
<div class="msg-left">
|
||||
<h2>{{ item.name }}</h2>
|
||||
<p>{{ item.fileSizeStr }}</p>
|
||||
</div>
|
||||
<img :src="mapIcon(item.name)" />
|
||||
</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" />
|
||||
<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,747 @@
|
||||
<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>
|
||||
<ai-open-data type="userName" :openid="item.createUserId" class="name"></ai-open-data>
|
||||
</div>
|
||||
<div class="item-info item-dept">
|
||||
<span class="label">创建部门:</span>
|
||||
<ai-open-data type="departmentName" :openid="item.createUserDept" class="name"></ai-open-data>
|
||||
</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" v-model="deptList" @change="getEffect" dialogTitle="选择部门">
|
||||
<div class="time-select">
|
||||
<span class="dept-name" style="color:#999;" v-if="deptList && !deptList.length">宣发部门</span>
|
||||
<ai-open-data class="dept-name" type="departmentName" :openid="deptList[0]" v-else/>
|
||||
<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="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: '',
|
||||
}
|
||||
},
|
||||
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')
|
||||
},
|
||||
methods: {
|
||||
...mapActions(['initOpenData', 'transCanvas']),
|
||||
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 = this.deptList[0] || ''
|
||||
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'])
|
||||
}
|
||||
})
|
||||
},
|
||||
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 items = [], xData = [], yData = []
|
||||
res.data.map((item) => {
|
||||
this.departBarData.push(item)
|
||||
var i = {type: 'departmentName', id: item.deptId, corpid: this.user.info.corpId}
|
||||
items.push(i)
|
||||
yData.push(item.taskCount)
|
||||
})
|
||||
|
||||
this.initOpenData({canvas:true})
|
||||
this.transCanvas(items).then((data) => {
|
||||
xData = data.items.map((i) => {
|
||||
return i.data
|
||||
})
|
||||
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)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.AppAnnounceStatistics {
|
||||
height: 100%;
|
||||
.flex-between{
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.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;
|
||||
}
|
||||
}
|
||||
.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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
::v-deep .el-calendar-table:not(.is-range) td.next,
|
||||
::v-deep .el-calendar-table:not(.is-range) td.prev {
|
||||
color: #ccc;
|
||||
}
|
||||
::v-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;
|
||||
}
|
||||
::v-deep .el-calendar__header{
|
||||
display: none;
|
||||
}
|
||||
::v-deep .el-calendar__body{
|
||||
padding: 0;
|
||||
}
|
||||
::v-deep .el-calendar-table thead th:nth-of-type(1){
|
||||
border-left: 1px solid #eee;
|
||||
}
|
||||
::v-deep .el-calendar-table thead th:nth-of-type(7){
|
||||
border-right: 1px solid #eee;
|
||||
}
|
||||
::v-deep .el-calendar-table tr td:first-child {
|
||||
border-left: 1px solid #eee;
|
||||
}
|
||||
::v-deep .el-calendar-table tr:first-child td {
|
||||
border-top: 1px solid #eee;
|
||||
}
|
||||
::v-deep .el-calendar-table td {
|
||||
border-bottom: 1px solid #eee;
|
||||
border-right: 1px solid #eee;
|
||||
}
|
||||
::v-deep .el-timeline-item__timestamp.is-top{
|
||||
margin-bottom: 0;
|
||||
padding-top: 0;
|
||||
}
|
||||
::v-deep .el-timeline-item__node{
|
||||
background-color: #26F;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
left: 1px;
|
||||
}
|
||||
::v-deep .el-card{
|
||||
border: none;
|
||||
}
|
||||
::v-deep .el-card__body{
|
||||
padding: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
::v-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;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .AiPicker{
|
||||
display: inline-block;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user