diff --git a/src/assets/image/yunhai-logo.svg b/src/assets/image/yunhai-logo.svg new file mode 100644 index 0000000..7d1d358 --- /dev/null +++ b/src/assets/image/yunhai-logo.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/assets/styles/appicon.mask.css b/src/assets/styles/appicon.mask.css new file mode 100644 index 0000000..a8db9f3 --- /dev/null +++ b/src/assets/styles/appicon.mask.css @@ -0,0 +1,33 @@ +/* appicon 图标(CSS mask + currentColor,data-uri 自包含),共 2 个。 + 用法 ;命名空间隔离:类名恒为 .appicon*,无 .icon-*。 */ + +.appicon { + font-family: inherit; + font-style: normal; + font-size: 16px; + line-height: 1; + display: inline-block; + vertical-align: middle; +} +.appicon::before { + content: "" !important; + display: block; + width: 1em; + height: 1em; + background-color: currentColor; + -webkit-mask-position: center; + mask-position: center; + -webkit-mask-repeat: no-repeat; + mask-repeat: no-repeat; + -webkit-mask-size: contain; + mask-size: contain; +} + +.appicon-tongzhi::before { + -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1024 1024'%3E%3Cpath d='M853.33 725.33H938.67V810.67H85.33V725.33H170.67V426.67C170.67 238.15 323.49 85.33 512 85.33C700.51 85.33 853.33 238.15 853.33 426.67V725.33ZM768 725.33V426.67C768 285.28 653.38 170.67 512 170.67C370.62 170.67 256 285.28 256 426.67V725.33H768ZM384 896H640V981.33H384V896Z' %3E%3C/path%3E%3C/svg%3E"); + mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1024 1024'%3E%3Cpath d='M853.33 725.33H938.67V810.67H85.33V725.33H170.67V426.67C170.67 238.15 323.49 85.33 512 85.33C700.51 85.33 853.33 238.15 853.33 426.67V725.33ZM768 725.33V426.67C768 285.28 653.38 170.67 512 170.67C370.62 170.67 256 285.28 256 426.67V725.33H768ZM384 896H640V981.33H384V896Z' %3E%3C/path%3E%3C/svg%3E"); +} +.appicon-wenjuan::before { + -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1024 1024'%3E%3Cpath d='M725.33 85.33V170.67H853.61C877.02 170.67 896 189.65 896 213.05V896.28C896 919.69 877.02 938.67 853.61 938.67H170.39C146.98 938.67 128 919.68 128 896.28V213.05C128 189.64 146.98 170.67 170.39 170.67H298.67V85.33H725.33ZM298.67 256H213.33V853.33H810.67V256H725.33V341.33H298.67V256ZM384 682.67V768H298.67V682.67H384ZM384 554.67V640H298.67V554.67H384ZM384 426.67V512H298.67V426.67H384ZM640 170.67H384V256H640V170.67Z' %3E%3C/path%3E%3C/svg%3E"); + mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1024 1024'%3E%3Cpath d='M725.33 85.33V170.67H853.61C877.02 170.67 896 189.65 896 213.05V896.28C896 919.69 877.02 938.67 853.61 938.67H170.39C146.98 938.67 128 919.68 128 896.28V213.05C128 189.64 146.98 170.67 170.39 170.67H298.67V85.33H725.33ZM298.67 256H213.33V853.33H810.67V256H725.33V341.33H298.67V256ZM384 682.67V768H298.67V682.67H384ZM384 554.67V640H298.67V554.67H384ZM384 426.67V512H298.67V426.67H384ZM640 170.67H384V256H640V170.67Z' %3E%3C/path%3E%3C/svg%3E"); +} diff --git a/src/assets/styles/componets/_app_container.scss b/src/assets/styles/componets/_app_container.scss index 55151b8..e172111 100644 --- a/src/assets/styles/componets/_app_container.scss +++ b/src/assets/styles/componets/_app_container.scss @@ -56,3 +56,53 @@ // border-radius: 2px; // background: rgba(255, 255, 255, 0.25); } + +/* ===================== AppIcon 矢量图标三档 scene(方案 §4 渲染契约) ===================== + * 图标资源只管形状,容器管底色与图标色;底色为端侧派生 token(不落库)。 + * 形状类(.appicon-<名> 的 mask data-uri)来自全局 appicon.mask.css; + * AppIcon.vue 组件按 scene/tint 组合类名与内联覆盖(tint=application_info.icon_color 人工配置色)。 + * 尺寸对齐上方 img 位图(60px / 18% 圆角),保证矢量与位图在网格里视觉一致。 + */ +.appicon { + display: inline-block; + line-height: 1; + vertical-align: middle; + box-sizing: border-box; +} + +.appicon-tile { + // PC 应用卡:方块底 + 白图标(对齐位图 60px/18%) + --appicon-bg: var(--brand, #366ef4); // 端侧主题 token(通道 CSS 不可达时兜底蓝) + width: 60px; + height: 60px; + border-radius: 18%; + background: var(--appicon-bg); + color: #fff; + font-size: 44px; + display: inline-flex; + align-items: center; + justify-content: center; +} + +.appicon-circle { + // App 首页快捷:正圆底 + 白图标 + --appicon-bg: var(--brand, #366ef4); + width: 50px; + height: 50px; + border-radius: 50%; + background: var(--appicon-bg); + color: #fff; + font-size: 36px; + display: inline-flex; + align-items: center; + justify-content: center; +} + +.appicon-plain { + // 无底线性:图标色继承(分组色 / tint) + width: auto; + height: auto; + background: transparent; + color: var(--appicon-ink, currentColor); + font-size: 26px; +} diff --git a/src/assets/styles/main.scss b/src/assets/styles/main.scss index b9d845a..234433e 100644 --- a/src/assets/styles/main.scss +++ b/src/assets/styles/main.scss @@ -6,6 +6,12 @@ @use "utils/utils"; @use "utils/bsch_title"; +// AppIcon 资产库(CSS mask 版,data-uri 自包含): +// 拷贝自 D:\SoftProject\yunhai\YschAppIcons\appicon.mask.css(资产库 build_mask_css.py 产物)。 +// 同步方式:资产库重跑构建后整文件覆盖本处,避免 P1 静态应用部署顺序依赖与跨域问题。 +// 注意:必须 @use 在 componets/* 之前——scene 档(.appicon-tile 等)需覆盖本文件的 .appicon 基类字号。 +@use "appicon.mask.css"; + @use "componets/status"; @use "componets/small_table"; @use "componets/my_table"; diff --git a/src/components/AppIcon.vue b/src/components/AppIcon.vue new file mode 100644 index 0000000..c99c88c --- /dev/null +++ b/src/components/AppIcon.vue @@ -0,0 +1,36 @@ + + + diff --git a/src/components/SearchPanel.vue b/src/components/SearchPanel.vue index 91895c4..a60abc5 100644 --- a/src/components/SearchPanel.vue +++ b/src/components/SearchPanel.vue @@ -13,7 +13,9 @@
- + +
{{ item.name }}
@@ -26,10 +28,22 @@ import { useDefaultStore } from "@/store"; import { ref, inject, computed, onMounted, watch } from "vue"; import vuescroll from "vuescroll"; +import AppIcon from "@/components/AppIcon.vue"; +import { appiconKeyOf } from "@/constants/appIconRules"; import useCurrentInstance from "@/utils/hook/useCurrentInstance"; const { $utils } = useCurrentInstance(); +/** + * 矢量渲染判定(方案 §5.4 回退链,与 AppList.vue / index.vue 同口径): + * icon_key 命中 → 矢量;有位图 URL → 位图(存量零回归);URL 空且关键词命中 → 矢量;否则默认图。 + */ +function vectorIconOf(item: any): string { + if (item?.iconKey) return item.iconKey; + if (item?.icon) return ""; + return appiconKeyOf(item?.name || ""); +} + const refInput = ref(); const searchName = ref(); diff --git a/src/constants/appIconRules.ts b/src/constants/appIconRules.ts new file mode 100644 index 0000000..67286bb --- /dev/null +++ b/src/constants/appIconRules.ts @@ -0,0 +1,43 @@ +/** + * 应用名称关键词 → AppIcon 资产库图标键映射(D4:两端各持一份,关键词列与 MobilePortal 完全一致)。 + * + * 定位(方案 §5.4 / E4):只做兜底、不做主路径——仅在「icon_key 未配置 且 无 icon URL」时生效 + * (替代默认占位图);有 URL 的存量应用恒定位图渲染,零回归。 + * + * 值列语义:appicon 图标键(如 tongzhi);空串 = 该关键词暂无对应图标(dormant,资产库补图后填值激活)。 + * 一致性断言:YschAppIcons/verify_map.mjs 深比较两端关键词列(含顺序);值列两端允许不同 + * (MobilePortal 用 wd-icon 名,本表用 appicon 键)。 + */ +export const APP_ICON_RULES: [string, string][] = [ + ['请假', ''], + ['课程', ''], + ['课表', ''], + ['通知', ''], + ['公告', ''], + ['报修', ''], + ['文印', ''], + ['打印', ''], + ['公文', ''], + ['作业', ''], + ['班级', ''], + ['家校', ''], + ['会议', ''], + ['场馆', ''], + ['申购', ''], + ['申领', ''], + ['物品', ''], + ['通讯录', ''], + ['邮箱', ''], + ['工资', ''], + ['财务', ''], + ['成绩', ''], +] + +/** 名称命中关键词时返回对应 appicon 图标键;无命中/值为空返回 ''(不渲染矢量,走原回退)。 */ +export function appiconKeyOf(name: string): string { + if (!name) return '' + for (const [kw, key] of APP_ICON_RULES) { + if (name.includes(kw)) return key + } + return '' +} diff --git a/src/views/AppList.vue b/src/views/AppList.vue index fa35116..331d0de 100644 --- a/src/views/AppList.vue +++ b/src/views/AppList.vue @@ -30,7 +30,9 @@ ]" > - + +
{{ citem.name }}
@@ -60,10 +62,10 @@ ]" > - + +
{{ item.name }}
@@ -79,6 +81,7 @@