liu
2 天以前 fe2d6627b8f1002af7a31b08f6f43bec034d04ee
src/views/wxcp/activity/data.ts
@@ -2,6 +2,8 @@
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import type { WxCpActivityApi } from '#/api/wxcp/activity';
import { ACTIVITY_TYPE } from '#/api/wxcp/activity';
import {
  ACTIVITY_STATUS_OPTIONS,
  PUSH_SCOPE_OPTIONS,
@@ -12,11 +14,52 @@
/** 表单类型 */
export type ActivityFormType = 'create' | 'update' | 'detail';
/** 活动模板类型选项 */
export const ACTIVITY_TYPE_OPTIONS = [
  {
    label: '纯通知(只推一条文本)',
    value: ACTIVITY_TYPE.TEXT,
  },
  {
    label: '单条消息(可点击卡片)',
    value: ACTIVITY_TYPE.MESSAGE,
  },
  {
    label: '图片通知(上传图片推送)',
    value: ACTIVITY_TYPE.IMAGE,
  },
  {
    label: '附件通知(推送文件供下载)',
    value: ACTIVITY_TYPE.FILE,
  },
  {
    label: '数据采集/评价(填写表单)',
    value: ACTIVITY_TYPE.FORM,
  },
];
/** 采集字段类型选项 */
export const FIELD_TYPE_OPTIONS = [
  { label: '单行文本', value: 'text' },
  { label: '多行文本', value: 'textarea' },
  { label: '数字', value: 'number' },
  { label: '日期', value: 'date' },
  { label: '下拉选择', value: 'select' },
  { label: '单选', value: 'radio' },
  { label: '多选', value: 'checkbox' },
  { label: '评分', value: 'rating' },
];
const DATETIME_PROPS = {
  showTime: true,
  valueFormat: 'YYYY-MM-DD HH:mm:ss',
  format: 'YYYY-MM-DD HH:mm:ss',
} as const;
/** 仅数据采集模板需要报名时间与名额 */
function isFormType(values: Record<string, unknown>) {
  return values.activityType === ACTIVITY_TYPE.FORM;
}
/** 活动表单 */
export function useActivityFormSchema(
@@ -30,6 +73,19 @@
      dependencies: { triggerFields: [''], show: () => false },
    },
    {
      fieldName: 'activityType',
      label: '活动模板',
      component: 'Select',
      componentProps: {
        options: ACTIVITY_TYPE_OPTIONS,
        placeholder: '请选择活动模板',
        disabled: readonly,
      },
      rules: 'required',
      help: '不同模板决定推送形态:纯通知/单条消息/图片/附件,或带表单的数据采集',
      formItemClass: 'col-span-2',
    },
    {
      fieldName: 'title',
      label: '活动标题',
      component: 'Input',
@@ -38,6 +94,22 @@
        disabled: readonly,
      },
      rules: 'required',
      formItemClass: 'col-span-2',
    },
    {
      fieldName: 'buttonText',
      label: '按钮文案',
      component: 'Input',
      componentProps: {
        placeholder: '如:查看详情 / 立即报名',
        disabled: readonly,
      },
      dependencies: {
        triggerFields: ['activityType'],
        show: (values) =>
          values.activityType === ACTIVITY_TYPE.MESSAGE ||
          values.activityType === ACTIVITY_TYPE.FORM,
      },
      formItemClass: 'col-span-2',
    },
    {
@@ -64,12 +136,20 @@
      label: '报名开始',
      component: 'DatePicker',
      componentProps: { ...DATETIME_PROPS, disabled: readonly },
      dependencies: {
        triggerFields: ['activityType'],
        show: isFormType,
      },
    },
    {
      fieldName: 'signupEndTime',
      label: '报名截止',
      component: 'DatePicker',
      componentProps: { ...DATETIME_PROPS, disabled: readonly },
      dependencies: {
        triggerFields: ['activityType'],
        show: isFormType,
      },
    },
    {
      fieldName: 'signupLimit',
@@ -81,8 +161,13 @@
        class: 'w-full',
        disabled: readonly,
      },
      defaultValue: 0,
      rules: 'required',
      help: '填 0 表示不限名额',
      dependencies: {
        triggerFields: ['activityType'],
        show: isFormType,
      },
    },
    {
      // 封面走附件中间表:这里提交 blobIds,回显读 attachmentList(见 form.vue 的映射函数)
@@ -114,6 +199,100 @@
        disabled: readonly,
      },
      formItemClass: 'col-span-2',
    },
    {
      // 详情图片走另一套附件关系(recordType = wxcp_activity_detail),与封面互不影响。
      // 报名页把它排在「活动详情」文字下方、按原图比例完整展示(不裁剪),
      // 所以二维码/海报这类被裁就失效的图必须放这里,别放封面。
      fieldName: 'detailBlobIds',
      label: '详情图片',
      component: 'ImageUpload',
      componentProps: {
        valueKey: 'id',
        resultField: 'id',
        maxNumber: 5,
        multiple: true,
        disabled: readonly,
      },
      help: '选填,最多 5 张;活动页按原图比例完整显示不裁剪,二维码建议放这里',
      formItemClass: 'col-span-2',
    },
    {
      // 图片通知模板:推送时逐张发图片消息(企业微信图片消息)
      fieldName: 'imageBlobIds',
      label: '推送图片',
      component: 'ImageUpload',
      componentProps: {
        valueKey: 'id',
        resultField: 'id',
        maxNumber: 9,
        multiple: true,
        disabled: readonly,
      },
      dependencies: {
        triggerFields: ['activityType'],
        show: (values) => values.activityType === ACTIVITY_TYPE.IMAGE,
      },
      help: '推送时逐张发送图片消息,最多 9 张',
      formItemClass: 'col-span-2',
    },
    {
      // 附件通知模板:推送时逐个发文件消息,接收人可直接下载
      fieldName: 'fileBlobIds',
      label: '推送附件',
      component: 'FileUpload',
      componentProps: {
        valueKey: 'id',
        maxNumber: 5,
        multiple: true,
        showDescription: !readonly,
        disabled: readonly,
      },
      dependencies: {
        triggerFields: ['activityType'],
        show: (values) => values.activityType === ACTIVITY_TYPE.FILE,
      },
      help: '推送时逐个发送文件消息,单个不超过 20MB,最多 5 个',
      formItemClass: 'col-span-2',
    },
    {
      fieldName: 'ratingEnabled',
      label: '开启评价',
      component: 'Switch',
      componentProps: { disabled: readonly },
      dependencies: {
        triggerFields: ['activityType'],
        show: isFormType,
      },
    },
    {
      fieldName: 'ratingTitle',
      label: '评价标题',
      component: 'Input',
      componentProps: {
        placeholder: '如:活动满意度评价',
        disabled: readonly,
      },
      dependencies: {
        triggerFields: ['activityType', 'ratingEnabled'],
        show: (values) => isFormType(values) && values.ratingEnabled === true,
      },
    },
    {
      fieldName: 'ratingMax',
      label: '最高星级',
      component: 'InputNumber',
      componentProps: {
        min: 1,
        max: 10,
        class: 'w-full',
        disabled: readonly,
      },
      defaultValue: 5,
      dependencies: {
        triggerFields: ['activityType', 'ratingEnabled'],
        show: (values) => isFormType(values) && values.ratingEnabled === true,
      },
    },
    {
      fieldName: 'remark',
@@ -160,6 +339,11 @@
/** 活动列表字段 */
export function useActivityGridColumns(): VxeTableGridOptions<WxCpActivityApi.Activity>['columns'] {
  return [
    {
      field: 'activityTypeName',
      title: '模板',
      width: 150,
    },
    {
      field: 'title',
      title: '活动标题',
@@ -234,6 +418,18 @@
      slots: { default: 'content' },
    },
    {
      field: 'fieldValues',
      title: '采集内容',
      minWidth: 200,
      slots: { default: 'fieldValues' },
    },
    {
      field: 'ratingScore',
      title: '评价',
      width: 80,
      slots: { default: 'ratingScore' },
    },
    {
      field: 'attachment',
      title: '附件',
      width: 80,