build / build (push) Successful in 42s
- components/widgets:widgetRegistry(defineAsyncComponent 按需加载)+ EvaluateWidget/SyllabusWidget/WeekplanWidget,props widgetId、emit loaded、内部自行取数、ResizeObserver 自报真实高度;呈现只保留语义不逐像素复刻旧 html - views/index.vue:iframe 单分支改三分支(内置组件 / compType=2 走 :srcdoc + sandbox="allow-scripts allow-same-origin allow-forms"(不给 allow-top-navigation)/ 兜底「该小工具暂不可用」不白屏);:src="item.url" 与候选池 url 依赖删除;postMessage 身份下发只服务片段分支,高度统一收口 find.height - utils/widgetFragment.ts:wrapFragment 两段注入——取数桥在 head(早于片段自身脚本,否则 yhWidget undefined)、高度上报在 body 之后;</script> 拆拼防提前闭合门户脚本;节流用 setTimeout 尾沿 + 300/1200ms 兜底(iframe 隐藏期子文档不出动画帧,rAF 会把上报永久吞掉、帧高卡 min-height 撑出内层滚动);桥 URL 走 serviceHost 且自行解平台信封 data - views/Settings.vue:新增 admin pane「widget」(ADMIN_PANES/ALL_PANES/「系统」组导航项/v-else-if 链分支),普通用户导航隐藏且 URL 直达落 no-perm 黄条 - views/widget/WidgetManage.vue:双卡管理页(内置/自定义分组列表 + 名称/键/类型/data_code/排序/启用/sch_id 表单 + CodeMirror + 上传 .html 走 FileReader 填编辑器,不落地文件不产生 URL;内置条目 content 只读) - _widget.scss:--wg-* 六令牌 + 深玻璃 blur(18px) saturate(140%) + 描边 + 投影;拖拽态加深 blur(22px) 不再翻白;空态与 +/− 前景改走 token(配套 widget-add/sub/empty.svg 由硬编码色改 currentColor,widget-empty 原为内嵌 PNG 无法着色故换线性版);.widget-item 浅底深字保持不动 - UserSettingApi.ts:getWidgetData / getWidgetContent / GetWidgetCatalogList / SaveWidgetCatalog - 另含 src/store/index.ts 的 getWidgetAppIds 未配置态 .reverse()(非本会话所写,按用户确认一并提交:与 getWidgetAppList 降序比较器对齐,使未配置态按 widget_catalog.sort 正序渲染)
122 lines
3.1 KiB
Vue
122 lines
3.1 KiB
Vue
<template>
|
|
<div class="wg-evaluate" ref="refRoot">
|
|
<Skeleton
|
|
v-if="loading"
|
|
style="padding: 15px"
|
|
:loading="true"
|
|
:title="false"
|
|
:paragraph="{ rows: 4 }"
|
|
animated
|
|
/>
|
|
<ul v-else-if="list.length > 0" class="tpk-ul">
|
|
<li v-for="item in list" :key="item.id">
|
|
<a :href="courseDetailUrl(item.id)" target="_blank" rel="noopener noreferrer" :title="item.title">
|
|
<span class="title">{{ item.title }}</span>
|
|
<span class="sub">{{ item.lectureteaName }} | {{ item.subName }}</span>
|
|
<span class="date">{{ formatDate(item.lectureTime) }}</span>
|
|
</a>
|
|
</li>
|
|
</ul>
|
|
<div v-else class="no-data">暂无数据</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts" setup>
|
|
import { onMounted, onUnmounted, ref } from "vue";
|
|
import UserSettingApi from "@/api/UserSettingApi";
|
|
|
|
defineProps<{ widgetId: number }>();
|
|
const emit = defineEmits(["loaded"]);
|
|
|
|
const refRoot = ref<HTMLElement | null>(null);
|
|
const loading = ref(true);
|
|
const list = ref<any[]>([]);
|
|
let observer: ResizeObserver | null = null;
|
|
|
|
onMounted(async () => {
|
|
if (window.ResizeObserver && refRoot.value) {
|
|
observer = new ResizeObserver(reportHeight);
|
|
observer.observe(refRoot.value);
|
|
}
|
|
try {
|
|
const data: any = await UserSettingApi.getWidgetData("evaluate", "page=0&count=5");
|
|
list.value = (data && data.list) || [];
|
|
} catch (e) {
|
|
console.warn("[widget] evaluate 取数失败", e);
|
|
}
|
|
loading.value = false;
|
|
reportHeight();
|
|
});
|
|
|
|
onUnmounted(() => {
|
|
if (observer) observer.disconnect();
|
|
});
|
|
|
|
function reportHeight() {
|
|
if (refRoot.value) emit("loaded", refRoot.value.offsetHeight);
|
|
}
|
|
|
|
function formatDate(lectureTime: string) {
|
|
return (lectureTime || "").slice(0, 10);
|
|
}
|
|
|
|
/** 跳转链接由前端拼(口径同旧 evaluate_index.js getLinkUrl),候选池不再下发任何 html 地址 */
|
|
function courseDetailUrl(id: number) {
|
|
return window.location.origin + "/EvaluateCourese/front/#/courseDetail?id=" + id;
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.wg-evaluate {
|
|
padding: 6px 0 4px;
|
|
}
|
|
.tpk-ul {
|
|
list-style: none;
|
|
margin: 0;
|
|
padding: 0;
|
|
li {
|
|
margin: 0 15px;
|
|
padding: 6px 0;
|
|
border-bottom: 1px solid #eee;
|
|
&:last-child {
|
|
border-bottom: 0;
|
|
}
|
|
a {
|
|
display: flex;
|
|
align-items: center;
|
|
text-decoration: none;
|
|
}
|
|
}
|
|
.title {
|
|
flex: 1 1 auto;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
line-height: 26px;
|
|
color: #333;
|
|
}
|
|
.sub {
|
|
flex: 0 0 auto;
|
|
font-size: 12px;
|
|
color: #bbb;
|
|
line-height: 26px;
|
|
margin-left: 10px;
|
|
}
|
|
.date {
|
|
flex: 0 0 auto;
|
|
font-size: 12px;
|
|
color: #666;
|
|
line-height: 26px;
|
|
margin-left: 10px;
|
|
}
|
|
}
|
|
.no-data {
|
|
min-height: 90px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
color: #b9c2cc;
|
|
font-size: 13px;
|
|
}
|
|
</style>
|