feat(P4): precompute移植+app.js sources双向回填+回归1003/1003+验收体积/文件/data.json
Deploy to GitHub Pages / deploy (push) Failing after 16s
Regression / regression (push) Failing after 15m2s

This commit is contained in:
aurora-admin
2026-09-12 14:18:41 +08:00
parent 16f365a045
commit c65a69c34e
401 changed files with 22932 additions and 140 deletions
+81
View File
@@ -0,0 +1,81 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Aurora Admin · AnchorNav (H5)</title>
<link rel="stylesheet" href="../.design_library/aurora-admin/colors_and_type.css">
<link rel="stylesheet" href="./AnchorNav.css">
<style>
.demo { padding: 24px 200px 400px 24px; background: var(--au-color-page-bg); font-family: var(--font-family); color: var(--au-color-text-body); }
h1 { font-size: 20px; margin: 0 0 24px; color: var(--au-color-text-title); }
.sub { color: var(--au-color-text-secondary); margin: 0 0 24px; font-size: 12px; }
section { background: var(--au-color-card-bg); border: 1px solid var(--au-color-border); border-radius: 8px; padding: 20px 24px; margin-bottom: 24px; scroll-margin-top: 24px; }
section h2 { font-size: 16px; margin: 0 0 8px; }
section p { color: var(--au-color-text-tertiary); line-height: 1.8; margin: 0; }
</style>
</head>
<body>
<div class="demo">
<h1>Aurora Admin · AnchorNav 组件(纯 H5)</h1>
<p class="sub">对齐 AnchorNav 规范:右侧目录、滚动高亮、层级嵌套、点击平滑滚动</p>
<nav class="aa-anchor fixed" id="anchor"></nav>
<section id="intro"><h2>1. 产品简介</h2><p>本系统是一套企业级中后台解决方案……(长文本占位,可滚动测试高亮)</p><p style="margin-top:40px">更多内容用于撑高页面,方便观察当前章节高亮效果。</p></section>
<section id="install"><h2>2. 安装与初始化</h2><p>通过 npm 安装后,在入口文件引入主题与组件库。</p><p style="margin-top:40px">配置项说明略。</p></section>
<section id="guide">
<h2>3. 开发指南</h2>
<p>包含布局、主题与国际化三部分。</p>
<div id="layout" style="margin-top:16px"><h3>3.1 布局</h3><p>侧边栏 + 顶栏的经典后台布局。</p></div>
<div id="theme" style="margin-top:16px"><h3>3.2 主题</h3><p>通过 CSS 变量统一调整品牌色。</p></div>
</section>
<section id="faq"><h2>4. 常见问题</h2><p>收集部署与升级中的高频问题。</p><p style="margin-top:40px">FAQ 列表略。</p></section>
</div>
<script>
const ITEMS = [
{ key: 'intro', label: '产品简介' },
{ key: 'install', label: '安装与初始化' },
{ key: 'guide', label: '开发指南', children: [
{ key: 'layout', label: '布局' },
{ key: 'theme', label: '主题' }
] },
{ key: 'faq', label: '常见问题' }
];
const allKeys = [];
(function collect(list) { list.forEach(i => { allKeys.push(i.key); if (i.children) collect(i.children); }); })(ITEMS);
const anchor = document.getElementById('anchor');
function render() {
anchor.innerHTML = ITEMS.map(it => {
let html = `<button class="aa-anchor-item" role="link" tabindex="0" data-key="${it.key}">${it.label}</button>`;
if (it.children) {
html += '<div class="aa-anchor-sub">' + it.children.map(c => `<button class="aa-anchor-item" role="link" tabindex="0" data-key="${c.key}">${c.label}</button>`).join('') + '</div>';
}
return html;
}).join('');
}
render();
anchor.addEventListener('click', (e) => {
const btn = e.target.closest('.aa-anchor-item');
if (!btn) return;
const el = document.getElementById(btn.dataset.key);
if (el) window.scrollTo({ top: el.getBoundingClientRect().top + window.scrollY - 24, behavior: 'smooth' });
});
function updateActive() {
const pos = window.scrollY + 80;
let active = allKeys[0];
for (const k of allKeys) {
const el = document.getElementById(k);
if (el && el.offsetTop <= pos) active = k;
}
anchor.querySelectorAll('.aa-anchor-item').forEach(b => b.classList.toggle('is-active', b.dataset.key === active));
}
window.addEventListener('scroll', updateActive);
updateActive();
</script>
</body>
</html>
+59
View File
@@ -0,0 +1,59 @@
import React, { useState, useEffect } from 'react';
import './AnchorNav.css';
/**
* Aurora Admin AnchorNav(React)
* 对齐 组件7.txt AnchorNav 规范:右侧目录、滚动高亮、层级嵌套、点击平滑滚动
*
* props:
* - items : [{ key, label, children? }](key 对应页面元素 id)
* - fixed
* - offset : 滚动偏移(避开吸顶高度)
*/
export default function AnchorNav({ items = [], fixed = false, offset = 24 }) {
const allKeys = [];
(function collect(list) { list.forEach(i => { allKeys.push(i.key); if (i.children) collect(i.children); }); })(items);
const [active, setActive] = useState(items[0] ? items[0].key : '');
const go = (key) => {
const el = document.getElementById(key);
if (el) window.scrollTo({ top: el.getBoundingClientRect().top + window.scrollY - offset, behavior: 'smooth' });
};
useEffect(() => {
const onScroll = () => {
const pos = window.scrollY + 80;
let cur = allKeys[0];
for (const k of allKeys) {
const el = document.getElementById(k);
if (el && el.offsetTop <= pos) cur = k;
}
setActive(cur);
};
window.addEventListener('scroll', onScroll);
return () => window.removeEventListener('scroll', onScroll);
}, []);
return (
<nav className={`aa-anchor${fixed ? ' fixed' : ''}`}>
{items.map(it => (
<div key={it.key}>
<button className={`aa-anchor-item${active === it.key ? ' is-active' : ''}`} onClick={() => go(it.key)}>{it.label}</button>
{it.children && (
<div className="aa-anchor-sub">
{it.children.map(c => (
<button key={c.key} className={`aa-anchor-item${active === c.key ? ' is-active' : ''}`} onClick={() => go(c.key)}>{c.label}</button>
))}
</div>
)}
</div>
))}
</nav>
);
}
/*
用法示例:
import AnchorNav from './AnchorNav';
const items = [{ key: 'intro', label: '简介' }, { key: 'guide', label: '指南', children: [{ key: 'layout', label: '布局' }] }];
<AnchorNav items={items} fixed />
*/
+62
View File
@@ -0,0 +1,62 @@
<template>
<nav class="aa-anchor" :class="{ fixed }">
<template v-for="(it, i) in items" :key="it.key">
<button class="aa-anchor-item" :class="{ 'is-active': active === it.key }" @click="go(it.key)">{{ it.label }}</button>
<div v-if="it.children" class="aa-anchor-sub">
<button
v-for="c in it.children" :key="c.key"
class="aa-anchor-item" :class="{ 'is-active': active === c.key }"
@click="go(c.key)"
>{{ c.label }}</button>
</div>
</template>
</nav>
</template>
<script>
export default {
name: 'AaAnchorNav',
props: {
items: { type: Array, required: true }, // [{ key, label, children? }]
fixed: { type: Boolean, default: false },
offset: { type: Number, default: 24 }
},
data() { return { active: this.items[0] ? this.items[0].key : '' }; },
computed: {
allKeys() {
const out = [];
(function collect(list) { list.forEach(i => { out.push(i.key); if (i.children) collect(i.children); }); })(this.items);
return out;
}
},
methods: {
go(key) {
const el = document.getElementById(key);
if (el) window.scrollTo({ top: el.getBoundingClientRect().top + window.scrollY - this.offset, behavior: 'smooth' });
},
onScroll() {
const pos = window.scrollY + 80;
let cur = this.allKeys[0];
for (const k of this.allKeys) {
const el = document.getElementById(k);
if (el && el.offsetTop <= pos) cur = k;
}
this.active = cur;
}
},
mounted() { window.addEventListener('scroll', this.onScroll); },
beforeDestroy() { window.removeEventListener('scroll', this.onScroll); }
};
</script>
<!-- 样式对齐 组件7.txt AnchorNav 规范 -->
<style>
.aa-anchor { font-family: var(--font-family, -apple-system, "PingFang SC", "Microsoft YaHei", sans-serif); width: 160px; }
.aa-anchor.fixed { position: fixed; right: 24px; top: 80px; }
.aa-anchor-item { display: block; padding: 6px 12px; font-size: 13px; color: #6E6E6E; cursor: pointer; border-left: 2px solid #E8ECF1; line-height: 1.4; transition: color .15s, border-color .15s; background: none; border-top: none; border-right: none; border-bottom: none; text-align: left; width: 100%; }
.aa-anchor-item:hover { color: #2F54EB; }
.aa-anchor-item.is-active { color: #2F54EB; border-left-color: #2F54EB; font-weight: 500; }
.aa-anchor-sub { padding-left: 8px; }
.aa-anchor-sub .aa-anchor-item { border-left: none; padding-left: 20px; }
.aa-anchor-sub .aa-anchor-item.is-active { border-left: 2px solid #2F54EB; }
</style>
+56
View File
@@ -0,0 +1,56 @@
<template>
<nav class="aa-anchor" :class="{ fixed }">
<template v-for="(it, i) in items" :key="it.key">
<button class="aa-anchor-item" :class="{ 'is-active': active === it.key }" @click="go(it.key)">{{ it.label }}</button>
<div v-if="it.children" class="aa-anchor-sub">
<button
v-for="c in it.children" :key="c.key"
class="aa-anchor-item" :class="{ 'is-active': active === c.key }"
@click="go(c.key)"
>{{ c.label }}</button>
</div>
</template>
</nav>
</template>
<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue';
const props = defineProps({
items: { type: Array, required: true }, // [{ key, label, children? }](key 对应页面元素 id)
fixed: { type: Boolean, default: false },
offset: { type: Number, default: 24 } // 滚动偏移(避开吸顶高度)
});
const active = ref(props.items[0] ? props.items[0].key : '');
const allKeys = [];
(function collect(list) { list.forEach(i => { allKeys.push(i.key); if (i.children) collect(i.children); }); })(props.items);
function go(key) {
const el = document.getElementById(key);
if (el) window.scrollTo({ top: el.getBoundingClientRect().top + window.scrollY - props.offset, behavior: 'smooth' });
}
function onScroll() {
const pos = window.scrollY + 80;
let cur = allKeys[0];
for (const k of allKeys) {
const el = document.getElementById(k);
if (el && el.offsetTop <= pos) cur = k;
}
active.value = cur;
}
onMounted(() => window.addEventListener('scroll', onScroll));
onBeforeUnmount(() => window.removeEventListener('scroll', onScroll));
</script>
<!-- 样式对齐 组件7.txt AnchorNav 规范 -->
<style scoped>
.aa-anchor { font-family: var(--font-family, -apple-system, "PingFang SC", "Microsoft YaHei", sans-serif); width: 160px; }
.aa-anchor.fixed { position: fixed; right: 24px; top: 80px; }
.aa-anchor-item { display: block; padding: 6px 12px; font-size: 13px; color: #6E6E6E; cursor: pointer; border-left: 2px solid #E8ECF1; line-height: 1.4; transition: color .15s, border-color .15s; background: none; border-top: none; border-right: none; border-bottom: none; text-align: left; width: 100%; }
.aa-anchor-item:hover { color: #2F54EB; }
.aa-anchor-item.is-active { color: #2F54EB; border-left-color: #2F54EB; font-weight: 500; }
.aa-anchor-sub { padding-left: 8px; }
.aa-anchor-sub .aa-anchor-item { border-left: none; padding-left: 20px; }
.aa-anchor-sub .aa-anchor-item.is-active { border-left: 2px solid #2F54EB; }
</style>