管理员-通知公告

This commit is contained in:
曹磊 2024-09-04 22:09:14 +08:00
parent 9b000143ee
commit e968810260
15 changed files with 999 additions and 248 deletions

View File

@ -117,6 +117,7 @@ public class SysAnnouncementController {
Result<IPage<SysAnnouncement>> result = new Result<IPage<SysAnnouncement>>(); Result<IPage<SysAnnouncement>> result = new Result<IPage<SysAnnouncement>>();
sysAnnouncement.setDelFlag(CommonConstant.DEL_FLAG_0.toString()); sysAnnouncement.setDelFlag(CommonConstant.DEL_FLAG_0.toString());
QueryWrapper<SysAnnouncement> queryWrapper = QueryGenerator.initQueryWrapper(sysAnnouncement, req.getParameterMap()); QueryWrapper<SysAnnouncement> queryWrapper = QueryGenerator.initQueryWrapper(sysAnnouncement, req.getParameterMap());
queryWrapper.orderByDesc("create_time");
Page<SysAnnouncement> page = new Page<SysAnnouncement>(pageNo,pageSize); Page<SysAnnouncement> page = new Page<SysAnnouncement>(pageNo,pageSize);
IPage<SysAnnouncement> pageList = sysAnnouncementService.page(page, queryWrapper); IPage<SysAnnouncement> pageList = sysAnnouncementService.page(page, queryWrapper);
result.setSuccess(true); result.setSuccess(true);
@ -256,7 +257,7 @@ public class SysAnnouncementController {
sysAnnouncement.setSender(currentUserName); sysAnnouncement.setSender(currentUserName);
boolean ok = sysAnnouncementService.updateById(sysAnnouncement); boolean ok = sysAnnouncementService.updateById(sysAnnouncement);
if(ok) { if(ok) {
result.success("系统通知推送成功"); result.success("通知推送成功");
if(sysAnnouncement.getMsgType().equals(CommonConstant.MSG_TYPE_ALL)) { if(sysAnnouncement.getMsgType().equals(CommonConstant.MSG_TYPE_ALL)) {
// 补全公告和用户之前的关系 // 补全公告和用户之前的关系
sysAnnouncementService.batchInsertSysAnnouncementSend(sysAnnouncement.getId(), sysAnnouncement.getTenantId()); sysAnnouncementService.batchInsertSysAnnouncementSend(sysAnnouncement.getId(), sysAnnouncement.getTenantId());
@ -315,7 +316,7 @@ public class SysAnnouncementController {
sysAnnouncement.setCancelTime(new Date()); sysAnnouncement.setCancelTime(new Date());
boolean ok = sysAnnouncementService.updateById(sysAnnouncement); boolean ok = sysAnnouncementService.updateById(sysAnnouncement);
if(ok) { if(ok) {
result.success("系统通知撤销成功"); result.success("通知撤销成功");
if (oConvertUtils.isNotEmpty(sysAnnouncement.getDtTaskId())) { if (oConvertUtils.isNotEmpty(sysAnnouncement.getDtTaskId())) {
try { try {
dingtalkService.recallMessage(sysAnnouncement.getDtTaskId()); dingtalkService.recallMessage(sysAnnouncement.getDtTaskId());

View File

@ -133,6 +133,28 @@ public class SysUserController {
return sysUserService.queryPageList(req, queryWrapper, pageSize, pageNo); return sysUserService.queryPageList(req, queryWrapper, pageSize, pageNo);
} }
/**
* 获取租户下专家数据
* @param user
* @param pageNo
* @param pageSize
* @param req
* @return
*/
@RequestMapping(value = "/expertList", method = RequestMethod.GET)
public Result<IPage<SysUser>> queryExpertPageList(SysUser user,@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
@RequestParam(name="pageSize", defaultValue="10") Integer pageSize,HttpServletRequest req) {
List<String> userIds = new ArrayList<>();
//------------------------------------------------------------------------------------------------
//是否开启系统管理模块的多租户数据隔离SAAS多租户模式
if (MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL) {
String tenantId = oConvertUtils.getString(TenantContext.getTenant(), "-1");
userIds = userTenantService.getUserIdsByTenantId(Integer.valueOf(tenantId));
}
//------------------------------------------------------------------------------------------------
return sysUserService.queryExpertPageList(pageSize, pageNo, userIds, req);
}
/** /**
* 获取系统用户数据查询全部用户不做租户隔离 * 获取系统用户数据查询全部用户不做租户隔离
* *

View File

@ -222,4 +222,13 @@ public interface SysUserMapper extends BaseMapper<SysUser> {
*/ */
@Select("select id,phone from sys_user where phone = #{phone} and username = #{username}") @Select("select id,phone from sys_user where phone = #{phone} and username = #{username}")
SysUser getUserByNameAndPhone(@Param("phone") String phone, @Param("username") String username); SysUser getUserByNameAndPhone(@Param("phone") String phone, @Param("username") String username);
/**
* 根据用户Ids,查询橘色下用户信息
* @param userIds
* @param username 用户账户名称
* @param realname 用户姓名
* @return
*/
IPage<SysUser> queryExpertPageList(Page page,@Param("userIds")List<String> userIds,@Param("username") String username,@Param("realname") String realname);
} }

View File

@ -298,4 +298,30 @@
and sut.tenant_id=#{tenantId} and sut.tenant_id=#{tenantId}
and sut.status = '1' and sut.status = '1'
</select> </select>
<!-- 通过多个用户IDS查询角色下的用户信息 -->
<select id="queryExpertPageList" resultType="org.jeecg.modules.system.entity.SysUser">
select * from sys_user
where id in (
select user_id from sys_user_role x inner join sys_role y on x.role_id = y.id and y.role_name = '专家'
)
and del_flag = 0
<if test="userIds!=null and userIds.size()>0">
and id in (
<foreach collection="userIds" index="index" item="id" open="(" separator="," close=")">
#{id}
</foreach>
)
</if>
<if test="username!=null and username!=''">
<bind name="bindusername" value="'%'+username+'%'"/>
and username like #{bindusername}
</if>
<if test="realname!=null and realname!=''">
<bind name="bindrealname" value="'%'+realname+'%'"/>
and realname like #{bindrealname}
</if>
order by create_time
</select>
</mapper> </mapper>

View File

@ -44,6 +44,16 @@ public interface ISysUserService extends IService<SysUser> {
*/ */
Result<IPage<SysUser>> queryPageList(HttpServletRequest req, QueryWrapper<SysUser> queryWrapper, Integer pageSize, Integer pageNo); Result<IPage<SysUser>> queryPageList(HttpServletRequest req, QueryWrapper<SysUser> queryWrapper, Integer pageSize, Integer pageNo);
/**
* 查询专家数据列表
*
* @param pageSize
* @param pageNo
* @param req
* @return
*/
Result<IPage<SysUser>> queryExpertPageList(Integer pageSize, Integer pageNo,List<String> userIds, HttpServletRequest req);
/** /**
* 重置密码 * 重置密码
* *

View File

@ -233,6 +233,17 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
return result; return result;
} }
@Override
public Result<IPage<SysUser>> queryExpertPageList(Integer pageSize, Integer pageNo,List<String> userIds, HttpServletRequest req) {
String username = req.getParameter("username");
String realname = req.getParameter("realname");
Result<IPage<SysUser>> result = new Result<IPage<SysUser>>();
Page<SysUser> page = new Page<SysUser>(pageNo, pageSize);
IPage<SysUser> pageList = userMapper.queryExpertPageList(page, userIds, username, realname);
result.setSuccess(true);
result.setResult(pageList);
return result;
}
@Override @Override
@CacheEvict(value = {CacheConstant.SYS_USERS_CACHE}, allEntries = true) @CacheEvict(value = {CacheConstant.SYS_USERS_CACHE}, allEntries = true)

View File

@ -14,6 +14,7 @@ enum Api {
getDictItems = '/sys/dict/getDictItems/', getDictItems = '/sys/dict/getDictItems/',
getTableList = '/sys/user/queryUserComponentData', getTableList = '/sys/user/queryUserComponentData',
getCategoryData = '/sys/category/loadAllData', getCategoryData = '/sys/category/loadAllData',
expertList = '/sys/user/expertList',
} }
/** /**
@ -37,6 +38,14 @@ export const getUserList = (params) => {
return defHttp.get({ url: Api.userList, params }); return defHttp.get({ url: Api.userList, params });
}; };
/**
*
* @param params
*/
export const getExpertList = (params) => {
return defHttp.get({ url: Api.expertList, params });
};
/** /**
* *
* @param params * @param params

View File

@ -39,6 +39,7 @@ import { CountdownInput } from '/@/components/CountDown';
//自定义组件 //自定义组件
// import JAreaLinkage from './jeecg/components/JAreaLinkage.vue'; // import JAreaLinkage from './jeecg/components/JAreaLinkage.vue';
import JSelectUser from './jeecg/components/JSelectUser.vue'; import JSelectUser from './jeecg/components/JSelectUser.vue';
import JSelectExpert from './jeecg/components/JSelectExpert.vue';
import JSelectPosition from './jeecg/components/JSelectPosition.vue'; import JSelectPosition from './jeecg/components/JSelectPosition.vue';
import JSelectRole from './jeecg/components/JSelectRole.vue'; import JSelectRole from './jeecg/components/JSelectRole.vue';
import JImageUpload from './jeecg/components/JImageUpload.vue'; import JImageUpload from './jeecg/components/JImageUpload.vue';
@ -122,6 +123,7 @@ componentMap.set(
); );
componentMap.set('JSelectPosition', JSelectPosition); componentMap.set('JSelectPosition', JSelectPosition);
componentMap.set('JSelectUser', JSelectUser); componentMap.set('JSelectUser', JSelectUser);
componentMap.set('JSelectExpert', JSelectExpert);
componentMap.set('JSelectRole', JSelectRole); componentMap.set('JSelectRole', JSelectRole);
componentMap.set('JImageUpload', JImageUpload); componentMap.set('JImageUpload', JImageUpload);
componentMap.set('JDictSelectTag', JDictSelectTag); componentMap.set('JDictSelectTag', JDictSelectTag);

View File

@ -0,0 +1,222 @@
<!--用户选择组件-->
<template>
<div class="JselectUser">
<JSelectBiz @change="handleSelectChange" @handleOpen="handleOpen" :loading="loadingEcho" v-bind="attrs"></JSelectBiz>
<!-- update-begin--author:liaozhiyang---date:20240515---forQQYUN-9260必填模式下会影响到弹窗内antd组件的样式 -->
<a-form-item>
<ExpertSelectModal
:rowKey="rowKey"
@register="regModal"
@getSelectResult="setValue"
v-bind="getBindValue"
:excludeUserIdList="excludeUserIdList"
@close="handleClose"
/>
</a-form-item>
<!-- update-end--author:liaozhiyang---date:20240515---forQQYUN-9260必填模式下会影响到弹窗内antd组件的样式 -->
</div>
</template>
<script lang="ts">
import { unref } from 'vue';
import ExpertSelectModal from './modal/ExpertSelectModal.vue';
import JSelectBiz from './base/JSelectBiz.vue';
import { defineComponent, ref, reactive, watchEffect, watch, provide } from 'vue';
import { useModal } from '/@/components/Modal';
import { propTypes } from '/@/utils/propTypes';
import { useRuleFormItem } from '/@/hooks/component/useFormItem';
import { useAttrs } from '/@/hooks/core/useAttrs';
import { SelectValue } from 'ant-design-vue/es/select';
import { cloneDeep } from 'lodash-es';
export default defineComponent({
name: 'JSelectUser',
components: {
ExpertSelectModal,
JSelectBiz,
},
inheritAttrs: false,
props: {
value: propTypes.oneOfType([propTypes.string, propTypes.array]),
labelKey: {
type: String,
default: 'realname',
},
rowKey: {
type: String,
default: 'username',
},
params: {
type: Object,
default: () => {},
},
//update-begin---author:wangshuai ---date:20230703 forQQYUN-56855------------
//id
excludeUserIdList:{
type: Array,
default: () => [],
}
//update-end---author:wangshuai ---date:20230703 forQQYUN-56855------------
},
emits: ['options-change', 'change', 'update:value'],
setup(props, { emit }) {
const emitData = ref<any[]>();
//model
const [regModal, { openModal }] = useModal();
//
// const [state] = useRuleFormItem(props, 'value', 'change', emitData);
//
const selectOptions = ref<SelectValue>([]);
//
let selectValues = reactive<Recordable>({
value: [],
change: false,
});
let tempSave: any = [];
//
const loadingEcho = ref<boolean>(false);
// selectOptions,xxxBiz
provide('selectOptions', selectOptions);
// selectValues,xxxBiz
provide('selectValues', selectValues);
// loadingEcho,xxxBiz
provide('loadingEcho', loadingEcho);
const tag = ref(false);
const attrs = useAttrs();
/**
* 监听组件值
*/
watchEffect(() => {
// update-begin--author:liaozhiyang---date:20240611---forTV360X-576
//update-begin-author:liusq---date:2024-06-03--for: [TV360X-840]
tempSave = [];
//update-end-author:liusq---date:2024-06-03--for:[TV360X-840]
// update-end--author:liaozhiyang---date:20240611---forTV360X-576
props.value && initValue();
//
if (!props.value) {
selectValues.value = [];
}
});
/**
* 监听selectValues变化
*/
// watch(selectValues, () => {
// if (selectValues) {
// state.value = selectValues.value;
// }
// });
//update-begin---author:wangshuai ---date:20230703 forQQYUN-56855------------
const excludeUserIdList = ref<any>([]);
/**
* 需要监听一下excludeUserIdList否则modal获取不到
*/
watch(()=>props.excludeUserIdList,(data)=>{
excludeUserIdList.value = data;
},{ immediate: true })
//update-end---author:wangshuai ---date:20230703 forQQYUN-56855------------
/**
* 打卡弹出框
*/
function handleOpen() {
tag.value = true;
openModal(true, {
isUpdate: false,
});
}
/**
* 将字符串值转化为数组
*/
function initValue() {
let value = props.value ? props.value : [];
if (value && typeof value === 'string' && value != 'null' && value != 'undefined') {
// state.value = value.split(',');
selectValues.value = value.split(',');
tempSave = value.split(',');
} else {
// VUEN-857
selectValues.value = value;
tempSave = cloneDeep(value);
}
}
/**
* 设置下拉框的值
*/
function setValue(options, values) {
selectOptions.value = options;
//emitData.value = values.join(",");
// state.value = values;
selectValues.value = values;
send(values);
}
const getBindValue = Object.assign({}, unref(props), unref(attrs));
// update-begin--author:liaozhiyang---date:20240517---forQQYUN-9366
const handleClose = () => {
if (tempSave.length) {
selectValues.value = cloneDeep(tempSave);
} else {
send(tempSave);
}
};
const handleSelectChange = (values) => {
tempSave = cloneDeep(values);
send(tempSave);
};
const send = (values) => {
let result = typeof props.value == "string" ? values.join(',') : values;
emit('update:value', result);
emit('change', result);
};
// update-end--author:liaozhiyang---date:20240517---forQQYUN-9366
return {
// state,
attrs,
selectOptions,
getBindValue,
selectValues,
loadingEcho,
tag,
regModal,
setValue,
handleOpen,
excludeUserIdList,
handleClose,
handleSelectChange,
};
},
});
</script>
<style lang="less" scoped>
// update-begin--author:liaozhiyang---date:20240515---forQQYUN-9260antd
.JselectUser {
> .ant-form-item {
display: none;
}
}
// update-end--author:liaozhiyang---date:20240515---forQQYUN-9260antd
.j-select-row {
@width: 82px;
.left {
width: calc(100% - @width - 8px);
}
.right {
width: @width;
}
.full {
width: 100%;
}
:deep(.ant-select-search__field) {
display: none !important;
}
}
</style>

View File

@ -0,0 +1,293 @@
<!--用户选择框-->
<template>
<div>
<BasicModal
v-bind="$attrs"
@register="register"
:title="modalTitle"
:width="showSelected ? '1200px' : '900px'"
wrapClassName="j-user-select-modal"
@ok="handleOk"
@cancel="handleCancel"
:maxHeight="maxHeight"
:centered="true"
destroyOnClose
@visible-change="visibleChange"
>
<a-row>
<a-col :span="showSelected ? 18 : 24">
<BasicTable
ref="tableRef"
:columns="columns"
:scroll="tableScroll"
v-bind="getBindValue"
:useSearchForm="true"
:formConfig="formConfig"
:api="getExpertList"
:searchInfo="searchInfo"
:rowSelection="rowSelection"
:indexColumnProps="indexColumnProps"
:afterFetch="afterFetch"
>
<!-- update-begin-author:taoyan date:2022-5-25 for: VUEN-1112一对多 用户选择 未显示选择条数及清空 -->
<template #tableTitle></template>
<!-- update-end-author:taoyan date:2022-5-25 for: VUEN-1112一对多 用户选择 未显示选择条数及清空 -->
</BasicTable>
</a-col>
<a-col :span="showSelected ? 6 : 0">
<BasicTable
v-bind="selectedTable"
:dataSource="selectRows"
:useSearchForm="true"
:formConfig="{ showActionButtonGroup: false, baseRowStyle: { minHeight: '40px' } }"
>
<!--操作栏-->
<template #action="{ record }">
<a href="javascript:void(0)" @click="handleDeleteSelected(record)"><Icon icon="ant-design:delete-outlined"></Icon></a>
</template>
</BasicTable>
</a-col>
</a-row>
</BasicModal>
</div>
</template>
<script lang="ts">
import { defineComponent, unref, ref, watch } from 'vue';
import { BasicModal, useModalInner } from '/@/components/Modal';
import { getExpertList } from '/@/api/common/api';
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
import { useSelectBiz } from '/@/components/Form/src/jeecg/hooks/useSelectBiz';
import { useAttrs } from '/@/hooks/core/useAttrs';
import { selectProps } from '/@/components/Form/src/jeecg/props/props';
export default defineComponent({
name: 'UserSelectModal',
components: {
//BasicTable
BasicModal,
BasicTable: createAsyncComponent(() => import('/@/components/Table/src/BasicTable.vue'), {
loading: true,
}),
},
props: {
...selectProps,
//
modalTitle: {
type: String,
default: '选择用户',
},
//update-begin---author:wangshuai ---date:20230703 forQQYUN-56855------------
//id
excludeUserIdList: {
type: Array,
default: [],
},
//update-end---author:wangshuai ---date:20230703 forQQYUN-56855------------
},
emits: ['register', 'getSelectResult', 'close'],
setup(props, { emit, refs }) {
// update-begin-author:taoyan date:2022-5-24 for: VUEN-1086
const tableScroll = ref<any>({ x: false });
const tableRef = ref();
const maxHeight = ref(600);
//
const [register, { closeModal }] = useModalInner(() => {
if (window.innerWidth < 900) {
tableScroll.value = { x: 900 };
} else {
tableScroll.value = { x: false };
}
//update-begin-author:taoyan date:2022-6-2 for: VUEN-1112
setTimeout(() => {
if (tableRef.value) {
tableRef.value.setSelectedRowKeys(selectValues['value'] || []);
}
}, 800);
//update-end-author:taoyan date:2022-6-2 for: VUEN-1112
});
// update-end-author:taoyan date:2022-5-24 for: VUEN-1086
const attrs = useAttrs();
//
const config = {
canResize: false,
bordered: true,
size: 'small',
};
const getBindValue = Object.assign({}, unref(props), unref(attrs), config);
const [{ rowSelection, visibleChange, selectValues, indexColumnProps, getSelectResult, handleDeleteSelected, selectRows }] = useSelectBiz(
getExpertList,
getBindValue,
emit
);
const searchInfo = ref(props.params);
// update-begin--author:liaozhiyang---date:20230811---forissues/657
watch(rowSelection.selectedRowKeys, (newVal) => {
//update-begin---author:wangshuai ---date: 20230829 fornull------------
if(tableRef.value){
tableRef.value.setSelectedRowKeys(newVal);
}
//update-end---author:wangshuai ---date: 20230829 fornull------------
});
// update-end--author:liaozhiyang---date:20230811---forissues/657
//form
const formConfig = {
baseColProps: {
xs: 24,
sm: 8,
md: 6,
lg: 8,
xl: 6,
xxl: 6,
},
//update-begin-author:taoyan date:2022-5-24 for: VUEN-1086 ---
actionColOptions: {
xs: 24,
sm: 8,
md: 8,
lg: 8,
xl: 8,
xxl: 8,
},
//update-end-author:taoyan date:2022-5-24 for: VUEN-1086 ---
schemas: [
{
label: '账号',
field: 'username',
component: 'JInput',
},
{
label: '姓名',
field: 'realname',
component: 'JInput',
},
],
};
//
const columns = [
{
title: '用户账号',
dataIndex: 'username',
width: 120,
align: 'left',
},
{
title: '用户姓名',
dataIndex: 'realname',
width: 120,
},
{
title: '性别',
dataIndex: 'sex_dictText',
width: 50,
},
{
title: '手机号码',
dataIndex: 'phone',
width: 120,
},
{
title: '邮箱',
dataIndex: 'email',
// width: 40,
},
{
title: '状态',
dataIndex: 'status_dictText',
width: 80,
},
];
//table
const selectedTable = {
pagination: false,
showIndexColumn: false,
scroll: { y: 390 },
size: 'small',
canResize: false,
bordered: true,
rowKey: 'id',
columns: [
{
title: '用户姓名',
dataIndex: 'realname',
width: 40,
},
{
title: '操作',
dataIndex: 'action',
align: 'center',
width: 40,
slots: { customRender: 'action' },
},
],
};
/**
* 确定选择
*/
function handleOk() {
getSelectResult((options, values) => {
//
emit('getSelectResult', options, values);
//
closeModal();
});
}
//update-begin---author:wangshuai ---date:20230703 forQQYUN-56855------------
/**
* 用户返回结果逻辑查询
*/
function afterFetch(record) {
let excludeList = props.excludeUserIdList;
if(!excludeList){
return record;
}
let arr:any[] = [];
//id
if(excludeList.length>0 && record && record.length>0){
for(let item of record){
if(excludeList.indexOf(item.id)<0){
arr.push({...item})
}
}
return arr;
}
return record;
}
// update-begin--author:liaozhiyang---date:20240517---forQQYUN-9366
const handleCancel = () => {
emit('close');
};
// update-end--author:liaozhiyang---date:20240517---forQQYUN-9366
//update-end---author:wangshuai ---date:20230703 forQQYUN-56855------------
// update-begin--author:liaozhiyang---date:20240607---forTV360X-30510
const clientHeight = document.documentElement.clientHeight * 200;
maxHeight.value = clientHeight > 600 ? 600 : clientHeight;
// update-end--author:liaozhiyang---date:20240607---forTV360X-30510
return {
//config,
handleOk,
searchInfo,
register,
indexColumnProps,
visibleChange,
getBindValue,
getExpertList,
formConfig,
columns,
rowSelection,
selectRows,
selectedTable,
handleDeleteSelected,
tableScroll,
tableRef,
afterFetch,
handleCancel,
maxHeight,
};
},
});
</script>

View File

@ -118,6 +118,7 @@ export type ComponentType =
| 'JSelectPosition' | 'JSelectPosition'
| 'JSelectRole' | 'JSelectRole'
| 'JSelectUser' | 'JSelectUser'
| 'JSelectExpert'
| 'JImageUpload' | 'JImageUpload'
| 'JDictSelectTag' | 'JDictSelectTag'
| 'JSelectDept' | 'JSelectDept'

View File

@ -1,24 +1,39 @@
<template> <template>
<BasicModal v-bind="$attrs" @register="registerModal" title="查看详情" :showCancelBtn="false" :showOkBtn="false" :maxHeight="500"> <BasicModal v-bind="$attrs" @register="registerModal" title="查看详情" :showCancelBtn="false" :showOkBtn="false" width="900px">
<iframe :src="frameSrc" class="detail-iframe" /> <BasicForm @register="registerForm" disabled />
</BasicModal> </BasicModal>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { BasicModal, useModalInner } from '/@/components/Modal'; import { ref, computed, unref } from 'vue';
import { propTypes } from '/@/utils/propTypes'; import { BasicModal, useModalInner } from '/@/components/Modal';
// props import { BasicForm, useForm } from '/@/components/Form/index';
defineProps({ import { formSchema } from './notice.data';
frameSrc: propTypes.string.def(''),
}); //
const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({
schemas: formSchema,
showActionButtonGroup: false,
});
//
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
//
await resetFields();
setModalProps({ confirmLoading: false });
if (data.record.userIds) {
data.record.userIds = data.record.userIds.substring(0, data.record.userIds.length - 1);
}
// //
const [registerModal] = useModalInner(); await setFieldsValue({
...data.record,
});
});
</script> </script>
<style scoped lang="less"> <style scoped lang="less">
.detail-iframe { .detail-iframe {
border: 0; border: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
min-height: 500px; min-height: 500px;
} }
</style> </style>

View File

@ -4,57 +4,57 @@
</BasicModal> </BasicModal>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, computed, unref } from 'vue'; import { ref, computed, unref } from 'vue';
import { BasicModal, useModalInner } from '/@/components/Modal'; import { BasicModal, useModalInner } from '/@/components/Modal';
import { BasicForm, useForm } from '/@/components/Form/index'; import { BasicForm, useForm } from '/@/components/Form/index';
import { formSchema } from './notice.data'; import { formSchema } from './notice.data';
import { saveOrUpdate } from './notice.api'; import { saveOrUpdate } from './notice.api';
// Emits // Emits
const emit = defineEmits(['register', 'success']); const emit = defineEmits(['register', 'success']);
const isUpdate = ref(true); const isUpdate = ref(true);
// //
const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({ const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({
schemas: formSchema, schemas: formSchema,
showActionButtonGroup: false, showActionButtonGroup: false,
}); });
// //
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => { const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
// //
await resetFields(); await resetFields();
setModalProps({ confirmLoading: false }); setModalProps({ confirmLoading: false });
isUpdate.value = !!data?.isUpdate; isUpdate.value = !!data?.isUpdate;
if (unref(isUpdate)) { if (unref(isUpdate)) {
if (data.record.userIds) { if (data.record.userIds) {
data.record.userIds = data.record.userIds.substring(0, data.record.userIds.length - 1); data.record.userIds = data.record.userIds.substring(0, data.record.userIds.length - 1);
}
//
await setFieldsValue({
...data.record,
});
}
});
//
const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑'));
//
async function handleSubmit(v) {
try {
let values = await validate();
setModalProps({ confirmLoading: true });
//
//update-begin-author:liusq---date:20230404--for: [issue#429]undefined ---
if(values.msgType==='ALL'){
values.userIds = '';
}else{
values.userIds += ',';
}
//update-end-author:liusq---date:20230404--for: [issue#429]undefined ---
await saveOrUpdate(values, isUpdate.value);
//
closeModal();
//
emit('success');
} finally {
setModalProps({ confirmLoading: false });
} }
//
await setFieldsValue({
...data.record,
});
} }
});
//
const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑'));
//
async function handleSubmit(v) {
try {
let values = await validate();
setModalProps({ confirmLoading: true });
//
//update-begin-author:liusq---date:20230404--for: [issue#429]undefined ---
if(values.msgType==='ALL'){
values.userIds = '';
}else{
values.userIds += ',';
}
//update-end-author:liusq---date:20230404--for: [issue#429]undefined ---
await saveOrUpdate(values, isUpdate.value);
//
closeModal();
//
emit('success');
} finally {
setModalProps({ confirmLoading: false });
}
}
</script> </script>

View File

@ -1,168 +1,296 @@
<template> <template>
<div> <div>
<BasicTable @register="registerTable" :rowSelection="rowSelection"> <div class="table-container">
<template #tableTitle> <div class="title-form">
<a-button preIcon="ant-design:plus-outlined" type="primary" @click="handleAdd">新建</a-button> <a-row>
<!-- <a-button type="primary" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button>--> <a-col :span="2" class="item-text-right">标题</a-col>
<!-- <j-upload-button type="primary" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button>--> <a-col :span="6">
<a-dropdown v-if="selectedRowKeys.length > 0"> <j-input style="width: 80%;!important;" placeholder="请输入标题" v-model:value="titile"></j-input>
<template #overlay> </a-col>
<a-menu> <a-col :span="10">
<a-menu-item key="1" @click="batchHandleDelete"> <a-button style="margin-left: 8px" preIcon="ant-design:search-outlined" type="primary" @click="handleSelect">查询</a-button>
<Icon icon="ant-design:delete-outlined"></Icon> <a-button style="margin-left: 8px" preIcon="ic:baseline-restart-alt" @click="handleClear">重置</a-button>
删除 </a-col>
</a-menu-item> </a-row>
</a-menu> </div>
</template> <div class="item-table" v-loading="tableDataLoading">
<a-button <div v-if="noticeList.length > 0">
>批量操作 <a-row style="padding: 10px 0px;">
<Icon style="fontsize: 12px" icon="ant-design:down-outlined"></Icon> <a-col :span="6">
</a-button> <a-button preIcon="ant-design:plus-outlined" type="primary" @click="handleAdd">新建</a-button>
</a-dropdown> </a-col>
</template> </a-row>
<template #action="{ record }"> <div v-for="notice in noticeList">
<TableAction :actions="getActions(record)" :dropDownActions="getDropDownAction(record)" /> <a-row class="item-header-border">
</template> <a-col :span="16">
</BasicTable> <span class="item-title">{{notice.titile}}{{showDictValue(notice.sendStatus, statusData)}}</span>
<NoticeModal @register="registerModal" @success="reload" /> </a-col>
<DetailModal @register="register" :frameSrc="iframeUrl" /> <a-col :span="8" class="item-text-right">
<a-button v-if="notice.sendStatus!=1" class="item-button-border" type="link" @click="handleEdit(notice)">编辑</a-button>
<a-button v-if="notice.sendStatus!=1" class="item-button-border" type="link" @click="handleDelete(notice)">删除</a-button>
<a-button v-if="notice.sendStatus!=1" class="item-button-border" type="link" @click="handleRelease(notice)">发布</a-button>
<a-button v-if="notice.sendStatus==1" class="item-button-border" type="link" @click="handleDetail(notice)">详情</a-button>
<a-button v-if="notice.sendStatus==1" class="item-button-border" type="link" @click="handleReturn(notice)">撤回</a-button>
</a-col>
</a-row>
<a-row class="item-content-border">
<a-col :span="24">
<div class="item-content" v-html="notice.msgContent"></div>
</a-col>
</a-row>
<a-row class="item-bottom-border">
<a-col :span="24">
<div class="item-text-right item-padding-right item-bottom">{{notice.createTime}}</div>
</a-col>
</a-row>
</div>
<div class="item-text-right item-padding-right">
<a-pagination
v-model:current="pageNo"
v-model:page-size-options="pageSizeOptions"
v-model:pageSize="pageSize"
v-model:total="total"
size="small"
show-size-changer
show-quick-jumper
:show-total="total => `共 ${total} 条数据`"
@change="onChange"
/>
</div>
</div>
<div v-if="noticeList.length == 0">
<a-empty style="padding-top: 100px;">
<template #description>
<p>
通知通告空空如也
</p>
<p>
尽快给专家发送通知通告吧
</p>
</template>
<a-button type="primary">新建通知</a-button>
</a-empty>
</div>
</div>
</div>
<DetailModal @register="detailModal"/>
<NoticeModal @register="noticeModal" @success="handleSelect" />
</div> </div>
</template> </template>
<script lang="ts" name="system-notice" setup> <script lang="ts" name="system-notice" setup>
import { ref } from 'vue'; import {createVNode, onMounted, ref} from 'vue';
import { BasicTable, TableAction } from '/@/components/Table'; import { Modal } from 'ant-design-vue';
import { useModal } from '/@/components/Modal'; import {JInput} from '/@/components/Form';
import NoticeModal from './NoticeModal.vue'; import {defHttp} from "@/utils/http/axios";
import DetailModal from './DetailModal.vue'; import { Pagination } from 'ant-design-vue';
import { useMethods } from '/@/hooks/system/useMethods'; import {getToken} from "@/utils/auth";
import { useGlobSetting } from '/@/hooks/setting'; import {useModal} from "@/components/Modal";
import { getToken } from '/@/utils/auth'; import DetailModal from './DetailModal.vue';
import { columns, searchFormSchema } from './notice.data'; import NoticeModal from './NoticeModal.vue';
import { getList, deleteNotice, batchDeleteNotice, getExportUrl, getImportUrl, doReleaseData, doReovkeData } from './notice.api'; import {useGlobSetting} from "@/hooks/setting";
import { useListPage } from '/@/hooks/system/useListPage'; import {ExclamationCircleOutlined} from "@ant-design/icons-vue";
const glob = useGlobSetting(); const glob = useGlobSetting();
const [registerModal, { openModal }] = useModal(); const [detailModal, { openModal: openDetail }] = useModal();
const [register, { openModal: openDetail }] = useModal(); const [noticeModal, { openModal }] = useModal();
const iframeUrl = ref(''); const iframeUrl = ref('');
const APagination = Pagination;
// onMounted(()=>{
const { prefixCls, onExportXls, onImportXls, tableContext, doRequest } = useListPage({ handleClear();
designScope: 'notice-template', })
tableProps: {
title: '消息通知', const statusData = ref([{id:'0',value:'草稿'},{id:'1',value:'已发布'},{id:'2',value:'已撤销'}]);
api: getList,
columns: columns, //
formConfig: { const pageNo = ref<number>(1);
schemas: searchFormSchema, //
}, const pageSize = ref<number>(10);
}, //
exportConfig: { const pageSizeOptions = ref<any>(['10', '20', '50', '100']);
name: '消息通知列表', //
url: getExportUrl, const total = ref<number>(1);
},
importConfig: { let titile = ref('');
url: getImportUrl, const noticeList = ref<any>([]);
}, const tableDataLoading = ref(false);
const onChange = (pageNumber: number) => {
handleSelect();
};
function showDictValue(data, datas){
const dictItem = datas.find(item => data === item.id);
return dictItem ? dictItem.value : '';
}
function handleSelect() {
tableDataLoading.value = true;
noticeList.value = [];
let params = {
"titile":titile.value,
"pageNo":pageNo.value,
"pageSize":pageSize.value,
}
defHttp.get({ url: "/sys/annountCement/list", params:params}).then((res)=>{
noticeList.value = res.records;
total.value = res.total;
}); });
tableDataLoading.value = false;
}
const [registerTable, { reload }, { rowSelection, selectedRowKeys }] = tableContext; function handleClear() {
titile.value = '';
pageNo.value = 1;
pageSize.value = 10;
handleSelect();
}
/** //
* 新增事件 function handleDetail(record){
*/ openDetail(true,{
function handleAdd() { record,
openModal(true, { isUpdate: true,
isUpdate: false, showFooter: true,
}); });
} }
/** //
* 编辑事件 function handleAdd(){
*/ openModal(true, {
function handleEdit(record) { isUpdate: false,
openModal(true, { });
record, }
isUpdate: true,
});
}
/** //
* 删除事件 function handleEdit(record){
*/ openModal(true, {
async function handleDelete(record) { record,
await deleteNotice({ id: record.id }, reload); isUpdate: true,
} });
}
//
function handleDelete(record){
Modal.confirm({
title: '确定删除该通知吗?',
icon: createVNode(ExclamationCircleOutlined),
onOk() {
let params = {"id":record.id}
return defHttp.delete({ url: "/sys/annountCement/delete", data: params }, { joinParamsToUrl: true }).then(() => {
handleSelect();
});
},
onCancel() {},
});
}
//
function handleRelease(record){
Modal.confirm({
title: '确定发布该通知吗?',
icon: createVNode(ExclamationCircleOutlined),
onOk() {
let params = {"id":record.id}
defHttp.get({ url: "/sys/annountCement/doReleaseData", params }).then(()=>{
handleSelect();
});
},
onCancel() {},
});
}
//
function handleReturn(record){
Modal.confirm({
title: '确定撤回该通知吗?',
icon: createVNode(ExclamationCircleOutlined),
onOk() {
let params = {"id":record.id}
defHttp.get({ url: "/sys/annountCement/doReovkeData", params }).then(()=>{
handleSelect();
});
},
onCancel() {},
});
}
/**
* 批量删除事件
*/
async function batchHandleDelete() {
doRequest(() => batchDeleteNotice({ ids: selectedRowKeys.value }));
}
/**
* 发布
*/
async function handleRelease(id) {
await doReleaseData({ id });
reload();
}
/**
* 撤销
*/
async function handleReovke(id) {
await doReovkeData({ id });
reload();
}
/**
* 查看
*/
function handleDetail(record) {
iframeUrl.value = `${glob.uploadUrl}/sys/annountCement/show/${record.id}?token=${getToken()}`;
openDetail(true);
}
/**
* 操作列定义
* @param record
*/
function getActions(record) {
return [
{
label: '编辑',
onClick: handleEdit.bind(null, record),
ifShow: record.sendStatus == 0,
},
];
}
/**
* 下拉操作栏
*/
function getDropDownAction(record) {
return [
{
label: '删除',
ifShow: record.sendStatus != 1,
popConfirm: {
title: '是否确认删除',
confirm: handleDelete.bind(null, record),
},
},
{
label: '发布',
ifShow: record.sendStatus == 0,
onClick: handleRelease.bind(null, record.id),
},
{
label: '撤销',
ifShow: record.sendStatus == 1,
popConfirm: {
title: '确定要撤销吗?',
confirm: handleReovke.bind(null, record.id),
},
},
{
label: '查看',
onClick: handleDetail.bind(null, record),
},
];
}
</script> </script>
<style lang="less">
.table-container {
padding: 10px;
}
.title-form{
padding: 8px 10px 8px 10px;
margin-bottom: 8px;
background-color: #ffffff;
border-radius: 2px;
line-height: 46px;
}
.item-table{
padding: 6px;
background-color: #ffffff;
border-radius: 2px;
min-height: 600px;
}
.item-header-border{
border-style: solid;
border-top-width: 1px;
border-bottom-width: 0px;
border-left-width: 1px;
border-right-width: 1px;
border-color: #333333;
}
.item-content-border{
border-style: solid;
border-top-width: 1px;
border-bottom-width: 1px;
border-left-width: 1px;
border-right-width: 1px;
border-color: #333333;
}
.item-bottom-border{
border-style: solid;
border-top-width: 0px;
border-bottom-width: 1px;
border-left-width: 1px;
border-right-width: 1px;
border-color: #333333;
margin-bottom: 30px;
}
.item-button-border{
border-style: solid;
border-left-width: 1px;
border-color: #e5e7eb;
}
.item-text-right{
text-align: right;
}
.item-title{
font-weight: bold;
font-size: 16px;
padding-left: 10px;
}
.item-content{
padding: 10px;
}
.item-bottom{
line-height: 30px;
}
.item-padding-right{
padding-right: 8px;
}
</style>

View File

@ -86,6 +86,7 @@ export const formSchema: FormSchema[] = [
dictCode: 'msg_category', dictCode: 'msg_category',
placeholder: '请选择类型', placeholder: '请选择类型',
}, },
show: false,
}, },
{ {
field: 'titile', field: 'titile',
@ -96,12 +97,12 @@ export const formSchema: FormSchema[] = [
placeholder: '请输入标题', placeholder: '请输入标题',
}, },
}, },
{ // {
field: 'msgAbstract', // field: 'msgAbstract',
label: '摘要', // label: '摘要',
component: 'InputTextArea', // component: 'InputTextArea',
required: true, // required: true,
}, // },
// { // {
// field: 'endTime', // field: 'endTime',
// label: '截至日期', // label: '截至日期',
@ -116,7 +117,7 @@ export const formSchema: FormSchema[] = [
{ {
field: 'msgType', field: 'msgType',
label: '接收用户', label: '接收用户',
defaultValue: 'ALL', defaultValue: 'USER',
component: 'JDictSelectTag', component: 'JDictSelectTag',
required: true, required: true,
componentProps: { componentProps: {
@ -124,33 +125,34 @@ export const formSchema: FormSchema[] = [
dictCode: 'msg_type', dictCode: 'msg_type',
placeholder: '请选择发布范围', placeholder: '请选择发布范围',
}, },
show: false,
}, },
{ {
field: 'userIds', field: 'userIds',
label: '指定用户', label: '指定专家',
component: 'JSelectUser', component: 'JSelectExpert',
required: true, required: true,
componentProps: { componentProps: {
rowKey: 'id', rowKey: 'id',
labelKey: 'username', labelKey: 'realname',
}, },
ifShow: ({ values }) => values.msgType == 'USER', ifShow: ({ values }) => values.msgType == 'USER',
}, },
{ // {
field: 'priority', // field: 'priority',
label: '优先级', // label: '优先级',
defaultValue: 'H', // defaultValue: 'H',
component: 'JDictSelectTag', // component: 'JDictSelectTag',
componentProps: { // componentProps: {
dictCode: 'priority', // dictCode: 'priority',
type: 'radio', // type: 'radio',
placeholder: '请选择优先级', // placeholder: '请选择优先级',
}, // },
}, // },
{ {
field: 'msgContent', field: 'msgContent',
label: '内容', label: '内容',
component: 'Input', component: 'JEditor',
render: render.renderTinymce, // render: render.renderTinymce,
}, },
]; ];