docs(requirements): 需求裁决对照表 v2、功能模块清单与 M1 设计产物入库(移除被 v2 取代的旧清单)

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
liuwenxinandClaude Code committed 2026-10-13 09:26:21 +08:00
1 parent 8668e58c30
commit e568ebde61
9 files changed
+1896

No files matched your search

+45
View File
@@ -0,0 +1,45 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).echarts={})}(this,(function(t){"use strict";
/*! *****************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */var e=function(t,n){return e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n])},e(t,n)};function n(t,n){if("function"!=typeof n&&null!==n)throw new TypeError("Class extends value "+String(n)+" is not a constructor or null");function i(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(i.prototype=n.prototype,new i)}var i=function(){this.firefox=!1,this.ie=!1,this.edge=!1,this.newEdge=!1,this.weChat=!1},r=new function(){this.browser=new i,this.node=!1,this.wxa=!1,this.worker=!1,this.svgSupported=!1,this.touchEventsSupported=!1,this.pointerEventsSupported=!1,this.domSupported=!1,this.transformSupported=!1,this.transform3dSupported=!1,this.hasGlobalWindow="undefined"!=typeof window};"object"==typeof wx&&"function"==typeof wx.getSystemInfoSync?(r.wxa=!0,r.touchEventsSupported=!0):"undefined"==typeof document&&"undefined"!=typeof self?r.worker=!0:"undefined"==typeof navigator||0===navigator.userAgent.indexOf("Node.js")?(r.node=!0,r.svgSupported=!0):function(t,e){var n=e.browser,i=t.match(/Firefox\/([\d.]+)/),r=t.match(/MSIE\s([\d.]+)/)||t.match(/Trident\/.+?rv:(([\d.]+))/),o=t.match(/Edge?\/([\d.]+)/),a=/micromessenger/i.test(t);i&&(n.firefox=!0,n.version=i[1]);r&&(n.ie=!0,n.version=r[1]);o&&(n.edge=!0,n.version=o[1],n.newEdge=+o[1].split(".")[0]>18);a&&(n.weChat=!0);e.svgSupported="undefined"!=typeof SVGRect,e.touchEventsSupported="ontouchstart"in window&&!n.ie&&!n.edge,e.pointerEventsSupported="onpointerdown"in window&&(n.edge||n.ie&&+n.version>=11),e.domSupported="undefined"!=typeof document;var s=document.documentElement.style;e.transform3dSupported=(n.ie&&"transition"in s||n.edge||"WebKitCSSMatrix"in window&&"m11"in new WebKitCSSMatrix||"MozPerspective"in s)&&!("OTransition"in s),e.transformSupported=e.transform3dSupported||n.ie&&+n.version>=9}(navigator.userAgent,r);var o="sans-serif",a="12px "+o;var s,l,u=function(t){var e={};if("undefined"==typeof JSON)return e;for(var n=0;n<t.length;n++){var i=String.fromCharCode(n+32),r=(t.charCodeAt(n)-20)/100;e[i]=r}return e}("007LLmW'55;N0500LLLLLLLLLL00NNNLzWW\\\\WQb\\0FWLg\\bWb\\WQ\\WrWWQ000CL5LLFLL0LL**F*gLLLL5F0LF\\FFF5.5N"),h={createCanvas:function(){return"undefined"!=typeof document&&document.createElement("canvas")},measureText:function(t,e){if(!s){var n=h.createCanvas();s=n&&n.getContext("2d")}if(s)return l!==e&&(l=s.font=e||a),s.measureText(t);t=t||"";var i=/((?:\d+)?\.?\d*)px/.exec(e=e||a),r=i&&+i[1]||12,o=0;if(e.indexOf("mono")>=0)o=r*t.length;else for(var c=0;c<t.length;c++){var p=u[t[c]];o+=null==p?r:p*r}return{width:o}},loadImage:function(t,e,n){var i=new Image;return i.onload=e,i.onerror=n,i.src=t,i}};function c(t){for(var e in h)t[e]&&(h[e]=t[e])}var p=V(["Function","RegExp","Date","Error","CanvasGradient","CanvasPattern","Image","Canvas"],(function(t,e){return t["[object "+e+"]"]=!0,t}),{}),d=V(["Int8","Uint8","Uint8Clamped","Int16","Uint16","Int32","Uint32","Float32","Float64"],(function(t,e){return t["[object "+e+"Array]"]=!0,t}),{}),f=Object.prototype.toString,g=Array.prototype,y=g.forEach,v=g.filter,m=g.slice,x=g.map,_=function(){}.constructor,b=_?_.prototype:null,w="__proto__",S=2311;function M(){return S++}function I(){for(var t=[],e=0;e<arguments.length;e++)t[e]=arguments[e];"undefined"!=typeof console&&console.error.apply(console,t)}function T(t){if(null==t||"object"!=typeof t)return t;var e=t,n=f.call(t);if("[object Array]"===n){if(!pt(t)){e=[];for(var i=0,r=t.length;i<r;i++)e[i]=T(t[i])}}else if(d[n]){if(!pt(t)){var o=t.constructor;if(o.from)e=o.from(t);else{e=new o(t.length);for(i=0,r=t.length;i<r;i++)e[i]=t[i]}}}else if(!p[n]&&!pt(t)&&!J(t))for(var a in e={},t)t.hasOwnProperty(a)&&a!==w&&(e[a]=T(t[a]));return e}function C(t,e,n){if(!q(e)||!q(t))return n?T(e):t;for(var i in e)if(e.hasOwnProperty(i)&&i!==w){var r=t[i],o=e[i];!q(o)||!q(r)||Y(o)||Y(r)||J(o)||J(r)||K(o)||K(r)||pt(o)||pt(r)?!n&&i in t||(t[i]=T(e[i])):C(r,o,n)}return t}function D(t,e){for(var n=t[0],i=1,r=t.length;i<r;i++)n=C(n,t[i],e);return n}function A(t,e){if(Object.assign)Object.assign(t,e);else for(var n in e)e.hasOwnProperty(n)&&n!==w&&(t[n]=e[n]);return t}function k(t,e,n){for(var i=G(e),r=0;r<i.length;r++){var o=i[r];(n?null!=e[o]:null==t[o])&&(t[o]=e[o])}return t}var L=h.createCanvas;function P(t,e){if(t){if(t.indexOf)return t.indexOf(e);for(var n=0,i=t.length;n<i;n++)if(t[n]===e)return n}return-1}function O(t,e){var n=t.prototype;function i(){}for(var r in i.prototype=e.prototype,t.prototype=new i,n)n.hasOwnProperty(r)&&(t.prototype[r]=n[r]);t.prototype.constructor=t,t.superClass=e}function R(t,e,n){if(t="prototype"in t?t.prototype:t,e="prototype"in e?e.prototype:e,Object.getOwnPropertyNames)for(var i=Object.getOwnPropertyNames(e),r=0;r<i.length;r++){var o=i[r];"constructor"!==o&&(n?null!=e[o]:null==t[o])&&(t[o]=e[o])}else k(t,e,n)}function N(t){retuLine truncated
/*!
* ZRender, a high performance 2d drawing library.
*
* Copyright (c) 2013, Baidu Inc.
* All rights reserved.
*
* LICENSE
* https://github.com/ecomfe/zrender/blob/master/LICENSE.txt
*/
var Fr={},Gr={};var Wr,Hr=function(){function t(t,e,n){var i=this;this._sleepAfterStill=10,this._stillFrameAccum=0,this._needsRefresh=!0,this._needsRefreshHover=!0,this._darkMode=!1,n=n||{},this.dom=e,this.id=t;var o=new rn,a=n.renderer||"canvas";Fr[a]||(a=G(Fr)[0]),n.useDirtyRect=null!=n.useDirtyRect&&n.useDirtyRect;var s=new Fr[a](e,o,n,t),l=n.ssr||s.ssrOnly;this.storage=o,this.painter=s;var u,h=r.node||r.worker||l?null:new or(s.getViewportRoot(),s.root),c=n.useCoarsePointer;(null==c||"auto"===c?r.touchEventsSupported:!!c)&&(u=rt(n.pointerSize,44)),this.handler=new Ye(o,s,h,s.root,u),this.animation=new Wi({stage:{update:l?null:function(){return i._flush(!0)}}}),l||this.animation.start()}return t.prototype.add=function(t){!this._disposed&&t&&(this.storage.addRoot(t),t.addSelfToZr(this),this.refresh())},t.prototype.remove=function(t){!this._disposed&&t&&(this.storage.delRoot(t),t.removeSelfFromZr(this),this.refresh())},t.prototype.configLayer=function(t,e){this._disposed||(this.painter.configLayer&&this.painter.configLayer(t,e),this.refresh())},t.prototype.setBackgroundColor=function(t){this._disposed||(this.painter.setBackgroundColor&&this.painter.setBackgroundColor(t),this.refresh(),this._backgroundColor=t,this._darkMode=function(t){if(!t)return!1;if("string"==typeof t)return oi(t,1)<.4;if(t.colorStops){for(var e=t.colorStops,n=0,i=e.length,r=0;r<i;r++)n+=oi(e[r].color,1);return(n/=i)<.4}return!1}(t))},t.prototype.getBackgroundColor=function(){return this._backgroundColor},t.prototype.setDarkMode=function(t){this._darkMode=t},t.prototype.isDarkMode=function(){return this._darkMode},t.prototype.refreshImmediately=function(t){this._disposed||(t||this.animation.update(!0),this._needsRefresh=!1,this.painter.refresh(),this._needsRefresh=!1)},t.prototype.refresh=function(){this._disposed||(this._needsRefresh=!0,this.animation.start())},t.prototype.flush=function(){this._disposed||this._flush(!1)},t.prototype._flush=function(t){var e,n=Bi();this._needsRefresh&&(e=!0,this.refreshImmediately(t)),this._needsRefreshHover&&(e=!0,this.refreshHoverImmediately());var i=Bi();e?(this._stillFrameAccum=0,this.trigger("rendered",{elapsedTime:i-n})):this._sleepAfterStill>0&&(this._stillFrameAccum++,this._stillFrameAccum>this._sleepAfterStill&&this.animation.stop())},t.prototype.setSleepAfterStill=function(t){this._sleepAfterStill=t},t.prototype.wakeUp=function(){this._disposed||(this.animation.start(),this._stillFrameAccum=0)},t.prototype.refreshHover=function(){this._needsRefreshHover=!0},t.prototype.refreshHoverImmediately=function(){this._disposed||(this._needsRefreshHover=!1,this.painter.refreshHover&&"canvas"===this.painter.getType()&&this.painter.refreshHover())},t.prototype.resize=function(t){this._disposed||(t=t||{},this.painter.resize(t.width,t.height),this.handler.resize())},t.prototype.clearAnimation=function(){this._disposed||this.animation.clear()},t.prototype.getWidth=function(){if(!this._disposed)return this.painter.getWidth()},t.prototype.getHeight=function(){if(!this._disposed)return this.painter.getHeight()},t.prototype.setCursorStyle=function(t){this._disposed||this.handler.setCursorStyle(t)},t.prototype.findHover=function(t,e){if(!this._disposed)return this.handler.findHover(t,e)},t.prototype.on=function(t,e,n){return this._disposed||this.handler.on(t,e,n),this},t.prototype.off=function(t,e){this._disposed||this.handler.off(t,e)},t.prototype.trigger=function(t,e){this._disposed||this.handler.trigger(t,e)},t.prototype.clear=function(){if(!this._disposed){for(var t=this.storage.getRoots(),e=0;e<t.length;e++)t[e]instanceof Br&&t[e].removeSelfFromZr(this);this.storage.delAllRoots(),this.painter.clear()}},t.prototype.dispose=function(){var t;this._disposed||(this.animation.stop(),this.clear(),this.storage.dispose(),this.painter.dispose(),this.handler.dispose(),this.animation=this.storage=this.painter=this.handler=null,this._disposed=!0,t=this.id,delete Gr[t])},t}();function Yr(t,e){var n=new Hr(M(),t,e);return Gr[n.id]=n,n}function Xr(t,e){Fr[t]=e}function Ur(t){if("function"==typeof Wr)return Wr(t)}function Zr(t){Wr=t}var jr=Object.freeze({__proto__:null,init:Yr,dispose:function(t){t.dispose()},disposeAll:function(){for(var t in Gr)Gr.hasOwnProperty(t)&&Gr[t].dispose();Gr={}},getInstance:function(t){return Gr[t]},registerPainter:Xr,getElementSSRData:Ur,registerSSRDataGetter:Zr,version:"5.6.0"}),qr=1e-4;function Kr(t,e,n,i){var r=e[0],o=e[1],a=n[0],s=n[1],l=o-r,u=s-a;if(0===l)return 0===u?a:(a+s)/2;if(i)if(l>0){if(t<=r)return a;if(t>=o)return s}else{if(t>=r)return a;if(t<=o)return s}else{if(t===r)return a;if(t===o)return s}return(t-r)/l*u+a}function $r(t,e){switch(t){case"center":case"middle":t="50%";break;case"left":case"top":t="0%";break;case"right":case"bottom":t="100%"}return U(t)?(n=t,n.replace(/^\s+|\s+$/g,"")).match(/%$/)?parseFloat(t)/100*e:parseFloat(t):null==t?NaN:+t;var n}function Jr(t,e,n){return null==e&&(e=10),e=Math.min(Math.max(0,e),20),t=(+t).toFixed(e),n?t:+t}function Qr(t){return t.sort((funLine truncated
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

+976
View File
@@ -0,0 +1,976 @@
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<title>衍水工资系统 · 视觉方向预览</title>
<style>
/* ============================================================
设计体系 v3(质感版):中性灰白 · 靛蓝点缀 · 微质感
质感来源(而非装饰):
1) 表面微渐变 —— 1–2% 明度差,暗示受光方向
2) 半透明描边 —— 边界在不同底色上自然融合
3) 分层阴影 —— 近距实影 + 远距弥散影叠加
4) 内高光 / 内阴影 —— 浮起与凹陷的材质暗示
5) 极微噪点 —— 去除纯色的「塑料感」
6) 精确排版 —— 字距、等宽数字、行高的一致节律
============================================================ */
:root {
--ys-indigo: #2e4ba8;
--ys-indigo-hi: #3a58bc; /* 渐变亮端 */
--ys-indigo-deep: #243c8b;
--ys-indigo-wash: #edf1fa;
--ys-paper: #ffffff;
--ys-mist: #f4f5f8; /* 页面底 */
--ys-aside-1: #f2f4f8; /* 侧栏渐变起 */
--ys-aside-2: #ecedf3; /* 侧栏渐变止 */
--ys-ink: #1c2333;
--ys-ink-2: #5b6577;
--ys-ink-3: #9aa3b2;
--ys-line: rgba(28, 35, 51, 0.09); /* 半透明描边 */
--ys-line-soft: rgba(28, 35, 51, 0.065);
--ys-ok: #1e9e6a; --ys-ok-wash-1: #ecf8f2; --ys-ok-wash-2: #e4f3ec;
--ys-warn: #c98a1b; --ys-warn-wash-1: #fbf4e4; --ys-warn-wash-2: #f8efd9;
--ys-danger: #c94f4f; --ys-danger-wash: #fbeded;
--ys-radius: 10px;
--ys-radius-sm: 7px;
--ys-font: 'PingFang SC', 'Microsoft YaHei', 'Noto Sans SC', -apple-system,
'Segoe UI', 'Helvetica Neue', Arial, sans-serif;
--ys-ease: cubic-bezier(0.25, 0.1, 0.25, 1);
/* 分层阴影:近距定义轮廓,远距弥散氛围 */
--ys-shadow-card: 0 1px 2px rgba(28, 35, 51, 0.04), 0 3px 10px rgba(28, 35, 51, 0.03);
--ys-shadow-raise: 0 1px 2px rgba(28, 35, 51, 0.05), 0 6px 18px rgba(28, 35, 51, 0.07);
/* 极微噪点:去除大色块的塑料感(内联 SVG,无外部依赖) */
--ys-noise: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
/* 品牌字:思源黑体(现代几何黑体;实施时自托管 4 字子集,内网可用) */
--ys-font-brand: 'Noto Sans SC', 'PingFang SC', 'Microsoft YaHei', sans-serif;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: var(--ys-font);
color: var(--ys-ink);
background-color: var(--ys-mist);
/* 点阵网格:22px 间距的 1px 微点 —— 给背景「秩序与密度」,不再空旷 */
background-image: radial-gradient(rgba(28, 35, 51, 0.07) 1px, transparent 1px);
background-size: 24px 24px;
font-size: 14px;
line-height: 1.6;
-webkit-font-smoothing: antialiased;
}
/* 噪点覆盖层:全页 2.2% 强度,肉眼几乎无感,但色块不再是「纯色塑料」 */
body::after {
content: ''; position: fixed; inset: 0; z-index: 2147483647;
pointer-events: none; opacity: 0.022; background-image: var(--ys-noise);
}
.num { font-variant-numeric: tabular-nums; }
.wrap { max-width: 1180px; margin: 0 auto; padding: 48px 32px 96px; }
.section { margin-top: 64px; }
.section > h2 {
font-size: 13px; font-weight: 500; letter-spacing: 0.08em;
color: var(--ys-ink-3); text-transform: uppercase;
display: flex; align-items: center; gap: 10px; margin-bottom: 20px;
}
.section > h2::after { content: ''; height: 1px; flex: 1; background: var(--ys-line); }
/* 签名元素:水线 */
.waterline {
width: 56px; height: 2px; border-radius: 1px;
background: linear-gradient(90deg, var(--ys-indigo), rgba(46, 75, 168, 0));
margin: 10px 0 0;
}
/* ---------- 封面 ---------- */
.cover { padding: 24px 0 8px; }
.cover .brand {
font-family: var(--ys-font-brand);
font-size: 15px; font-weight: 500; letter-spacing: 0.32em; color: var(--ys-ink-2);
}
.cover h1 { font-size: 30px; font-weight: 600; margin-top: 18px; letter-spacing: -0.01em; }
.cover .sub { color: var(--ys-ink-2); margin-top: 10px; font-size: 15px; }
.cover .tags { display: flex; gap: 8px; margin-top: 22px; flex-wrap: wrap; }
.tag {
font-size: 12px; color: var(--ys-ink-2);
background: linear-gradient(180deg, #ffffff, #fbfcfe);
border: 1px solid var(--ys-line); border-radius: 999px; padding: 4px 12px;
box-shadow: 0 1px 2px rgba(28, 35, 51, 0.03);
}
/* ---------- 色板 ---------- */
.swatches { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; }
.swatch {
background: linear-gradient(180deg, #ffffff, #fcfcfe);
border: 1px solid var(--ys-line); border-radius: var(--ys-radius);
overflow: hidden; box-shadow: var(--ys-shadow-card);
}
.swatch .chip { height: 76px; }
.swatch .meta { padding: 10px 14px 12px; }
.swatch .name { font-size: 13px; font-weight: 600; }
.swatch .hex { font-size: 12px; color: var(--ys-ink-2); margin-top: 2px; }
.swatch .use { font-size: 12px; color: var(--ys-ink-3); margin-top: 6px; line-height: 1.5; }
/* ---------- 字体 ---------- */
.type-sheet {
background: linear-gradient(180deg, #ffffff, #fcfcfe);
border: 1px solid var(--ys-line); border-radius: var(--ys-radius);
padding: 26px 28px; box-shadow: var(--ys-shadow-card);
}
.type-row { display: flex; align-items: baseline; gap: 24px; padding: 12px 0; border-bottom: 1px dashed var(--ys-line-soft); }
.type-row:last-child { border-bottom: 0; }
.type-row .label { width: 150px; flex: none; font-size: 12px; color: var(--ys-ink-3); }
.t-page-title { font-size: 18px; font-weight: 600; letter-spacing: -0.01em; }
.t-card-title { font-size: 15px; font-weight: 600; }
.t-body { font-size: 14px; }
.t-th { font-size: 12px; font-weight: 500; letter-spacing: 0.04em; color: var(--ys-ink-2); }
.t-amount { font-size: 15px; font-weight: 600; font-variant-numeric: tabular-nums; }
.amount-demo {
margin-top: 18px;
background: linear-gradient(180deg, #ffffff, #fcfcfe);
border: 1px solid var(--ys-line); border-radius: var(--ys-radius);
padding: 18px 28px; box-shadow: var(--ys-shadow-card);
}
.amount-demo table { width: 100%; border-collapse: collapse; font-variant-numeric: tabular-nums; }
.amount-demo th {
text-align: right; font-size: 12px; font-weight: 500; letter-spacing: 0.04em;
color: var(--ys-ink-2); padding: 6px 0; border-bottom: 1px solid var(--ys-line);
}
.amount-demo th:first-child { text-align: left; }
.amount-demo td { text-align: right; padding: 9px 0; border-bottom: 1px solid var(--ys-line-soft); font-size: 13px; }
.amount-demo td:first-child { text-align: left; color: var(--ys-ink-2); }
.amount-demo tr:last-child td { border-bottom: 0; font-weight: 600; font-size: 15px; }
/* 品牌字候选(思源黑体已装于本机;实施时自托管子集) */
.brand-candidates { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; margin-top: 14px; }
.bc {
background: linear-gradient(180deg, #ffffff, #fcfcfe);
border: 1px solid var(--ys-line); border-radius: var(--ys-radius);
box-shadow: var(--ys-shadow-card); padding: 20px 24px; text-align: center;
}
.bc-cap { font-size: 11px; color: var(--ys-ink-3); margin-top: 12px; }
.bc-rec { color: var(--ys-indigo); font-weight: 500; margin-left: 4px; }
/* ---------- 组件 ---------- */
.comp-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.comp-card {
background: linear-gradient(180deg, #ffffff, #fcfcfe);
border: 1px solid var(--ys-line); border-radius: var(--ys-radius);
padding: 22px 24px; box-shadow: var(--ys-shadow-card);
}
.comp-card h3 { font-size: 13px; font-weight: 600; color: var(--ys-ink-2); margin-bottom: 16px; letter-spacing: 0.02em; }
.row { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.btn {
height: 34px; padding: 0 16px; border-radius: var(--ys-radius-sm);
font-size: 13px; font-family: inherit; cursor: pointer;
border: 1px solid transparent;
transition: all 150ms var(--ys-ease);
}
/* 主按钮:微渐变 + 内高光 + 静置浅影 —— hover 抬升 1px、影加深 */
.btn-primary {
color: #fff;
background: linear-gradient(180deg, var(--ys-indigo-hi), var(--ys-indigo));
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.18), 0 1px 2px rgba(46, 75, 168, 0.22);
}
.btn-primary:hover {
background: linear-gradient(180deg, #31509f, var(--ys-indigo-deep));
transform: translateY(-1px);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.18), 0 4px 12px rgba(46, 75, 168, 0.3);
}
.btn-primary:active { transform: translateY(0); box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.18); }
.btn-default {
background: linear-gradient(180deg, #ffffff, #fbfcfe); color: var(--ys-ink);
border-color: var(--ys-line); box-shadow: 0 1px 2px rgba(28, 35, 51, 0.03);
}
.btn-default:hover { color: var(--ys-indigo); border-color: rgba(46, 75, 168, 0.45); }
.btn-danger { background: linear-gradient(180deg, #ffffff, #fbfcfe); color: var(--ys-danger); border-color: rgba(201, 79, 79, 0.28); }
.btn-danger:hover { border-color: rgba(201, 79, 79, 0.6); }
.btn-text { background: none; color: var(--ys-indigo); padding: 0 6px; height: auto; }
.btn-text:hover { color: var(--ys-indigo-deep); }
.btn-ghost-hover { pointer-events: none; } /* 预览:静态展示 hover 态 */
.input {
height: 34px; padding: 0 12px; border-radius: var(--ys-radius-sm);
border: 1px solid rgba(28, 35, 51, 0.13); background: #fff;
font-size: 13px; font-family: inherit; color: var(--ys-ink); width: 190px;
box-shadow: inset 0 1px 2px rgba(28, 35, 51, 0.035); /* 微凹陷:输入区的材质暗示 */
transition: border-color 150ms var(--ys-ease), box-shadow 150ms var(--ys-ease);
}
.input::placeholder { color: var(--ys-ink-3); }
.input:focus, .input.focused {
outline: none; border-color: var(--ys-indigo);
box-shadow: inset 0 1px 2px rgba(28, 35, 51, 0.03), 0 0 0 3px rgba(46, 75, 168, 0.13);
}
.pill { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; padding: 2px 10px; border-radius: 999px; white-space: nowrap; }
.pill::before { content: ''; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.pill-ok { color: var(--ys-ok); background: linear-gradient(180deg, var(--ys-ok-wash-1), var(--ys-ok-wash-2)); }
.pill-off { color: var(--ys-ink-2); background: linear-gradient(180deg, #f4f5f8, #eff1f5); }
.pill-warn { color: var(--ys-warn); background: linear-gradient(180deg, var(--ys-warn-wash-1), var(--ys-warn-wash-2)); }
.pager { display: flex; gap: 6px; align-items: center; font-size: 13px; color: var(--ys-ink-2); }
.pager .pg {
min-width: 30px; height: 30px; display: inline-flex; align-items: center; justify-content: center;
border-radius: var(--ys-radius-sm); border: 1px solid var(--ys-line);
background: linear-gradient(180deg, #ffffff, #fbfcfe); font-variant-numeric: tabular-nums;
box-shadow: 0 1px 2px rgba(28, 35, 51, 0.03);
}
.pager .pg.cur {
background: linear-gradient(180deg, var(--ys-indigo-hi), var(--ys-indigo));
border-color: transparent; color: #fff;
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.18), 0 1px 2px rgba(46, 75, 168, 0.22);
}
/* ---------- 应用界面 ---------- */
.app-shot {
border: 1px solid var(--ys-line); border-radius: 14px; overflow: hidden;
background: var(--ys-mist); box-shadow: 0 12px 40px rgba(28, 35, 51, 0.1);
}
.app { display: grid; grid-template-columns: 220px 1fr; min-height: 620px; }
.aside {
background: linear-gradient(180deg, var(--ys-aside-1), var(--ys-aside-2));
border-right: 1px solid var(--ys-line);
padding: 20px 14px; display: flex; flex-direction: column;
}
.aside .logo { font-family: var(--ys-font-brand); font-size: 15px; font-weight: 500; letter-spacing: 0.3em; color: var(--ys-ink); padding: 0 10px; }
.aside .logo-sub { font-size: 11px; color: var(--ys-ink-3); letter-spacing: 0.06em; padding: 0 10px; margin-top: 4px; }
.menu-group { margin-top: 26px; }
.menu-label { font-size: 11px; letter-spacing: 0.1em; color: var(--ys-ink-3); padding: 0 10px; margin-bottom: 8px; }
.menu-item {
display: flex; align-items: center; gap: 10px; padding: 9px 10px; border-radius: var(--ys-radius-sm);
font-size: 13px; color: var(--ys-ink-2); position: relative; margin-bottom: 2px;
transition: all 150ms var(--ys-ease);
}
.menu-item:hover { color: var(--ys-ink); background: rgba(255, 255, 255, 0.55); }
/* 当前项:白底「浮起」——微渐变 + 内高光 + 分层阴影 */
.menu-item.active {
color: var(--ys-indigo); font-weight: 500;
background: linear-gradient(180deg, #ffffff, #fbfcfe);
box-shadow: inset 0 1px 0 #fff, 0 1px 2px rgba(28, 35, 51, 0.06), 0 4px 10px rgba(28, 35, 51, 0.06);
}
.menu-item.active::before {
content: ''; position: absolute; left: -14px; top: 8px; bottom: 8px; width: 2px;
border-radius: 1px; background: var(--ys-indigo);
}
.menu-item svg { width: 16px; height: 16px; flex: none; opacity: 0.7; }
.menu-item.active svg { opacity: 1; }
.aside-foot { margin-top: auto; padding: 0 10px 2px; }
.aside-foot-text { font-size: 11px; color: var(--ys-ink-3); letter-spacing: 0.06em; }
.main { display: flex; flex-direction: column; }
.topbar {
height: 52px;
background: linear-gradient(180deg, #ffffff, #fdfdfe);
border-bottom: 1px solid var(--ys-line);
box-shadow: 0 1px 0 rgba(28, 35, 51, 0.015);
display: flex; align-items: center; justify-content: space-between; padding: 0 22px;
}
.crumb { font-size: 13px; color: var(--ys-ink-3); }
.crumb b { color: var(--ys-ink); font-weight: 500; }
.topbar .who { display: flex; align-items: center; gap: 12px; font-size: 13px; color: var(--ys-ink-2); }
.topbar .who .logout { color: var(--ys-ink-3); }
.topbar .who .avatar {
width: 26px; height: 26px; border-radius: 50%;
background: linear-gradient(180deg, var(--ys-indigo-wash), #e4eaf7);
box-shadow: inset 0 1px 0 #fff, 0 1px 2px rgba(28, 35, 51, 0.06);
color: var(--ys-indigo); font-size: 12px;
display: inline-flex; align-items: center; justify-content: center;
}
.content {
padding: 22px; flex: 1;
/* 顶部受光:白光 + 靛蓝微光叠加,内容区有「空气感」 */
background:
radial-gradient(1100px 320px at 50% -110px, rgba(46, 75, 168, 0.055), rgba(46, 75, 168, 0) 65%),
radial-gradient(900px 220px at 50% -80px, rgba(255, 255, 255, 0.85), rgba(255, 255, 255, 0) 70%);
}
.page-head { display: flex; align-items: flex-end; justify-content: space-between; margin-bottom: 18px; }
.page-head h1 { font-size: 18px; font-weight: 600; letter-spacing: -0.01em; }
.page-head .desc { font-size: 12px; color: var(--ys-ink-3); margin-top: 4px; }
.filter {
background: linear-gradient(180deg, #ffffff, #fcfcfe);
border: 1px solid var(--ys-line); border-radius: var(--ys-radius);
padding: 14px 16px; display: flex; gap: 10px; align-items: center; margin-bottom: 14px;
box-shadow: var(--ys-shadow-card);
}
.filter .spacer { flex: 1; }
.card {
background: linear-gradient(180deg, #ffffff, #fcfcfe);
border: 1px solid var(--ys-line); border-radius: var(--ys-radius);
box-shadow: var(--ys-shadow-card); overflow: hidden;
}
table.grid { width: 100%; border-collapse: collapse; }
table.grid th {
text-align: left; font-size: 12px; font-weight: 500; letter-spacing: 0.04em;
color: var(--ys-ink-2); background: linear-gradient(180deg, #fafbfc, #f5f6f9);
padding: 10px 16px; border-bottom: 1px solid var(--ys-line);
}
table.grid td { padding: 12px 16px; border-bottom: 1px solid var(--ys-line-soft); font-size: 13px; }
table.grid tr:last-child td { border-bottom: 0; }
table.grid tbody tr { transition: background 120ms var(--ys-ease); }
table.grid tbody tr:hover { background: #f7f9fd; }
.cell-code { font-family: 'SFMono-Regular', Consolas, monospace; font-size: 12px; color: var(--ys-ink-2); }
.cell-muted { color: var(--ys-ink-2); }
.cell-actions a { color: var(--ys-indigo); font-size: 13px; margin-right: 12px; cursor: pointer; }
.cell-actions a.muted { color: var(--ys-ink-3); }
.card-foot { padding: 12px 16px; display: flex; justify-content: flex-end; border-top: 1px solid var(--ys-line); background: linear-gradient(180deg, #fdfdfe, #fbfcfe); }
/* ---------- 全局规范表 ---------- */
.spec-table { width: 100%; border-collapse: collapse; font-size: 12.5px; }
.spec-table td { padding: 7px 8px; border-bottom: 1px solid var(--ys-line-soft); color: var(--ys-ink-2); vertical-align: top; line-height: 1.6; }
.spec-table tr:last-child td { border-bottom: 0; }
.spec-table td:first-child { color: var(--ys-ink); font-weight: 500; white-space: nowrap; }
.spec-table td.num { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
.spec-table td.bad { color: var(--ys-ink-3); text-decoration: line-through; text-decoration-color: rgba(201, 79, 79, 0.35); }
.spec-table td.good { color: var(--ys-ink); }
/* ---------- 首页仪表盘(Bento Grid) ---------- */
.bento { display: grid; grid-template-columns: repeat(4, 1fr); grid-auto-rows: 102px; gap: 14px; }
.bento-card {
background: linear-gradient(180deg, #ffffff, #fcfcfe);
border: 1px solid var(--ys-line); border-radius: var(--ys-radius);
box-shadow: var(--ys-shadow-card);
padding: 17px 20px; display: flex; flex-direction: column;
/* 微动效:入场交错上浮 + hover 抬升 2px(prefers-reduced-motion 下全部关闭) */
animation: rise 320ms var(--ys-ease) backwards;
transition: transform 180ms var(--ys-ease), box-shadow 180ms var(--ys-ease);
}
.bento-card:hover { transform: translateY(-2px); box-shadow: var(--ys-shadow-raise); }
.b-head { display: flex; align-items: center; justify-content: space-between; }
.b-icon { width: 15px; height: 15px; color: var(--ys-ink-3); opacity: 0.8; }
.bento-card:nth-child(1) { animation-delay: 0ms; }
.bento-card:nth-child(2) { animation-delay: 45ms; }
.bento-card:nth-child(3) { animation-delay: 90ms; }
.bento-card:nth-child(4) { animation-delay: 135ms; }
.bento-card:nth-child(5) { animation-delay: 180ms; }
.bento-card:nth-child(6) { animation-delay: 225ms; }
.bento-card:nth-child(7) { animation-delay: 270ms; }
.bento-card:nth-child(8) { animation-delay: 315ms; }
@keyframes rise { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: translateY(0); } }
@media (prefers-reduced-motion: reduce) {
.bento-card, .login-card { animation: none; transition: none; }
}
.b-2x2 { grid-column: span 2; grid-row: span 2; }
.b-2x1 { grid-column: span 2; }
.b-eyebrow { font-size: 12px; font-weight: 500; letter-spacing: 0.04em; color: var(--ys-ink-2); }
.b-big { font-size: 30px; font-weight: 600; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; line-height: 1.15; margin-top: auto; }
.b-big small { font-size: 13px; font-weight: 500; color: var(--ys-ink-3); margin-left: 4px; letter-spacing: 0; }
.b-num { font-size: 24px; font-weight: 600; letter-spacing: -0.01em; font-variant-numeric: tabular-nums; line-height: 1.2; margin-top: auto; }
.b-num small { font-size: 12px; font-weight: 400; color: var(--ys-ink-3); margin-left: 3px; }
.b-sub { font-size: 11px; color: var(--ys-ink-3); margin-top: 3px; }
.b-up { color: var(--ys-ok); font-weight: 500; }
.b-todo { display: flex; align-items: baseline; gap: 8px; font-size: 13px; color: var(--ys-ink-2); }
.b-todo .cnt { color: var(--ys-indigo); font-weight: 600; font-variant-numeric: tabular-nums; }
/* ---------- 登录页 ---------- */
.login-shot { border: 1px solid var(--ys-line); border-radius: 14px; overflow: hidden; box-shadow: 0 12px 40px rgba(28, 35, 51, 0.1); }
.login { display: grid; grid-template-columns: 460px 1fr; min-height: 520px; }
.login-brand {
background: linear-gradient(168deg, #2c4aa6 0%, #223a85 55%, #17275c 100%);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.12);
padding: 46px 44px; display: flex; flex-direction: column; justify-content: space-between;
position: relative; overflow: hidden;
}
.login-brand .brandmark { font-family: var(--ys-font-brand); font-size: 19px; font-weight: 500; letter-spacing: 0.36em; color: #fff; }
.login-brand .slogan { font-size: 15px; color: rgba(255, 255, 255, 0.82); margin-top: 14px; line-height: 1.9; }
.login-brand .foot { font-size: 12px; color: rgba(255, 255, 255, 0.42); letter-spacing: 0.08em; }
.ripple { position: absolute; inset: auto 0 0 0; height: 220px; pointer-events: none; }
.ripple i { display: block; height: 1px; margin-top: 26px; }
.ripple i:nth-child(1) { background: linear-gradient(90deg, rgba(255,255,255,0.36), rgba(255,255,255,0.02)); }
.ripple i:nth-child(2) { margin-top: 22px; width: 92%; background: linear-gradient(90deg, rgba(255,255,255,0.30), rgba(255,255,255,0.02)); }
.ripple i:nth-child(3) { margin-top: 18px; width: 84%; background: linear-gradient(90deg, rgba(255,255,255,0.25), rgba(255,255,255,0.02)); }
.ripple i:nth-child(4) { margin-top: 15px; width: 74%; background: linear-gradient(90deg, rgba(255,255,255,0.20), rgba(255,255,255,0.02)); }
.ripple i:nth-child(5) { margin-top: 12px; width: 62%; background: linear-gradient(90deg, rgba(255,255,255,0.15), rgba(255,255,255,0.02)); }
.ripple i:nth-child(6) { margin-top: 10px; width: 48%; background: linear-gradient(90deg, rgba(255,255,255,0.11), rgba(255,255,255,0.02)); }
.login-form {
background: linear-gradient(180deg, #ffffff, #fdfdff);
box-shadow: inset 0 1px 0 #fff;
padding: 46px 56px; display: flex; flex-direction: column; justify-content: center;
}
.login-form h2 { font-size: 18px; font-weight: 600; letter-spacing: -0.01em; }
.login-form .hint { font-size: 13px; color: var(--ys-ink-3); margin: 6px 0 26px; }
.field { margin-bottom: 16px; }
.field label { display: block; font-size: 13px; color: var(--ys-ink-2); margin-bottom: 6px; }
.field .input { width: 100%; height: 38px; }
.captcha-row { display: flex; gap: 10px; }
.captcha-row .input { flex: 1; }
.captcha-box {
width: 104px; height: 38px; border: 1px solid var(--ys-line); border-radius: var(--ys-radius-sm);
display: flex; align-items: center; justify-content: center;
font-family: 'SFMono-Regular', Consolas, monospace; font-size: 17px; letter-spacing: 0.28em;
color: var(--ys-indigo); background: linear-gradient(180deg, #f7f8fb, #f1f3f8);
box-shadow: inset 0 1px 2px rgba(28, 35, 51, 0.04); user-select: none;
}
.login-btn { width: 100%; height: 38px; margin-top: 6px; font-size: 14px; }
/* 方案 B:居中卡片 */
.login-center {
position: relative; overflow: hidden;
min-height: 480px; display: flex; align-items: center; justify-content: center;
background-color: #f2f4f8;
background-image: radial-gradient(rgba(28, 35, 51, 0.07) 1px, transparent 1px);
background-size: 24px 24px;
padding: 40px;
}
/* 顶部光晕:靛蓝的「天光」,柔和地洒在登录卡上 */
.login-center::before {
content: ''; position: absolute; top: -160px; left: 50%; transform: translateX(-50%);
width: 860px; height: 460px; pointer-events: none;
background: radial-gradient(closest-side, rgba(46, 75, 168, 0.08), rgba(46, 75, 168, 0));
}
/* 背景涟漪:同心圆水波(「衍水」的品牌装饰,右上入画) */
.ripple-bg { position: absolute; top: -170px; right: -130px; width: 520px; height: 520px; pointer-events: none; }
.ripple-bg i {
position: absolute; inset: 0; border-radius: 50%;
border: 1px solid rgba(46, 75, 168, 0.09);
}
.ripple-bg i:nth-child(2) { inset: 65px; border-color: rgba(46, 75, 168, 0.07); }
.ripple-bg i:nth-child(3) { inset: 130px; border-color: rgba(46, 75, 168, 0.055); }
.ripple-bg i:nth-child(4) { inset: 195px; border: none; background: radial-gradient(circle, rgba(46, 75, 168, 0.05), rgba(46, 75, 168, 0.015)); }
.login-card {
position: relative; overflow: hidden;
animation: rise 320ms var(--ys-ease) backwards;
width: 400px;
background: linear-gradient(180deg, #ffffff, #fcfcfe);
border: 1px solid var(--ys-line); border-radius: 14px;
box-shadow: 0 2px 4px rgba(28, 35, 51, 0.04), 0 16px 40px rgba(28, 35, 51, 0.1);
padding: 30px 36px 32px;
}
.lc-brand { text-align: center; }
.lc-brand-name { font-family: var(--ys-font-brand); font-size: 17px; font-weight: 500; letter-spacing: 0.34em; color: var(--ys-ink); }
.lc-slogan { font-size: 12.5px; color: var(--ys-ink-3); margin-top: 8px; letter-spacing: 0.02em; }
.lc-form-head { font-size: 15px; font-weight: 600; margin-top: 26px; }
.lc-form-hint { font-size: 12px; color: var(--ys-ink-3); margin: 4px 0 18px; }
.lc-foot { text-align: center; margin-top: 16px; font-size: 11px; color: var(--ys-ink-3); letter-spacing: 0.08em; }
.login-card .input { width: 100%; height: 38px; }
.note { margin-top: 18px; font-size: 13px; color: var(--ys-ink-2); line-height: 1.9; }
.note b { color: var(--ys-ink); font-weight: 600; }
.states { display: flex; gap: 14px; margin-top: 12px; }
.state { text-align: center; }
.state .cap { font-size: 11px; color: var(--ys-ink-3); margin-top: 6px; }
</style>
</head>
<body>
<div class="wrap">
<!-- ============ 封面 ============ -->
<header class="cover" id="sec-cover">
<div class="brand">衍水集团</div>
<h1>营销人员工资管理系统 · 视觉方向</h1>
<div class="sub">企业级扁平 · 轻质感 · Bento 布局 · 品牌色点缀 · 微动效 · 精致文案</div>
<div class="waterline"></div>
<div class="tags">
<span class="tag">表面微渐变(受光)</span>
<span class="tag">半透明描边</span>
<span class="tag">分层阴影</span>
<span class="tag">内高光 / 内阴影</span>
<span class="tag">2% 噪点</span>
<span class="tag">等宽数字</span>
<span class="tag">120–180ms 轻动效</span>
</div>
</header>
<!-- ============ 色板 ============ -->
<section class="section" id="sec-palette">
<h2>01 · 色板与材质</h2>
<div class="swatches">
<div class="swatch">
<div class="chip" style="background:linear-gradient(180deg,#3a58bc,#2e4ba8)"></div>
<div class="meta"><div class="name">靛蓝</div><div class="hex num">#2E4BA8 ↑#3A58BC</div>
<div class="use">品牌色。按钮/链接/焦点/当前菜单,配微渐变与内高光</div></div>
</div>
<div class="swatch">
<div class="chip" style="background:linear-gradient(180deg,#f2f4f8,#ecedf3)"></div>
<div class="meta"><div class="name">侧栏灰</div><div class="hex num">#F2F4F8 → #ECEDF3</div>
<div class="use">侧栏微渐变(自上而下微沉)</div></div>
</div>
<div class="swatch">
<div class="chip" style="background:#f4f5f8"></div>
<div class="meta"><div class="name">雾灰</div><div class="hex num">#F4F5F8</div>
<div class="use">页面底</div></div>
</div>
<div class="swatch">
<div class="chip" style="background:linear-gradient(180deg,#ffffff,#fcfcfe);border-bottom:1px solid #e3e6ec"></div>
<div class="meta"><div class="name">纸白</div><div class="hex num">#FFFFFF → #FCFCFE</div>
<div class="use">卡片/表格:顶白底微灰的「受光」渐变</div></div>
</div>
<div class="swatch">
<div class="chip" style="background:#e4e7ec"></div>
<div class="meta"><div class="name">界线</div><div class="hex num">rgba(28,35,51,.09)</div>
<div class="use">1px 半透明描边:在不同底色上自然融合</div></div>
</div>
<div class="swatch">
<div class="chip" style="background:#1c2333"></div>
<div class="meta"><div class="name">墨色</div><div class="hex num">#1C2333</div>
<div class="use">主文字(冷调近黑)</div></div>
</div>
<div class="swatch">
<div class="chip" style="background:#5b6577"></div>
<div class="meta"><div class="name">次墨</div><div class="hex num">#5B6577</div>
<div class="use">次级文字、表头、说明</div></div>
</div>
<div class="swatch">
<div class="chip" style="background:linear-gradient(90deg,#1e9e6a,#c98a1b,#c94f4f)"></div>
<div class="meta"><div class="name">语义色</div><div class="hex num">#1E9E6A · #C98A1B · #C94F4F</div>
<div class="use">成功/警示/危险,浅底微渐变 + 深字</div></div>
</div>
</div>
</section>
<!-- ============ 字体与数字 ============ -->
<section class="section" id="sec-type">
<h2>02 · 字体与数字</h2>
<div class="type-sheet">
<div class="type-row"><span class="label">页面标题</span><span class="t-page-title">岗位角色</span><span class="label" style="width:auto">18px / 600 · 字距 −0.01em</span></div>
<div class="type-row"><span class="label">卡片标题</span><span class="t-card-title">计提参数 · 业务员个人户</span><span class="label" style="width:auto">15px / 600</span></div>
<div class="type-row"><span class="label">正文 / 表格</span><span class="t-body">回款天数 = 发货日首日起算,按自然日累计</span><span class="label" style="width:auto">14px / 400 · 13px / 400</span></div>
<div class="type-row"><span class="label">表头 / 标签</span><span class="t-th">岗位编码 公式模板 生效日期</span><span class="label" style="width:auto">12px / 500 · 字距 +0.04em</span></div>
<div class="type-row"><span class="label">品牌字</span><span style="font-weight:600;letter-spacing:.35em;font-size:15px">衍水集团</span><span class="label" style="width:auto">无衬线 600 · 大字距 · 仅品牌落款一处</span></div>
</div>
<div class="amount-demo">
<table>
<thead><tr><th>回款日期</th><th>回款金额(元)</th><th>回款天数</th><th>计提比例</th><th>绩效金额(元)</th></tr></thead>
<tbody>
<tr><td>2026-01-10</td><td>386,200.00</td><td>27</td><td>9.7‰</td><td>14,062.31</td></tr>
<tr><td>2026-02-18</td><td>1,240,000.00</td><td>361</td><td>4‰</td><td>19,840.00</td></tr>
<tr><td>合计</td><td>1,626,200.00</td><td>—</td><td>—</td><td>33,902.31</td></tr>
</tbody>
</table>
<div class="note">金额与比例一律<b>等宽数字(tabular-nums)右对齐</b>,合计行加粗放大半档——列对列、位对位,扫一眼就能核对。</div>
</div>
<div class="brand-candidates">
<div class="bc">
<div style="font-family:'Noto Sans SC',sans-serif;font-weight:500;letter-spacing:.32em;font-size:16px">衍水集团</div>
<div class="bc-cap">A · 思源黑体 500 · 0.32em <span class="bc-rec">当前应用</span></div>
</div>
<div class="bc">
<div style="font-family:'Noto Sans SC',sans-serif;font-weight:300;letter-spacing:.42em;font-size:16px">衍水集团</div>
<div class="bc-cap">B · 思源黑体 300 细体 · 0.42em</div>
</div>
<div class="bc">
<div style="font-family:'Microsoft YaHei',sans-serif;font-weight:600;letter-spacing:.25em;font-size:16px">衍水集团</div>
<div class="bc-cap">C · 微软雅黑 600 · 0.25em</div>
</div>
</div>
</section>
<!-- ============ 组件 ============ -->
<section class="section" id="sec-comp">
<h2>03 · 组件基调</h2>
<div class="comp-grid">
<div class="comp-card">
<h3>按钮 · 三态</h3>
<div class="states">
<div class="state"><button class="btn btn-primary btn-ghost-hover">新增岗位</button><div class="cap">静置</div></div>
<div class="state"><button class="btn btn-primary" style="background:linear-gradient(180deg,#31509f,#243c8b);transform:translateY(-1px);box-shadow:inset 0 1px 0 rgba(255,255,255,.18),0 4px 12px rgba(46,75,168,.3)">新增岗位</button><div class="cap">悬停:抬升 1px · 影加深</div></div>
<div class="state"><button class="btn btn-primary" style="box-shadow:inset 0 1px 2px rgba(0,0,0,.18)">新增岗位</button><div class="cap">按下:回落 · 内阴影</div></div>
</div>
<div class="note">微渐变 + 内高光给按钮「实体感」;次级按钮一律白底细边框,无阴影污染。</div>
</div>
<div class="comp-card">
<h3>输入框 · 状态</h3>
<div class="row">
<input class="input" placeholder="搜索岗位编码或名称" />
<input class="input focused" value="4/360" />
</div>
<div class="row" style="margin-top:14px">
<span class="pill pill-ok">启用</span>
<span class="pill pill-off">禁用</span>
<span class="pill pill-warn">待生效</span>
</div>
<div class="note">输入框带微内阴影(凹陷暗示);聚焦 = 靛蓝描边 + 3px 柔光外环。</div>
</div>
<div class="comp-card">
<h3>分页</h3>
<div class="pager">
<span class="pg">‹</span><span class="pg cur">1</span><span class="pg">2</span><span class="pg">3</span><span class="pg">›</span>
<span style="margin-left:10px">共 28 条 · 每页 10 条</span>
</div>
<div class="note" style="margin-top:14px">当前页与主按钮同材质:微渐变 + 内高光。</div>
</div>
<div class="comp-card">
<h3>动效原则</h3>
<div class="note">
过渡 120–180ms,<b>只做颜色、阴影与 1px 内的位移</b>;弹层淡入 + 4px 上移;
数字与表格不加动画;尊重 <b>prefers-reduced-motion</b>。
动效的目标是「顺滑可信」,不是表演。
</div>
</div>
</div>
</section>
<!-- ============ 应用界面 ============ -->
<section class="section" id="sec-app">
<h2>04 · 应用界面(布局与列表页)</h2>
<div class="app-shot">
<div class="app">
<aside class="aside">
<div class="logo">衍水集团</div>
<div class="logo-sub">营销人员工资管理系统</div>
<div class="waterline" style="width:22px;margin:10px 10px 0;"></div>
<div class="menu-group">
<div class="menu-item">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linejoin="round"><path d="M2.5 7 8 2.5 13.5 7v6.5H10V9.5H6v4H2.5Z"/></svg>
首页
</div>
</div>
<div class="menu-group">
<div class="menu-label">系统管理</div>
<div class="menu-item">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><circle cx="8" cy="5.5" r="2.5"/><path d="M3 13.5c0-2.5 2.2-4 5-4s5 1.5 5 4"/></svg>
用户管理
</div>
<div class="menu-item">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linejoin="round"><path d="M8 2 13 4v4c0 3-2 5-5 6-3-1-5-3-5-6V4Z"/></svg>
角色管理
</div>
<div class="menu-item active">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><rect x="2.5" y="3.5" width="11" height="9" rx="1.5"/><circle cx="6" cy="7.5" r="1.2"/><path d="M4.5 11c.3-1 1-1.5 1.5-1.5s1.2.5 1.5 1.5M9.5 6.5h2M9.5 9h2"/></svg>
岗位角色
</div>
<div class="menu-item">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><path d="M3 5h10M3 11h10"/><circle cx="6" cy="5" r="1.6"/><circle cx="10" cy="11" r="1.6"/></svg>
计提参数
</div>
<div class="menu-item">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><path d="M4 4.5h8M4 8h8M4 11.5h5"/></svg>
操作日志
</div>
</div>
<div class="aside-foot">
<div class="waterline" style="width:22px;margin:0 0 8px;"></div>
<div class="aside-foot-text">内部系统 · v0.1</div>
</div>
</aside>
<div class="main">
<div class="topbar">
<div class="crumb">系统管理 <span>/</span> <b>岗位角色</b></div>
<div class="who"><span class="avatar">管</span><span>管理员</span><span class="logout">退出登录</span></div>
</div>
<div class="content">
<div class="page-head">
<div>
<h1>岗位角色</h1>
<div class="desc">决定人员适用的计提公式模板与参数;新增岗位无需改代码</div>
<div class="waterline"></div>
</div>
<button class="btn btn-primary">新增岗位</button>
</div>
<div class="filter">
<input class="input" placeholder="岗位编码或名称" />
<input class="input" placeholder="状态:全部" style="width:130px" />
<button class="btn btn-primary">查询</button>
<button class="btn btn-default">重置</button>
<span class="spacer"></span>
</div>
<div class="card">
<table class="grid">
<thead>
<tr><th>岗位编码</th><th style="width:110px">岗位名称</th><th>公式模板</th><th>说明</th><th style="width:90px">状态</th><th style="width:150px">操作</th></tr>
</thead>
<tbody>
<tr>
<td class="cell-code">salesperson</td><td>营销员</td>
<td class="cell-muted">业务员个人户 · 天数线性递减</td>
<td class="cell-muted">回款天数线性递减(360 天=6‰,361 天起 4‰)</td>
<td><span class="pill pill-ok">启用</span></td>
<td class="cell-actions"><a>编辑</a><a class="muted" title="内置岗位不可删除">删除</a></td>
</tr>
<tr>
<td class="cell-code">sales_manager</td><td>营销经理</td>
<td class="cell-muted">营销经理 · 团队与全公司分成</td>
<td class="cell-muted">本团队 12.5% + 全公司 5%</td>
<td><span class="pill pill-ok">启用</span></td>
<td class="cell-actions"><a>编辑</a><a class="muted" title="内置岗位不可删除">删除</a></td>
</tr>
<tr>
<td class="cell-code">info_officer</td><td>信息员</td>
<td class="cell-muted">信息员 · 销售额固定比例</td>
<td class="cell-muted">本人销售额 × 1‰</td>
<td><span class="pill pill-ok">启用</span></td>
<td class="cell-actions"><a>编辑</a><a class="muted" title="内置岗位不可删除">删除</a></td>
</tr>
<tr>
<td class="cell-code">senior_sales</td><td>高级业务员</td>
<td class="cell-muted">业务员个人户 · 天数线性递减</td>
<td class="cell-muted">自定义岗位(新增岗位无需改代码)</td>
<td><span class="pill pill-off">禁用</span></td>
<td class="cell-actions"><a>编辑</a><a>删除</a></td>
</tr>
</tbody>
</table>
<div class="card-foot">
<div class="pager">
<span class="pg">‹</span><span class="pg cur">1</span><span class="pg">›</span>
<span style="margin-left:10px">共 4 条</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="note">
质感的三层材料:<b>侧栏</b>灰渐变(沉)→ <b>内容底</b>雾灰 + 顶部受光 → <b>卡片</b>纸白微渐变 + 半透明描边 + 分层阴影。
当前项白底浮起,白色被灰托住,不再扎眼。
</div>
</section>
<!-- ============ 首页仪表盘 ============ -->
<section class="section" id="sec-bento">
<h2>05 · 首页仪表盘(Bento Grid)</h2>
<div class="app-shot">
<div class="app">
<aside class="aside">
<div class="logo">衍水集团</div>
<div class="logo-sub">营销人员工资管理系统</div>
<div class="waterline" style="width:22px;margin:10px 10px 0;"></div>
<div class="menu-group">
<div class="menu-item active">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linejoin="round"><path d="M2.5 7 8 2.5 13.5 7v6.5H10V9.5H6v4H2.5Z"/></svg>
首页
</div>
</div>
<div class="menu-group">
<div class="menu-label">系统管理</div>
<div class="menu-item">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><circle cx="8" cy="5.5" r="2.5"/><path d="M3 13.5c0-2.5 2.2-4 5-4s5 1.5 5 4"/></svg>
用户管理
</div>
<div class="menu-item">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linejoin="round"><path d="M8 2 13 4v4c0 3-2 5-5 6-3-1-5-3-5-6V4Z"/></svg>
角色管理
</div>
<div class="menu-item">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><rect x="2.5" y="3.5" width="11" height="9" rx="1.5"/><circle cx="6" cy="7.5" r="1.2"/><path d="M4.5 11c.3-1 1-1.5 1.5-1.5s1.2.5 1.5 1.5M9.5 6.5h2M9.5 9h2"/></svg>
岗位角色
</div>
<div class="menu-item">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><path d="M3 5h10M3 11h10"/><circle cx="6" cy="5" r="1.6"/><circle cx="10" cy="11" r="1.6"/></svg>
计提参数
</div>
<div class="menu-item">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><path d="M4 4.5h8M4 8h8M4 11.5h5"/></svg>
操作日志
</div>
</div>
<div class="aside-foot">
<div class="waterline" style="width:22px;margin:0 0 8px;"></div>
<div class="aside-foot-text">内部系统 · v0.1</div>
</div>
</aside>
<div class="main">
<div class="topbar">
<div class="crumb"><b>仪表盘</b></div>
<div class="who"><span class="avatar">管</span><span>管理员</span><span class="logout">退出登录</span></div>
</div>
<div class="content">
<div class="page-head">
<div>
<h1>仪表盘</h1>
<div class="desc">数据截至今日 06:00 · 12 笔回款待核算</div>
<div class="waterline"></div>
</div>
</div>
<div class="bento">
<div class="bento-card b-2x2">
<div class="b-eyebrow">本月绩效总额</div>
<div class="b-big" style="color:var(--ys-indigo)">268,430.16<small>元</small></div>
<div class="b-sub">较上月 <span class="b-up">+12.4%</span> · 已核销 86 笔</div>
<div id="chartPerf" style="width:100%;height:40px;margin-top:12px"></div>
</div>
<div class="bento-card b-2x2">
<div class="b-eyebrow">近 6 个月回款</div>
<div class="b-sub" style="margin-top:2px">单位:万元</div>
<div id="chartRev" style="width:100%;height:78px;margin-top:auto"></div>
</div>
<div class="bento-card b-2x1">
<div class="b-eyebrow">待办</div>
<div style="margin-top:auto;display:flex;flex-direction:column;gap:4px">
<div class="b-todo"><span class="cnt">12 笔</span>回款待核算</div>
<div class="b-todo"><span class="cnt">3 笔</span>业务归属待确认</div>
</div>
</div>
<div class="bento-card">
<div class="b-head"><div class="b-eyebrow">营销人员</div>
<svg class="b-icon" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><circle cx="8" cy="5.5" r="2.5"/><path d="M3 13.5c0-2.5 2.2-4 5-4s5 1.5 5 4"/></svg>
</div>
<div class="b-num">36<small>人</small></div>
</div>
<div class="bento-card">
<div class="b-head"><div class="b-eyebrow">岗位角色</div>
<svg class="b-icon" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><rect x="2.5" y="3.5" width="11" height="9" rx="1.5"/><circle cx="6" cy="7.5" r="1.2"/><path d="M4.5 11c.3-1 1-1.5 1.5-1.5s1.2.5 1.5 1.5M9.5 6.5h2M9.5 9h2"/></svg>
</div>
<div class="b-num">3<small>个</small></div>
</div>
<div class="bento-card b-2x1">
<div class="b-eyebrow">常用操作</div>
<div class="row" style="margin-top:auto">
<button class="btn btn-primary" style="height:30px;font-size:12px;padding:0 13px">录入回款</button>
<button class="btn btn-default" style="height:30px;font-size:12px;padding:0 13px">计提参数</button>
<button class="btn btn-default" style="height:30px;font-size:12px;padding:0 13px">岗位角色</button>
</div>
</div>
<div class="bento-card">
<div class="b-head"><div class="b-eyebrow">计提参数</div>
<svg class="b-icon" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><path d="M3 5h10M3 11h10"/><circle cx="6" cy="5" r="1.6"/><circle cx="10" cy="11" r="1.6"/></svg>
</div>
<div class="b-num">16<small>项</small></div>
<div class="b-sub">版本 P20260101-00</div>
</div>
<div class="bento-card">
<div class="b-head"><div class="b-eyebrow">T+ 同步</div>
<svg class="b-icon" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><path d="M13 8a5 5 0 1 1-1.5-3.5"/><path d="M13 2.5V5h-2.5"/></svg>
</div>
<div class="b-num" style="color:var(--ys-ok)">正常</div>
<div class="b-sub">每周一 06:00</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="note">
<b>Bento Grid</b>:大小不一的卡片按重要性排布——绩效总额与回款趋势占 2×2 主角位,数字型指标 1×1 紧凑排列。
卡片入场为 <b>45ms 交错上浮(320ms)</b>,悬停抬升 2px、阴影加深——打开预览即可看到微动效。
</div>
</section>
<!-- ============ 登录页 ============ -->
<section class="section" id="sec-login">
<h2>06 · 登录页(重做)</h2>
<div class="login-shot">
<div class="login-center">
<div class="ripple-bg"><i></i><i></i><i></i><i></i></div>
<div style="position:relative">
<div class="login-card">
<div class="lc-brand">
<div class="lc-brand-name">衍水集团</div>
<div class="lc-slogan">把每一笔回款,算成一份踏实。</div>
<div class="waterline" style="width:40px;margin:14px auto 0"></div>
</div>
<div class="lc-form-head" style="margin-top:28px">欢迎回来</div>
<div class="lc-form-hint">请输入账号密码进入系统</div>
<div class="field">
<label>用户名</label>
<input class="input" placeholder="请输入用户名" />
</div>
<div class="field">
<label>密码</label>
<input class="input" type="password" placeholder="请输入密码" />
</div>
<div class="field">
<label>验证码</label>
<div class="captcha-row">
<input class="input" placeholder="请输入验证码" />
<div class="captcha-box">7K3P</div>
</div>
</div>
<button class="btn btn-primary login-btn">登 录</button>
</div>
<div class="lc-foot">© 衍水集团 · 内部系统</div>
</div>
</div>
</div>
<div class="note">
背景三层:<b>点阵网格</b>(秩序)+ <b>顶部靛蓝天光</b>(氛围)+ <b>右上涟漪同心圆</b>(「衍水」的品牌装饰);
卡片内品牌区承担门面——品牌字、标语、水线;表单以「欢迎回来」承接。装饰与文案都来自「衍水」本身。
</div>
</section>
<!-- ============ 签名元素 ============ -->
<section class="section" id="sec-sign">
<h2>07 · 签名元素:水线</h2>
<div class="comp-card">
<div style="font-size:18px;font-weight:600;letter-spacing:-0.01em">计提参数</div>
<div class="waterline" style="width:56px"></div>
<div class="note" style="max-width:720px">
页面标题下的<b>渐隐靛蓝细线(56px,左实右虚)</b>——「衍水」之水的提纯,全站唯一的装饰性元素,
只在每个页面标题处出现一次。它与登录页的水纹层理同源:<b>品牌连续,而非推倒重来</b>。
</div>
</div>
</section>
<!-- ============ 微动效与精致文案(全局规范) ============ -->
<section class="section" id="sec-motion">
<h2>08 · 微动效与精致文案(全局规范)</h2>
<div class="comp-grid">
<div class="comp-card">
<h3>微动效 · 全站统一</h3>
<table class="spec-table">
<tr><td>页面 / 卡片入场</td><td>淡入 + 上浮 6px,45ms 交错</td><td class="num">320ms</td></tr>
<tr><td>按钮悬停 / 按下</td><td>抬升 1px、影加深 / 回落内阴影</td><td class="num">150ms</td></tr>
<tr><td>卡片悬停</td><td>抬升 2px、阴影加深</td><td class="num">180ms</td></tr>
<tr><td>输入聚焦</td><td>靛蓝描边 + 3px 柔光外环</td><td class="num">150ms</td></tr>
<tr><td>弹层 / 抽屉</td><td>淡入 + 上移 4px</td><td class="num">160ms</td></tr>
<tr><td>表格行</td><td>底色渐显(无位移)</td><td class="num">120ms</td></tr>
<tr><td>数据刷新</td><td>数字不做滚动动画(核对场景,动即干扰)</td><td class="num">—</td></tr>
<tr><td>无障碍</td><td>prefers-reduced-motion 时全部关闭</td><td class="num">—</td></tr>
</table>
<div class="note">目标不是「有动画」,而是<b>顺滑可信</b>:每次操作都有轻微、及时、可预期的反馈。</div>
</div>
<div class="comp-card">
<h3>精致文案 · 全站统一</h3>
<table class="spec-table">
<tr><td>按钮</td><td class="bad">提交</td><td class="good">保存变更 · 录入回款</td></tr>
<tr><td>空态</td><td class="bad">暂无数据</td><td class="good">还没有岗位角色,点「新增岗位」创建第一个</td></tr>
<tr><td>错误</td><td class="bad">操作失败</td><td class="good">岗位编码已存在,请换一个</td></tr>
<tr><td>危险确认</td><td class="bad">确定删除吗?</td><td class="good">删除后无法恢复,该岗位下的人员需重新归属</td></tr>
<tr><td>成功提示</td><td class="bad">操作成功</td><td class="good">岗位已创建 · 参数 11-01 起生效</td></tr>
<tr><td>页面描述</td><td class="bad">本页面用于管理</td><td class="good">决定人员适用的计提公式模板与参数;新增岗位无需改代码</td></tr>
</table>
<div class="note">说清楚<b>会发生什么</b>;动词开头、句子短;不道歉、不卖萌;<b>空态是邀请,错误是路标</b>。</div>
</div>
</div>
</section>
</div>
<script src="echarts.min.js"></script>
<script>
/* 仪表盘图表:ECharts 定制主题(圆角柱 / 无网格线 / 浅灰轴标签)——实施时前端引入 echarts 依赖 */
const chartFont = "'PingFang SC','Microsoft YaHei','Noto Sans SC',sans-serif";
const rev = echarts.init(document.getElementById('chartRev'), null, { renderer: 'svg' });
rev.setOption({
grid: { left: 0, right: 0, top: 6, bottom: 20, containLabel: true },
xAxis: {
type: 'category', data: ['5月', '6月', '7月', '8月', '9月', '10月'],
axisLine: { show: false }, axisTick: { show: false },
axisLabel: { color: '#9aa3b2', fontSize: 9, margin: 10, fontFamily: chartFont }
},
yAxis: { type: 'value', show: false },
series: [{
type: 'bar', barWidth: 22, data: [34, 42, 30, 48, 38, 56],
itemStyle: {
borderRadius: [3, 3, 0, 0],
color: (p) => p.dataIndex === 5
? new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: '#3a58bc' }, { offset: 1, color: '#2e4ba8' }])
: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: '#d5def3' }, { offset: 1, color: '#e8edf8' }])
}
}]
});
const perf = echarts.init(document.getElementById('chartPerf'), null, { renderer: 'svg' });
perf.setOption({
grid: { left: 0, right: 0, top: 6, bottom: 2 },
xAxis: { type: 'category', show: false, boundaryGap: false, data: [1, 2, 3, 4, 5, 6, 7] },
yAxis: { type: 'value', show: false, min: 0 },
series: [{
type: 'line', data: [8, 13, 10, 19, 23, 29, 33], smooth: 0.4, symbol: 'none',
lineStyle: { color: '#2e4ba8', width: 1.6 },
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'rgba(46,75,168,.10)' }, { offset: 1, color: 'rgba(46,75,168,0)' }
])
}
}]
});
</script>
</body>
</html>