dev #1
@ -4,11 +4,10 @@
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta name="theme-color" content="#17201d" />
|
||||
<title>蝶雅风险预测</title>
|
||||
<title>蝶雅风险预警助手</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@ import dd from "dingtalk-jsapi";
|
||||
import { getDingTalkConfig, loginWithDingTalk } from "@/api/auth";
|
||||
import type { AuthTokenData } from "@/types/auth";
|
||||
|
||||
function isDingTalkContainer() {
|
||||
export function isDingTalkContainer() {
|
||||
return (
|
||||
typeof navigator !== "undefined" && /DingTalk/i.test(navigator.userAgent)
|
||||
);
|
||||
|
||||
@ -95,9 +95,9 @@ const visibleActions = computed(() =>
|
||||
<template>
|
||||
<section class="welcome">
|
||||
<div class="welcome__mark">蝶</div>
|
||||
<h1>你好,我是风险预估助手 v2.3</h1>
|
||||
<h1>你好,我是风险预警助手</h1>
|
||||
<p>
|
||||
双引擎风险预估:历史异常经验引擎 +
|
||||
双引擎风险预警:历史异常经验引擎 +
|
||||
判定标准规则引擎,帮助你在立项、开发和量产阶段提前识别风险。
|
||||
</p>
|
||||
|
||||
|
||||
@ -50,8 +50,7 @@ function prefetch(item: string) {
|
||||
<header class="app-header">
|
||||
<RouterLink class="brand" :to="{ name: 'assessment' }">
|
||||
<span class="brand__mark">蝶</span>
|
||||
<span class="brand__name">风险预估助手</span>
|
||||
<span class="brand__version">v2.3</span>
|
||||
<span class="brand__name">风险预警助手</span>
|
||||
<span class="engine-badge">双引擎</span>
|
||||
</RouterLink>
|
||||
|
||||
@ -143,11 +142,6 @@ function prefetch(item: string) {
|
||||
font-weight: 650;
|
||||
}
|
||||
|
||||
.brand__version {
|
||||
color: var(--color-text-faint);
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.engine-badge {
|
||||
border: 1px solid var(--color-accent-soft);
|
||||
border-radius: 999px;
|
||||
@ -252,7 +246,6 @@ nav a.active {
|
||||
padding-inline: 12px;
|
||||
}
|
||||
|
||||
.brand__version,
|
||||
.engine-badge,
|
||||
.top-navigation,
|
||||
.header-icon,
|
||||
|
||||
@ -6,9 +6,10 @@ import {
|
||||
ShieldCheck,
|
||||
Smartphone,
|
||||
} from "@lucide/vue";
|
||||
import { computed, ref } from "vue";
|
||||
import { computed, onMounted, ref } from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
|
||||
import { isDingTalkContainer } from "@/api/dingtalk";
|
||||
import { useAuthStore } from "@/stores/auth.store";
|
||||
|
||||
const auth = useAuthStore();
|
||||
@ -17,6 +18,7 @@ const mode = ref<"password" | "dingtalk">("password");
|
||||
const useDevelopmentLogin = ref(true);
|
||||
const username = ref("local-admin");
|
||||
const password = ref("risk-admin-2026");
|
||||
const autoDingTalkAttempted = ref(false);
|
||||
|
||||
// 登录后的统一落点是智能对话页,避免从其他受保护页面跳转到登录后
|
||||
// 又回到原页面,保证用户进入系统后先看到对话工作台。
|
||||
@ -46,6 +48,13 @@ async function submitDingTalk() {
|
||||
// The store exposes the server or container message below the form.
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (!isDingTalkContainer() || autoDingTalkAttempted.value) return;
|
||||
autoDingTalkAttempted.value = true;
|
||||
mode.value = "dingtalk";
|
||||
void submitDingTalk();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -54,7 +63,7 @@ async function submitDingTalk() {
|
||||
<div class="login-card__brand">
|
||||
<span class="login-card__mark">蝶</span>
|
||||
<div>
|
||||
<strong>风险预估助手</strong>
|
||||
<strong>风险预警助手</strong>
|
||||
<small>Dieya Risk Prediction Console</small>
|
||||
</div>
|
||||
</div>
|
||||
@ -62,7 +71,7 @@ async function submitDingTalk() {
|
||||
<div class="login-card__intro">
|
||||
<span class="eyebrow">SECURE ACCESS</span>
|
||||
<h1>登录系统</h1>
|
||||
<p>使用企业账号或钉钉工作台进入风险预估平台。</p>
|
||||
<p>使用企业账号或钉钉工作台进入风险预警平台。</p>
|
||||
</div>
|
||||
|
||||
<div class="login-tabs" role="tablist" aria-label="登录方式">
|
||||
@ -126,8 +135,14 @@ async function submitDingTalk() {
|
||||
|
||||
<div v-else class="dingtalk-panel">
|
||||
<div class="dingtalk-panel__icon"><Smartphone :size="22" /></div>
|
||||
<strong>从钉钉工作台快速进入</strong>
|
||||
<p>在钉钉容器中点击授权,系统会读取组织身份并自动匹配角色权限。</p>
|
||||
<strong>{{ auth.loading ? "正在获取钉钉身份" : "从钉钉工作台快速进入" }}</strong>
|
||||
<p>
|
||||
{{
|
||||
auth.loading
|
||||
? "系统正在验证组织身份并匹配角色权限,请稍候。"
|
||||
: "系统会读取组织身份并自动匹配角色权限。"
|
||||
}}
|
||||
</p>
|
||||
<button
|
||||
class="login-submit"
|
||||
type="button"
|
||||
|
||||
@ -130,7 +130,7 @@ onMounted(() => void load());
|
||||
<header class="dashboard-header">
|
||||
<div>
|
||||
<p class="eyebrow">RISK INTELLIGENCE</p>
|
||||
<h1>数据看板 <small>v2.3</small></h1>
|
||||
<h1>数据看板</h1>
|
||||
<p class="dashboard-subtitle">
|
||||
历史异常、供应商风险与标准覆盖的全局视图
|
||||
</p>
|
||||
|
||||
@ -127,7 +127,7 @@ async function downloadWord() {
|
||||
const url = URL.createObjectURL(blob);
|
||||
const anchor = document.createElement("a");
|
||||
anchor.href = url;
|
||||
anchor.download = `蝶雅新品风险预估报告-${report.value.subjectId}.docx`;
|
||||
anchor.download = `蝶雅新品风险预警报告-${report.value.subjectId}.docx`;
|
||||
anchor.click();
|
||||
URL.revokeObjectURL(url);
|
||||
}
|
||||
@ -138,7 +138,7 @@ async function downloadPdf() {
|
||||
const url = URL.createObjectURL(response.data);
|
||||
const anchor = document.createElement("a");
|
||||
anchor.href = url;
|
||||
anchor.download = `蝶雅新品风险预估报告-${report.value.subjectId}.pdf`;
|
||||
anchor.download = `蝶雅新品风险预警报告-${report.value.subjectId}.pdf`;
|
||||
anchor.click();
|
||||
URL.revokeObjectURL(url);
|
||||
}
|
||||
@ -215,9 +215,9 @@ function dimensionConclusion(item: {
|
||||
当前会话暂无报告,请返回对话后从风险评估结果卡片点击“生成报告”。
|
||||
</p>
|
||||
<article v-else class="report-sheet">
|
||||
<h1>新品风险预估报告</h1>
|
||||
<h1>新品风险预警报告</h1>
|
||||
<p class="report-subtitle">
|
||||
蝶雅产品部 · 风险预估系统 · 自动生成 · {{ generatedAt }}
|
||||
蝶雅产品部 · 风险预警系统 · 自动生成 · {{ generatedAt }}
|
||||
</p>
|
||||
<div class="report-meta">
|
||||
<span><b>产品/评估对象:</b>{{ report.subjectId }}</span>
|
||||
@ -445,7 +445,7 @@ function dimensionConclusion(item: {
|
||||
</p>
|
||||
|
||||
<footer class="report-footer">
|
||||
<span>编制:蝶雅风险预估系统</span
|
||||
<span>编制:蝶雅风险预警系统</span
|
||||
><span>生成时间:{{ generatedAt }}</span>
|
||||
</footer>
|
||||
</article>
|
||||
|
||||
@ -87,7 +87,7 @@ const permissionRows = [
|
||||
},
|
||||
{ role: "审核员", assess: true, submit: false, review: true, weights: false },
|
||||
{
|
||||
role: "普通用户",
|
||||
role: "user",
|
||||
assess: true,
|
||||
submit: false,
|
||||
review: false,
|
||||
|
||||
@ -101,7 +101,7 @@ const loadingText = computed(() =>
|
||||
loading.value ? "正在调用风险评分引擎…" : "",
|
||||
);
|
||||
const canMonitor = computed(
|
||||
() => auth.user?.role === "admin" || auth.user?.role === "manager",
|
||||
() => auth.user?.role === "admin" || auth.user?.role === "product_manager",
|
||||
);
|
||||
|
||||
onMounted(async () => {
|
||||
|
||||
@ -9,7 +9,7 @@ const router = createRouter({
|
||||
});
|
||||
|
||||
router.afterEach((to) => {
|
||||
document.title = `${String(to.meta.title ?? "风险预测")} | 蝶雅风险预测`;
|
||||
document.title = `${String(to.meta.title ?? "风险预警助手")} | 蝶雅风险预警助手`;
|
||||
});
|
||||
|
||||
router.beforeEach(async (to) => {
|
||||
|
||||
@ -2,7 +2,7 @@ export const roleLabels: Record<string, string> = {
|
||||
admin: "管理员",
|
||||
product_manager: "产品经理",
|
||||
reviewer: "审核员",
|
||||
普通用户: "普通用户",
|
||||
user: "普通用户",
|
||||
};
|
||||
|
||||
export function roleLabel(role: string | null | undefined) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user