diff --git a/src/api/globals.d.ts b/src/api/globals.d.ts index 1b46d84..c58bdeb 100644 --- a/src/api/globals.d.ts +++ b/src/api/globals.d.ts @@ -223,6 +223,8 @@ export interface ApplicationInfoRequest { name: string; categoryId: number; desc?: string; + appCode?: string; + appNature?: string; clients?: number[]; pcUrl?: string; pcIcon?: string; @@ -230,6 +232,7 @@ export interface ApplicationInfoRequest { appIcon?: string; officialAccountUrl?: string; dingtalkUrl?: string; + miniprogramUrl?: string; } export interface SysUserMoveRequest { userId: number; @@ -766,6 +769,8 @@ export interface ApplicationInfoVo { desc?: string; appKey?: number; appSecret?: string; + appCode?: string; + appNature?: string; clients?: number[]; pcUrl?: string; pcIcon?: string; @@ -773,6 +778,7 @@ export interface ApplicationInfoVo { appIcon?: string; officialAccountUrl?: string; dingtalkUrl?: string; + miniprogramUrl?: string; } export interface BasePageResultApplicationInfoVo { total?: number; diff --git a/src/views/app/AddAppContainer.vue b/src/views/app/AddAppContainer.vue index cf97a84..268ee15 100644 --- a/src/views/app/AddAppContainer.vue +++ b/src/views/app/AddAppContainer.vue @@ -22,7 +22,7 @@ let onSuccessCallback: (() => void) | null = null; // useForm 托管提交 const { form, loading: submitting, send: sendForm, onSuccess, onError } = useForm( (dto) => Apis.AppSettings.addApp({ data: dto }), - { initialForm: { name: '', categoryId: undefined, desc: '', clients: [], pcUrl: '', pcIcon: '', appUrl: '', appIcon: '', officialAccountUrl: '', dingtalkUrl: '' }, resetAfterSubmiting: true } + { initialForm: { name: '', categoryId: undefined, desc: '', appCode: '', appNature: 'BUSINESS', clients: [], pcUrl: '', pcIcon: '', appUrl: '', appIcon: '', officialAccountUrl: '', dingtalkUrl: '' }, resetAfterSubmiting: true } ); onSuccess(() => { @@ -50,6 +50,8 @@ async function handleSubmit(formData: Record) { name: formData.name, categoryId: formData.categoryId, desc: formData.desc, + appCode: formData.appCode, + appNature: formData.appNature, clients: formData.clients, pcUrl: formData.pcUrl, pcIcon: formData.pcIcon, diff --git a/src/views/app/AppForm.vue b/src/views/app/AppForm.vue index 757b192..d269655 100644 --- a/src/views/app/AppForm.vue +++ b/src/views/app/AppForm.vue @@ -33,6 +33,21 @@ + + + + + + {{ natureBase ? '基石应用(不进开通/授权/模块管理)' : '业务应用' }} + + + + + + + + + @@ -173,6 +188,8 @@ const defaultForm = (): Record => ({ desc: '', appKey: null, appSecret: '', + appCode: '', + appNature: 'BUSINESS', clients: [] as number[], pcUrl: '', pcIcon: '', @@ -221,12 +238,22 @@ const clientOptions = [ { value: 32, label: '钉钉' }, ]; +/* ---------- 应用性质 Switch(开=BASE 基石 / 关=BUSINESS 业务) ---------- */ +const natureBase = computed({ + get: () => form.appNature === 'BASE', + set: (val: boolean) => { form.appNature = val ? 'BASE' : 'BUSINESS'; }, +}); + /* ---------- 校验规则(学校模式不校验 categoryId——类型字段不展示且不可改) ---------- */ const rules = computed(() => ({ name: [{ required: true, message: '请输入应用名称', trigger: 'blur' }], ...(props.schoolMode ? {} : { categoryId: [{ required: true, type: 'number' as const, message: '请选择应用类型', trigger: 'change' }], }), + // 技术标识仅新增必填(后端 Create 组同口径);编辑留空 = 保持原值(存量孤儿行允许继续观察) + ...((props.schoolMode || props.isEdit) ? {} : { + appCode: [{ required: true, message: '请输入技术标识', trigger: 'blur' }], + }), })); /* ---------- 提交 ---------- */ @@ -348,4 +375,11 @@ function onVisibleChange(val: boolean) { overflow-y: auto; } } + +/* 应用性质说明文字 */ +.nature-hint { + margin-left: 8px; + color: #808695; + font-size: 12px; +} diff --git a/src/views/app/AppList.vue b/src/views/app/AppList.vue index 2b37c4e..31919d2 100644 --- a/src/views/app/AppList.vue +++ b/src/views/app/AppList.vue @@ -168,18 +168,26 @@ const columns = [ return h("span", arr.map((v) => map[v] ?? v).join("、")); }, }, + { + title: "性质", + key: "appNature", + width: 80, + render: (h: any, { row }: any) => h("span", row.appNature === "BASE" ? "基石" : "业务"), + }, { title: "操作", key: "action", align: 'center', width: 280, render: (h: any, { row }: any) => { - // SCHOOL 模式:仅编辑(名称/描述/图标,写学校覆盖表);模块管理/推送设置/删除全部隐藏 + // SCHOOL 模式:仅编辑(名称/描述/图标,写学校覆盖表);模块管理/推送设置/删除全部隐藏。 + // 基石应用(app_nature=BASE)只做身份注册:模块/推送/删除置灰,「编辑」保持可用(密钥轮换入口) + const base = row.appNature === "BASE"; const actions = [$utils.operatingTextHandle(h, '编辑', '', () => handleEdit(row))]; if (!isSchoolMode.value) { - actions.push($utils.operatingTextHandle(h, '模块管理', '', () => goModuleManage(row))); - actions.push($utils.operatingTextHandle(h, '推送设置', '', () => openPushSetting(row))); - actions.push($utils.operatingTextHandle(h, '删除', 'text-error', () => handleDelete(row))); + actions.push($utils.operatingTextHandle(h, '模块管理', '', () => goModuleManage(row), base)); + actions.push($utils.operatingTextHandle(h, '推送设置', '', () => openPushSetting(row), base)); + actions.push($utils.operatingTextHandle(h, '删除', 'text-error', () => handleDelete(row), base)); } return actions; } diff --git a/src/views/app/EditAppContainer.vue b/src/views/app/EditAppContainer.vue index c9227e0..2c9a8e8 100644 --- a/src/views/app/EditAppContainer.vue +++ b/src/views/app/EditAppContainer.vue @@ -34,7 +34,7 @@ const { form, loading: submitting, send: sendForm, onSuccess, onError } = useFor data: dto, params: props.schoolId != null ? { schoolId: props.schoolId } : undefined, }), - { initialForm: { id: null, name: '', categoryId: undefined, desc: '', clients: [], pcUrl: '', pcIcon: '', appUrl: '', appIcon: '', officialAccountUrl: '', dingtalkUrl: '' }, resetAfterSubmiting: true } + { initialForm: { id: null, name: '', categoryId: undefined, desc: '', appCode: '', appNature: 'BUSINESS', clients: [], pcUrl: '', pcIcon: '', appUrl: '', appIcon: '', officialAccountUrl: '', dingtalkUrl: '' }, resetAfterSubmiting: true } ); onSuccess(() => { @@ -80,6 +80,8 @@ async function handleSubmit(formData: Record) { name: formData.name, categoryId: formData.categoryId, desc: formData.desc, + appCode: formData.appCode, + appNature: formData.appNature, clients: formData.clients, pcUrl: formData.pcUrl, pcIcon: formData.pcIcon,