feat(P4): precompute移植+app.js sources双向回填+回归1003/1003+验收体积/文件/data.json
This commit is contained in:
@@ -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>
|
||||
@@ -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>} />
|
||||
*/
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
Reference in New Issue
Block a user