diff --git a/src/api/AppSettingApi.ts b/src/api/AppSettingApi.ts deleted file mode 100644 index 562ba08..0000000 --- a/src/api/AppSettingApi.ts +++ /dev/null @@ -1,63 +0,0 @@ -import Abstract from "@/utils/axios/abstract"; -import { PageData, PageParams } from "@/types/Basics"; - -const path = "/api"; - -export interface AppCategoryItem { - id?: number; - name: string; - apiUrl: string; - dataKey: string; - paramsKey: string; - roleType: number; - cId?: number; - cDate?: string; - resDate?: string; -} - -/** 系统设置-应用管理(应用类别 CRUD + 模板管理) */ -class AppSettingApi extends Abstract { - /** 应用分页列表 */ - getAppCategoryList(params: PageParams & { roleType: number; name?: string }) { - const url = path + "/GetAppCategoryList"; - return this.getRequest({ url, params }); - } - - /** 保存应用(新增/编辑) */ - saveAppCategory(data: AppCategoryItem) { - const url = path + "/SaveAppCategory"; - return this.postRequest({ url, data }); - } - - /** 删除应用 */ - deleteAppCategory(id: number) { - const url = path + "/DelAppCategory"; - return this.postRequest({ url, params: { id } }); - } - - /** 查询应用详情 */ - findAppCategory(id: number) { - const url = path + "/FindAppCategory"; - return this.getRequest({ url, params: { id } }); - } - - /** 刷新资源时间戳(上传模板后调用) */ - updateResDate(id: number) { - const url = path + "/UpdateResDate"; - return this.postRequest({ url, params: { id } }); - } - - /** 模板文件列表 */ - getTempList(appModId: number) { - const url = path + "/GetTempList"; - return this.getRequest({ url, params: { appModId } }); - } - - /** 保存模板文件内容(JSON body,避免大文件内容超出 URL/请求头长度限制) */ - saveTempFile(appModId: number, fileName: string, content: string) { - const url = path + "/SaveTempFile"; - return this.postRequest({ url, data: { appModId, fileName, content } }); - } -} - -export default new AppSettingApi(); diff --git a/src/api/UserSettingApi.ts b/src/api/UserSettingApi.ts index 89f0109..70a12b8 100644 --- a/src/api/UserSettingApi.ts +++ b/src/api/UserSettingApi.ts @@ -1,4 +1,4 @@ -import { DesktopAppTypeEnum, LightApp, UserSettingInfo, WidgetPositionResp } from "@/types"; +import { DesktopAppTypeEnum, LightApp, UserSettingInfo, WidgetCatalog, WidgetPositionResp } from "@/types"; import { BaseDict, PageData, PageParams } from "@/types/Basics"; import Abstract from "@/utils/axios/abstract"; @@ -107,13 +107,38 @@ class UserSettings extends Abstract { getWidgetCatalogList() { const url = path + "/GetWidgetCatalogList"; - return this.getRequest({ url }); + return this.getRequest({ url }); } - saveWidgetCatalog(catalog: Record) { + /** 新增/编辑全局目录(仅超管):scopeType/roleTypes/roleAlias/scopeSchIds 一并提交 */ + saveWidgetCatalog(catalog: Partial & Record) { const url = path + "/SaveWidgetCatalog"; return this.postRequest({ url, data: catalog }); } + + /** 删除全局目录(仅超管),后端连带删点名表与校级覆盖行 */ + deleteWidgetCatalog(id: number) { + const url = path + "/DeleteWidgetCatalog"; + return this.postRequest({ url, params: { id } }); + } + + /** 读本校覆盖行(编辑回显):schId 由后端取当前登录校 */ + getWidgetSchoolSetting(widgetId: number) { + const url = path + "/GetWidgetSchoolSetting"; + return this.getRequest({ url, params: { widgetId } }); + } + + /** 保存本校覆盖(校管/超管):schId 由后端强制取当前登录校,前端不传 */ + saveWidgetSchoolSetting(setting: Record) { + const url = path + "/SaveWidgetSchoolSetting"; + return this.postRequest({ url, data: setting }); + } + + /** 机构树(仅超管):递归裁剪到学校层,children 即学校列表,用于可见范围多选 */ + getSchTree() { + const url = path + "/getSchTree"; + return this.getRequest({ url }); + } } export default new UserSettings(); diff --git a/src/components/Header.vue b/src/components/Header.vue index f698f74..f4d65d5 100644 --- a/src/components/Header.vue +++ b/src/components/Header.vue @@ -613,11 +613,6 @@ async function toggleWidgetShow() { await UserSettingApi.toggleWidgetShow(id); } -function linkSysSetting() { - isUserCardShow.value = false; - router.push("/syssetting"); -} - function linkBackendManage() { isUserCardShow.value = false; const url = `${$conf.baseHost}/userbase/front/index.html`; diff --git a/src/router/routes.ts b/src/router/routes.ts index 5f07ed3..4b5b794 100644 --- a/src/router/routes.ts +++ b/src/router/routes.ts @@ -7,8 +7,6 @@ import LightApp from "@/views/LightApp.vue"; import Stats from "@/views/Stats.vue"; import StatsRelay from "@/views/StatsRelay/index.vue"; import TeacherCopilot from "@/views/TeacherCopilot.vue"; -import SysSetting from "@/views/SysSetting.vue"; -import SysTempManage from "@/views/SysTempManage.vue"; const routes: RouteRecordRaw[] = [ { @@ -59,18 +57,6 @@ const routes: RouteRecordRaw[] = [ component: TeacherCopilot, meta: { title: "教师助手" }, }, - { - path: "/syssetting", - name: "SysSetting", - component: SysSetting, - meta: { title: "系统设置" }, - }, - { - path: "/syssetting/tempmanage/:id", - name: "SysTempManage", - component: SysTempManage, - meta: { title: "模板管理" }, - }, { path: "/msg", name: "Msg", diff --git a/src/types/index.ts b/src/types/index.ts index bda2e9c..2235940 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -51,6 +51,36 @@ export interface WidgetPositionResp extends WidgetPosition { schId?: number; } +/** 小组件候选池目录行(widget_catalog + 管理端视角附加字段) */ +export interface WidgetCatalog { + id?: number; + /** 组件键:内置 = 前端 widgetRegistry 的键;自定义 = 自定义标识 */ + code: string; + /** 显示名(校管视角已按「校级别名 > 角色命名 > 名称」合成) */ + name: string; + /** 1 = 前端内置组件 2 = 自定义 HTML 片段 */ + compType: number; + content?: string | null; + dataCode?: string | null; + /** 下发范围:0 = 全部学校 1 = 白名单 2 = 黑名单 */ + scopeType?: number; + /** 点名的学校 id 列表(scopeType=1/2 时有效) */ + scopeSchIds?: number[]; + /** 可见角色:逗号分隔 RoleTypeEnum;NULL/空 = 全角色 */ + roleTypes?: string | null; + /** 角色专属命名 JSON 文本:{"2":"全校课表"} */ + roleAlias?: string | null; + /** 校管视角:本校别名 */ + alias?: string | null; + /** 校管视角:超管下发的全局名称 */ + originalName?: string | null; + /** 校管视角:本校是否已有覆盖行 */ + covered?: boolean; + sort?: number; + enabled?: number; + updateTime?: string | null; +} + export interface BschTransferRoleInfo { roleInfo: RoleInfo; ticket: string; diff --git a/src/views/Settings.vue b/src/views/Settings.vue index a96a6b5..55087ba 100644 --- a/src/views/Settings.vue +++ b/src/views/Settings.vue @@ -22,13 +22,8 @@ - -
- -
- - -
+ +
@@ -722,7 +717,6 @@ import { ref, reactive, computed, watch } from "vue"; import { useRoute, useRouter } from "vue-router"; import { useDefaultStore } from "@/store"; import useCurrentInstance from "@/utils/hook/useCurrentInstance"; -import SysSetting from "@/views/SysSetting.vue"; import WidgetManage from "@/views/widget/WidgetManage.vue"; import BaseApi from "@/api/BaseApi"; import SysSettingApi from "@/api/SysSettingApi"; @@ -747,7 +741,7 @@ import { Message } from "view-ui-plus"; * profile 读 store.userInfo(手机/邮箱本人可改:UpdateContact 直写 UserBase,2026-10-02 任务B); * password 走 updatePassword + 确认登出流程(照抄 UserInfoModal); * avatar 移植 UserInfoModal 直传上传(「使用默认头像」保持占位,存储方案本轮不做); - * logo/wallpaper 池管理(列表 + 直传 + 删除)照抄 SysSetting.vue,LOGO 保存走 saveSchLogo(schId 后端按登录人推断); + * logo/wallpaper 池管理(列表 + 直传 + 删除)照抄旧系统设置页管理语义,LOGO 保存走 saveSchLogo(schId 后端按登录人推断); * 壁纸「点选即生效」的 checkWallpaper 个人语义只保留在 my 层,默认层只维护可选池(不再代用户指定)。 */ @@ -757,13 +751,13 @@ const store = useDefaultStore(); const { $conf } = useCurrentInstance(); const isAdmin = computed(() => !!store.getIsAdmin); -/** 超管判据与 SysSetting.vue 的 isSuperAdmin 同源(userInfo.type==1);徽标三态用 */ +/** 超管判据 = userInfo.type==1;徽标三态用 */ const isSuper = computed(() => store.userInfo?.type == 1); /** 普通用户不可用的管理 pane(导航隐藏;URL 直达渲染 noperm 黄条,不白屏不报错)。 * 三层化(S4)后「头像/主题/壁纸」所有身份都可用——每角色只编辑自己那一层,不再是管理项 */ -const ADMIN_PANES = ["logo", "sidebar", "sys", "statset", "widget"]; -const ALL_PANES = ["profile", "password", "avatar", "theme", "wallpaper", "desktop", "logo", "sidebar", "sys", "statset", "widget", "noperm"]; +const ADMIN_PANES = ["logo", "sidebar", "statset", "widget"]; +const ALL_PANES = ["profile", "password", "avatar", "theme", "wallpaper", "desktop", "logo", "sidebar", "statset", "widget", "noperm"]; /** 历史 ?pane= 键兼容(S4 重命名:mytheme/schooltheme→theme、mywallpaper→wallpaper),保证旧链接不 404/不白屏 */ const LEGACY_PANE_KEYS: Record = { @@ -793,8 +787,6 @@ watch(curPane, pane => { }); const isDenied = computed(() => !isAdmin.value && ADMIN_PANES.includes(curPane.value)); -/** sys pane 内嵌旧路由页 SysSetting(管理员态自带机构树+内容双卡) */ -const showSys = computed(() => isAdmin.value && curPane.value === "sys"); function setPane(key: string) { curPane.value = key; @@ -823,7 +815,6 @@ const NAV_PORTAL: NavItem[] = [ { key: "sidebar", name: "边栏设置", icon: svgWrap('') }, ]; const NAV_SYSTEM: NavItem[] = [ - { key: "sys", name: "系统设置", icon: svgWrap('') }, { key: "statset", name: "统计设置", icon: svgWrap('') }, { key: "widget", name: "小组件管理", icon: svgWrap('') }, ]; @@ -984,7 +975,7 @@ function onAvatarFormatError() { Message.error("仅支持 jpg/jpeg/png/gif/webp 格式图片!"); } -/* ===== logo / wallpaper:管理列表 + 直传 + 删除(照抄 SysSetting.vue 管理语义) ===== */ +/* ===== logo / wallpaper:管理列表 + 直传 + 删除(沿用旧系统设置页管理语义) ===== */ const logoManageList = ref([]); const wallpaperManageList = ref([]); const logoSelUrl = ref(""); @@ -2029,7 +2020,7 @@ watch( diff --git a/src/views/SysTempManage.vue b/src/views/SysTempManage.vue deleted file mode 100644 index 0c88563..0000000 --- a/src/views/SysTempManage.vue +++ /dev/null @@ -1,235 +0,0 @@ - - - - - diff --git a/src/views/msg/index.vue b/src/views/msg/index.vue index 6ba3005..59f99cf 100644 --- a/src/views/msg/index.vue +++ b/src/views/msg/index.vue @@ -429,7 +429,7 @@ function fmtTime(sendTime?: string) { diff --git a/src/views/widget/WidgetEditModal.vue b/src/views/widget/WidgetEditModal.vue new file mode 100644 index 0000000..06d20dc --- /dev/null +++ b/src/views/widget/WidgetEditModal.vue @@ -0,0 +1,1143 @@ + + + + + diff --git a/src/views/widget/WidgetManage.vue b/src/views/widget/WidgetManage.vue index 879f035..ac48b59 100644 --- a/src/views/widget/WidgetManage.vue +++ b/src/views/widget/WidgetManage.vue @@ -1,365 +1,651 @@ +
-

- 内置组件的内容在 front/src/components/widgets/ 里,此处只登记键与展示名,编辑器置灰; - 上传走 FileReader 读成文本填入编辑器,不落地成文件、不产生任何 URL。 -

- +
+ ℹ️ + 可见范围三态(超管专属):全部学校 / 指定学校可见(白名单,只有选中的学校下发)/ + 指定学校不可见(黑名单,除选中学校外都下发)。
校级可覆盖项(校管理员):启用 / 可见角色 / 排序 / 别名。
+
+ + +
diff --git a/src/views/widget/WidgetRegisterModal.vue b/src/views/widget/WidgetRegisterModal.vue new file mode 100644 index 0000000..3e5753e --- /dev/null +++ b/src/views/widget/WidgetRegisterModal.vue @@ -0,0 +1,342 @@ + + + + +