16 Commits

Author SHA1 Message Date
qsh
f6ed6575c4 sc 2024-09-14 16:37:31 +08:00
qsh
cab0b3f2eb sc 2024-09-13 17:41:08 +08:00
qsh
f415e0cfce Merge branch 'main' of http://114.55.169.15:3000/qiushanhe/ss-crm-manage-web into dev-cjl 2024-09-13 10:38:00 +08:00
qsh
90f7513ca8 sc 2024-09-13 10:18:32 +08:00
qsh
cad9fbb0e0 sc 2024-09-12 16:29:50 +08:00
qsh
187c156e88 sc 2024-09-12 09:45:33 +08:00
842e6ea24b sc 2024-09-12 01:59:30 +08:00
qsh
fb466e207c sc 2024-09-10 18:05:19 +08:00
qsh
8a857e03af sc 2024-09-10 17:00:39 +08:00
qsh
7de4adeaad sc 2024-09-10 16:58:25 +08:00
qsh
3e714a0bc8 sc 2024-09-10 16:38:04 +08:00
qsh
3678c5fcc4 sc 2024-09-06 18:09:25 +08:00
qsh
ecc89f47bb sc 2024-09-05 17:35:19 +08:00
qsh
41e256aabb Merge branch 'main' of http://114.55.169.15:3000/qiushanhe/ss-crm-manage-web into dev-cjl
cj
2024-09-05 16:26:50 +08:00
qsh
cc5648414e sc 2024-09-05 15:32:39 +08:00
qsh
0555c0e42e sc 2024-09-05 15:26:28 +08:00
15 changed files with 356 additions and 216 deletions

View File

@@ -71,3 +71,10 @@ export const getAppInfo = (instanceId: number) => {
url: '/admin-api/system/serviceInstance/getInstanceInfo?instanceId=' + instanceId url: '/admin-api/system/serviceInstance/getInstanceInfo?instanceId=' + instanceId
}) })
} }
export const bindWx = (data: any) => {
return request.post({
url: '/admin-api/system/user/bind/wx',
data
})
}

View File

@@ -1,5 +1,4 @@
import request from '@/config/axios' import request from '@/config/axios'
import qs from 'qs'
export interface NotifyMessageVO { export interface NotifyMessageVO {
id: number id: number
@@ -16,35 +15,39 @@ export interface NotifyMessageVO {
} }
// 查询站内信消息列表 // 查询站内信消息列表
export const getNotifyMessagePage = async (params: PageParam) => { export const getNotifyMessagePage = async (params: any) => {
return await request.get({ url: '/admin-api/system/notify-message/page', params }) return await request.get({ url: '/admin-api/system/notify-message/page', params })
} }
// 获得我的站内信分页 // 获得我的站内信分页
export const getMyNotifyMessagePage = async (params: PageParam) => { export const getMyNotifyMessagePage = async (params: any) => {
return await request.get({ url: '/admin-api/system/notify-message/my-page', params }) return await request.get({ url: '/admin-api/system/notify-message/my-page', params })
} }
// 批量标记已读 // 批量标记已读
export const updateNotifyMessageRead = async (ids) => { export const updateNotifyMessageRead = async (data: any) => {
return await request.put({ return await request.put({
url: url: '/admin-api/system/notify-message/update-read?',
'/admin-api/system/notify-message/update-read?' + data
qs.stringify({ ids: ids }, { indices: false })
}) })
} }
// 标记所有站内信为已读 // 标记所有站内信为已读
export const updateAllNotifyMessageRead = async () => { export const updateAllNotifyMessageRead = async (data: any) => {
return await request.put({ url: '/admin-api/system/notify-message/update-all-read' }) return await request.put({ url: '/admin-api/system/notify-message/update-all-read', data })
} }
// 获取当前用户的最新站内信列表 // 获取当前用户的最新站内信列表
export const getUnreadNotifyMessageList = async () => { export const getUnreadNotifyMessageList = async (params: any) => {
return await request.get({ url: '/admin-api/system/notify-message/get-unread-list' }) return await request.get({ url: '/admin-api/system/notify-message/get-unread-list', params })
} }
// 获得当前用户的未读站内信数量 // 获得当前用户的未读站内信数量
export const getUnreadNotifyMessageCount = async () => { export const getUnreadNotifyMessageCount = async (params: any) => {
return await request.get({ url: '/admin-api/system/notify-message/get-unread-count' }) return await request.get({ url: '/admin-api/system/notify-message/get-unread-count', params })
}
// 获取详情
export const getNotifyMessageDetail = async (id: number) => {
return await request.get({ url: '/admin-api/system/notify-message/get', params: { id } })
} }

View File

@@ -205,6 +205,8 @@ service.interceptors.response.use(
if (msg === '无效的刷新令牌') { if (msg === '无效的刷新令牌') {
// hard coding忽略这个提示直接登出 // hard coding忽略这个提示直接登出
console.log(msg) console.log(msg)
} else if (code == 18888) {
return { data }
} else { } else {
ElNotification.error({ title: msg }) ElNotification.error({ title: msg })
if (code == 403) { if (code == 403) {

View File

@@ -1,6 +1,9 @@
<script lang="ts" name="Message" setup> <script lang="ts" name="Message" setup>
import { formatDate } from '@/utils/formatTime' import { formatDate } from '@/utils/formatTime'
import * as NotifyMessageApi from '@/api/system/notify/message' import * as NotifyMessageApi from '@/api/system/notify/message'
import { useUserStore } from '@/store/modules/user'
const userStore = useUserStore()
const { push } = useRouter() const { push } = useRouter()
const activeName = ref('notice') const activeName = ref('notice')
@@ -9,16 +12,21 @@ const list = ref<any[]>([]) // 消息列表
// 获得消息列表 // 获得消息列表
const getList = async () => { const getList = async () => {
list.value = await NotifyMessageApi.getUnreadNotifyMessageList() const data = await NotifyMessageApi.getUnreadNotifyMessageList({
roleId: userStore.getUser?.currentRole
})
list.value = data.list
// 强制设置 unreadCount 为 0避免小红点因为轮询太慢不消除 // 强制设置 unreadCount 为 0避免小红点因为轮询太慢不消除
unreadCount.value = 0 unreadCount.value = 0
} }
// 获得未读消息数 // 获得未读消息数
const getUnreadCount = async () => { const getUnreadCount = async () => {
NotifyMessageApi.getUnreadNotifyMessageCount().then((data) => { NotifyMessageApi.getUnreadNotifyMessageCount({ roleId: userStore.getUser?.currentRole }).then(
unreadCount.value = data (data) => {
}) unreadCount.value = data
}
)
} }
// 跳转我的站内信 // 跳转我的站内信
@@ -34,9 +42,9 @@ onMounted(() => {
// 首次加载小红点 // 首次加载小红点
getUnreadCount() getUnreadCount()
// 轮询刷新小红点 // 轮询刷新小红点
// msgInterval.value = setInterval(() => { msgInterval.value = setInterval(() => {
// getUnreadCount() getUnreadCount()
// }, 1000 * 60 * 2) }, 1000 * 60 * 2)
}) })
onUnmounted(() => { onUnmounted(() => {
@@ -56,10 +64,9 @@ onUnmounted(() => {
<div class="message-list"> <div class="message-list">
<template v-for="item in list" :key="item.id"> <template v-for="item in list" :key="item.id">
<div class="message-item"> <div class="message-item">
<img alt="" class="message-icon" src="@/assets/imgs/avatar.gif" />
<div class="message-content"> <div class="message-content">
<span class="message-title"> <span class="message-title">
{{ item.templateNickname }}{{ item.templateContent }} {{ item.title }}
</span> </span>
<span class="message-date"> <span class="message-date">
{{ formatDate(item.createTime) }} {{ formatDate(item.createTime) }}
@@ -94,7 +101,7 @@ onUnmounted(() => {
.message-item { .message-item {
display: flex; display: flex;
align-items: center; align-items: center;
padding: 20px 0; padding: 5px 0;
border-bottom: 1px solid var(--el-border-color-light); border-bottom: 1px solid var(--el-border-color-light);
&:last-child { &:last-child {
@@ -113,6 +120,7 @@ onUnmounted(() => {
.message-title { .message-title {
margin-bottom: 5px; margin-bottom: 5px;
font-weight: bold;
} }
.message-date { .message-date {

View File

@@ -17,6 +17,7 @@ const { loadStart, loadDone } = usePageLoading()
const whiteList = [ const whiteList = [
'/login', '/login',
'/mp-login', '/mp-login',
'/nm-detail',
'/social-login', '/social-login',
'/auth-redirect', '/auth-redirect',
'/bind', '/bind',

View File

@@ -181,6 +181,16 @@ const remainingRouter: AppRouteRecordRaw[] = [
noTagsView: true noTagsView: true
} }
}, },
{
path: '/nm-detail',
component: () => import('@/views/Profile/NotifyMessageDetail.vue'),
name: 'NMDetail',
meta: {
hidden: true,
title: '通知详情',
noTagsView: true
}
},
{ {
path: '/403', path: '/403',
component: () => import('@/views/Error/403.vue'), component: () => import('@/views/Error/403.vue'),

View File

@@ -9,6 +9,7 @@ interface UserVO {
id: number id: number
avatar: string avatar: string
nickname: string nickname: string
currentRole: number
} }
interface UserInfoVO { interface UserInfoVO {
permissions: string[] permissions: string[]
@@ -25,7 +26,8 @@ export const useUserStore = defineStore('admin-user', {
user: { user: {
id: 0, id: 0,
avatar: '', avatar: '',
nickname: '' nickname: '',
currentRole: 0
} }
}), }),
getters: { getters: {
@@ -72,7 +74,8 @@ export const useUserStore = defineStore('admin-user', {
this.user = { this.user = {
id: 0, id: 0,
avatar: '', avatar: '',
nickname: '' nickname: '',
currentRole: 0
} }
}, },
refresh() { refresh() {

View File

@@ -23,7 +23,11 @@
<el-table-column prop="name" label="部门名称" /> <el-table-column prop="name" label="部门名称" />
<el-table-column prop="leader" label="负责人" width="120" /> <el-table-column prop="leader" label="负责人" width="120" />
<el-table-column prop="sort" label="排序" width="200" /> <el-table-column prop="sort" label="排序" width="200" />
<el-table-column prop="status" label="状态" width="100" /> <el-table-column prop="status" label="状态" width="100">
<template #default="{ row }">
{{ ['启用', '禁用'][row.status] }}
</template>
</el-table-column>
<el-table-column label="创建时间" prop="createTime" width="180" :formatter="dateFormatter" /> <el-table-column label="创建时间" prop="createTime" width="180" :formatter="dateFormatter" />
<el-table-column label="操作" class-name="fixed-width" width="240"> <el-table-column label="操作" class-name="fixed-width" width="240">
<template #default="scope"> <template #default="scope">

View File

@@ -3,8 +3,8 @@
<el-form :model="form" ref="formRef" :rules="rules" label-width="auto" v-loading="formLoading"> <el-form :model="form" ref="formRef" :rules="rules" label-width="auto" v-loading="formLoading">
<el-form-item label="开启通知"> <el-form-item label="开启通知">
<el-radio-group v-model="form.status"> <el-radio-group v-model="form.status">
<el-radio :label="1"> 开启 </el-radio> <el-radio :label="0"> 开启 </el-radio>
<el-radio :label="0"> 关闭 </el-radio> <el-radio :label="1"> 关闭 </el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>

View File

@@ -1,11 +1,4 @@
<template> <template>
<div class="head-container">
<el-input v-model="deptName" class="mb-20px" clearable placeholder="请输入部门名称">
<template #prefix>
<Icon icon="ep:search" />
</template>
</el-input>
</div>
<div class="head-container"> <div class="head-container">
<el-tree <el-tree
ref="treeRef" ref="treeRef"
@@ -26,7 +19,6 @@ import { ElTree } from 'element-plus'
import * as DeptApi from '@/api/system/dept' import * as DeptApi from '@/api/system/dept'
import { defaultProps, handleTree } from '@/utils/tree' import { defaultProps, handleTree } from '@/utils/tree'
const deptName = ref('')
const deptList = ref<Tree[]>([]) // 树形结构 const deptList = ref<Tree[]>([]) // 树形结构
const treeRef = ref<InstanceType<typeof ElTree>>() const treeRef = ref<InstanceType<typeof ElTree>>()

View File

@@ -139,7 +139,8 @@ const formData = ref({
remark: '', remark: '',
status: CommonStatusEnum.ENABLE, status: CommonStatusEnum.ENABLE,
roleIds: [], roleIds: [],
hireDate: '' hireDate: '',
isNewUserConfirm: false
}) })
const formRules = ref<any>({ const formRules = ref<any>({
username: [{ required: true, message: '登录账号不能为空', trigger: 'blur' }], username: [{ required: true, message: '登录账号不能为空', trigger: 'blur' }],
@@ -192,8 +193,14 @@ const submitForm = async () => {
try { try {
const data = formData.value as unknown as UserApi.UserVO const data = formData.value as unknown as UserApi.UserVO
if (formType.value === 'create') { if (formType.value === 'create') {
await UserApi.createUser(data) const resp = await UserApi.createUser(data)
message.success(t('common.createSuccess')) if (resp.code == 18888) {
await message.confirm(resp.msg)
formData.value.isNewUserConfirm = true
submitForm()
} else {
message.success(t('common.createSuccess'))
}
} else { } else {
await UserApi.updateUser(data) await UserApi.updateUser(data)
message.success(t('common.updateSuccess')) message.success(t('common.updateSuccess'))
@@ -220,7 +227,8 @@ const resetForm = () => {
remark: '', remark: '',
status: CommonStatusEnum.ENABLE, status: CommonStatusEnum.ENABLE,
roleIds: [], roleIds: [],
hireDate: formatDate(new Date(), 'YYYY-MM-DD') hireDate: formatDate(new Date(), 'YYYY-MM-DD'),
isNewUserConfirm: false
} }
formRef.value?.resetFields() formRef.value?.resetFields()
} }

View File

@@ -7,6 +7,9 @@
<el-form-item> <el-form-item>
<el-input v-model="searchForm.name" placeholder="线索名称" clearable /> <el-input v-model="searchForm.name" placeholder="线索名称" clearable />
</el-form-item> </el-form-item>
<el-form-item>
<el-input v-model="searchForm.mobile" placeholder="联系方式" clearable />
</el-form-item>
<el-form-item> <el-form-item>
<el-select v-model="searchForm.state" placeholder="审核状态" clearable style="width: 120px"> <el-select v-model="searchForm.state" placeholder="审核状态" clearable style="width: 120px">
<el-option label="待审核" :value="1" /> <el-option label="待审核" :value="1" />
@@ -133,8 +136,8 @@
@selection-change="handleSelectionChange" @selection-change="handleSelectionChange"
> >
<el-table-column type="selection" width="60" :selectable="(row) => row.state == 1" /> <el-table-column type="selection" width="60" :selectable="(row) => row.state == 1" />
<el-table-column prop="signId" label="成交单号" min-width="180px" /> <el-table-column prop="signId" label="成交单号" min-width="150px" />
<el-table-column prop="name" label="线索名称" width="150px" /> <el-table-column prop="name" label="线索名称" width="120px" />
<el-table-column prop="phone" label="联系方式" width="120px" />companyProfit <el-table-column prop="phone" label="联系方式" width="120px" />companyProfit
<el-table-column prop="money" label="回款金额" min-width="120px"> <el-table-column prop="money" label="回款金额" min-width="120px">
<template #default="{ row }"> <template #default="{ row }">
@@ -207,6 +210,12 @@
label="转化人" label="转化人"
min-width="90" min-width="90"
/> />
<el-table-column
v-if="appStore.getAppInfo?.instanceType == 1"
prop="area"
label="区域"
min-width="90"
/>
<el-table-column prop="signUserName" label="登记人" min-width="90" /> <el-table-column prop="signUserName" label="登记人" min-width="90" />
<el-table-column <el-table-column
prop="dealDate" prop="dealDate"
@@ -312,7 +321,7 @@ import DialogBatchAudit from './DialogBatchAudit.vue'
import { removeNullField } from '@/utils' import { removeNullField } from '@/utils'
import { useAppStore } from '@/store/modules/app' import { useAppStore } from '@/store/modules/app'
import { dateFormatter } from '@/utils/formatTime' import { dateFormatter, formatDate } from '@/utils/formatTime'
const userStore = useUserStore() const userStore = useUserStore()
const message = useMessage() // 消息弹窗 const message = useMessage() // 消息弹窗
@@ -331,6 +340,7 @@ const searchForm = ref({
applyTime: [], applyTime: [],
applyUser: undefined, applyUser: undefined,
checkTime: [], checkTime: [],
phone: undefined,
pageNo: 1, pageNo: 1,
pageSize: 20 pageSize: 20
}) })
@@ -358,6 +368,7 @@ function handleReset() {
applyTime: [], applyTime: [],
applyUser: undefined, applyUser: undefined,
checkTime: [], checkTime: [],
mobile: undefined,
pageNo: 1, pageNo: 1,
pageSize: 20 pageSize: 20
} }
@@ -454,7 +465,7 @@ async function handleUpdate(row) {
companyProfit: row.companyProfit, companyProfit: row.companyProfit,
personProfit: row.personProfit, personProfit: row.personProfit,
isPayoff: row.isPayoffValue, isPayoff: row.isPayoffValue,
applyTime: row.applyTime applyTime: formatDate(row.applyTime)
}) })
.then(() => { .then(() => {
message.success('修改成功') message.success('修改成功')

View File

@@ -9,12 +9,17 @@
<el-input v-model="form.password" placeholder="请输入密码" show-password type="password" /> <el-input v-model="form.password" placeholder="请输入密码" show-password type="password" />
</el-form-item> </el-form-item>
</el-form> </el-form>
<el-button type="primary" class="w-full" @click="onSubmit">授权登陆</el-button> <el-button type="primary" :disabled="formLoading" class="w-full" @click="onSubmit">
<div v-if="form.code">code: {{ form.code }}</div> 授权登陆
</el-button>
</div> </div>
</template> </template>
<script setup name="MPLogin"> <script setup name="MPLogin">
import { bindWx } from '@/api/login'
const message = useMessage() // 消息弹窗
const form = ref({ const form = ref({
code: undefined, code: undefined,
username: undefined, username: undefined,
@@ -38,13 +43,29 @@ const params = ref({
scope: 'snsapi_base' // snsapi_base 静默授权获取 open id snsapi_userinfo 需要用户授权,获取详细信息 scope: 'snsapi_base' // snsapi_base 静默授权获取 open id snsapi_userinfo 需要用户授权,获取详细信息
// state:'code', // a-zA-Z0-9的参数值最多128字节 // state:'code', // a-zA-Z0-9的参数值最多128字节
}) })
function onSubmit() {
const formLoading = ref(false)
async function onSubmit() {
// 这些需要判断没有 code 情况拉起授权登陆,有就结束放在重复拉起授权登陆 // 这些需要判断没有 code 情况拉起授权登陆,有就结束放在重复拉起授权登陆
if (!form.value.code) { if (!form.value.code) {
const access_url = WX_AUTH_URL + `${new URLSearchParams(params.value)}` + REDIRECT const access_url = WX_AUTH_URL + `${new URLSearchParams(params.value)}` + REDIRECT
location.href = access_url location.href = access_url
} else { } else {
alert(`授权成功!`) // 校验表单
if (!formRef.value) return
const valid = await formRef.value.validate()
if (!valid) return
// 提交请求
formLoading.value = true
try {
await bindWx(form.value)
message.success('绑定成功')
window.close()
} catch (error) {
console.log(error)
} finally {
formLoading.value = false
}
} }
} }

View File

@@ -1,177 +1,98 @@
<template> <template>
<doc-alert title="站内信配置" url="https://doc.iocoder.cn/notify/" /> <!-- 搜索工作栏 -->
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="0">
<el-form-item>
<el-select
v-model="queryParams.messageType"
placeholder="消息类型"
clearable
filterable
@change="handleQuery"
>
<el-option
v-for="item in typeOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-select
v-model="queryParams.readStatus"
placeholder="状态"
clearable
filterable
@change="handleQuery"
>
<el-option label="已读" :value="true" />
<el-option label="未读" :value="false" />
</el-select>
</el-form-item>
<el-form-item>
<el-button :disabled="selectedIds.length == 0" @click="handleUpdateList">
标记已读
</el-button>
<el-button @click="handleUpdateAll"> 全部已读 </el-button>
</el-form-item>
</el-form>
<ContentWrap> <el-text class="mb-10px" type="danger">tips: 双击展示消息详情</el-text>
<!-- 搜索工作栏 -->
<el-form
class="-mb-15px"
:model="queryParams"
ref="queryFormRef"
:inline="true"
label-width="68px"
>
<el-form-item label="用户编号" prop="userId">
<el-input
v-model="queryParams.userId"
placeholder="请输入用户编号"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="用户类型" prop="userType">
<el-select
v-model="queryParams.userType"
placeholder="请选择用户类型"
clearable
class="!w-240px"
>
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.USER_TYPE)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="模板编码" prop="templateCode">
<el-input
v-model="queryParams.templateCode"
placeholder="请输入模板编码"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="模版类型" prop="templateType">
<el-select
v-model="queryParams.templateType"
placeholder="请选择模版类型"
clearable
class="!w-240px"
>
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_NOTIFY_TEMPLATE_TYPE)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="创建时间" prop="createTime">
<el-date-picker
v-model="queryParams.createTime"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
class="!w-240px"
/>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
</el-form-item>
</el-form>
</ContentWrap>
<!-- 列表 --> <!-- 列表 -->
<ContentWrap> <el-table
<el-table v-loading="loading" :data="list"> ref="tableRef"
<el-table-column label="编号" align="center" prop="id" /> v-loading="loading"
<el-table-column label="用户类型" align="center" prop="userType"> :data="list"
<template #default="scope"> row-key="id"
<dict-tag :type="DICT_TYPE.USER_TYPE" :value="scope.row.userType" /> @selection-change="handleSelectionChange"
</template> @row-dblclick="handleDetail"
</el-table-column> >
<el-table-column label="用户编号" align="center" prop="userId" width="80" /> <el-table-column type="selection" :selectable="selectable" reserve-selection width="60px" />
<el-table-column label="模板编码" align="center" prop="templateCode" width="80" /> <el-table-column label="类型" align="left" prop="messageTypeName" width="200px" />
<el-table-column label="发送人名称" align="center" prop="templateNickname" width="180" /> <el-table-column label="标题" align="left" prop="title" />
<el-table-column <el-table-column
label="模版内容" label="时间"
align="center" align="left"
prop="templateContent" prop="createTime"
width="200" width="180"
show-overflow-tooltip :formatter="dateFormatter"
/>
<el-table-column
label="模版参数"
align="center"
prop="templateParams"
width="180"
show-overflow-tooltip
>
<template #default="scope"> {{ scope.row.templateParams }}</template>
</el-table-column>
<el-table-column label="模版类型" align="center" prop="templateType" width="120">
<template #default="scope">
<dict-tag :type="DICT_TYPE.SYSTEM_NOTIFY_TEMPLATE_TYPE" :value="scope.row.templateType" />
</template>
</el-table-column>
<el-table-column label="是否已读" align="center" prop="readStatus" width="100">
<template #default="scope">
<dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.readStatus" />
</template>
</el-table-column>
<el-table-column
label="阅读时间"
align="center"
prop="readTime"
width="180"
:formatter="dateFormatter"
/>
<el-table-column
label="创建时间"
align="center"
prop="createTime"
width="180"
:formatter="dateFormatter"
/>
<el-table-column label="操作" align="center" fixed="right">
<template #default="scope">
<el-button
link
type="primary"
@click="openDetail(scope.row)"
v-hasPermi="['system:notify-message:query']"
>
详情
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<Pagination
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/> />
</ContentWrap> <el-table-column label="状态" align="left" width="100px">
<template #default="{ row }">
<!-- 表单弹窗详情 --> <el-tag :type="row.readStatus ? 'success' : 'info'">
<!-- <NotifyMessageDetail ref="detailRef" /> --> {{ row.readStatus ? '已读' : '未读' }}
</el-tag>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<Pagination
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</template> </template>
<script lang="ts" setup name="NotifyMessage"> <script lang="ts" setup name="NotifyMessage">
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
import { dateFormatter } from '@/utils/formatTime' import { dateFormatter } from '@/utils/formatTime'
import * as NotifyMessageApi from '@/api/system/notify/message' import * as NotifyMessageApi from '@/api/system/notify/message'
// import NotifyMessageDetail from './NotifyMessageDetail.vue' import { useUserStore } from '@/store/modules/user'
import { getGeneralSysDictData } from '@/api/system/dict/dict.data'
defineOptions({ name: 'SystemNotifyMessage' }) const router = useRouter()
const userStore = useUserStore()
const message = useMessage() // 消息
const loading = ref(true) // 列表的加载中 const loading = ref(true) // 列表的加载中
const total = ref(0) // 列表的总页数 const total = ref(0) // 列表的总页数
const list = ref([]) // 列表的数据 const list = ref<any[]>([]) // 列表的数据
const queryParams = reactive({ const queryParams = reactive({
pageNo: 1, pageNo: 1,
pageSize: 10, pageSize: 20,
userType: undefined, messageType: undefined,
userId: undefined, readStatus: undefined
templateCode: undefined,
templateType: undefined,
createTime: []
}) })
const queryFormRef = ref() // 搜索的表单 const queryFormRef = ref() // 搜索的表单
@@ -179,7 +100,10 @@ const queryFormRef = ref() // 搜索的表单
const getList = async () => { const getList = async () => {
loading.value = true loading.value = true
try { try {
const data = await NotifyMessageApi.getNotifyMessagePage(queryParams) const data = await NotifyMessageApi.getMyNotifyMessagePage({
...queryParams,
roleId: userStore.getUser?.currentRole
})
list.value = data.list list.value = data.list
total.value = data.total total.value = data.total
} finally { } finally {
@@ -187,26 +111,83 @@ const getList = async () => {
} }
} }
/** 某一行,是否允许选中 */
const selectable = (row: any) => {
return !row.readStatus
}
/** 搜索按钮操作 */ /** 搜索按钮操作 */
const handleQuery = () => { const handleQuery = () => {
queryParams.pageNo = 1 queryParams.pageNo = 1
getList() getList()
} }
/** 重置按钮操作 */ async function handleDetail(row: any) {
const resetQuery = () => { if (!row.readStatus) {
queryFormRef.value.resetFields() await handleReadOne(row.id)
handleQuery() }
const url = router.resolve({
path: '/nm-detail',
query: { id: row.id }
})
window.open(url.href, '_blank')
} }
/** 详情操作 */ const tableRef = ref() // 表格的 Ref
const detailRef = ref() const selectedIds = ref<number[]>([]) // 表格的选中 ID 数组
const openDetail = (data: NotifyMessageApi.NotifyMessageVO) => {
detailRef.value.open(data) /** 标记一条站内信已读 */
const handleReadOne = async (id: number) => {
await NotifyMessageApi.updateNotifyMessageRead({
ids: [id]
})
await getList()
}
/** 标记全部站内信已读 **/
const handleUpdateAll = async () => {
await NotifyMessageApi.updateAllNotifyMessageRead({
roleId: userStore.getUser?.currentRole
})
message.success('全部已读成功!')
tableRef.value.clearSelection()
await getList()
}
/** 标记一些站内信已读 **/
const handleUpdateList = async () => {
if (selectedIds.value.length === 0) {
return
}
await NotifyMessageApi.updateNotifyMessageRead({
ids: selectedIds.value,
roleId: userStore.getUser?.currentRole
})
message.success('批量已读成功!')
tableRef.value.clearSelection()
await getList()
}
/** 当表格选择项发生变化时会触发该事件 */
const handleSelectionChange = (array: NotifyMessageApi.NotifyMessageVO[]) => {
selectedIds.value = []
if (!array) {
return
}
array.forEach((row) => selectedIds.value.push(row.id))
}
const typeOptions = ref<any[]>([])
function getOptions() {
getGeneralSysDictData('message_type').then((data) => {
typeOptions.value = data
})
} }
/** 初始化 **/ /** 初始化 **/
onMounted(() => { onMounted(() => {
getOptions()
getList() getList()
}) })
</script> </script>

View File

@@ -0,0 +1,89 @@
<!--
* @Author: riverQiu
* @Date: 2024-09-11 18:42:37
* @LastEditors: riverQiu
* @LastEditTime: 2024-09-11 19:03:23
* @Description:
-->
<template>
<div class="container">
<ContentWrap style="max-width: 1000px; margin: 0 auto">
<div class="text-center">
<div class="mb-10px" style="font-size: 24px; letter-spacing: 2px">
{{ info.title }}
</div>
<el-text>
{{ formatDate(info.createTime, 'YYYY-MM-DD hh:mm:ss') }}
</el-text>
</div>
<el-divider direction="horizontal" />
<div v-dompurify-html="info.content"></div>
</ContentWrap>
</div>
</template>
<script setup name="NMDetail">
import { getNotifyMessageDetail, updateNotifyMessageRead } from '@/api/system/notify/message'
import { formatDate } from '@/utils/formatTime'
const route = useRoute()
const info = ref({})
function init() {
getNotifyMessageDetail(route.query.id).then((data) => {
info.value = data
if (!data.readStatus) {
handleReadOne(data.id)
}
})
}
/** 标记一条站内信已读 */
const handleReadOne = async (id) => {
await updateNotifyMessageRead({
ids: [id]
// roleId: userStore.getUser?.currentRole
})
await getList()
}
onMounted(() => {
init()
})
</script>
<style lang="scss" scoped>
.container {
padding: 20px;
max-height: 100%;
overflow-y: auto;
}
:deep(p) {
font-size: 14px;
}
:deep(table) {
margin-top: 10px;
border-collapse: separate;
text-indent: initial;
border-spacing: 1px;
text-align: left;
border-width: 1px;
box-sizing: border-box;
}
:deep(th) {
font-size: 14px;
text-align: left;
border-width: 1px;
box-sizing: border-box;
}
:deep(td) {
font-size: 12px;
text-align: left;
border-width: 1px;
box-sizing: border-box;
}
:deep(.el-card__body) {
padding: 20px 10px;
}
</style>