0.4.1更新消息提醒
This commit is contained in:
parent
916efb8df5
commit
3da7554476
|
@ -13,3 +13,5 @@ VUE_CLI_BABEL_TRANSPILE_MODULES = true
|
|||
# 七牛云域名
|
||||
VUE_APP_QINIU_DOMAIN = 'https://api.ccttiot.com'
|
||||
|
||||
# WebSocket地址
|
||||
VUE_APP_WS_HOST = 'ws://localhost:4001'
|
||||
|
|
|
@ -8,4 +8,7 @@ ENV = 'production'
|
|||
VUE_APP_BASE_API = '/prod-api'
|
||||
|
||||
# 七牛云域名
|
||||
VUE_APP_QINIU_DOMAIN = 'https://api.ccttiot.com'
|
||||
VUE_APP_QINIU_DOMAIN = 'https://api.ccttiot.com'
|
||||
|
||||
# WebSocket地址
|
||||
VUE_APP_WS_HOST = 'wss://pm.chuangtewl.com'
|
39
src/api/app/message.js
Normal file
39
src/api/app/message.js
Normal file
|
@ -0,0 +1,39 @@
|
|||
|
||||
import request from '@/utils/request'
|
||||
|
||||
/**
|
||||
* 获取本人接收的消息列表
|
||||
* @param {Object} query 查询参数
|
||||
* @returns {Promise}
|
||||
*/
|
||||
export function appGetReceiveList(query) {
|
||||
return request({
|
||||
url: '/app/message/receiveList',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 标记消息已读
|
||||
* @param {number} id 消息ID
|
||||
* @returns {Promise}
|
||||
*/
|
||||
export function appReadMessage(id) {
|
||||
return request({
|
||||
url: '/app/message/read',
|
||||
method: 'post',
|
||||
params: { id }
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询本人未读消息数量
|
||||
* @returns {Promise}
|
||||
*/
|
||||
export function appGetUnreadCount() {
|
||||
return request({
|
||||
url: '/app/message/unreadCount',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
44
src/api/bst/message.js
Normal file
44
src/api/bst/message.js
Normal file
|
@ -0,0 +1,44 @@
|
|||
import request from '@/utils/request'
|
||||
|
||||
// 查询消息列表
|
||||
export function listMessage(query) {
|
||||
return request({
|
||||
url: '/bst/message/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 查询消息详细
|
||||
export function getMessage(id) {
|
||||
return request({
|
||||
url: '/bst/message/' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 新增消息
|
||||
export function addMessage(data) {
|
||||
return request({
|
||||
url: '/bst/message',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 修改消息
|
||||
export function updateMessage(data) {
|
||||
return request({
|
||||
url: '/bst/message',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除消息
|
||||
export function delMessage(id) {
|
||||
return request({
|
||||
url: '/bst/message/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
|
@ -1,10 +1,5 @@
|
|||
<template>
|
||||
<div
|
||||
class="avatar-wrapper"
|
||||
:style="{
|
||||
backgroundColor: backgroundColor
|
||||
}"
|
||||
>
|
||||
<div class="avatar-wrapper" :style="{backgroundColor: backgroundColor}">
|
||||
<el-avatar :size="size" :src="src" v-if="src"/>
|
||||
<el-avatar :size="size" v-else :style="{fontSize: fontSize}">
|
||||
{{ displayChar }}
|
||||
|
@ -65,7 +60,7 @@ export default {
|
|||
const index = Math.abs(sum) % colors.length
|
||||
return colors[index]
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -11,12 +11,12 @@
|
|||
marginLeft: index !== 0 ? `-${size * 0.3}px` : '0',
|
||||
zIndex: list.length - index
|
||||
}"
|
||||
@click="handleClick(item)"
|
||||
>
|
||||
<avatar
|
||||
:size="size"
|
||||
:src="item[avatarProp]"
|
||||
:name="item[showProp]"
|
||||
:id="item[idProp]"
|
||||
:char-index="charIndex"
|
||||
/>
|
||||
</div>
|
||||
|
@ -31,25 +31,17 @@
|
|||
:width="360"
|
||||
>
|
||||
<div class="total-list">
|
||||
<div v-for="item in list" :key="item[idProp]" class="total-item">
|
||||
<div v-for="item in list" :key="item[idProp]" @click="handleClick(item)" class="total-item">
|
||||
<avatar
|
||||
:size="size"
|
||||
:src="item[avatarProp]"
|
||||
:name="item[showProp]"
|
||||
:id="item[idProp]"
|
||||
:char-index="charIndex"
|
||||
/>
|
||||
<span class="total-item-name">{{ item[showProp] }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
slot="reference"
|
||||
class="avatar-item total-text"
|
||||
:style="{
|
||||
marginLeft: `0px`,
|
||||
zIndex: 0
|
||||
}"
|
||||
>
|
||||
<div slot="reference" class="avatar-item total-text" style="margin-left: 0px; z-index: 0;">
|
||||
<span class="total-count">等{{ list.length }}{{ unit }}</span>
|
||||
</div>
|
||||
</el-popover>
|
||||
|
@ -96,6 +88,11 @@ export default {
|
|||
unit: {
|
||||
type: String,
|
||||
default: '项'
|
||||
},
|
||||
// 类型,可选:user用户
|
||||
bstType: {
|
||||
type: String,
|
||||
default: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
@ -110,6 +107,13 @@ export default {
|
|||
}
|
||||
},
|
||||
methods: {
|
||||
handleClick(item) {
|
||||
if (this.bstType === 'user') {
|
||||
this.$router.push({
|
||||
path: `/view/user/${item[this.idProp]}`
|
||||
})
|
||||
}
|
||||
},
|
||||
// 获取首字
|
||||
getFirstChar(name) {
|
||||
if (!name) {
|
||||
|
@ -192,6 +196,7 @@ export default {
|
|||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
cursor: pointer;
|
||||
|
||||
.total-item-name {
|
||||
font-size: 16px;
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
filterable
|
||||
:disabled="disabled"
|
||||
:multiple="multiple"
|
||||
v-on="$listeners"
|
||||
@change="handleChange"
|
||||
style="width: 100%;"
|
||||
>
|
||||
<el-option
|
||||
|
@ -65,6 +65,15 @@ export default {
|
|||
this.list = response.data;
|
||||
});
|
||||
},
|
||||
handleChange(val) {
|
||||
if (this.multiple) {
|
||||
let projectList = this.list.filter(item => val.includes(item.id));
|
||||
this.$emit("change", projectList);
|
||||
} else {
|
||||
let project = this.list.find(item => val === item.id);
|
||||
this.$emit("change", project);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
|
@ -6,8 +6,9 @@
|
|||
filterable
|
||||
:disabled="disabled"
|
||||
:multiple="multiple"
|
||||
v-on="$listeners"
|
||||
@change="handleChange"
|
||||
style="width: 100%;"
|
||||
@focus="handleFocus"
|
||||
>
|
||||
<div v-if="multiple" class="select-footer">
|
||||
<el-button size="mini" type="text" @click.stop="handleSelectAll">
|
||||
|
@ -15,7 +16,7 @@
|
|||
</el-button>
|
||||
</div>
|
||||
<el-option
|
||||
v-for="item in list"
|
||||
v-for="item in filterList"
|
||||
:key="item.userId"
|
||||
:label="item.nickName"
|
||||
:value="item.userId"
|
||||
|
@ -44,11 +45,19 @@ export default {
|
|||
multiple: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 过滤方法
|
||||
filterMethod: {
|
||||
type: Function,
|
||||
default: (data) => {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
list: [],
|
||||
filterList: []
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
@ -62,16 +71,20 @@ export default {
|
|||
},
|
||||
// 是否全选
|
||||
isAllSelected() {
|
||||
return this.multiple && this.list.length > 0 && Array.isArray(this.value) && this.value.length === this.list.length;
|
||||
return this.multiple && this.filterList.length > 0 && Array.isArray(this.value) && this.value.length === this.filterList.length;
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getList();
|
||||
},
|
||||
methods: {
|
||||
handleFocus() {
|
||||
this.filterList = this.filterMethod(this.list);
|
||||
},
|
||||
getList() {
|
||||
listAllUser().then(response => {
|
||||
this.list = response.data;
|
||||
this.filterList = response.data;
|
||||
});
|
||||
},
|
||||
// 全选
|
||||
|
@ -79,9 +92,18 @@ export default {
|
|||
if (this.isAllSelected) {
|
||||
this.$emit("input", []);
|
||||
} else {
|
||||
const allUserIds = this.list.map(item => item.userId);
|
||||
const allUserIds = this.filterList.map(item => item.userId);
|
||||
this.$emit("input", allUserIds);
|
||||
}
|
||||
},
|
||||
handleChange(val) {
|
||||
if (this.multiple) {
|
||||
let userList = this.list.filter(item => val.includes(item.userId));
|
||||
this.$emit("change", userList);
|
||||
} else {
|
||||
let user = this.list.find(item => val === item.userId);
|
||||
this.$emit("change", user);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div>
|
||||
<div class="screenfull-container">
|
||||
<svg-icon :icon-class="isFullscreen?'exit-fullscreen':'fullscreen'" @click="click" />
|
||||
</div>
|
||||
</template>
|
||||
|
@ -45,7 +45,13 @@ export default {
|
|||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
<style scoped lang="scss">
|
||||
.screenfull-container {
|
||||
cursor: pointer;
|
||||
&:hover svg {
|
||||
color: #409EFF;
|
||||
}
|
||||
}
|
||||
.screenfull-svg {
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
|
|
|
@ -8,7 +8,8 @@
|
|||
<div class="right-menu">
|
||||
<template v-if="device!=='mobile'">
|
||||
<search id="header-search" class="right-menu-item" />
|
||||
<screenfull id="screenfull" class="right-menu-item hover-effect" />
|
||||
<screenfull id="screenfull" class="right-menu-item" />
|
||||
<notice-tip id="notice-tip" class="right-menu-item" />
|
||||
|
||||
<!-- <el-tooltip content="布局大小" effect="dark" placement="bottom">-->
|
||||
<!-- <size-select id="size-select" class="right-menu-item hover-effect" />-->
|
||||
|
@ -49,6 +50,7 @@ import SizeSelect from '@/components/SizeSelect'
|
|||
import Search from '@/components/HeaderSearch'
|
||||
import RuoYiGit from '@/components/RuoYi/Git'
|
||||
import RuoYiDoc from '@/components/RuoYi/Doc'
|
||||
import NoticeTip from '@/views/bst/notice/noticeTip/index.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
@ -59,7 +61,8 @@ export default {
|
|||
SizeSelect,
|
||||
Search,
|
||||
RuoYiGit,
|
||||
RuoYiDoc
|
||||
RuoYiDoc,
|
||||
NoticeTip
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
|
|
|
@ -96,3 +96,17 @@ export const NoticeLevel = {
|
|||
MEDIUM: "2", // 中
|
||||
LOW: "3" // 低
|
||||
}
|
||||
|
||||
// 公告类型
|
||||
export const NoticeType = {
|
||||
NOTICE: "1", // 公告
|
||||
MESSAGE: "2" // 消息
|
||||
}
|
||||
|
||||
// 消息类型
|
||||
export const MessageBstType = {
|
||||
TASK: "task", // 任务
|
||||
TASK_SUBMIT: "task_submit", // 任务提交
|
||||
CUSTOMER: "customer", // 客户
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,9 @@
|
|||
<el-form-item label="分类" prop="classifyId">
|
||||
<attach-classify-select v-model="form.classifyId" check-strictly/>
|
||||
</el-form-item>
|
||||
<el-form-item label="所属部门" prop="deptId">
|
||||
<dept-select v-model="form.deptId" check-strictly/>
|
||||
</el-form-item>
|
||||
<el-form-item label="资源名称" prop="name" v-if="form.id != null">
|
||||
<el-input v-model="form.name" placeholder="请输入资源名称" />
|
||||
</el-form-item>
|
||||
|
@ -29,11 +32,14 @@
|
|||
import { addAttach, updateAttach, getAttach } from "@/api/bst/attach"
|
||||
import AttachClassifySelect from '@/components/Business/AttachClassify/AttachClassifySelect.vue'
|
||||
import { FileType } from '@/utils/constants'
|
||||
import { mapGetters } from 'vuex'
|
||||
import DeptSelect from '@/components/Business/Dept/DeptSelect.vue'
|
||||
|
||||
export default {
|
||||
name: "AttachClassifyEditDialog",
|
||||
components: {
|
||||
AttachClassifySelect
|
||||
AttachClassifySelect,
|
||||
DeptSelect
|
||||
},
|
||||
props: {
|
||||
show: {
|
||||
|
@ -71,6 +77,7 @@ export default {
|
|||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['deptId']),
|
||||
title() {
|
||||
return this.id ? '修改资源' : '新增资源'
|
||||
},
|
||||
|
@ -99,6 +106,7 @@ export default {
|
|||
id: null,
|
||||
name: null,
|
||||
classifyId: null,
|
||||
deptId: this.deptId,
|
||||
urls: null,
|
||||
...this.initData
|
||||
}
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="所属部门" prop="deptId">
|
||||
<dept-select v-model="queryParams.deptId" @change="handleQuery" check-strictly/>
|
||||
</el-form-item>
|
||||
<el-form-item label="创建人" prop="createId">
|
||||
<user-select v-model="queryParams.createId" @change="handleQuery"/>
|
||||
</el-form-item>
|
||||
|
@ -108,6 +111,8 @@ import AttachClassifyTree from '../attachClassify/components/AttachClassifyTree.
|
|||
import AttachCard from '@/components/AttachCard/index.vue';
|
||||
import UserSelect from '@/components/Business/User/UserSelect.vue';
|
||||
import AttachEditDialog from '@/views/bst/attach/components/AttachEditDialog.vue';
|
||||
import DeptSelect from '@/components/Business/Dept/DeptSelect.vue';
|
||||
|
||||
|
||||
// 默认排序字段
|
||||
const defaultSort = {
|
||||
|
@ -118,7 +123,7 @@ const defaultSort = {
|
|||
export default {
|
||||
name: "Attach",
|
||||
mixins: [$showColumns],
|
||||
components: {FormCol, AttachClassifyTree, AttachCard, UserSelect, AttachEditDialog},
|
||||
components: {FormCol, AttachClassifyTree, AttachCard, UserSelect, AttachEditDialog, DeptSelect},
|
||||
data() {
|
||||
return {
|
||||
row: {},
|
||||
|
@ -129,6 +134,7 @@ export default {
|
|||
{key: 'classifyName', visible: true, label: '分类', minWidth: null, sortable: true, overflow: false, align: 'center', width: null},
|
||||
{key: 'name', visible: false, label: '名称', minWidth: null, sortable: true, overflow: false, align: 'center', width: null},
|
||||
{key: 'url', visible: false, label: 'URL', minWidth: null, sortable: true, overflow: false, align: 'center', width: null},
|
||||
{key: 'deptName', visible: true, label: '所属部门', minWidth: null, sortable: true, overflow: false, align: 'center', width: null},
|
||||
{key: 'createName', visible: true, label: '创建人', minWidth: null, sortable: true, overflow: false, align: 'center', width: null},
|
||||
{key: 'createTime', visible: true, label: '创建时间', minWidth: null, sortable: true, overflow: false, align: 'center', width: null},
|
||||
],
|
||||
|
@ -161,6 +167,7 @@ export default {
|
|||
isAsc: defaultSort.order,
|
||||
id: null,
|
||||
classifyId: null,
|
||||
deptId: null,
|
||||
name: null,
|
||||
url: null,
|
||||
createId: null,
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<el-button type="primary" @click="submitForm" :loading="submitLoading" plain icon="el-icon-check">确 定</el-button>
|
||||
</edit-header>
|
||||
<div class="app-container">
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="80px" v-loading="loading">
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="80px" size="small" v-loading="loading">
|
||||
<el-row>
|
||||
<form-col :span="24" label="客户名称" prop="name">
|
||||
<el-input v-model="form.name" placeholder="请输入客户名称" />
|
||||
|
@ -57,18 +57,32 @@
|
|||
</el-select>
|
||||
</form-col>
|
||||
<form-col :span="span" label="跟进人" prop="followId">
|
||||
<user-select v-model="form.followId" />
|
||||
<user-select v-model="form.followId" :disabled="disabledFollowUser" />
|
||||
</form-col>
|
||||
<form-col :span="24" label="备注" prop="remark">
|
||||
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
|
||||
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" maxlength="200" show-word-limit />
|
||||
</form-col>
|
||||
<form-col :span="span" label="顾虑点" prop="concern">
|
||||
<el-input v-model="form.concern" type="textarea" placeholder="请输入顾虑点" maxlength="200" show-word-limit />
|
||||
</form-col>
|
||||
<form-col :span="span" label="痛点" prop="pain">
|
||||
<el-input v-model="form.pain" type="textarea" placeholder="请输入痛点" maxlength="200" show-word-limit />
|
||||
</form-col>
|
||||
<form-col :span="span" label="关注点" prop="attention">
|
||||
<el-input v-model="form.attention" type="textarea" placeholder="请输入关注点" maxlength="200" show-word-limit />
|
||||
</form-col>
|
||||
<form-col :span="span" label="需求点" prop="demand">
|
||||
<el-input v-model="form.demand" type="textarea" placeholder="请输入需求点" maxlength="200" show-word-limit />
|
||||
</form-col>
|
||||
</el-row>
|
||||
|
||||
<el-tabs v-if="form.id == null">
|
||||
<el-tab-pane label="跟进记录">
|
||||
<customer-follow-form :form="form.follow" :hide="['customerId']" :prop-prefix="'follow.'" :span="span"/>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
<template v-if="form.id == null">
|
||||
<el-tabs>
|
||||
<el-tab-pane label="跟进记录">
|
||||
<customer-follow-form :form="form.follow" :hide="['customerId']" prop-prefix="follow." :span="span"/>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</template>
|
||||
|
||||
</el-form>
|
||||
</div>
|
||||
|
@ -84,6 +98,7 @@ import UserSelect from '@/components/Business/User/UserSelect.vue';
|
|||
import CustomerFollowForm from '@/views/bst/customerFollow/components/CustomerFollowForm.vue';
|
||||
import { parseTime } from '@/utils/ruoyi';
|
||||
import EditHeader from '@/components/EditHeader/index.vue';
|
||||
import { checkRole } from '@/utils/permission';
|
||||
export default {
|
||||
name: "CustomerEdit",
|
||||
components: { FormCol, UserSelect, CustomerFollowForm, EditHeader },
|
||||
|
@ -132,6 +147,10 @@ export default {
|
|||
},
|
||||
computed: {
|
||||
...mapGetters(['userId']),
|
||||
// 禁用选择跟进人的情况
|
||||
disabledFollowUser() {
|
||||
return !checkRole(['sys_admin', 'admin']);
|
||||
},
|
||||
title() {
|
||||
return this.id ? '修改客户' : '新增客户';
|
||||
},
|
||||
|
|
|
@ -18,6 +18,10 @@
|
|||
<el-descriptions-item label="备注">{{ detail.remark | dv }}</el-descriptions-item>
|
||||
<el-descriptions-item label="创建时间">{{ detail.createTime | dv }}</el-descriptions-item>
|
||||
<el-descriptions-item label="最后跟进时间">{{ detail.lastFollowTime | dv }}</el-descriptions-item>
|
||||
<el-descriptions-item label="顾虑点">{{ detail.concern | dv }}</el-descriptions-item>
|
||||
<el-descriptions-item label="痛点">{{ detail.pain | dv }}</el-descriptions-item>
|
||||
<el-descriptions-item label="关注点">{{ detail.attention | dv }}</el-descriptions-item>
|
||||
<el-descriptions-item label="需求点">{{ detail.demand | dv }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-card>
|
||||
|
||||
|
|
375
src/views/bst/message/index.vue
Normal file
375
src/views/bst/message/index.vue
Normal file
|
@ -0,0 +1,375 @@
|
|||
<template>
|
||||
<div class="app-container">
|
||||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
|
||||
<el-form-item label="接收人" prop="userId">
|
||||
<el-input
|
||||
v-model="queryParams.userId"
|
||||
placeholder="请输入接收人"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="业务ID" prop="bstId">
|
||||
<el-input
|
||||
v-model="queryParams.bstId"
|
||||
placeholder="请输入业务ID"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="标题" prop="title">
|
||||
<el-input
|
||||
v-model="queryParams.title"
|
||||
placeholder="请输入标题"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否已读" prop="isRead">
|
||||
<el-input
|
||||
v-model="queryParams.isRead"
|
||||
placeholder="请输入是否已读"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="已读时间" prop="readTime">
|
||||
<el-date-picker clearable
|
||||
v-model="queryParams.readTime"
|
||||
type="date"
|
||||
value-format="yyyy-MM-dd"
|
||||
placeholder="请选择已读时间">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
icon="el-icon-plus"
|
||||
size="mini"
|
||||
@click="handleAdd"
|
||||
v-has-permi="['bst:message:add']"
|
||||
>新增</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="danger"
|
||||
plain
|
||||
icon="el-icon-delete"
|
||||
size="mini"
|
||||
:disabled="multiple"
|
||||
@click="handleDelete"
|
||||
v-has-permi="['bst:message:remove']"
|
||||
>删除</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="warning"
|
||||
plain
|
||||
icon="el-icon-download"
|
||||
size="mini"
|
||||
@click="handleExport"
|
||||
v-has-permi="['bst:message:export']"
|
||||
>导出</el-button>
|
||||
</el-col>
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList" :columns="columns"></right-toolbar>
|
||||
</el-row>
|
||||
|
||||
<el-table v-loading="loading" :data="messageList" @selection-change="handleSelectionChange" :default-sort="defaultSort" @sort-change="onSortChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<template v-for="column of showColumns">
|
||||
<el-table-column
|
||||
:key="column.key"
|
||||
:label="column.label"
|
||||
:prop="column.key"
|
||||
:align="column.align"
|
||||
:min-width="column.minWidth"
|
||||
:sort-orders="orderSorts"
|
||||
:sortable="column.sortable"
|
||||
:show-overflow-tooltip="column.overflow"
|
||||
:width="column.width"
|
||||
>
|
||||
<template slot-scope="d">
|
||||
<template v-if="column.key === 'id'">
|
||||
{{d.row[column.key]}}
|
||||
</template>
|
||||
<template v-else>
|
||||
{{d.row[column.key]}}
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</template>
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-edit"
|
||||
@click="handleUpdate(scope.row)"
|
||||
v-has-permi="['bst:message:edit']"
|
||||
>修改</el-button>
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-delete"
|
||||
@click="handleDelete(scope.row)"
|
||||
v-has-permi="['bst:message:remove']"
|
||||
>删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
v-show="total>0"
|
||||
:total="total"
|
||||
:page.sync="queryParams.pageNum"
|
||||
:limit.sync="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
|
||||
<!-- 添加或修改消息对话框 -->
|
||||
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body :close-on-click-modal="false">
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
|
||||
<el-row>
|
||||
<form-col :span="span" label="接收人" prop="userId">
|
||||
<el-input v-model="form.userId" placeholder="请输入接收人" />
|
||||
</form-col>
|
||||
<form-col :span="span" label="业务ID" prop="bstId">
|
||||
<el-input v-model="form.bstId" placeholder="请输入业务ID" />
|
||||
</form-col>
|
||||
<form-col :span="span" label="标题" prop="title">
|
||||
<el-input v-model="form.title" placeholder="请输入标题" />
|
||||
</form-col>
|
||||
<form-col :span="span" label="内容">
|
||||
<editor v-model="form.content" :min-height="192"/>
|
||||
</form-col>
|
||||
<form-col :span="span" label="是否已读" prop="isRead">
|
||||
<el-input v-model="form.isRead" placeholder="请输入是否已读" />
|
||||
</form-col>
|
||||
<form-col :span="span" label="已读时间" prop="readTime">
|
||||
<el-date-picker clearable
|
||||
v-model="form.readTime"
|
||||
type="date"
|
||||
value-format="yyyy-MM-dd"
|
||||
placeholder="请选择已读时间">
|
||||
</el-date-picker>
|
||||
</form-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||||
<el-button @click="cancel">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listMessage, getMessage, delMessage, addMessage, updateMessage } from "@/api/bst/message";
|
||||
import { $showColumns } from '@/utils/mixins';
|
||||
import FormCol from "@/components/FormCol/index.vue";
|
||||
|
||||
// 默认排序字段
|
||||
const defaultSort = {
|
||||
prop: "createTime",
|
||||
order: "descending"
|
||||
}
|
||||
|
||||
export default {
|
||||
name: "Message",
|
||||
mixins: [$showColumns],
|
||||
components: {FormCol},
|
||||
data() {
|
||||
return {
|
||||
span: 24,
|
||||
// 字段列表
|
||||
columns: [
|
||||
{key: 'id', visible: true, label: 'ID', minWidth: null, sortable: true, overflow: false, align: 'center', width: null},
|
||||
{key: 'userId', visible: true, label: '接收人', minWidth: null, sortable: true, overflow: false, align: 'center', width: null},
|
||||
{key: 'bstType', visible: true, label: '业务类型', minWidth: null, sortable: true, overflow: false, align: 'center', width: null},
|
||||
{key: 'bstId', visible: true, label: '业务ID', minWidth: null, sortable: true, overflow: false, align: 'center', width: null},
|
||||
{key: 'title', visible: true, label: '标题', minWidth: null, sortable: true, overflow: false, align: 'center', width: null},
|
||||
{key: 'content', visible: true, label: '内容', minWidth: null, sortable: true, overflow: false, align: 'center', width: null},
|
||||
{key: 'isRead', visible: true, label: '是否已读', minWidth: null, sortable: true, overflow: false, align: 'center', width: null},
|
||||
{key: 'readTime', visible: true, label: '已读时间', minWidth: null, sortable: false, overflow: false, align: 'center', width: "100"},
|
||||
],
|
||||
// 排序方式
|
||||
orderSorts: ['ascending', 'descending', null],
|
||||
// 遮罩层
|
||||
loading: true,
|
||||
// 选中数组
|
||||
ids: [],
|
||||
// 非单个禁用
|
||||
single: true,
|
||||
// 非多个禁用
|
||||
multiple: true,
|
||||
// 显示搜索条件
|
||||
showSearch: true,
|
||||
// 总条数
|
||||
total: 0,
|
||||
// 消息表格数据
|
||||
messageList: [],
|
||||
// 弹出层标题
|
||||
title: "",
|
||||
// 是否显示弹出层
|
||||
open: false,
|
||||
defaultSort,
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 20,
|
||||
orderByColumn: defaultSort.prop,
|
||||
isAsc: defaultSort.order,
|
||||
id: null,
|
||||
userId: null,
|
||||
bstType: null,
|
||||
bstId: null,
|
||||
title: null,
|
||||
content: null,
|
||||
isRead: null,
|
||||
readTime: null
|
||||
},
|
||||
// 表单参数
|
||||
form: {},
|
||||
// 表单校验
|
||||
rules: {
|
||||
userId: [
|
||||
{ required: true, message: "接收人不能为空", trigger: "blur" }
|
||||
],
|
||||
bstType: [
|
||||
{ required: true, message: "业务类型不能为空", trigger: "change" }
|
||||
],
|
||||
title: [
|
||||
{ required: true, message: "标题不能为空", trigger: "blur" }
|
||||
],
|
||||
isRead: [
|
||||
{ required: true, message: "是否已读不能为空", trigger: "blur" }
|
||||
],
|
||||
createTime: [
|
||||
{ required: true, message: "创建时间不能为空", trigger: "blur" }
|
||||
],
|
||||
}
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.getList();
|
||||
},
|
||||
methods: {
|
||||
/** 当排序按钮被点击时触发 **/
|
||||
onSortChange(column) {
|
||||
if (column.order == null) {
|
||||
this.queryParams.orderByColumn = defaultSort.prop;
|
||||
this.queryParams.isAsc = defaultSort.order;
|
||||
} else {
|
||||
this.queryParams.orderByColumn = column.prop;
|
||||
this.queryParams.isAsc = column.order;
|
||||
}
|
||||
this.getList();
|
||||
},
|
||||
/** 查询消息列表 */
|
||||
getList() {
|
||||
this.loading = true;
|
||||
listMessage(this.queryParams).then(response => {
|
||||
this.messageList = response.rows;
|
||||
this.total = response.total;
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
// 取消按钮
|
||||
cancel() {
|
||||
this.open = false;
|
||||
this.reset();
|
||||
},
|
||||
// 表单重置
|
||||
reset() {
|
||||
this.form = {
|
||||
id: null,
|
||||
userId: null,
|
||||
bstType: null,
|
||||
bstId: null,
|
||||
title: null,
|
||||
content: null,
|
||||
isRead: null,
|
||||
createTime: null,
|
||||
readTime: null
|
||||
};
|
||||
this.resetForm("form");
|
||||
},
|
||||
/** 搜索按钮操作 */
|
||||
handleQuery() {
|
||||
this.queryParams.pageNum = 1;
|
||||
this.getList();
|
||||
},
|
||||
/** 重置按钮操作 */
|
||||
resetQuery() {
|
||||
this.resetForm("queryForm");
|
||||
this.handleQuery();
|
||||
},
|
||||
// 多选框选中数据
|
||||
handleSelectionChange(selection) {
|
||||
this.ids = selection.map(item => item.id)
|
||||
this.single = selection.length!==1
|
||||
this.multiple = !selection.length
|
||||
},
|
||||
/** 新增按钮操作 */
|
||||
handleAdd() {
|
||||
this.reset();
|
||||
this.open = true;
|
||||
this.title = "添加消息";
|
||||
},
|
||||
/** 修改按钮操作 */
|
||||
handleUpdate(row) {
|
||||
this.reset();
|
||||
const id = row.id || this.ids
|
||||
getMessage(id).then(response => {
|
||||
this.form = response.data;
|
||||
this.open = true;
|
||||
this.title = "修改消息";
|
||||
});
|
||||
},
|
||||
/** 提交按钮 */
|
||||
submitForm() {
|
||||
this.$refs["form"].validate(valid => {
|
||||
if (valid) {
|
||||
if (this.form.id != null) {
|
||||
updateMessage(this.form).then(response => {
|
||||
this.$modal.msgSuccess("修改成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
});
|
||||
} else {
|
||||
addMessage(this.form).then(response => {
|
||||
this.$modal.msgSuccess("新增成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
/** 删除按钮操作 */
|
||||
handleDelete(row) {
|
||||
const ids = row.id || this.ids;
|
||||
this.$modal.confirm('是否确认删除消息编号为"' + ids + '"的数据项?').then(function() {
|
||||
return delMessage(ids);
|
||||
}).then(() => {
|
||||
this.getList();
|
||||
this.$modal.msgSuccess("删除成功");
|
||||
}).catch(() => {});
|
||||
},
|
||||
/** 导出按钮操作 */
|
||||
handleExport() {
|
||||
this.download('bst/message/export', {
|
||||
...this.queryParams
|
||||
}, `message_${new Date().getTime()}.xlsx`)
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
|
@ -10,9 +10,14 @@
|
|||
>
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="80px" v-loading="loading">
|
||||
<el-row>
|
||||
<form-col :span="24" label="标题" prop="title">
|
||||
<form-col :span="span" label="标题" prop="title">
|
||||
<el-input v-model="form.title" placeholder="请输入标题" />
|
||||
</form-col>
|
||||
<form-col :span="span" label="类型" prop="type">
|
||||
<el-radio-group v-model="form.type" placeholder="请选择类型" style="width: 100%;">
|
||||
<el-radio-button v-for="dict in dict.type.notice_type" :key="dict.value" :label="dict.value">{{ dict.label }}</el-radio-button>
|
||||
</el-radio-group>
|
||||
</form-col>
|
||||
<form-col :span="span" label="重要程度" prop="level">
|
||||
<el-radio-group v-model="form.level" placeholder="请选择重要程度" style="width: 100%;">
|
||||
<el-radio-button v-for="dict in dict.type.notice_level" :key="dict.value" :label="dict.value">{{ dict.label }}</el-radio-button>
|
||||
|
@ -51,7 +56,7 @@ import { NoticeLevel } from '@/utils/enums';
|
|||
export default {
|
||||
name: "NoticeEditDialog",
|
||||
components: { FormCol, DeptSelect, UserSelect },
|
||||
dicts: ['notice_level'],
|
||||
dicts: ['notice_level', 'notice_type'],
|
||||
props: {
|
||||
show: {
|
||||
type: Boolean,
|
||||
|
|
|
@ -151,7 +151,7 @@
|
|||
<script>
|
||||
import { listNotice, delNotice } from "@/api/bst/notice";
|
||||
import { $showColumns } from '@/utils/mixins';
|
||||
import NoticeEditDialog from './components/NoticeEditDialog.vue';
|
||||
import NoticeEditDialog from '@/views/bst/notice/components/NoticeEditDialog.vue';
|
||||
import BooleanTag from '@/components/BooleanTag/index.vue';
|
||||
import AvatarList from '@/components/AvatarList/index.vue';
|
||||
|
||||
|
|
307
src/views/bst/notice/noticeTip/index.vue
Normal file
307
src/views/bst/notice/noticeTip/index.vue
Normal file
|
@ -0,0 +1,307 @@
|
|||
<template>
|
||||
<div class="bst-notice-container">
|
||||
<el-popover
|
||||
placement="bottom"
|
||||
width="500"
|
||||
trigger="click"
|
||||
popper-class="bst-notice-popover"
|
||||
@show="handleAfterEnter"
|
||||
>
|
||||
<div slot="reference">
|
||||
<el-badge :hidden="unreadCount <= 0" :value="unreadCount" :max="99" class="notice-badge">
|
||||
<i class="el-icon-bell"></i>
|
||||
</el-badge>
|
||||
</div>
|
||||
|
||||
<el-row type="flex" justify="space-between" style="padding:10px;">
|
||||
<div class="filter-section">
|
||||
<el-radio-group v-model="queryParams.isRead" size="mini" @change="handleQuery">
|
||||
<el-radio-button :label="null">全部</el-radio-button>
|
||||
<el-radio-button :label="false">未读</el-radio-button>
|
||||
<el-radio-button :label="true">已读</el-radio-button>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
<el-button type="text" size="mini" @click="handleRead(null)">全部已读</el-button>
|
||||
</el-row>
|
||||
|
||||
<div class="notice-list" @scroll="handleScroll">
|
||||
<el-collapse accordion v-if="messgeList.length" @change="handleChangeCollapse">
|
||||
<el-collapse-item v-for="message in messgeList" :name="message.id">
|
||||
<div slot="title" class="notice-title-box">
|
||||
<div class="notice-title">
|
||||
<dict-tag :options="dict.type.message_bst_type" :value="message.bstType" size="mini"/>
|
||||
[{{message.title}}]
|
||||
{{message.content}}
|
||||
</div>
|
||||
<el-badge is-dot :hidden="message.isRead">
|
||||
<div class="notice-time">{{message.createTime}}</div>
|
||||
</el-badge>
|
||||
</div>
|
||||
<div class="notice-content" @click="handleClickMessage(message)">{{message.content}}</div>
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
<el-empty v-if="messgeList.length == 0 && finished" description="暂无消息"></el-empty>
|
||||
<div v-if="!finished && !loading" class="loading-more">下拉加载更多</div>
|
||||
<div v-if="finished && messgeList.length > 0" class="loading-more">没有更多了</div>
|
||||
<div v-if="loading" class="loading-more"><i class="el-icon-loading"></i>加载中...</div>
|
||||
</div>
|
||||
</el-popover>
|
||||
|
||||
<task-view-dialog :show.sync="showTaskDialog" :id="bstId" />
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { appGetReceiveList, appReadMessage, appGetUnreadCount } from '@/api/app/message'
|
||||
import { getToken } from '@/utils/auth'
|
||||
import { MessageBstType } from '@/utils/enums'
|
||||
import TaskViewDialog from '@/views/bst/task/components/TaskViewDialog.vue'
|
||||
|
||||
export default {
|
||||
name: 'NoticeTip',
|
||||
components: {
|
||||
TaskViewDialog
|
||||
},
|
||||
dicts: ['message_bst_type'],
|
||||
data() {
|
||||
return {
|
||||
messgeList: [],
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
isRead: null
|
||||
},
|
||||
unreadCount: 0,
|
||||
selectedNotice: null,
|
||||
detailVisible: false,
|
||||
ws: null,
|
||||
loading: false,
|
||||
total: 0,
|
||||
row: null,
|
||||
finished: false,
|
||||
showTaskDialog: false,
|
||||
bstId: null
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getUnReadCount();
|
||||
this.initWebSocket();
|
||||
},
|
||||
mounted() {
|
||||
this.tryGetPermission();
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (this.ws) {
|
||||
this.ws.close()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 点击消息
|
||||
handleClickMessage(message) {
|
||||
if (message == null) {
|
||||
return;
|
||||
}
|
||||
this.bstId = message.bstId;
|
||||
|
||||
if (message.bstType == MessageBstType.TASK) {
|
||||
this.showTaskDialog = true;
|
||||
}
|
||||
|
||||
|
||||
},
|
||||
// 进入后获取未读消息数量和列表
|
||||
handleAfterEnter() {
|
||||
this.getUnReadCount();
|
||||
this.getList();
|
||||
},
|
||||
// 获取未读消息数量
|
||||
async getUnReadCount() {
|
||||
const res = await appGetUnreadCount();
|
||||
this.unreadCount = res.data;
|
||||
},
|
||||
// 获取通知列表
|
||||
async getList() {
|
||||
this.total = 0;
|
||||
this.messgeList = [];
|
||||
this.queryParams.pageNum = 0;
|
||||
await this.lodList();
|
||||
},
|
||||
async lodList() {
|
||||
this.queryParams.pageNum ++;
|
||||
this.loading = true;
|
||||
try {
|
||||
const res = await appGetReceiveList(this.queryParams);
|
||||
this.messgeList.push(...res.rows);
|
||||
this.total = res.total;
|
||||
this.finished = this.messgeList.length >= this.total;
|
||||
} catch (error) {
|
||||
console.error('获取消息列表失败:', error)
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
initWebSocket() {
|
||||
const token = getToken(); // 获取token
|
||||
this.ws = new WebSocket(`${process.env.VUE_APP_WS_HOST}/ws/message?token=${token}`);
|
||||
|
||||
this.ws.onopen = () => {
|
||||
console.log('WebSocket连接成功');
|
||||
};
|
||||
|
||||
this.ws.onmessage = (event) => {
|
||||
// 处理消息
|
||||
let message = JSON.parse(event.data);
|
||||
this.showDesktopNotification(message);
|
||||
this.unreadCount ++;
|
||||
};
|
||||
|
||||
this.ws.onclose = (event) => {
|
||||
console.log('WebSocket连接关闭,尝试重连...');
|
||||
setTimeout(this.initWebSocket, 5000); // 5秒后重连
|
||||
};
|
||||
|
||||
this.ws.onerror = (error) => {
|
||||
console.error('WebSocket错误:', error);
|
||||
};
|
||||
},
|
||||
// 桌面通知
|
||||
showDesktopNotification(message) {
|
||||
this.tryGetPermission();
|
||||
if (Notification.permission === 'granted') {
|
||||
new Notification(`${message.title}`, {
|
||||
body: message.content,
|
||||
icon: '/favicon.ico'
|
||||
})
|
||||
}
|
||||
},
|
||||
// 获取通知权限
|
||||
tryGetPermission() {
|
||||
if (Notification.permission !== 'granted') {
|
||||
Notification.requestPermission();
|
||||
}
|
||||
},
|
||||
// 处理折叠
|
||||
handleChangeCollapse(name) {
|
||||
let row = this.messgeList.find(item => item.id == name);
|
||||
if (row != null && !row.isRead) {
|
||||
this.handleRead(row.id);
|
||||
}
|
||||
},
|
||||
// 处理消息已读
|
||||
async handleRead(id) {
|
||||
// 调用接口
|
||||
let res = await appReadMessage(id);
|
||||
if (res.code === 200 && res.data > 0) {
|
||||
this.getUnReadCount();
|
||||
if (id != null) {
|
||||
this.messgeList.forEach(item => {
|
||||
if (item.id == id) {
|
||||
item.isRead = true;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.getList();
|
||||
}
|
||||
}
|
||||
},
|
||||
// 查询
|
||||
handleQuery() {
|
||||
this.queryParams.pageNum = 1;
|
||||
this.getList();
|
||||
},
|
||||
handleScroll(e) {
|
||||
const { scrollHeight, scrollTop, clientHeight } = e.target;
|
||||
// 距离底部20px时触发加载
|
||||
if (scrollHeight - scrollTop - clientHeight < 20 && !this.loading && !this.finished) {
|
||||
this.lodList();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.bst-notice-container {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
|
||||
.notice-badge {
|
||||
cursor: pointer;
|
||||
|
||||
::v-deep .el-badge__content {
|
||||
top: 12px;
|
||||
right: 12px;
|
||||
}
|
||||
|
||||
.el-icon-bell {
|
||||
font-size: 20px;
|
||||
color: #606266;
|
||||
|
||||
&:hover {
|
||||
color: #409EFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.notice-list {
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
padding: 10px;
|
||||
|
||||
.loading-more {
|
||||
text-align: center;
|
||||
color: #909399;
|
||||
font-size: 12px;
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
.notice-title-box {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
flex-direction: row;
|
||||
width: calc(100% - 1em);
|
||||
|
||||
.notice-title {
|
||||
padding-left: 10px;
|
||||
position: relative;
|
||||
font-size: 12px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.notice-time {
|
||||
position: relative;
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
align-items: center;
|
||||
height: 1.5em;
|
||||
line-height: 1.5em;
|
||||
min-width: 120px;
|
||||
margin-left: 6px;
|
||||
}
|
||||
}
|
||||
.notice-content {
|
||||
cursor: pointer;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
font-size: 12px;
|
||||
color: #606266;
|
||||
transition: color 0.3s;
|
||||
&:hover {
|
||||
color: #409EFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss">
|
||||
.bst-notice-popover {
|
||||
padding: 0 !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
|
@ -11,17 +11,17 @@
|
|||
<el-form ref="form" :model="form" :rules="rules" label-width="80px" v-loading="loading">
|
||||
<el-row>
|
||||
<form-col :span="24" label="项目" prop="projectId">
|
||||
<project-select v-model="form.projectId" :disabled="initData.projectId != null"/>
|
||||
<project-select v-model="form.projectId" :disabled="initData.projectId != null" @change="onChangeProject"/>
|
||||
</form-col>
|
||||
<form-col :span="24" label="附件" prop="picture">
|
||||
<image-upload v-model="form.picture" :file-type="FileType"/>
|
||||
</form-col>
|
||||
<form-col :span="span" label="类型" prop="type">
|
||||
<form-col :span="24" label="类型" prop="type">
|
||||
<el-radio-group v-model="form.type">
|
||||
<el-radio-button v-for="dict in dict.type.task_type" :key="dict.value" :label="dict.value">{{ dict.label }}</el-radio-button>
|
||||
</el-radio-group>
|
||||
</form-col>
|
||||
<form-col :span="span" label="优先级" prop="level">
|
||||
<form-col :span="24" label="优先级" prop="level">
|
||||
<el-radio-group v-model="form.level">
|
||||
<el-radio-button v-for="dict in dict.type.task_level" :key="dict.value" :label="dict.value">{{ dict.label }}</el-radio-button>
|
||||
</el-radio-group>
|
||||
|
@ -30,7 +30,7 @@
|
|||
<el-input v-model="form.description" placeholder="请输入任务内容" type="textarea" maxlength="1000" show-word-limit/>
|
||||
</form-col>
|
||||
<form-col :span="24" label="负责人" prop="ownerIds">
|
||||
<user-select v-model="form.ownerIds" multiple />
|
||||
<user-select v-model="form.ownerIds" multiple :filter-method="filterOwnerMethod"/>
|
||||
</form-col>
|
||||
<form-col :span="span" label="截止时间" prop="expireTime">
|
||||
<el-date-picker clearable
|
||||
|
@ -120,6 +120,29 @@ export default {
|
|||
}
|
||||
},
|
||||
methods: {
|
||||
filterOwnerMethod(data) {
|
||||
console.log("filterOwnerMethod", data, this.form);
|
||||
if (this.form.projectId == null) {
|
||||
return data;
|
||||
}
|
||||
if (this.form.projectOwnerId == null || this.form.projectFollowId == null || this.form.projectMemberIds == null) {
|
||||
return [];
|
||||
}
|
||||
// 过滤,项目负责人、项目跟进人、项目成员
|
||||
let userList = data.filter(item => {
|
||||
return item.userId === this.form.projectOwnerId || item.userId === this.form.projectFollowId || this.form.projectMemberIds.includes(item.userId);
|
||||
});
|
||||
return userList;
|
||||
},
|
||||
onChangeProject(project) {
|
||||
this.form.projectOwnerId = project.ownerId;
|
||||
this.form.projectFollowId = project.followId;
|
||||
this.form.projectMemberIds = project.memberIds;
|
||||
if (this.form.ownerIds.length > 0) {
|
||||
this.form.ownerIds = [];
|
||||
this.$message("由于更换了项目,负责人已清空");
|
||||
}
|
||||
},
|
||||
/** 获取详细信息 */
|
||||
getInfo(id) {
|
||||
this.loading = true;
|
||||
|
|
|
@ -53,7 +53,7 @@
|
|||
</el-card>
|
||||
|
||||
<!-- 提交记录、审核 -->
|
||||
<task-verify-panel :task="detail" :submit-list="detail.submitList" @success="getInfo(detail.id)"/>
|
||||
<task-verify-panel :task="detail" :submit-list="detail.submitList" @success="onSubmit"/>
|
||||
|
||||
</el-col>
|
||||
|
||||
|
@ -72,7 +72,7 @@
|
|||
</el-row>
|
||||
|
||||
<!-- 取消任务 -->
|
||||
<task-cancel-dialog :id="detail.id" :show.sync="showCancelDialog" @success="getInfo(detail.id)"/>
|
||||
<task-cancel-dialog :id="detail.id" :show.sync="showCancelDialog" @success="onCancel"/>
|
||||
|
||||
</el-drawer>
|
||||
</template>
|
||||
|
@ -128,6 +128,17 @@ export default {
|
|||
}
|
||||
},
|
||||
methods: {
|
||||
onCancel() {
|
||||
this.refreshList();
|
||||
this.getInfo(this.detail.id);
|
||||
},
|
||||
onSubmit() {
|
||||
this.refreshList();
|
||||
this.getInfo(this.detail.id);
|
||||
},
|
||||
refreshList() {
|
||||
this.$emit('refresh');
|
||||
},
|
||||
getRealUrl,
|
||||
// 取消任务
|
||||
handleCancel() {
|
||||
|
|
|
@ -121,11 +121,12 @@
|
|||
</template>
|
||||
<template v-else-if="column.key === 'createTime'">
|
||||
创建:{{d.row.createTime | dv}}<br/>
|
||||
截止:{{d.row.expireTime | dv}}
|
||||
截止:{{d.row.expireTime | dv}}<br/>
|
||||
完成:{{d.row.passTime | dv}}<br/>
|
||||
</template>
|
||||
<template v-else-if="column.key === 'owner'">
|
||||
<div style="margin: 0 auto; width: fit-content">
|
||||
<avatar-list :list="d.row.ownerList" :max-count="3" unit="人" :char-index="-1"/>
|
||||
<avatar-list :list="d.row.ownerList" :max-count="3" unit="人" :char-index="-1" bst-type="user"/>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
|
@ -181,6 +182,7 @@
|
|||
<task-view-dialog
|
||||
:show.sync="showViewDialog"
|
||||
:id="row.id"
|
||||
@refresh="getList"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -227,14 +229,13 @@ export default {
|
|||
columns: [
|
||||
{key: 'id', visible: false, label: 'ID', minWidth: null, sortable: true, overflow: false, align: 'center', width: "80"},
|
||||
{key: 'description', visible: true, label: '任务内容', minWidth: "350", sortable: false, overflow: false, align: 'left', width: null},
|
||||
{key: 'type', visible: true, label: '类型', minWidth: null, sortable: true, overflow: false, align: 'center', width: "80"},
|
||||
{key: 'level', visible: true, label: '优先', minWidth: null, sortable: true, overflow: false, align: 'center', width: "80"},
|
||||
{key: 'status', visible: true, label: '状态', minWidth: null, sortable: true, overflow: false, align: 'center', width: "80"},
|
||||
{key: 'picture', visible: true, label: '图片', minWidth: null, sortable: true, overflow: false, align: 'center', width: null},
|
||||
{key: 'projectName', visible: true, label: '项目', minWidth: null, sortable: true, overflow: false, align: 'center', width: null},
|
||||
{key: 'owner', visible: true, label: '负责人', minWidth: null, sortable: false, overflow: false, align: 'center', width: "150"},
|
||||
{key: 'createName', visible: true, label: '创建人', minWidth: null, sortable: true, overflow: false, align: 'center', width: null},
|
||||
{key: 'createTime', visible: true, label: '时间', minWidth: null, sortable: true, overflow: false, align: 'center', width: "190"},
|
||||
{key: 'submitCount', visible: true, label: '提交', minWidth: null, sortable: false, overflow: false, align: 'center', width: "50"},
|
||||
{key: 'passCount', visible: true, label: '完成', minWidth: null, sortable: false, overflow: false, align: 'center', width: "50"},
|
||||
{key: 'createTime', visible: true, label: '时间', minWidth: null, sortable: true, overflow: false, align: 'left', width: "190"},
|
||||
],
|
||||
// 排序方式
|
||||
orderSorts: ['ascending', 'descending', null],
|
||||
|
|
Loading…
Reference in New Issue
Block a user