目录代码整合

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

View File

@@ -0,0 +1,186 @@
<template>
<ai-detail>
<template slot="title">
<ai-title :title="detail.id ? '编辑公告' : '创建公告'" isShowBack isShowBottomBorder
@onBackClick="$parent.goBack"></ai-title>
</template>
<template #content>
<ai-card title="基本信息">
<template #content>
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<el-form-item label="公告标题" prop="title">
<el-input v-model="form.title" size="small" placeholder="请输入" show-word-limit maxlength="30"></el-input>
</el-form-item>
<el-form-item label="公告内容" prop="content">
<ai-editor v-model="form.content" :instance="instance"/>
</el-form-item>
<el-form-item label="附件">
<ai-uploader :instance="instance" v-model="form.files" fileType="file" isShowTip></ai-uploader>
</el-form-item>
<el-form-item label="发送对象" prop="persons">
<el-row type="flex" align="middle">
<div class="text-area">
<span v-text="item.name"/>
<span v-if="persons.length">{{ persons.length }}</span>
</div>
<ai-wechat-selecter v-model="form.persons" :instance="instance" @change="onChange">
<el-button type="info">选择</el-button>
</ai-wechat-selecter>
</el-row>
</el-form-item>
<el-row type="flex">
<el-form-item label="发送时间" prop="type">
<el-radio-group v-model="form.type" @change="form.releaseTime = null">
<el-radio :label="0">立即发送</el-radio>
<el-radio :label="1">定时发送</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item prop="releaseTime" class="picker" v-if="form.type==1">
<el-date-picker
v-model="form.releaseTime"
style="margin-left: 10px;"
value-format="yyyy-MM-dd HH:mm:ss"
size="small"
type="datetime"
placeholder="请选择">
</el-date-picker>
</el-form-item>
</el-row>
</el-form>
</template>
</ai-card>
</template>
<template #footer>
<el-button @click="$parent.goBack">取消</el-button>
<el-button type="primary" @click="confim(0)">保存</el-button>
<el-button type="primary" @click="confim(1)">发布</el-button>
</template>
</ai-detail>
</template>
<script>
export default {
name: "add",
props: {
instance: Function,
dict: Object,
detail: Object,
},
data() {
return {
form: {
id: null,
title: "",
content: "",
files: [],
persons: [],
type: 0,
releaseTime: null,
},
persons: [],
}
},
computed: {
rules() {
return {
title: [
{required: true, message: '请输入公告标题'},
],
content: [
{required: true, message: '请输入公告内容'},
],
persons: [
{required: true, message: '请选择发送对象'},
],
type: [
{required: true},
],
releaseTime: [
{required: true, message: '请选择发送时间'},
],
};
}
},
methods: {
onChange(e) {
this.form.persons = e;
this.persons = e;
this.$refs["form"].validateField("persons");
},
confim(e) {
this.$refs["form"].validate(v => {
if (v) {
if (this.form.releaseTime && (new Date(this.form.releaseTime).getTime() <= Date.now())) {
return this.$message.error("发送时间要大于当前时间")
}
this.instance.post("/app/appannouncement/addOrUpdate", {
...this.form,
status: e
}).then(res => {
if (res.code == 0) {
this.$message.success(e == 0 ? "保存成功" : "发布成功");
this.$parent.goBack();
}
})
}
})
},
getDetail() {
this.instance.post("/app/appannouncement/detail", null, {
params: {
id: this.detail.id
}
}).then(res => {
if (res && res.data) {
Object.keys(this.form).map(e => this.form[e] = res.data[e]);
this.form.type = res.data.releaseTime ? 1 : 0;
}
})
},
},
mounted() {
if (this.detail?.id) {
this.getDetail();
}
}
}
</script>
<style lang="scss" scoped>
::v-deep .picker {
width: 300px;
.el-form-item__content {
margin-left: 0 !important;
}
}
.text-area {
width: 995px;
height: 32px;
background-color: #F5F5F5;
border: 1px solid #d0d4dc;
border-radius: 2px;
display: flex;
align-items: center;
box-sizing: border-box;
padding: 0 6px;
color: #666666;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
::v-deep .AiOpenData {
height: auto !important;
&:after {
content: "、";
}
&:nth-child(2):after {
content: "";
}
}
</style>

View File

@@ -0,0 +1,95 @@
<template>
<ai-detail>
<template slot="title">
<ai-title title="公告详情" isShowBack isShowBottomBorder @onBackClick="$parent.goBack"></ai-title>
</template>
<template #content>
<ai-card :title="detailObj.title" class="title">
<template #content>
<el-row type="flex" justify="space-between" class="info">
<span>时间{{ detailObj.releaseTime }}</span>
<span style="display:flex">发布单位
<span v-text="detailObj.unitName"/>
</span>
<span style="display:flex">发布人
<span v-text="detailObj.releaseUserName"/>
</span>
</el-row>
<div v-html="detailObj.content" style="margin: 20px 0;"></div>
</template>
</ai-card>
<ai-card title="附件" v-if="detailObj.files && detailObj.files.length">
<template #content>
<el-row type="flex" justify="space-between" class="file" v-for="(item,index) in detailObj.files" :key="index"
@click.native="open(item)">
<span>{{ item.fileName }}</span>
<span>{{ (item.size / 1024).toFixed(2) }}KB</span>
</el-row>
</template>
</ai-card>
</template>
</ai-detail>
</template>
<script>
export default {
name: "detail",
props: {
instance: Function,
dict: Object,
detail: Object
},
data() {
return {
detailObj: {},
}
},
methods: {
open(item) {
window.open(item.url);
}
},
mounted() {
this.instance.post("/app/appannouncement/detail", null, {
params: {
id: this.detail.id
}
}).then(res => {
if (res && res.data) {
this.detailObj = res.data;
}
})
}
}
</script>
<style lang="scss" scoped>
::v-deep .title {
.aibar-left {
width: 100%;
text-align: center;
}
}
.file {
height: 40px;
line-height: 40px;
padding: 0 8px;
font-size: 14px;
color: #333;
background: #fff;
border-radius: 4px;
border: 1px solid #d0d4dc;
margin-bottom: 16px;
cursor: pointer;
}
.info {
& > span {
font-size: 14px;
color: #333;
}
}
</style>

View File

@@ -0,0 +1,204 @@
<template>
<ai-detail>
<template slot="title">
<ai-title title="公告详情" isShowBack isShowBottomBorder @onBackClick="$parent.goBack"></ai-title>
</template>
<template #content>
<ai-sidebar v-model="index" :tabTitle="tabTitle" @change="onChange"></ai-sidebar>
<template v-if="index==0">
<ai-card :title="detailObj.title" class="title">
<template #content>
<el-row type="flex" justify="space-between" class="info">
<span>时间{{ detailObj.releaseTime }}</span>
<span style="display:flex">发布单位
<span v-text="detailObj.unitName"/>
</span>
<span style="display:flex">发布人
<span v-text="detailObj.releaseUserName"/>
</span>
</el-row>
<div v-html="detailObj.content" style="margin: 20px 0;"></div>
</template>
</ai-card>
<ai-card title="附件" v-if="detailObj.files && detailObj.files.length">
<template #right>
<span class="Edit" @click="downFileAll"><i class="iconfont iconDownload"></i>下载全部</span>
</template>
<template #content>
<ai-file-list :fileList="detailObj.files" :fileOps="{ name: 'fileName', size: 'size' }"></ai-file-list>
</template>
</ai-card>
</template>
<template v-else>
<ai-list>
<template #content>
<ai-search-bar>
<template #left>
<ai-select
v-model="search.readStatus"
@change="search.current=1,getList()"
placeholder="查阅状态"
:selectList="dict.getDict('announcementReadStatus')"
></ai-select>
</template>
<template #right>
<el-input v-model="search.readUserName" @keyup.enter.native="getList()" placeholder="姓名"
size="small" suffix-icon="iconfont iconSearch" clearable
@clear="search.current=1,getList()"></el-input>
</template>
</ai-search-bar>
<ai-table
:tableData="tableData"
:col-configs="colConfigs"
:total="total"
:current.sync="search.current"
:size.sync="search.size"
@getList="getList">
<el-table-column slot="readUserName" label="姓名" align="center">
<template slot-scope="{ row }">
<span v-text="row.readUserName"/>
</template>
</el-table-column>
<el-table-column slot="unitName" label="所属部门" align="center">
<template slot-scope="{ row }">
<span v-text="row.unitName"/>
</template>
</el-table-column>
</ai-table>
</template>
</ai-list>
</template>
</template>
</ai-detail>
</template>
<script>
export default {
name: "manageDetail",
props: {
instance: Function,
dict: Object,
detail: Object
},
data() {
return {
index: 0,
tableData: [],
total: 0,
detailObj: {},
search: {
current: 1,
size: 10
}
}
},
computed: {
tabTitle() {
return ["公告详情", "查询情况"];
},
colConfigs() {
return [
{slot: "readUserName"},
{prop: "readUserPhone", label: "手机号", align: "center"},
{slot: "unitName"},
{
prop: "readStatus", label: "查阅状态", align: "center",
render: (h, {row}) => [<span
style={{color: this.dict.getColor("announcementReadStatus", row.readStatus)}}>{this.dict.getLabel("announcementReadStatus", row.readStatus)}</span>]
},
];
}
},
methods: {
downFileAll() {
if (this.detailObj.files.length > 0) {
this.instance.post('/app/appannouncement/downLoadAllFileForDetail', null, {
responseType: 'blob',
params: {
id: this.detailObj.id
}
}).then((res) => {
const link = document.createElement('a')
let blob = new Blob([res], {type: 'application/octet-stream'})
link.style.display = 'none'
link.href = URL.createObjectURL(blob)
var num = ''
for (let i = 0; i < 10; i++) {
num += Math.ceil(Math.random() * 10)
}
link.setAttribute('download', '公告文件' + '.zip')
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
})
} else {
this.$message.error('暂无附件提供下载')
}
},
onChange(val) {
if (val == 0) {
this.getDetail();
} else {
this.getList();
}
},
getDetail() {
this.instance.post("/app/appannouncement/detail", null, {
params: {
id: this.detail.id
}
}).then(res => {
if (res && res.data) {
this.detailObj = res.data;
}
})
},
getList() {
this.instance.post("/app/appannouncementreader/list", null, {
params: {
announcementId: this.detail.id,
...this.search
}
}).then(res => {
if (res && res.data) {
this.tableData = res.data.records;
this.total = res.data.total;
}
})
},
},
created() {
this.dict.load("announcementReadStatus").then(this.getDetail);
}
}
</script>
<style lang="scss" scoped>
::v-deep .title {
.aibar-left {
width: 100%;
text-align: center;
}
}
.file {
height: 40px;
line-height: 40px;
padding: 0 8px;
font-size: 14px;
color: #333;
background: #fff;
border-radius: 4px;
border: 1px solid #d0d4dc;
margin-bottom: 16px;
cursor: pointer;
}
.info {
& > span {
font-size: 14px;
color: #333;
}
}
</style>

View File

@@ -0,0 +1,267 @@
<template>
<section style="height: 100%;">
<ai-list isTabs>
<template slot="content">
<ai-search-bar>
<template #left>
<ai-select v-model="search.status" placeholder="发布状态" :selectList="dict.getDict('announcementStatus')"
@change="search.current = 1, getList()"></ai-select>
<el-date-picker
type="daterange"
size="small"
v-model="date"
@change="search.current = 1,getList()"
range-separator=""
value-format="yyyy-MM-dd"
start-placeholder="开始日期"
end-placeholder="结束日期">
</el-date-picker>
</template>
<template slot="right">
<el-input
v-model="search.title"
size="small"
v-throttle="() => {search.current = 1, getList()}"
placeholder="标题"
clearable
@clear="search.current = 1, search.title = '', getList()"
suffix-icon="iconfont iconSearch">
</el-input>
</template>
</ai-search-bar>
<ai-search-bar>
<template #left>
<el-button icon="iconfont iconAdd" type="primary" @click="add">创建公告</el-button>
</template>
</ai-search-bar>
<ai-table
:tableData="tableData"
:col-configs="colConfigs"
:total="total"
:current.sync="search.current"
:size.sync="search.size"
@getList="getList">
<el-table-column slot="releaseUserName" label="发布人" align="center">
<template slot-scope="{ row }">
<span v-text="row.releaseUserName"/>
</template>
</el-table-column>
<el-table-column slot="unitName" label="发布部门" align="center">
<template slot-scope="{ row }">
<span v-text="row.unitName"/>
</template>
</el-table-column>
<el-table-column slot="options" width="250" label="操作" align="center">
<template slot-scope="{ row }">
<el-button type="text" @click="toDetail(row)">详情</el-button>
<el-button type="text" v-if="row.status==0" @click="publish(row,0)">发布</el-button>
<el-button type="text" v-if="row.status==1" @click="publish(row,1)">撤回</el-button>
<el-button type="text" @click="toEdit(row)" v-if="row.status==0 || row.status==3">编辑</el-button>
<el-button type="text" @click="handleDel(row)">删除</el-button>
</template>
</el-table-column>
</ai-table>
</template>
</ai-list>
<ai-dialog
title="查阅状态"
:visible.sync="visible"
@closed="row={},readList=[]"
:customFooter="true"
width="800px">
<template v-if="readObj.read && readObj.read.length">
<header>已读人员</header>
<div class="wrap">
<div class="item" v-for="(item,index) in readObj.read" :key="index">
<img :src="item.avatar" alt="">
<span v-text="item.name"/>
</div>
</div>
</template>
<template v-if="readObj.unRead && readObj.unRead.length">
<header>未读人员</header>
<div class="wrap">
<div class="item" v-for="(item,index) in readObj.unRead" :key="index">
<img :src="item.avatar" alt="">
<span v-text="item.name"/>
</div>
</div>
</template>
</ai-dialog>
</section>
</template>
<script>
export default {
name: "noticeManage",
props: {
instance: Function,
dict: Object
},
data() {
return {
search: {
title: "",
status: "",
size: 10,
current: 1,
},
date: [],
tableData: [],
total: 0,
visible: false,
row: {},
readObj: {},
}
},
computed: {
colConfigs() {
return [
{prop: 'title', label: '标题'},
{
prop: 'readNum', label: '查询状态', align: 'center',
render: (h, {row}) => [<span class='status'
onClick={this.showDialog.bind(this, row)}>{row.readNum}人已读</span>,
<span class='status' onClick={this.showDialog.bind(this, row)}>{row.unReadNum}人未读</span>]
},
{slot: 'releaseUserName'},
{slot: 'unitName'},
{prop: 'releaseTime', label: '发布时间', align: 'center'},
{
prop: 'status', label: '发布状态', align: 'center',
render: (h, {row}) => [<span
style={{color: this.dict.getColor("announcementStatus", row.status)}}>{this.dict.getLabel("announcementStatus", row.status)}</span>]
},
{slot: 'options'},
];
}
},
methods: {
showDialog(row) {
this.row = row;
this.getReadList();
},
toDetail(row) {
this.$emit('goPage', {
comp: 'manageDetail',
row
});
},
toEdit(row) {
this.$emit('goPage', {
comp: 'add',
row
});
},
publish(row, status) {
this.$confirm(`是否要${status == 0 ? '发布' : '撤回'}该公告?`).then(() => {
this.instance.post("/app/appannouncement/update-status", null, {
params: {
id: row.id
}
}).then(res => {
if (res.code == 0) {
this.$message.success(status == 0 ? '发布成功' : '撤回成功');
this.getList();
}
})
})
},
handleDel(row) {
this.$confirm("是否要删除该公布?").then(() => {
this.instance.post("/app/appannouncement/delete", null, {
params: {
ids: row.id
}
}).then(res => {
if (res.code == 0) {
this.$message.success("删除成功");
this.getList();
}
})
})
},
add() {
this.$emit('goPage', {
comp: 'add',
row: {},
});
},
getReadList() {
this.instance.post("/app/appannouncementreader/list-unread", null, {
params: {
id: this.row.id
}
}).then(res => {
if (res && res.data) {
this.readObj = res.data;
this.visible = true;
}
})
},
getList() {
this.instance.post("/app/appannouncement/list-mgr", null, {
params: {
...this.search,
startTime: this.date?.length ? this.date[0] : null,
endTime: this.date?.length ? this.date[1] : null,
}
}).then(res => {
if (res && res.data) {
this.tableData = res.data.records;
this.total = res.data.total;
}
})
}
},
created() {
this.dict.load("announcementStatus").then(this.getList)
}
}
</script>
<style lang="scss" scoped>
::v-deep .status {
color: rgba(41, 107, 251, 100);
cursor: pointer;
}
header {
font-size: 14px;
color: #333333;
margin-bottom: 10px;
}
::v-deep .wrap {
display: flex;
align-items: center;
flex-wrap: wrap;
.item {
width: 50px;
display: flex;
flex-direction: column;
justify-content: center;
margin-right: 22px;
margin-bottom: 22px;
img {
width: 100%;
height: 50px;
border-radius: 50%;
}
span {
font-size: 14px;
color: #333333;
text-align: center;
}
}
}
</style>

View File

@@ -0,0 +1,217 @@
<template>
<ai-list isTabs>
<template #content>
<ai-search-bar>
<template #left>
<ai-select
v-model="search.readStatus"
@change="getList()"
placeholder="查阅状态"
:selectList="dict.getDict('announcementReadStatus')"
></ai-select>
<el-date-picker
v-model="date"
@change="search.current = 1,getList()"
type="daterange"
size="small"
value-format="yyyy-MM-dd"
range-separator=""
start-placeholder="开始日期"
end-placeholder="结束日期">
</el-date-picker>
</template>
<template #right>
<el-input v-model="search.title" @keyup.enter.native="getList()" placeholder="标题"
size="small" suffix-icon="iconfont iconSearch" clearable
@clear="search.current=1,getList()"></el-input>
</template>
</ai-search-bar>
<div class="body">
<ul v-if="tableData.length">
<li v-for="(item,index) in tableData" :key="index" @click="goDetail(item)">
<label>
<!-- <em v-if="item.readStatus==0"></em>-->
<div class="status" v-if="item.readStatus==0">未读</div>
<div class="status read" v-else>已读</div>
{{ item.title }}</label>
<el-row type="flex" justify="space-between" class="row">
<span style="display:flex">
<b>发布人</b>
<span v-text="item.releaseUserName"/>
</span>
<span style="display:flex">
<b>发布部门</b>
<span v-text="item.unitName"/>
</span>
<span>
<b>发布日期</b>
{{ item.releaseTime }}</span>
</el-row>
</li>
</ul>
<div class="no-data" style="height:160px;" v-else></div>
</div>
<div class="pagination" v-if="tableData.length>0">
<el-pagination
@current-change="handleCurrentChange"
@size-change="handleSizeChange"
background
:current-page.sync="search.current"
:page-sizes="[5, 10, 50, 100,200]"
:page-size="search.size"
layout="slot,->,prev, pager, next,sizes,jumper"
:total="total">
<div class="page" style="text-align: left">
<em>{{ total }}</em>
条记录
</div>
</el-pagination>
</div>
</template>
</ai-list>
</template>
<script>
export default {
name: "recentNotice",
props: {
instance: Function,
dict: Object,
},
data() {
return {
search: {
readStatus: "",
title: "",
current: 1,
size: 10,
},
date: [],
tableData: [],
total: 0,
}
},
methods: {
pickerChange(e) {
console.log(e);
},
goDetail(item) {
this.$emit('goPage', {
row: item,
comp: 'detail'
});
},
getList() {
this.instance.post(`/app/appannouncement/list-latest`, null, {
params: {
...this.search,
startTime: this.date?.length ? this.date[0] : null,
endTime: this.date?.length ? this.date[1] : null,
}
}).then(res => {
if (res && res.data) {
this.tableData = res.data.records;
this.total = res.data.total;
}
});
},
handleCurrentChange(val) {
this.search.current = val;
this.getList();
},
handleSizeChange(val) {
this.search.size = val;
this.getList();
},
},
created() {
this.dict.load("announcementReadStatus").then(_ => this.getList())
}
}
</script>
<style lang="scss" scoped>
.body {
ul {
overflow: hidden;
padding: 0;
margin: 0;
li {
height: 86px;
background: #FFFFFF;
border-radius: 4px;
box-sizing: border-box;
padding: 16px 215px 16px 32px;
margin-top: 10px;
cursor: pointer;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
label {
display: flex;
align-items: center;
position: relative;
font-size: 16px;
color: #222222;
.status {
width: 40px;
height: 20px;
background: #FEF4E5;
color: #F79300;
border-radius: 4px;
font-size: 12px;
font-weight: bold;
display: flex;
align-items: center;
justify-content: center;
margin-right: 4px;
}
.read {
background: #EEEEEE;
color: #999999;
}
em {
width: 8px;
height: 8px;
background: #ff4422;
border-radius: 50%;
position: absolute;
left: -16px;
top: 4px;
}
}
}
::v-deep .row {
margin-top: 10px;
span {
font-size: 14px;
color: #222222;
b {
font-size: 14px;
color: #888888;
}
}
}
}
}
::v-deep .page {
font-size: 12px;
color: #555555;
em {
font-style: normal;
color: rgb(34, 102, 255);
}
}
</style>