mirror of
				https://github.com/continew-org/continew-admin-ui.git
				synced 2025-11-04 10:57:08 +08:00 
			
		
		
		
	merge dev into dev
feat: 新增用户选择器 通知公告可以指定通知范围 Created-by: kiki1373639299 Author-id: 86659 MR-id: 188386 Commit-by: KAI Merged-by: Charles_7c E2E-issues: Description: <!-- 非常感谢您的 PR!在提交之前,请务必确保您 PR 的代码经过了完整测试,并且通过了代码规范检查。 --> <!-- 在 [] 中输入 x 来勾选) --> ## PR 类型 <!-- 您的 PR 引入了哪种类型的变更? --> <!-- 只支持选择一种类型,如果有多种类型,可以在更新日志中增加 “类型” 列。 --> - [X] 新 feature - [ ] Bug 修复 - [ ] 功能增强 - [ ] 文档变更 - [ ] 代码样式变更 - [ ] 重构 - [ ] 性能改进 - [ ] 单元测试 - [ ] CI/CD - [ ] 其他 ## PR 目的 <!-- 描述一下您的 PR 解决了什么问题。如果可以,请链接到相关 issues。 --> ## 解决方案 <!-- 详细描述您是如何解决的问题 --> ## PR 测试 <!-- 如果可以,请为您的 PR 添加或更新单元测试。 --> <!-- 请描述一下您是如何测试 PR 的。例如:创建/更新单元测试或添加相关的截图。 --> ## Changelog | 模块 | Changelog | Related issues | |-----|-----------| -------------- | | src/api/system | 新增查询用户列表接口 以及通知公告字段类型变更 | | | src/component/UserSelect | 新增用户选择器 | | | src/view/system/notice/add | 适配用户选择器 以及新增通知范围 | | <!-- 如果有多种类型的变更,可以在变更日志表中增加 “类型” 列,该列的值与上方 “PR 类型” 相同。 --> <!-- Related issues 格式为 Closes #<issue号>,或者 Fixes #<issue号>,或者 Resolves #<issue号>。 --> ## 其他信息 <!-- 请描述一下还有哪些注意事项。例如:如果引入了一个不向下兼容的变更,请描述其影响。 --> ## 提交前确认 - [X] PR 代码经过了完整测试,并且通过了代码规范检查 - [ ] 已经完整填写 Changelog,并链接到了相关 issues - [X] PR 代码将要提交到 dev 分支 See merge request: continew/continew-admin-ui!1
This commit is contained in:
		@@ -40,6 +40,7 @@ export interface UserQuery {
 | 
			
		||||
  createTime?: Array<string>
 | 
			
		||||
  deptId?: string
 | 
			
		||||
  sort: Array<string>
 | 
			
		||||
  userIds?: Array<string>
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface UserPageQuery extends UserQuery, PageQuery {
 | 
			
		||||
@@ -190,6 +191,8 @@ export interface NoticeResp {
 | 
			
		||||
  type: string
 | 
			
		||||
  effectiveTime: string
 | 
			
		||||
  terminateTime: string
 | 
			
		||||
  noticeScope: number
 | 
			
		||||
  noticeUsers: Array<string>
 | 
			
		||||
  createUserString: string
 | 
			
		||||
  createTime: string
 | 
			
		||||
  updateUserString: string
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,9 @@ const BASE_URL = '/system/user'
 | 
			
		||||
export function listUser(query: T.UserPageQuery) {
 | 
			
		||||
  return http.get<PageRes<T.UserResp[]>>(`${BASE_URL}`, query)
 | 
			
		||||
}
 | 
			
		||||
export function listAllUser(query: Partial<T.UserPageQuery>) {
 | 
			
		||||
  return http.get<T.UserResp[]>(`${BASE_URL}/list`, query)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** @desc 查询用户详情 */
 | 
			
		||||
export function getUser(id: string) {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										238
									
								
								src/components/UserSelect/component/UserSelectContent.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										238
									
								
								src/components/UserSelect/component/UserSelectContent.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,238 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="container">
 | 
			
		||||
    <a-row :gutter="16">
 | 
			
		||||
      <a-col :span="24" :md="5" class="section">
 | 
			
		||||
        <a-input v-model="searchKey" placeholder="请输入部门名称" allow-clear>
 | 
			
		||||
          <template #prefix>
 | 
			
		||||
            <icon-search />
 | 
			
		||||
          </template>
 | 
			
		||||
        </a-input>
 | 
			
		||||
        <a-tree
 | 
			
		||||
            ref="treeRef"
 | 
			
		||||
            :data="treeData"
 | 
			
		||||
            block-node
 | 
			
		||||
            @select="handleDeptSelect"
 | 
			
		||||
        />
 | 
			
		||||
      </a-col>
 | 
			
		||||
 | 
			
		||||
      <a-col :span="24" :md="14" class="section">
 | 
			
		||||
        <GiTable
 | 
			
		||||
            v-model:selectedKeys="selectedKeys"
 | 
			
		||||
            style="min-height: 600px;"
 | 
			
		||||
            row-key="id"
 | 
			
		||||
            :data="dataList"
 | 
			
		||||
            :columns="tableColumns"
 | 
			
		||||
            :loading="loading"
 | 
			
		||||
            :scroll="{ x: '100%', y: '100%' }"
 | 
			
		||||
            :pagination="pagination"
 | 
			
		||||
            :disabled-tools="['size', 'fullscreen', 'setting', 'refresh']"
 | 
			
		||||
            :row-selection="{ type: props.multiple ? 'checkbox' : 'radio', showCheckedAll: true }"
 | 
			
		||||
            @select="onRowSelect"
 | 
			
		||||
            @select-all="onTableSelectAll"
 | 
			
		||||
            @refresh="search"
 | 
			
		||||
        >
 | 
			
		||||
          <template #top>
 | 
			
		||||
            <div>
 | 
			
		||||
              <a-space class="mt-5">
 | 
			
		||||
                <a-input v-model="queryForm.description" placeholder="用户名/昵称/描述" />
 | 
			
		||||
                <a-button @click="search">
 | 
			
		||||
                  <template #icon>
 | 
			
		||||
                    <icon-search />
 | 
			
		||||
                  </template>
 | 
			
		||||
                </a-button>
 | 
			
		||||
                <a-button @click="onRefresh">
 | 
			
		||||
                  <template #icon>
 | 
			
		||||
                    <icon-refresh />
 | 
			
		||||
                  </template>
 | 
			
		||||
                </a-button>
 | 
			
		||||
              </a-space>
 | 
			
		||||
            </div>
 | 
			
		||||
            <a-alert class="mt-5">
 | 
			
		||||
              <template v-if="selectedKeys.length > 0">
 | 
			
		||||
                已选中{{ selectedKeys.length }}条记录(可跨页)
 | 
			
		||||
              </template>
 | 
			
		||||
              <template v-else>
 | 
			
		||||
                未选中任何项目
 | 
			
		||||
              </template>
 | 
			
		||||
              <template v-if="selectedKeys.length > 0" #action>
 | 
			
		||||
                <a-link @click="onClearSelected">清空</a-link>
 | 
			
		||||
              </template>
 | 
			
		||||
            </a-alert>
 | 
			
		||||
          </template>
 | 
			
		||||
 | 
			
		||||
          <template #status="{ record }">
 | 
			
		||||
            <GiCellStatus :status="record.status" />
 | 
			
		||||
          </template>
 | 
			
		||||
        </GiTable>
 | 
			
		||||
      </a-col>
 | 
			
		||||
 | 
			
		||||
      <a-col :span="24" :md="5" class="section">
 | 
			
		||||
        <a-card title="已选用户">
 | 
			
		||||
          <a-table :columns="rightColumn" :data="selectedData">
 | 
			
		||||
            <template #action="{ record }">
 | 
			
		||||
              <a-button @click="handleDeleteSelectUser(record)">
 | 
			
		||||
                <icon-delete />
 | 
			
		||||
              </a-button>
 | 
			
		||||
            </template>
 | 
			
		||||
          </a-table>
 | 
			
		||||
        </a-card>
 | 
			
		||||
      </a-col>
 | 
			
		||||
    </a-row>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import type { TreeNodeData } from '@arco-design/web-vue'
 | 
			
		||||
import { useDept } from '@/hooks/app'
 | 
			
		||||
import { useTable } from '@/hooks'
 | 
			
		||||
import { listAllUser, listUser } from '@/apis'
 | 
			
		||||
import type { UserItem, UserSelectPropType } from '@/components/UserSelect/type'
 | 
			
		||||
 | 
			
		||||
const props = withDefaults(defineProps<UserSelectPropType & { selectedUsers: string | string[] }>(), {
 | 
			
		||||
  multiple: false,
 | 
			
		||||
  selectedUsers: () => []
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
const emit = defineEmits(['update:selectedUsers'])
 | 
			
		||||
 | 
			
		||||
// 查询表单引用
 | 
			
		||||
const queryForm = ref({ description: '' })
 | 
			
		||||
 | 
			
		||||
// 部门树引用
 | 
			
		||||
const treeRef = ref()
 | 
			
		||||
const selectedKeys = ref<string[]>([])
 | 
			
		||||
const selectedDeptId = ref<string>('')
 | 
			
		||||
const selectedData = ref<any[]>([])
 | 
			
		||||
 | 
			
		||||
const { tableData: dataList, loading, pagination, search } = useTable(
 | 
			
		||||
  (page) => listUser({ ...queryForm.value, deptId: selectedDeptId.value, sort: [], ...page }),
 | 
			
		||||
  { immediate: false, formatResult: (data) => data.map((i) => ({ ...i, disabled: false })) }
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// 刷新表单
 | 
			
		||||
const onRefresh = () => {
 | 
			
		||||
  queryForm.value.description = ''
 | 
			
		||||
  search()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 使用 useDept 钩子获取部门列表数据
 | 
			
		||||
const { deptList, getDeptList } = useDept({
 | 
			
		||||
  onSuccess: () => {
 | 
			
		||||
    nextTick(() => treeRef.value?.expandAll(true))
 | 
			
		||||
  }
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
// 部门树过滤函数
 | 
			
		||||
const deptTreeSearch = (keyword: string, data: TreeNodeData[]): TreeNodeData[] => {
 | 
			
		||||
  return data
 | 
			
		||||
    .map((item) => ({
 | 
			
		||||
      ...item,
 | 
			
		||||
      children: item.children ? deptTreeSearch(keyword, item.children) : []
 | 
			
		||||
    }))
 | 
			
		||||
    .filter(
 | 
			
		||||
      (item) =>
 | 
			
		||||
        item.title?.toLowerCase().includes(keyword.toLowerCase()) || item.children?.length
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 过滤树数据
 | 
			
		||||
const searchKey = ref('')
 | 
			
		||||
const treeData = computed(() => {
 | 
			
		||||
  return searchKey.value ? deptTreeSearch(searchKey.value, deptList.value) : deptList.value
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
// 表格列定义
 | 
			
		||||
const tableColumns = [
 | 
			
		||||
  { title: '昵称', dataIndex: 'nickname' },
 | 
			
		||||
  { title: '部门', dataIndex: 'deptName' },
 | 
			
		||||
  { title: '角色', dataIndex: 'roleNames' },
 | 
			
		||||
  { title: '手机号', dataIndex: 'phone' },
 | 
			
		||||
  { title: '邮箱', dataIndex: 'email' },
 | 
			
		||||
  { title: '状态', dataIndex: 'status', slotName: 'status' }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
// 右侧已选用户列定义
 | 
			
		||||
const rightColumn = [
 | 
			
		||||
  { title: '昵称', dataIndex: 'nickname' },
 | 
			
		||||
  { title: '操作', dataIndex: 'action', slotName: 'action' }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
// 处理部门选择
 | 
			
		||||
const handleDeptSelect = (keys: Array<any>) => {
 | 
			
		||||
  selectedDeptId.value = keys[0] || ''
 | 
			
		||||
  search()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const emitSelectedUsers = () => {
 | 
			
		||||
  emit('update:selectedUsers', selectedKeys.value)
 | 
			
		||||
}
 | 
			
		||||
// 从选中列表中移除用户
 | 
			
		||||
const handleDeleteSelectUser = (user: UserItem) => {
 | 
			
		||||
  selectedData.value = selectedData.value.filter((item) => item.id !== user.id)
 | 
			
		||||
  selectedKeys.value = selectedData.value.map((item) => item.id)
 | 
			
		||||
  emitSelectedUsers()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 行选择事件
 | 
			
		||||
const onRowSelect = (rowKeys: string[], rowKey: string, record: UserItem) => {
 | 
			
		||||
  selectedData.value = props.multiple
 | 
			
		||||
    ? rowKeys.includes(rowKey)
 | 
			
		||||
      ? [...selectedData.value, record]
 | 
			
		||||
      : selectedData.value.filter((item) => item.id !== rowKey)
 | 
			
		||||
    : [record]
 | 
			
		||||
 | 
			
		||||
  selectedKeys.value = selectedData.value.map((item) => item.id)
 | 
			
		||||
  emitSelectedUsers()
 | 
			
		||||
}
 | 
			
		||||
// 全选事件
 | 
			
		||||
const onTableSelectAll = (checked: boolean) => {
 | 
			
		||||
  selectedData.value = checked
 | 
			
		||||
    ? [...selectedData.value, ...dataList.value.filter((item) => !selectedKeys.value.includes(item.id))]
 | 
			
		||||
    : []
 | 
			
		||||
  selectedKeys.value = selectedData.value.map((item) => item.id)
 | 
			
		||||
  emitSelectedUsers()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 清空所有选中数据
 | 
			
		||||
const onClearSelected = () => {
 | 
			
		||||
  selectedData.value = []
 | 
			
		||||
  selectedKeys.value = []
 | 
			
		||||
  emitSelectedUsers()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 初始化函数
 | 
			
		||||
const init = (selectUsers: string[]) => {
 | 
			
		||||
  getDeptList()
 | 
			
		||||
  search()
 | 
			
		||||
  if (selectUsers && selectUsers.length > 0) {
 | 
			
		||||
    // admin的id是number 不是string 类型 所以处理一下
 | 
			
		||||
    listAllUser({ userIds: selectUsers }).then((dataList) => {
 | 
			
		||||
      selectedData.value = dataList.data.map((data) => {
 | 
			
		||||
        return { ...data, id: `${data.id}` }
 | 
			
		||||
      })
 | 
			
		||||
    })
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
watch(() => props.selectedUsers, (newValue) => {
 | 
			
		||||
  const newSelectedKeys = Array.isArray(newValue) ? newValue : [newValue]
 | 
			
		||||
  selectedKeys.value = newSelectedKeys.filter(Boolean)
 | 
			
		||||
  selectedData.value = dataList.value.filter((item) => selectedKeys.value.includes(item.id))
 | 
			
		||||
}, { immediate: true })
 | 
			
		||||
 | 
			
		||||
defineExpose({ init, onClearSelected })
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped>
 | 
			
		||||
.container {
 | 
			
		||||
  padding: 20px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.section {
 | 
			
		||||
  margin-bottom: 20px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.mt-5 {
 | 
			
		||||
  margin-top: 5px;
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										110
									
								
								src/components/UserSelect/index.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								src/components/UserSelect/index.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,110 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div>
 | 
			
		||||
    <div style="display: flex;">
 | 
			
		||||
      <a-select
 | 
			
		||||
          v-model="selectedUsers"
 | 
			
		||||
          :allow-clear="true"
 | 
			
		||||
          :multiple="props.multiple"
 | 
			
		||||
          :max-tag-count="4"
 | 
			
		||||
          :field-names="{ value: 'id', label: 'nickname' }"
 | 
			
		||||
          :options="options"
 | 
			
		||||
          @change="handleSelectChange"
 | 
			
		||||
      />
 | 
			
		||||
      <a-tooltip content="选择用户">
 | 
			
		||||
        <a-button @click="onOpen">
 | 
			
		||||
          <template #icon>
 | 
			
		||||
            <icon-plus />
 | 
			
		||||
          </template>
 | 
			
		||||
        </a-button>
 | 
			
		||||
      </a-tooltip>
 | 
			
		||||
    </div>
 | 
			
		||||
    <a-modal
 | 
			
		||||
        v-model:visible="visible"
 | 
			
		||||
        title="用户选择"
 | 
			
		||||
        :width="width >= 1350 ? 1350 : '100%'"
 | 
			
		||||
        :esc-to-close="true"
 | 
			
		||||
        @ok="handleModalOk"
 | 
			
		||||
    >
 | 
			
		||||
      <UserSelectContent
 | 
			
		||||
          ref="userSelectContentRef"
 | 
			
		||||
          :value="selectedUsers"
 | 
			
		||||
          :multiple="props.multiple"
 | 
			
		||||
          :selected-users="selectedUsers"
 | 
			
		||||
          @update:selected-users="updateSelectedUsers"
 | 
			
		||||
      />
 | 
			
		||||
    </a-modal>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { useWindowSize } from '@vueuse/core'
 | 
			
		||||
import UserSelectContent from './component/UserSelectContent.vue'
 | 
			
		||||
import { type UserResp, listAllUser } from '@/apis'
 | 
			
		||||
import type { UserSelectPropType } from '@/components/UserSelect/type'
 | 
			
		||||
 | 
			
		||||
const props = withDefaults(defineProps<UserSelectPropType>(), {
 | 
			
		||||
  multiple: false, // 是否支持多选
 | 
			
		||||
  value: ''
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
const emit = defineEmits(['update:value'])
 | 
			
		||||
 | 
			
		||||
const visible = ref<boolean>(false) // 控制弹窗显示的状态
 | 
			
		||||
const { width } = useWindowSize() // 获取窗口的宽度,用于设置弹窗宽度
 | 
			
		||||
const options = ref<UserResp[]>([]) // 保存用户选项列表
 | 
			
		||||
const userSelectContentRef = ref() // 引用 UserSelectContent 组件实例
 | 
			
		||||
const selectedUsers = ref<string[]>([]) // 保存已选择的用户
 | 
			
		||||
// 打开用户选择弹窗
 | 
			
		||||
const onOpen = () => {
 | 
			
		||||
  visible.value = true
 | 
			
		||||
  userSelectContentRef.value.init(selectedUsers.value) // 调用子组件的初始化方法
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 发出数据更新事件
 | 
			
		||||
const emitDataChange = () => {
 | 
			
		||||
  emit('update:value', selectedUsers.value.filter(Boolean)) // 发出更新事件
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 处理用户选择变更事件
 | 
			
		||||
const handleSelectChange = (value: any) => {
 | 
			
		||||
  selectedUsers.value = props.multiple ? value : [...value]
 | 
			
		||||
  emitDataChange() // 每次选择变化时发出更新事件
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 更新已选择的用户列表
 | 
			
		||||
const updateSelectedUsers = (users: string[]) => {
 | 
			
		||||
  selectedUsers.value = users
 | 
			
		||||
  emitDataChange() // 每次选择变化时发出更新事件
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 弹窗确认按钮点击事件
 | 
			
		||||
const handleModalOk = () => {
 | 
			
		||||
  emitDataChange() // 确认时发出数据更新事件
 | 
			
		||||
  visible.value = false // 关闭弹窗
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 组件挂载后初始化用户列表
 | 
			
		||||
onMounted(async () => {
 | 
			
		||||
  const { data } = await listAllUser({}) // 获取所有用户
 | 
			
		||||
  options.value = data.map((user) => {
 | 
			
		||||
    user.id = String(user.id)
 | 
			
		||||
    user.disabled = false // 初始化时设置用户未被禁用
 | 
			
		||||
    return user
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  // 初始化选择的用户
 | 
			
		||||
  selectedUsers.value = Array.isArray(props.value) ? props.value : props.value.split(',')
 | 
			
		||||
})
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped>
 | 
			
		||||
:deep(.arco-input-append) {
 | 
			
		||||
  padding: 0;
 | 
			
		||||
 | 
			
		||||
  .arco-btn {
 | 
			
		||||
    border-top-left-radius: 0;
 | 
			
		||||
    border-bottom-left-radius: 0;
 | 
			
		||||
    border: 1px solid transparent;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										13
									
								
								src/components/UserSelect/type.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/components/UserSelect/type.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
			
		||||
export interface UserSelectPropType {
 | 
			
		||||
  multiple: boolean
 | 
			
		||||
  value: string | string[]
 | 
			
		||||
}
 | 
			
		||||
export interface UserItem {
 | 
			
		||||
  id: string
 | 
			
		||||
  nickname: string
 | 
			
		||||
  deptName: string
 | 
			
		||||
  roleNames: string
 | 
			
		||||
  phone: string
 | 
			
		||||
  email: string
 | 
			
		||||
  status: number
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										2
									
								
								src/types/components.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								src/types/components.d.ts
									
									
									
									
										vendored
									
									
								
							@@ -48,6 +48,8 @@ declare module 'vue' {
 | 
			
		||||
    RouterView: typeof import('vue-router')['RouterView']
 | 
			
		||||
    SecondForm: typeof import('./../components/GenCron/CronForm/component/second-form.vue')['default']
 | 
			
		||||
    TextCopy: typeof import('./../components/TextCopy/index.vue')['default']
 | 
			
		||||
    UserSelect: typeof import('./../components/UserSelect/index.vue')['default']
 | 
			
		||||
    UserSelectContent: typeof import('./../components/UserSelect/component/UserSelectContent.vue')['default']
 | 
			
		||||
    Verify: typeof import('./../components/Verify/index.vue')['default']
 | 
			
		||||
    VerifyPoints: typeof import('./../components/Verify/Verify/VerifyPoints.vue')['default']
 | 
			
		||||
    VerifySlide: typeof import('./../components/Verify/Verify/VerifySlide.vue')['default']
 | 
			
		||||
 
 | 
			
		||||
@@ -1,29 +1,33 @@
 | 
			
		||||
<template>
 | 
			
		||||
    <div ref="containerRef" class="detail">
 | 
			
		||||
        <div class="detail_header">
 | 
			
		||||
            <a-affix :target="(containerRef as HTMLElement)">
 | 
			
		||||
                <a-page-header title="通知公告" :subtitle="type === 'edit' ? '修改' : '新增'" @back="onBack">
 | 
			
		||||
                    <template #extra>
 | 
			
		||||
                        <a-button type="primary" @click="onReleased">
 | 
			
		||||
                          <template #icon>
 | 
			
		||||
                            <icon-save v-if="type === 'edit'" />
 | 
			
		||||
                            <icon-send v-else />
 | 
			
		||||
                          </template>
 | 
			
		||||
                          <template #default>
 | 
			
		||||
                            {{ type === 'edit' ? '保存' : '发布' }}
 | 
			
		||||
                          </template>
 | 
			
		||||
                        </a-button>
 | 
			
		||||
                    </template>
 | 
			
		||||
                </a-page-header>
 | 
			
		||||
            </a-affix>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="detail_content" style="display: flex; flex-direction: column;">
 | 
			
		||||
            <GiForm ref="formRef" v-model="form" :options="options" :columns="columns" />
 | 
			
		||||
            <div style="flex: 1;">
 | 
			
		||||
                <AiEditor v-model="form.content" />
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
  <div ref="containerRef" class="detail">
 | 
			
		||||
    <div class="detail_header">
 | 
			
		||||
      <a-affix :target="(containerRef as HTMLElement)">
 | 
			
		||||
        <a-page-header title="通知公告" :subtitle="type === 'edit' ? '修改' : '新增'" @back="onBack">
 | 
			
		||||
          <template #extra>
 | 
			
		||||
            <a-button type="primary" @click="onReleased">
 | 
			
		||||
              <template #icon>
 | 
			
		||||
                <icon-save v-if="type === 'edit'" />
 | 
			
		||||
                <icon-send v-else />
 | 
			
		||||
              </template>
 | 
			
		||||
              <template #default>
 | 
			
		||||
                {{ type === 'edit' ? '保存' : '发布' }}
 | 
			
		||||
              </template>
 | 
			
		||||
            </a-button>
 | 
			
		||||
          </template>
 | 
			
		||||
        </a-page-header>
 | 
			
		||||
      </a-affix>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="detail_content" style="display: flex; flex-direction: column;">
 | 
			
		||||
      <GiForm ref="formRef" v-model="form" :options="options" :columns="columns">
 | 
			
		||||
        <template #noticeUsers>
 | 
			
		||||
          <UserSelect v-model:value="form.noticeUsers" :multiple="true" class="w-full" />
 | 
			
		||||
        </template>
 | 
			
		||||
      </GiForm>
 | 
			
		||||
      <div style="flex: 1;">
 | 
			
		||||
        <AiEditor v-model="form.content" />
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup lang="tsx">
 | 
			
		||||
@@ -46,7 +50,8 @@ const { form, resetForm } = useForm({
 | 
			
		||||
  type: '',
 | 
			
		||||
  effectiveTime: '',
 | 
			
		||||
  terminateTime: '',
 | 
			
		||||
  content: ''
 | 
			
		||||
  content: '',
 | 
			
		||||
  noticeScope: 1
 | 
			
		||||
})
 | 
			
		||||
const options: Options = {
 | 
			
		||||
  form: { size: 'large' },
 | 
			
		||||
@@ -88,7 +93,24 @@ const columns: Columns = reactive([
 | 
			
		||||
    props: {
 | 
			
		||||
      showTime: true
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    label: '通知范围',
 | 
			
		||||
    field: 'noticeScope',
 | 
			
		||||
    type: 'radio-group',
 | 
			
		||||
    options: [{ label: '所有人', value: 1 }, { label: '指定用户', value: 2 }],
 | 
			
		||||
    rules: [{ required: true, message: '请选择通知范围' }]
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    label: '指定用户',
 | 
			
		||||
    field: 'noticeUsers',
 | 
			
		||||
    type: 'input',
 | 
			
		||||
    hide: () => {
 | 
			
		||||
      return form.noticeScope === 1
 | 
			
		||||
    },
 | 
			
		||||
    rules: [{ required: true, message: '请选择指定用户' }]
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
])
 | 
			
		||||
// 修改
 | 
			
		||||
const onUpdate = async (id: string) => {
 | 
			
		||||
@@ -103,6 +125,8 @@ const onReleased = async () => {
 | 
			
		||||
  const isInvalid = await formRef.value?.formRef?.validate()
 | 
			
		||||
  if (isInvalid) return false
 | 
			
		||||
  try {
 | 
			
		||||
    // 通知范围 所有人 去除指定用户
 | 
			
		||||
    form.noticeUsers = form.noticeScope === 1 ? null : form.noticeUsers
 | 
			
		||||
    if (type === 'edit') {
 | 
			
		||||
      await updateNotice(form, id as string)
 | 
			
		||||
      Message.success('修改成功')
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user