|
@@ -7,7 +7,7 @@
|
|
|
<el-form-item label="通知类型" prop="circularObj" :rules="[{ required: true, message: '请选择通知类型型', trigger: 'change' }]">
|
|
|
<el-select
|
|
|
v-model="state.ruleForm.circularObj"
|
|
|
- placeholder="请选择通知类型型"
|
|
|
+ placeholder="请选择通知类型"
|
|
|
value-key="dicDataValue"
|
|
|
class="w100"
|
|
|
@change="
|
|
@@ -42,8 +42,8 @@
|
|
|
placeholder="请选择失效时间"
|
|
|
value-format="YYYY-MM-DD[T]HH:mm:ss"
|
|
|
class="w100"
|
|
|
- :disabled-date="disabledDate"
|
|
|
- popper-class="no-atTheMoment"
|
|
|
+ :disabled-date="disabledDate"
|
|
|
+ popper-class="no-atTheMoment"
|
|
|
/>
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
@@ -67,71 +67,57 @@
|
|
|
<editor v-model:get-html="state.ruleForm.content" placeholder="请输入通知内容" height="450px" />
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
|
- <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
|
|
|
- <el-form-item label="通知对象" prop="circularType" :rules="[{ required: true, message: '请选择通知对象', trigger: 'change' }]">
|
|
|
- <el-select v-model="state.ruleForm.circularType" placeholder="请选择通知对象" class="w100">
|
|
|
- <el-option v-for="item in circularTypeEnum" :value="item.key" :key="item.key" :label="item.value" />
|
|
|
- </el-select>
|
|
|
- </el-form-item>
|
|
|
- </el-col>
|
|
|
- <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" v-if="state.ruleForm.circularType === 1">
|
|
|
- <el-divider content-position="left">
|
|
|
- <span>选择通知人</span>
|
|
|
- </el-divider>
|
|
|
+ <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
|
|
|
+ <el-form-item label="通知对象" prop="circularType" :rules="[{ required: true, message: '请选择通知对象', trigger: 'change' }]">
|
|
|
+ <el-radio-group v-model="state.ruleForm.circularType">
|
|
|
+ <el-radio :label="item.key" v-for="item in circularTypeEnum" :key="item.key">{{item.value}}</el-radio>
|
|
|
+ </el-radio-group>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col
|
|
|
+ :xs="24"
|
|
|
+ :sm="24"
|
|
|
+ :md="24"
|
|
|
+ :lg="24"
|
|
|
+ :xl="24"
|
|
|
+ v-if="state.ruleForm.circularType === 1"
|
|
|
+ style="border: var(--el-border); border-radius: var(--el-border-radius-base)"
|
|
|
+ class="pd15 mb20"
|
|
|
+ >
|
|
|
<div class="flex-center-align mb10">
|
|
|
- <el-input v-model="state.searchContent" placeholder="请输入搜索内容" class="w100" clearable>
|
|
|
+ <el-input v-model="state.searchContent" placeholder="通知人姓名/账号" class="w100" clearable>
|
|
|
<template #prefix>
|
|
|
<SvgIcon name="ele-Search" />
|
|
|
</template>
|
|
|
</el-input>
|
|
|
</div>
|
|
|
- <el-table :data="tables" @selection-change="handleSelectionChange" max-height="500" ref="multipleTableRef" row-key="id">
|
|
|
- <el-table-column type="selection" label="请选择" width="40" :reserve-selection="true" align="center" />
|
|
|
- <el-table-column prop="name" label="姓名" show-overflow-tooltip width="170"></el-table-column>
|
|
|
- <el-table-column prop="userName" label="账号" show-overflow-tooltip width="170"></el-table-column>
|
|
|
- <el-table-column prop="organization.name" label="所属部门" show-overflow-tooltip width="190"></el-table-column>
|
|
|
- <el-table-column prop="staffNo" label="工号" show-overflow-tooltip width="120"></el-table-column>
|
|
|
- <el-table-column prop="organization.orgTypeText" label="部门类别" show-overflow-tooltip></el-table-column>
|
|
|
- <template #empty>
|
|
|
- <Empty />
|
|
|
- </template>
|
|
|
- </el-table>
|
|
|
+ <div style="height: 400px">
|
|
|
+ <el-auto-resizer>
|
|
|
+ <template #default="{ height, width }">
|
|
|
+ <el-table-v2 :columns="columns" :data="tables" :width="width" :height="height" fixed />
|
|
|
+ </template>
|
|
|
+ </el-auto-resizer>
|
|
|
+ </div>
|
|
|
</el-col>
|
|
|
- <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12" v-if="state.ruleForm.circularType === 2">
|
|
|
- <el-form-item label="选择部门" prop="org" :rules="[{ required: true, message: '请选择部门', trigger: 'change' }]">
|
|
|
- <!-- <el-tree-select-->
|
|
|
- <!-- :props="{ label: 'name' }"-->
|
|
|
- <!-- node-key="id"-->
|
|
|
- <!-- class="w100"-->
|
|
|
- <!-- ref="treeSelectRef"-->
|
|
|
- <!-- v-model="state.ruleForm.org"-->
|
|
|
- <!-- :data="circularOrgOptions"-->
|
|
|
- <!-- multiple-->
|
|
|
- <!-- :render-after-expand="false"-->
|
|
|
- <!-- show-checkbox-->
|
|
|
- <!-- check-strictly-->
|
|
|
- <!-- default-expand-all-->
|
|
|
- <!-- filterable-->
|
|
|
- <!-- @check="selectOrg"-->
|
|
|
- <!-- collapse-tags-->
|
|
|
- <!-- collapse-tags-tooltip-->
|
|
|
- <!-- placeholder="请选择部门"-->
|
|
|
- <!-- />-->
|
|
|
- <el-cascader
|
|
|
- :options="circularOrgOptions"
|
|
|
- filterable
|
|
|
- :props="{ value: 'id', label: 'name', emitPath: false, multiple: true }"
|
|
|
- placeholder="请选择部门"
|
|
|
- class="w100"
|
|
|
- v-model="state.ruleForm.org"
|
|
|
- ref="treeSelectRef"
|
|
|
- collapse-tags
|
|
|
- collapse-tags-tooltip
|
|
|
- :max-collapse-tags="3"
|
|
|
- @change="selectOrg"
|
|
|
- >
|
|
|
- </el-cascader>
|
|
|
- </el-form-item>
|
|
|
+ <el-col
|
|
|
+ :xs="24"
|
|
|
+ :sm="24"
|
|
|
+ :md="24"
|
|
|
+ :lg="24"
|
|
|
+ :xl="24"
|
|
|
+ v-if="state.ruleForm.circularType === 2"
|
|
|
+ style="border: var(--el-border); border-radius: var(--el-border-radius-base)"
|
|
|
+ class="pd15 mb20"
|
|
|
+ >
|
|
|
+ <el-input v-model="query" placeholder="部门名称" @input="onQueryChanged" clearable class="mb10" />
|
|
|
+ <el-tree-v2
|
|
|
+ :data="circularOrgOptions"
|
|
|
+ :props="{ value: 'id', label: 'name' }"
|
|
|
+ show-checkbox
|
|
|
+ :height="400"
|
|
|
+ ref="treeSelectRef"
|
|
|
+ :filter-method="filterMethod"
|
|
|
+ />
|
|
|
</el-col>
|
|
|
</el-row>
|
|
|
</template>
|
|
@@ -168,8 +154,8 @@
|
|
|
placeholder="请选择失效时间"
|
|
|
value-format="YYYY-MM-DD[T]HH:mm:ss"
|
|
|
class="w100"
|
|
|
- :disabled-date="disabledDate"
|
|
|
- popper-class="no-atTheMoment"
|
|
|
+ :disabled-date="disabledDate"
|
|
|
+ popper-class="no-atTheMoment"
|
|
|
/>
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
@@ -212,13 +198,14 @@
|
|
|
</el-dialog>
|
|
|
</template>
|
|
|
|
|
|
-<script setup lang="ts" name="noticeDetail">
|
|
|
-import { reactive, ref, defineAsyncComponent, computed } from 'vue';
|
|
|
+<script setup lang="tsx" name="noticeDetail">
|
|
|
+import { reactive, ref, defineAsyncComponent, computed, unref, FunctionalComponent, Ref } from 'vue';
|
|
|
import '@wangeditor/editor/dist/css/style.css'; // 引入 css
|
|
|
import { bulletinAdd, bulletinAddBaseData, circularAdd, circularAddBaseData, getAllUsers } from '/@/api/auxiliary/notice';
|
|
|
import { throttle } from '/@/utils/tools';
|
|
|
-import { ElMessage, FormInstance } from 'element-plus';
|
|
|
-import {disabledDate} from "/@/utils/constants";
|
|
|
+import { CheckboxValueType, ElMessage, FormInstance } from 'element-plus';
|
|
|
+import { disabledDate } from '/@/utils/constants';
|
|
|
+import { ElCheckbox } from 'element-plus';
|
|
|
// 引入组件
|
|
|
const Editor = defineAsyncComponent(() => import('/@/components/Editor/index.vue')); // 富文本编辑器
|
|
|
// 定义子组件向父组件传值/事件
|
|
@@ -289,39 +276,108 @@ const changeOrg = () => {
|
|
|
const currentNode = orgRef.value.getCheckedNodes();
|
|
|
state.ruleForm.sourceOrgName = currentNode[0].label;
|
|
|
};
|
|
|
-const tables = computed(() => {
|
|
|
- // 模糊搜索
|
|
|
- if (!state.searchContent) return userTables.value;
|
|
|
- // filter() 方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。
|
|
|
- // 注意: filter() 不会对空数组进行检测。
|
|
|
- // 注意: filter() 不会改变原始数组。
|
|
|
- return userTables.value.filter((data: any) => {
|
|
|
- // some() 方法用于检测数组中的元素是否满足指定条件;
|
|
|
- // some() 方法会依次执行数组的每个元素:
|
|
|
- // 如果有一个元素满足条件,则表达式返回true , 剩余的元素不会再执行检测;
|
|
|
- // 如果没有满足条件的元素,则返回false。
|
|
|
- // 注意: some() 不会对空数组进行检测。
|
|
|
- // 注意: some() 不会改变原始数组。
|
|
|
- return Object.keys(data).some((key) => {
|
|
|
- // indexOf() 返回某个指定的字符在某个字符串中首次出现的位置,如果没有找到就返回-1;
|
|
|
- // 该方法对大小写敏感!所以之前需要toLowerCase()方法将所有查询到内容变为小写。
|
|
|
- return String(data[key]).toLowerCase().indexOf(state.searchContent) > -1;
|
|
|
- });
|
|
|
- });
|
|
|
-});
|
|
|
-// 选择用户(账号)
|
|
|
-const multipleSelection = ref<any[]>([]); // 选中的数据
|
|
|
-const multipleTableRef = ref<RefType>(); // 表格ref
|
|
|
-const handleSelectionChange = (row: any) => {
|
|
|
- if (row) {
|
|
|
- multipleSelection.value = row;
|
|
|
- }
|
|
|
+
|
|
|
+type SelectionCellProps = {
|
|
|
+ value: boolean;
|
|
|
+ intermediate?: boolean;
|
|
|
+ onChange: (value: CheckboxValueType) => void;
|
|
|
};
|
|
|
+
|
|
|
+const SelectionCell: FunctionalComponent<SelectionCellProps> = ({ value, intermediate = false, onChange }) => {
|
|
|
+ return <ElCheckbox onChange={onChange} modelValue={value} indeterminate={intermediate} />;
|
|
|
+};
|
|
|
+const tables = computed({
|
|
|
+ get() {
|
|
|
+ // 注意: filter() 不会改变原始数组。
|
|
|
+ // 模糊搜索
|
|
|
+ if (!state.searchContent) return userTables.value;
|
|
|
+ // filter() 方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。
|
|
|
+ // 注意: filter() 不会对空数组进行检测。
|
|
|
+ return userTables.value.filter((data: any) => {
|
|
|
+ // some() 方法用于检测数组中的元素是否满足指定条件;
|
|
|
+ // some() 方法会依次执行数组的每个元素:
|
|
|
+ // 如果有一个元素满足条件,则表达式返回true , 剩余的元素不会再执行检测;
|
|
|
+ // 如果没有满足条件的元素,则返回false。
|
|
|
+ // 注意: some() 不会对空数组进行检测。
|
|
|
+ // 注意: some() 不会改变原始数组。
|
|
|
+ return Object.keys(data).some((key) => {
|
|
|
+ // indexOf() 返回某个指定的字符在某个字符串中首次出现的位置,如果没有找到就返回-1;
|
|
|
+ // 该方法对大小写敏感!所以之前需要toLowerCase()方法将所有查询到内容变为小写。
|
|
|
+ return String(data[key]).toLowerCase().indexOf(state.searchContent) > -1;
|
|
|
+ });
|
|
|
+ });
|
|
|
+ },
|
|
|
+ set(val) {
|
|
|
+ // userTables.value = val;
|
|
|
+ },
|
|
|
+});
|
|
|
+const columns = [
|
|
|
+ {
|
|
|
+ key: 'selection',
|
|
|
+ width: 50,
|
|
|
+ align: 'center',
|
|
|
+ cellRenderer: ({ rowData }) => {
|
|
|
+ const onChange = (value: CheckboxValueType) => (rowData.checked = value);
|
|
|
+ return <SelectionCell value={rowData.checked} onChange={onChange} />;
|
|
|
+ },
|
|
|
+ headerCellRenderer: () => {
|
|
|
+ const _data = unref(tables);
|
|
|
+ const onChange = (value: CheckboxValueType) =>
|
|
|
+ (tables.value = _data.map((row) => {
|
|
|
+ row.checked = value;
|
|
|
+ return row;
|
|
|
+ }));
|
|
|
+ const allSelected = _data.every((row) => row.checked);
|
|
|
+ const containsChecked = _data.some((row) => row.checked);
|
|
|
+
|
|
|
+ return <SelectionCell value={allSelected} intermediate={containsChecked && !allSelected} onChange={onChange} />;
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ key: 'name',
|
|
|
+ dataKey: 'name',
|
|
|
+ title: '姓名',
|
|
|
+ width: 300,
|
|
|
+ align: 'center',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ key: 'name',
|
|
|
+ dataKey: 'userName',
|
|
|
+ title: '账号',
|
|
|
+ width: 150,
|
|
|
+ align: 'center',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ key: 'organization.name',
|
|
|
+ dataKey: 'organization.name',
|
|
|
+ title: '所属部门',
|
|
|
+ width: 150,
|
|
|
+ align: 'center',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ key: 'staffNo',
|
|
|
+ dataKey: 'staffNo',
|
|
|
+ title: '工号',
|
|
|
+ width: 100,
|
|
|
+ align: 'center',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ key: 'organization.orgTypeText',
|
|
|
+ dataKey: 'organization.orgTypeText',
|
|
|
+ title: '部门类别',
|
|
|
+ width: 100,
|
|
|
+ align: 'center',
|
|
|
+ },
|
|
|
+];
|
|
|
+
|
|
|
+const query = ref('');
|
|
|
// 选择部门
|
|
|
const treeSelectRef = ref<RefType>();
|
|
|
-const selectOrgArray = ref<EmptyArrayType>([]);
|
|
|
-const selectOrg = () => {
|
|
|
- selectOrgArray.value = treeSelectRef.value.getCheckedNodes();
|
|
|
+const onQueryChanged = (query: string) => {
|
|
|
+ treeSelectRef.value!.filter(query);
|
|
|
+};
|
|
|
+const filterMethod = (query: string, node: any) => {
|
|
|
+ return node.name!.includes(query);
|
|
|
};
|
|
|
// 保存
|
|
|
const onSubmit = throttle(async (formEl: FormInstance | undefined) => {
|
|
@@ -331,18 +387,22 @@ const onSubmit = throttle(async (formEl: FormInstance | undefined) => {
|
|
|
loading.value = true;
|
|
|
switch (dialogTitle.value) {
|
|
|
case '新增通知':
|
|
|
- if (state.ruleForm.circularType === 1 && !multipleSelection.value.length) {
|
|
|
- ElMessage.error('请选择通知人');
|
|
|
+ const checkedTable = tables.value?.filter((item: any) => item.checked).map((item: any) => item);
|
|
|
+ const nodes = treeSelectRef.value?.getCheckedNodes();
|
|
|
+ if (state.ruleForm.circularType === 1 && !checkedTable.length) {
|
|
|
+ ElMessage.warning('请选择通知人');
|
|
|
+ loading.value = false;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (state.ruleForm.circularType === 2 && !nodes.length) {
|
|
|
+ ElMessage.warning('请选择通知部门');
|
|
|
+ loading.value = false;
|
|
|
return;
|
|
|
}
|
|
|
- if (state.ruleForm.circularType === 2 && !multipleSelection.value.length) {
|
|
|
- ElMessage.error('请选择通知部门');
|
|
|
- return;
|
|
|
- }
|
|
|
let circularReadGroups: { userId: any; userName: any }[] | { orgId: any; orgName: any }[] = [];
|
|
|
if (state.ruleForm.circularType === 1) {
|
|
|
//个人
|
|
|
- circularReadGroups = multipleSelection.value.map((item: any) => {
|
|
|
+ circularReadGroups = checkedTable.map((item: any) => {
|
|
|
return {
|
|
|
userId: item.id,
|
|
|
userName: item.name,
|
|
@@ -350,11 +410,11 @@ const onSubmit = throttle(async (formEl: FormInstance | undefined) => {
|
|
|
});
|
|
|
} else if (state.ruleForm.circularType === 2) {
|
|
|
// 部门
|
|
|
- circularReadGroups = selectOrgArray.value.map((item: any) => {
|
|
|
- return {
|
|
|
- orgId: item.value,
|
|
|
- orgName: item.label,
|
|
|
- };
|
|
|
+ circularReadGroups = nodes.map((item: any) => {
|
|
|
+ return {
|
|
|
+ orgId: item.id,
|
|
|
+ orgName: item.name,
|
|
|
+ };
|
|
|
});
|
|
|
}
|
|
|
const circularRequest = {
|
|
@@ -367,7 +427,7 @@ const onSubmit = throttle(async (formEl: FormInstance | undefined) => {
|
|
|
lostEfficacyTime: state.ruleForm.lostEfficacyTime,
|
|
|
sourceOrgId: state.ruleForm.sourceOrgId,
|
|
|
sourceOrgName: state.ruleForm.sourceOrgName,
|
|
|
- circularReadGroups,
|
|
|
+ circularReadGroups,
|
|
|
};
|
|
|
circularAdd(circularRequest)
|
|
|
.then(() => {
|
|
@@ -416,7 +476,7 @@ const closeDialog = () => {
|
|
|
state.dialogVisible = false;
|
|
|
};
|
|
|
const close = () => {
|
|
|
- ruleFormRef.value?.clearValidate();
|
|
|
+ ruleFormRef.value?.clearValidate();
|
|
|
ruleFormRef.value?.resetFields();
|
|
|
};
|
|
|
// 暴露变量
|