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
+84
View File
@@ -0,0 +1,84 @@
<!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 · Collapse (H5)</title>
<link rel="stylesheet" href="../.design_library/aurora-admin/colors_and_type.css">
<link rel="stylesheet" href="./Collapse.css">
<style>
.demo { padding: 24px; background: var(--au-color-page-bg); font-family: var(--font-family); }
h1 { font-size: 20px; margin: 0 0 4px; color: var(--au-color-text-title); }
.sub { color: var(--au-color-text-secondary); margin: 0 0 24px; font-size: 12px; }
.demo-block { max-width: 560px; margin-bottom: 24px; }
.demo-block > .hint { color: var(--au-color-text-secondary); font-size: 12px; margin: 0 0 12px; }
</style>
</head>
<body>
<div class="demo">
<h1>Aurora Admin · Collapse 组件(纯 H5)</h1>
<p class="sub">对齐规范:标题栏高40px、左侧箭头旋转90°、内容分割线、手风琴模式</p>
<div class="demo-block">
<p class="hint">手风琴模式(同时仅展开一个)</p>
<div class="aa-collapse" data-accordion>
<div class="aa-collapse-item is-open">
<div class="aa-collapse-header" role="button" tabindex="0"><span class="aa-collapse-arrow">▶</span><span class="aa-collapse-title">基本设置</span></div>
<div class="aa-collapse-content">系统名称、主题色、默认语言等基础配置。</div>
</div>
<div class="aa-collapse-item">
<div class="aa-collapse-header" role="button" tabindex="0"><span class="aa-collapse-arrow">▶</span><span class="aa-collapse-title">通知设置</span></div>
<div class="aa-collapse-content" hidden>邮件、短信、站内信通知开关。</div>
</div>
<div class="aa-collapse-item">
<div class="aa-collapse-header" role="button" tabindex="0"><span class="aa-collapse-arrow">▶</span><span class="aa-collapse-title">安全设置</span></div>
<div class="aa-collapse-content" hidden>登录保护、密码策略、IP 白名单。</div>
</div>
<div class="aa-collapse-item is-disabled">
<div class="aa-collapse-header" role="button" tabindex="0"><span class="aa-collapse-arrow">▶</span><span class="aa-collapse-title">高级(无权限)</span></div>
<div class="aa-collapse-content" hidden>仅管理员可见的高级选项。</div>
</div>
</div>
</div>
<div class="demo-block">
<p class="hint">非手风琴(可同时展开多个)</p>
<div class="aa-collapse">
<div class="aa-collapse-item is-open">
<div class="aa-collapse-header" role="button" tabindex="0"><span class="aa-collapse-arrow">▶</span><span class="aa-collapse-title">订单管理</span></div>
<div class="aa-collapse-content">查看与处理所有订单。</div>
</div>
<div class="aa-collapse-item is-open">
<div class="aa-collapse-header" role="button" tabindex="0"><span class="aa-collapse-arrow">▶</span><span class="aa-collapse-title">退款管理</span></div>
<div class="aa-collapse-content">退款审核与到账记录。</div>
</div>
</div>
</div>
</div>
<script>
document.querySelectorAll('.aa-collapse').forEach(root => {
const accordion = root.hasAttribute('data-accordion');
root.addEventListener('click', (e) => {
const header = e.target.closest('.aa-collapse-header');
if (!header) return;
const item = header.parentElement;
if (item.classList.contains('is-disabled')) return;
const open = item.classList.toggle('is-open');
const content = item.querySelector('.aa-collapse-content');
if (content) content.hidden = !open;
if (accordion && open) {
root.querySelectorAll('.aa-collapse-item.is-open').forEach(other => {
if (other !== item) {
other.classList.remove('is-open');
const c = other.querySelector('.aa-collapse-content');
if (c) c.hidden = true;
}
});
}
});
});
</script>
</body>
</html>
+74
View File
@@ -0,0 +1,74 @@
import React, { useState } from 'react';
import './Collapse.css';
/**
* Aurora Admin Collapse(React)
* 对齐 组件2.txt 规范:标题栏高40px、左侧箭头旋转90°、内容分割线、手风琴模式
*
* props:
* - items : [{ key, title, disabled? }]
* - accordion: Boolean(手风琴模式,同时仅展开一个)
* - value / defaultValue : 展开 key 数组(手风琴时为单个 key 字符串)
* - onChange(keys)
* - renderPanel(key) / children(key) : 返回对应面板内容
*/
export default function Collapse({
items = [],
accordion = false,
value,
defaultValue = accordion ? '' : [],
onChange,
renderPanel
}) {
const panelFn = renderPanel || (typeof children === 'function' ? children : null);
const [inner, setInner] = useState(defaultValue);
const open = value !== undefined ? value : inner;
const openList = accordion ? (open ? [open] : []) : (Array.isArray(open) ? open : []);
const isOpen = (k) => openList.includes(k);
const toggle = (item) => {
if (item.disabled) return;
let next;
if (accordion) {
next = isOpen(item.key) ? [] : [item.key];
} else {
next = isOpen(item.key) ? openList.filter(k => k !== item.key) : [...openList, item.key];
}
const result = accordion ? (next[0] || '') : next;
if (value === undefined) setInner(result);
onChange && onChange(result);
};
return (
<div className="aa-collapse">
{items.map((item) => (
<div
key={item.key}
className={`aa-collapse-item${isOpen(item.key) ? ' is-open' : ''}${item.disabled ? ' is-disabled' : ''}`}
>
<div className="aa-collapse-header" onClick={() => toggle(item)}>
<span className="aa-collapse-arrow">▶</span>
<span className="aa-collapse-title">{item.title}</span>
</div>
{isOpen(item.key) && (
<div className="aa-collapse-content">
{panelFn ? panelFn(item.key) : null}
</div>
)}
</div>
))}
</div>
);
}
/*
用法示例:
import Collapse from './Collapse';
const items = [
{ key: 'a', title: '基本设置' },
{ key: 'b', title: '通知设置' },
{ key: 'c', title: '高级', disabled: true }
];
<Collapse accordion items={items} defaultValue="a" renderPanel={(k) => <div>内容:{k}</div>} />
*/
+67
View File
@@ -0,0 +1,67 @@
<template>
<div class="aa-collapse">
<div
v-for="item in items" :key="item.key"
class="aa-collapse-item"
:class="{ 'is-open': isOpen(item.key), 'is-disabled': item.disabled }"
>
<div class="aa-collapse-header" @click="toggle(item)">
<span class="aa-collapse-arrow">▶</span>
<span class="aa-collapse-title">{{ item.title }}</span>
</div>
<div v-show="isOpen(item.key)" class="aa-collapse-content">
<slot :name="item.key"><slot /></slot>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'AaCollapse',
props: {
value: { type: [Array, String], default: () => [] }, // 展开 key 列表(手风琴时为单个 key)
items: { type: Array, required: true }, // [{ key, title, disabled? }]
accordion: { type: Boolean, default: false }
},
computed: {
openList() {
return this.accordion
? (this.value ? [this.value] : [])
: Array.isArray(this.value) ? this.value : [];
}
},
methods: {
isOpen(key) { return this.openList.includes(key); },
toggle(item) {
if (item.disabled) return;
let next;
if (this.accordion) {
next = this.isOpen(item.key) ? [] : [item.key];
} else {
next = this.isOpen(item.key)
? this.openList.filter(k => k !== item.key)
: [...this.openList, item.key];
}
this.$emit('input', this.accordion ? (next[0] || '') : next);
this.$emit('change', this.accordion ? (next[0] || '') : next);
}
}
};
</script>
<!-- 样式对齐 组件2.txt 规范 -->
<style>
.aa-collapse { border: 1px solid #E8ECF1; border-radius: 6px; overflow: hidden; font-family: var(--font-family, -apple-system, "PingFang SC", "Microsoft YaHei", sans-serif); color: #262626; background: #fff; }
.aa-collapse-item + .aa-collapse-item { border-top: 1px solid #E8ECF1; }
.aa-collapse-header { display: flex; align-items: center; gap: 8px; height: 40px; padding: 0 16px; cursor: pointer;
font-size: 14px; color: #262626; background: #fff; transition: background .15s; user-select: none; }
.aa-collapse-header:hover { background: #F5F7FA; }
.aa-collapse-item.is-disabled .aa-collapse-header { color: #BFBFBF; cursor: not-allowed; background: #fff; }
.aa-collapse-arrow { display: inline-flex; align-items: center; justify-content: center; width: 16px; height: 16px;
color: #6E6E6E; font-size: 12px; transition: transform .2s ease; transform: rotate(0deg); }
.aa-collapse-item.is-open .aa-collapse-arrow { transform: rotate(90deg); }
.aa-collapse-title { flex: 1; }
.aa-collapse-content { padding: 16px; font-size: 14px; line-height: 1.6; color: #595959; border-top: 1px solid #E8ECF1; background: #fff; }
.aa-collapse-item.is-disabled .aa-collapse-content { color: #BFBFBF; }
</style>
+65
View File
@@ -0,0 +1,65 @@
<template>
<div class="aa-collapse">
<div
v-for="item in items" :key="item.key"
class="aa-collapse-item"
:class="{ 'is-open': isOpen(item.key), 'is-disabled': item.disabled }"
>
<div class="aa-collapse-header" @click="toggle(item)">
<span class="aa-collapse-arrow">▶</span>
<span class="aa-collapse-title">{{ item.title }}</span>
</div>
<div v-show="isOpen(item.key)" class="aa-collapse-content">
<slot :name="item.key"><slot /></slot>
</div>
</div>
</div>
</template>
<script setup>
import { computed } from 'vue';
const props = defineProps({
modelValue: { type: [Array, String, null], default: () => [] }, // 展开 key 列表(手风琴时为单个 key)
items: { type: Array, required: true }, // [{ key, title, disabled? }]
accordion: { type: Boolean, default: false }
});
const emit = defineEmits(['update:modelValue', 'change']);
const openList = computed(() =>
props.accordion
? (props.modelValue ? [props.modelValue] : [])
: Array.isArray(props.modelValue) ? props.modelValue : []
);
function isOpen(key) { return openList.value.includes(key); }
function toggle(item) {
if (item.disabled) return;
let next;
if (props.accordion) {
next = isOpen(item.key) ? [] : [item.key];
} else {
next = isOpen(item.key)
? openList.value.filter(k => k !== item.key)
: [...openList.value, item.key];
}
emit('update:modelValue', props.accordion ? (next[0] ?? '') : next);
emit('change', props.accordion ? (next[0] ?? '') : next);
}
</script>
<!-- 样式对齐 组件2.txt 规范 -->
<style scoped>
.aa-collapse { border: 1px solid #E8ECF1; border-radius: 6px; overflow: hidden; font-family: var(--font-family, -apple-system, "PingFang SC", "Microsoft YaHei", sans-serif); color: #262626; background: #fff; }
.aa-collapse-item + .aa-collapse-item { border-top: 1px solid #E8ECF1; }
.aa-collapse-header { display: flex; align-items: center; gap: 8px; height: 40px; padding: 0 16px; cursor: pointer;
font-size: 14px; color: #262626; background: #fff; transition: background .15s; user-select: none; }
.aa-collapse-header:hover { background: #F5F7FA; }
.aa-collapse-item.is-disabled .aa-collapse-header { color: #BFBFBF; cursor: not-allowed; background: #fff; }
.aa-collapse-arrow { display: inline-flex; align-items: center; justify-content: center; width: 16px; height: 16px;
color: #6E6E6E; font-size: 12px; transition: transform .2s ease; transform: rotate(0deg); }
.aa-collapse-item.is-open .aa-collapse-arrow { transform: rotate(90deg); }
.aa-collapse-title { flex: 1; }
.aa-collapse-content { padding: 16px; font-size: 14px; line-height: 1.6; color: #595959; border-top: 1px solid #E8ECF1; background: #fff; }
.aa-collapse-item.is-disabled .aa-collapse-content { color: #BFBFBF; }
</style>