| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339 |
- <script setup lang="ts">
- import { ref, reactive, shallowRef, onMounted, nextTick } from 'vue';
- import type { NotifyModel, NotifyQuery } from '@/model/notify.model';
- import EditNotify from '@/components/EditNotify.vue';
- // 接口数据
- import { notifyMethod, deleteNotifyMethod, updateNotifyStatusMethod } from '@/request/api/notify.api';
- import { usePagination } from 'alova/client';
- import { notification } from 'ant-design-vue';
- import dayjs from 'dayjs';
- import { type VxeFormListeners, type VxeFormProps, type VxeGridInstance, type VxeGridListeners, type VxeGridProps, VxeUI } from 'vxe-pc-ui';
- const model = shallowRef<NotifyQuery>();
- const searchFormProps = reactive<VxeFormProps<NotifyQuery>>({
- titleWidth: 100,
- titleAlign: 'right',
- titleColon: true,
- data: {},
- items: [
- {
- field: 'name',
- title: '名称',
- span: 6,
- itemRender: { name: 'VxeInput', props: { placeholder: '请输入通知名称' } },
- },
- {
- field: 'sendTime',
- title: '发送时间',
- span: 8,
- slots: {
- default: 'createTimes',
- },
- },
- {
- span: 6,
- itemRender: {
- name: 'VxeButtonGroup',
- options: [
- { name: 'submits', type: 'submit', content: '查询', status: 'primary' },
- { name: 'reset', type: 'reset', content: '重置', status: 'warning' },
- { name: 'add', content: '新增', status: 'primary' },
- ],
- events: {
- click(slotParams: any, { name }: any) {
- if (name === 'add') {
- // 新增
- editConfirmed();
- }
- },
- },
- },
- },
- ],
- });
- const searchFormEmits: VxeFormListeners<NotifyQuery> = {
- // 查询
- submit({ data }) {
- data.sendTimeStart = sendTimeStart.value ? dayjs(sendTimeStart.value).format('YYYY-MM-DD HH:mm') : '';
- data.sendTimeEnd = sendTimeEnd.value ? dayjs(sendTimeEnd.value).format('YYYY-MM-DD HH:mm') : '';
- onSearch(data);
- },
- // 重置
- reset({ data }) {
- // 清空开始时间和结束时间
- sendTimeStart.value = '';
- sendTimeEnd.value = '';
- const resetData = { ...data };
- resetData.sendTimeStart = '';
- resetData.sendTimeEnd = '';
- onSearch(resetData);
- },
- };
- function onSearch(data: NotifyQuery) {
- model.value = { ...data };
- nextTick(() => {
- (searchFormProps.data as any)! = { ...data };
- });
- }
- const gridRef = ref<VxeGridInstance<NotifyModel>>();
- const gridOptions = reactive<VxeGridProps<NotifyModel>>({
- id: 'tag-list',
- border: true,
- showOverflow: true,
- height: 'auto',
- autoResize: true,
- syncResize: true,
- scrollY: { enabled: true, gt: 0 },
- rowConfig: {
- isHover: true,
- isCurrent: true,
- },
- toolbarConfig: {
- custom: true,
- zoom: true,
- slots: {
- tools: 'toolbar-extra',
- },
- },
- columnConfig: {
- resizable: true,
- },
- customConfig: {
- storage: true,
- },
- columns: [
- { type: 'seq', width: 70, fixed: 'left' },
- { field: 'name', title: '名称' },
- { field: 'pushType', title: '通知渠道', slots: { default: 'pushTypeCell' } },
- { field: 'tagNames', title: '用户标签' },
- { field: 'sendTime', title: '发送时间' },
- { field: 'sendCount', title: '已发条数' },
- {
- field: 'status',
- title: '启用状态',
- align: 'center',
- cellRender: {
- name: 'VxeSwitch',
- props: {
- openLabel: '启用',
- openValue: '0',
- closeLabel: '禁用',
- closeValue: '1',
- },
- events: {
- change({ row, rowIndex }, { value }) {
- row.status = { '1': '0', '0': '1' }[value as string] as any;
- updatePlanStatus(row, rowIndex, value);
- },
- },
- },
- },
- {
- field: 'action',
- title: '操作',
- align: 'center',
- width: 180,
- showOverflow: false,
- cellRender: {
- name: 'VxeButtonGroup',
- props: {
- mode: 'text',
- },
- options: [
- { content: '编辑', status: 'primary', name: 'editConfirmed' },
- { content: '删除', status: 'primary', name: 'deleteConfirmed' },
- ],
- events: {
- click({ row, rowIndex }: any, { name }: any) {
- let method;
- if (name === 'editConfirmed') {
- method = editConfirmed;
- } else if (name === 'deleteConfirmed') {
- method = deleteConfirmed;
- }
- method?.(row, rowIndex);
- },
- },
- },
- },
- ],
- data: [],
- });
- const gridEvents: VxeGridListeners = {};
- const {
- loading,
- page,
- pageSize,
- total,
- onSuccess,
- replace,
- refresh,
- remove,
- send: sendRefresh,
- } = usePagination((page, size) => notifyMethod(page, size, model.value), {
- initialData: { data: [], total: 0 },
- initialPage: 1,
- initialPageSize: 100,
- watchingStates: [model],
- immediate: true,
- });
- onSuccess((res: any) => {
- gridRef.value?.loadData(res?.data?.data ?? []);
- });
- onMounted(() => {
- onSearch(toRaw(searchFormProps.data) as any);
- });
- function deleteConfirmed(model: NotifyModel, index: number) {
- const { name } = model;
- VxeUI.modal.confirm({
- title: `删除通知`,
- content: `确认要删除 ${name} 通知吗?`,
- showClose: false,
- onConfirm() {
- deleteNotifyMethod(model).then(() => {
- notification.success({
- message: `删除通知: ${name}`,
- description: '操作成功',
- });
- refresh(page.value);
- });
- },
- });
- }
- function editConfirmed(model?: NotifyModel, index?: number) {
- const addType = `itemsList`;
- VxeUI.modal.open({
- title: model?.name ?? '通知',
- fullscreen: true,
- escClosable: true,
- destroyOnClose: true,
- id: `edit-notify-modal`,
- remember: true,
- storage: true,
- slots: {
- default() {
- return h(EditNotify, <any>{
- data: {
- ...model,
- addType,
- },
- onSubmit(data: NotifyModel) {
- refresh(page.value);
- VxeUI.modal.close(`edit-notify-modal`);
- },
- });
- },
- },
- });
- }
- function updatePlanStatus(model: NotifyModel, index: number, status: NotifyModel['status']) {
- const { id, name } = model;
- const label = { '1': '禁用', '0': '启用' }[status];
- VxeUI.modal.confirm({
- title: `启用状态`,
- content: `确认要 ${label} ${name} 吗?`,
- showClose: false,
- onConfirm() {
- updateNotifyStatusMethod({ id, status }).then(() => {
- notification.success({
- message: `${label}: ${name}`,
- description: '操作成功',
- });
- model.status = status;
- replace(model, index);
- });
- },
- });
- }
- // 日期验证
- const sendTimeStart = ref<string>('');
- const sendTimeEnd = ref<string>('');
- // 禁用结束时间的日期(早于开始时间的日期)
- function disabledEndDate(current: any) {
- if (!sendTimeStart.value) return false;
- return current && current < dayjs(sendTimeStart.value);
- }
- defineExpose({
- send: sendRefresh,
- });
- </script>
- <template>
- <div class="page-container flex flex-col">
- <header class="flex-none mt-4">
- <vxe-form v-bind="searchFormProps" v-on="searchFormEmits">
- <template #createTimes>
- <div class="date-range-container">
- <a-date-picker
- v-model:value="sendTimeStart"
- placeholder="请选择开始时间"
- style="flex: 1"
- format="YYYY-MM-DD HH:mm"
- :show-time="{ format: 'HH:mm' }"
- />
- <span class="date-separator">至</span>
- <a-date-picker
- v-model:value="sendTimeEnd"
- placeholder="请选择结束时间"
- style="flex: 1"
- format="YYYY-MM-DD HH:mm"
- :disabledDate="disabledEndDate"
- :show-time="{ format: 'HH:mm' }"
- />
- </div>
- </template>
- </vxe-form>
- </header>
- <main class="flex-auto overflow-hidden">
- <vxe-grid ref="gridRef" v-bind="gridOptions" v-on="gridEvents" :loading="loading">
- <template #pushTypeCell="{ row }">
- {{ row.pushType === '0' ? '站内' : '企业微信' }}
- </template>
- <template #conditioningProgramSupplierNameCell="{ row }">
- {{ row.conditioningProgramSupplierName == '0' ? '启用' : '禁用' }}
- </template>
- <template #toolbar-extra>
- <vxe-button style="margin-right: 12px" icon="vxe-icon-repeat" circle @click="refresh(page)"></vxe-button>
- </template>
- </vxe-grid>
- </main>
- <footer class="flex-none">
- <vxe-pager
- v-model:current-page="page"
- v-model:page-size="pageSize"
- :total="total"
- :layouts="['Home', 'PrevJump', 'PrevPage', 'Number', 'NextPage', 'NextJump', 'End', 'Sizes', 'FullJump', 'Total']"
- />
- </footer>
- </div>
- </template>
- <style scoped lang="scss">
- .page-container {
- height: 100%;
- display: flex;
- flex-direction: column;
- }
- .date-range-container {
- display: flex;
- align-items: center;
- gap: 12px;
- width: 100%;
- .vxe-input {
- flex: 1;
- min-width: 0;
- }
- .date-separator {
- color: #666;
- font-size: 14px;
- font-weight: 500;
- white-space: nowrap;
- padding: 0 8px;
- }
- }
- </style>
|