@yuku123/z-frontend-common 1.0.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1 +1,309 @@
1
- import{Avatar as H,Button as j,Dropdown as W,Layout as R,Menu as N,Spin as J,Tooltip as A}from"antd";import{DownOutlined as G,LoginOutlined as Q,MenuFoldOutlined as X,MenuUnfoldOutlined as Y}from"@ant-design/icons";import{Outlet as Z,useLocation as _,useNavigate as U}from"react-router-dom";import{useState as V}from"react";import{jsx as o,jsxs as m}from"react/jsx-runtime";var{Header:ee,Sider:te,Content:re}=R;function oe(e,t=.85){let n=/^#?([0-9a-f]{6})$/i.exec(e||"");if(!n)return e;let l=parseInt(n[1],16),f=Math.max(0,Math.min(255,Math.round((l>>16&255)*t))),r=Math.max(0,Math.min(255,Math.round((l>>8&255)*t))),s=Math.max(0,Math.min(255,Math.round((l&255)*t)));return"#"+(f<<16|r<<8|s).toString(16).padStart(6,"0")}function L({menuItems:e=[],appTitle:t="One Company",appShort:n="OC",appVersion:l,appIcon:f,appUser:r,loginPath:s,headerExtra:v,loading:C=!1}){let[i,c]=V(!1),F=U(),$=_(),P=({key:d})=>{F(d)},M=()=>{if(s)return s;let d=e&&e[0],a=d&&d.key;return typeof a=="string"&&a.endsWith("/home")?a.slice(0,-4)+"login":"/login"},z=(d,a=[])=>{for(let u of d||[])u?.key&&a.push(u.key),u?.children&&z(u.children,a);return a},D=(()=>{let d=z(e),a=$.pathname;return d.filter(u=>a===u||a.startsWith(u+"/")).sort((u,b)=>b.length-u.length)[0]||a})();return m(R,{style:{minHeight:"100vh"},children:[m(te,{trigger:null,collapsible:!0,collapsed:i,children:[o("div",{style:{height:64,display:"flex",alignItems:"center",justifyContent:"center"},children:(()=>{if(i){if(f){let{icon:d,color:a="#7c3aed",label:u=t}=f,b=o("div",{style:{width:36,height:36,borderRadius:9,background:`linear-gradient(135deg, ${a}, ${oe(a,.7)})`,display:"flex",alignItems:"center",justifyContent:"center",color:"#fff",fontSize:20,boxShadow:"0 2px 6px rgba(0,0,0,0.25)",overflow:"hidden"},children:d});return o(A,{title:u,placement:"right",children:b})}return n}return m("span",{style:{color:"#fff",fontWeight:600,fontSize:16,whiteSpace:"nowrap"},children:[t,l&&m("span",{style:{color:"rgba(255,255,255,0.55)",fontWeight:400,fontSize:12,marginLeft:4},children:["@",l]})]})})()}),C?o("div",{style:{padding:16,textAlign:"center"},children:o(J,{size:"small"})}):o(N,{theme:"dark",mode:"inline",selectedKeys:[D],items:e,onClick:P})]}),m(R,{children:[m(ee,{style:{height:48,lineHeight:"48px",padding:"0 16px",background:"#fff",display:"flex",alignItems:"center",justifyContent:"space-between",borderBottom:"1px solid #f1f5f9"},children:[o("span",{onClick:()=>c(!i),style:{fontSize:18,cursor:"pointer"},children:i?o(Y,{}):o(X,{})}),m("div",{style:{display:"flex",alignItems:"center",gap:12},children:[r&&o(W,{menu:{items:[{key:"profile",label:`${r.name}\uFF08${r.role||"\u7528\u6237"}\uFF09`,disabled:!0},{type:"divider"},{key:"logout",label:"\u9000\u51FA\u767B\u5F55",onClick:()=>{localStorage.removeItem("token"),localStorage.removeItem("userInfo"),window.location.href=M()}}]},placement:"bottomRight",children:m("span",{style:{cursor:"pointer",display:"inline-flex",alignItems:"center",gap:6},children:[o(H,{size:28,style:{background:"#7c3aed"},children:(r.name||"?").slice(0,1).toUpperCase()}),o("span",{style:{fontSize:13,color:"#0f172a"},children:r.name}),o(G,{style:{fontSize:10,color:"#94a3b8"}})]})}),!r&&o(j,{type:"primary",size:"small",icon:o(Q,{}),onClick:()=>{window.location.href=M()},children:"\u767B\u5F55"}),v]})]}),o(re,{style:{margin:16,padding:24,background:"#fff",minHeight:280},children:o(Z,{})})]})]})}import{useState as se}from"react";import{Alert as ae,Button as ie,Card as le,Form as S,Input as K,message as h}from"antd";import{LockOutlined as fe,UserOutlined as ue}from"@ant-design/icons";import ne from"axios";import"antd";function B(e){return e&&typeof e=="object"&&"code"in e&&"data"in e?e.code!==200?Promise.reject(new Error(e.message||"\u8BF7\u6C42\u5931\u8D25")):e.data:e}function O(e,t={}){let{tokenKey:n="token",userInfoKey:l="userInfo",unauthorizedRedirect:f="/login"}=t;return e.interceptors.request.use(r=>{let s=localStorage.getItem(n);return s&&(r.headers.Authorization=`Bearer ${s}`),r}),e.interceptors.response.use(r=>B(r.data),r=>{let s=r.response?.status;return s===401?(localStorage.removeItem(n),localStorage.removeItem(l),window.location.href=f):s===403?console.error("\u6CA1\u6709\u6743\u9650\u8BBF\u95EE\u8BE5\u8D44\u6E90"):s===500&&console.error("\u670D\u52A1\u5668\u5185\u90E8\u9519\u8BEF"),Promise.reject(r)}),e}function y(e={}){let t=ne.create({baseURL:e.baseURL??"/api",timeout:e.timeout??1e4});return O(t,{tokenKey:e.tokenKey,userInfoKey:e.userInfoKey,unauthorizedRedirect:e.unauthorizedRedirect})}var x=y(),q=y();import{jsx as p,jsxs as T}from"react/jsx-runtime";function I({title:e="\u7EDF\u4E00\u7BA1\u7406\u5E73\u53F0",mockAuth:t,loginApi:n="/auth/login",redirectUrl:l="/",onSuccess:f}){let[r,s]=se(!1),v=i=>{localStorage.setItem("token",t?"mock-"+t.username:i?.token||"token"),localStorage.setItem("userInfo",JSON.stringify(i||{})),h.success("\u767B\u5F55\u6210\u529F"+(t?"\uFF08mock \u6A21\u5F0F\uFF0C\u5F85 CTC/SSO \u63A5\u5165\uFF09":"")),f?f(i):window.location.href=l},C=async i=>{s(!0);try{if(t){i.username===t.username&&i.password===t.password?v(t.user):h.error("\u7528\u6237\u540D\u6216\u5BC6\u7801\u9519\u8BEF");return}let c=await x.post(n,i);c?.token?(localStorage.setItem("token",c.token),localStorage.setItem("userInfo",JSON.stringify(c.user||c)),h.success("\u767B\u5F55\u6210\u529F"),f?f(c):window.location.href=l):h.error("\u767B\u5F55\u5931\u8D25\uFF1A\u672A\u83B7\u53D6\u5230 token")}catch(c){h.error(c.response?.data?.message||c.message||"\u767B\u5F55\u5931\u8D25")}finally{s(!1)}};return p("div",{style:{height:"100vh",display:"flex",justifyContent:"center",alignItems:"center",background:"#f0f2f5"},children:T(le,{title:e,style:{width:400},children:[t&&p(ae,{type:"info",showIcon:!0,style:{marginBottom:16},message:`Mock \u6A21\u5F0F\uFF1A\u7528\u6237\u540D ${t.username} / \u5BC6\u7801 ${t.password}`}),T(S,{onFinish:C,size:"large",children:[p(S.Item,{name:"username",rules:[{required:!0,message:"\u8BF7\u8F93\u5165\u7528\u6237\u540D"}],children:p(K,{prefix:p(ue,{}),placeholder:"\u7528\u6237\u540D"})}),p(S.Item,{name:"password",rules:[{required:!0,message:"\u8BF7\u8F93\u5165\u5BC6\u7801"}],children:p(K.Password,{prefix:p(fe,{}),placeholder:"\u5BC6\u7801"})}),p(S.Item,{children:p(ie,{type:"primary",htmlType:"submit",loading:r,block:!0,children:"\u767B \u5F55"})})]})]})})}import{Tag as ce}from"antd";import{jsx as de}from"react/jsx-runtime";var w={1:{color:"green",text:"\u6B63\u5E38"},0:{color:"red",text:"\u7981\u7528"},pending:{color:"orange",text:"\u5F85\u5904\u7406"},approved:{color:"blue",text:"\u5DF2\u901A\u8FC7"},rejected:{color:"red",text:"\u5DF2\u62D2\u7EDD"}};function k({status:e,map:t}){let n=t?.[e]||w[e]||{color:"default",text:String(e)};return de(ce,{color:n.color,children:n.text})}import{Component as pe}from"react";import{Button as me,Result as ge}from"antd";import{jsx as E}from"react/jsx-runtime";var g=class extends pe{constructor(t){super(t),this.state={hasError:!1,error:null,errorInfo:null},this.handleReset=()=>{this.setState({hasError:!1,error:null,errorInfo:null}),typeof this.props.onReset=="function"&&this.props.onReset()}}static getDerivedStateFromError(t){return{hasError:!0,error:t}}componentDidCatch(t,n){console.error("[ErrorBoundary] caught error:",t,n),this.setState({errorInfo:n})}render(){return this.state.hasError?E(ge,{status:"error",title:"\u9875\u9762\u51FA\u9519\u4E86",subTitle:String(this.state.error?.message||this.state.error),extra:E(me,{type:"primary",onClick:this.handleReset,children:"\u91CD\u8BD5"})}):this.props.children}};var Ae={AppLayout:L,StatusTag:k,defaultStatusMap:w,LoginPage:I,ErrorBoundary:g,request:x,authRequest:q,createRequest:y};export{L as AppLayout,g as ErrorBoundary,I as LoginPage,k as StatusTag,q as authRequest,y as createRequest,Ae as default,w as defaultStatusMap,x as request,O as setupInterceptors,B as unwrapResponse};
1
+ import { C as xe, D as we, E as Ie, a as ke, F as be, G as Ce, L as Re, P as ve, b as ze, R as Me, S as Le, c as Oe, d as Be, T as Ee, e as je, f as Te, g as Ke, l as $e, n as De, p as Pe, r as qe, s as Fe, h as He } from "./PagedTable-D9Bw7uhG.js";
2
+ import { jsxs as h, jsx as r } from "react/jsx-runtime";
3
+ import { Layout as I, Spin as E, Menu as j, Dropdown as T, Avatar as K, Button as k, Tooltip as $, Card as D, Alert as P, Form as S, Input as v, message as p, Tag as q, Result as F } from "antd";
4
+ import { MenuUnfoldOutlined as H, MenuFoldOutlined as W, DownOutlined as N, LoginOutlined as G, UserOutlined as J, LockOutlined as Q } from "@ant-design/icons";
5
+ import { useNavigate as X, useLocation as Y, Outlet as Z } from "react-router-dom";
6
+ import { useState as z, Component as _ } from "react";
7
+ import U from "axios";
8
+ const { Header: V, Sider: A, Content: ee } = I;
9
+ function te(t, e = 0.85) {
10
+ const o = /^#?([0-9a-f]{6})$/i.exec(t || "");
11
+ if (!o) return t;
12
+ const d = parseInt(o[1], 16), u = Math.max(0, Math.min(255, Math.round((d >> 16 & 255) * e))), n = Math.max(0, Math.min(255, Math.round((d >> 8 & 255) * e))), a = Math.max(0, Math.min(255, Math.round((d & 255) * e)));
13
+ return "#" + (u << 16 | n << 8 | a).toString(16).padStart(6, "0");
14
+ }
15
+ function re({
16
+ menuItems: t = [],
17
+ appTitle: e = "One Company",
18
+ appShort: o = "OC",
19
+ appVersion: d,
20
+ appIcon: u,
21
+ appUser: n,
22
+ loginPath: a,
23
+ headerExtra: g,
24
+ loading: x = !1
25
+ }) {
26
+ const [i, m] = z(!1), y = X(), c = Y(), O = ({ key: f }) => {
27
+ y(f);
28
+ }, C = () => {
29
+ if (a) return a;
30
+ const f = t && t[0], l = f && f.key;
31
+ return typeof l == "string" && l.endsWith("/home") ? l.slice(0, -4) + "login" : "/login";
32
+ }, R = (f, l = []) => {
33
+ for (const s of f || [])
34
+ s != null && s.key && l.push(s.key), s != null && s.children && R(s.children, l);
35
+ return l;
36
+ }, B = (() => {
37
+ const f = R(t), l = c.pathname;
38
+ return f.filter((s) => l === s || l.startsWith(s + "/")).sort((s, w) => w.length - s.length)[0] || l;
39
+ })();
40
+ return /* @__PURE__ */ h(I, { style: { minHeight: "100vh" }, children: [
41
+ /* @__PURE__ */ h(A, { trigger: null, collapsible: !0, collapsed: i, children: [
42
+ /* @__PURE__ */ r("div", { style: {
43
+ height: 64,
44
+ display: "flex",
45
+ alignItems: "center",
46
+ justifyContent: "center"
47
+ }, children: (() => {
48
+ if (i) {
49
+ if (u) {
50
+ const { icon: f, color: l = "#7c3aed", label: s = e } = u, w = /* @__PURE__ */ r("div", { style: {
51
+ width: 36,
52
+ height: 36,
53
+ borderRadius: 9,
54
+ background: `linear-gradient(135deg, ${l}, ${te(l, 0.7)})`,
55
+ display: "flex",
56
+ alignItems: "center",
57
+ justifyContent: "center",
58
+ color: "#fff",
59
+ fontSize: 20,
60
+ boxShadow: "0 2px 6px rgba(0,0,0,0.25)",
61
+ overflow: "hidden"
62
+ }, children: f });
63
+ return /* @__PURE__ */ r($, { title: s, placement: "right", children: w });
64
+ }
65
+ return o;
66
+ }
67
+ return /* @__PURE__ */ h("span", { style: { color: "#fff", fontWeight: 600, fontSize: 16, whiteSpace: "nowrap" }, children: [
68
+ e,
69
+ d && /* @__PURE__ */ h("span", { style: {
70
+ color: "rgba(255,255,255,0.55)",
71
+ fontWeight: 400,
72
+ fontSize: 12,
73
+ marginLeft: 4
74
+ }, children: [
75
+ "@",
76
+ d
77
+ ] })
78
+ ] });
79
+ })() }),
80
+ x ? /* @__PURE__ */ r("div", { style: { padding: 16, textAlign: "center" }, children: /* @__PURE__ */ r(E, { size: "small" }) }) : /* @__PURE__ */ r(
81
+ j,
82
+ {
83
+ theme: "dark",
84
+ mode: "inline",
85
+ selectedKeys: [B],
86
+ items: t,
87
+ onClick: O
88
+ }
89
+ )
90
+ ] }),
91
+ /* @__PURE__ */ h(I, { children: [
92
+ /* @__PURE__ */ h(V, { style: {
93
+ height: 48,
94
+ lineHeight: "48px",
95
+ padding: "0 16px",
96
+ background: "#fff",
97
+ display: "flex",
98
+ alignItems: "center",
99
+ justifyContent: "space-between",
100
+ borderBottom: "1px solid #f1f5f9"
101
+ }, children: [
102
+ /* @__PURE__ */ r("span", { onClick: () => m(!i), style: { fontSize: 18, cursor: "pointer" }, children: i ? /* @__PURE__ */ r(H, {}) : /* @__PURE__ */ r(W, {}) }),
103
+ /* @__PURE__ */ h("div", { style: { display: "flex", alignItems: "center", gap: 12 }, children: [
104
+ n && /* @__PURE__ */ r(
105
+ T,
106
+ {
107
+ menu: {
108
+ items: [
109
+ { key: "profile", label: `${n.name}(${n.role || "用户"})`, disabled: !0 },
110
+ { type: "divider" },
111
+ {
112
+ key: "logout",
113
+ label: "退出登录",
114
+ onClick: () => {
115
+ localStorage.removeItem("token"), localStorage.removeItem("userInfo"), window.location.href = C();
116
+ }
117
+ }
118
+ ]
119
+ },
120
+ placement: "bottomRight",
121
+ children: /* @__PURE__ */ h("span", { style: { cursor: "pointer", display: "inline-flex", alignItems: "center", gap: 6 }, children: [
122
+ /* @__PURE__ */ r(K, { size: 28, style: { background: "#7c3aed" }, children: (n.name || "?").slice(0, 1).toUpperCase() }),
123
+ /* @__PURE__ */ r("span", { style: { fontSize: 13, color: "#0f172a" }, children: n.name }),
124
+ /* @__PURE__ */ r(N, { style: { fontSize: 10, color: "#94a3b8" } })
125
+ ] })
126
+ }
127
+ ),
128
+ !n && /* @__PURE__ */ r(
129
+ k,
130
+ {
131
+ type: "primary",
132
+ size: "small",
133
+ icon: /* @__PURE__ */ r(G, {}),
134
+ onClick: () => {
135
+ window.location.href = C();
136
+ },
137
+ children: "登录"
138
+ }
139
+ ),
140
+ g
141
+ ] })
142
+ ] }),
143
+ /* @__PURE__ */ r(ee, { style: { margin: 16, padding: 24, background: "#fff", minHeight: 280 }, children: /* @__PURE__ */ r(Z, {}) })
144
+ ] })
145
+ ] });
146
+ }
147
+ function ne(t) {
148
+ return t && typeof t == "object" && "code" in t && "data" in t ? t.code !== 200 ? Promise.reject(new Error(t.message || "请求失败")) : t.data : t;
149
+ }
150
+ function oe(t, e = {}) {
151
+ const {
152
+ tokenKey: o = "token",
153
+ userInfoKey: d = "userInfo",
154
+ unauthorizedRedirect: u = "/login"
155
+ } = e;
156
+ return t.interceptors.request.use((n) => {
157
+ const a = localStorage.getItem(o);
158
+ return a && (n.headers.Authorization = `Bearer ${a}`), n;
159
+ }), t.interceptors.response.use(
160
+ (n) => ne(n.data),
161
+ (n) => {
162
+ var g;
163
+ const a = (g = n.response) == null ? void 0 : g.status;
164
+ return a === 401 ? (localStorage.removeItem(o), localStorage.removeItem(d), window.location.href = u) : a === 403 ? console.error("没有权限访问该资源") : a === 500 && console.error("服务器内部错误"), Promise.reject(n);
165
+ }
166
+ ), t;
167
+ }
168
+ function b(t = {}) {
169
+ const e = U.create({
170
+ baseURL: t.baseURL ?? "/api",
171
+ timeout: t.timeout ?? 1e4
172
+ });
173
+ return oe(e, {
174
+ tokenKey: t.tokenKey,
175
+ userInfoKey: t.userInfoKey,
176
+ unauthorizedRedirect: t.unauthorizedRedirect
177
+ });
178
+ }
179
+ const M = b(), se = b();
180
+ function ae({
181
+ title: t = "统一管理平台",
182
+ mockAuth: e,
183
+ loginApi: o = "/auth/login",
184
+ redirectUrl: d = "/",
185
+ onSuccess: u
186
+ }) {
187
+ const [n, a] = z(!1), g = (i) => {
188
+ localStorage.setItem("token", e ? "mock-" + e.username : (i == null ? void 0 : i.token) || "token"), localStorage.setItem("userInfo", JSON.stringify(i || {})), p.success("登录成功" + (e ? "(mock 模式,待 CTC/SSO 接入)" : "")), u ? u(i) : window.location.href = d;
189
+ }, x = async (i) => {
190
+ var m, y;
191
+ a(!0);
192
+ try {
193
+ if (e) {
194
+ i.username === e.username && i.password === e.password ? g(e.user) : p.error("用户名或密码错误");
195
+ return;
196
+ }
197
+ const c = await M.post(o, i);
198
+ c != null && c.token ? (localStorage.setItem("token", c.token), localStorage.setItem("userInfo", JSON.stringify(c.user || c)), p.success("登录成功"), u ? u(c) : window.location.href = d) : p.error("登录失败:未获取到 token");
199
+ } catch (c) {
200
+ p.error(((y = (m = c.response) == null ? void 0 : m.data) == null ? void 0 : y.message) || c.message || "登录失败");
201
+ } finally {
202
+ a(!1);
203
+ }
204
+ };
205
+ return /* @__PURE__ */ r("div", { style: {
206
+ height: "100vh",
207
+ display: "flex",
208
+ justifyContent: "center",
209
+ alignItems: "center",
210
+ background: "#f0f2f5"
211
+ }, children: /* @__PURE__ */ h(D, { title: t, style: { width: 400 }, children: [
212
+ e && /* @__PURE__ */ r(
213
+ P,
214
+ {
215
+ type: "info",
216
+ showIcon: !0,
217
+ style: { marginBottom: 16 },
218
+ message: `Mock 模式:用户名 ${e.username} / 密码 ${e.password}`
219
+ }
220
+ ),
221
+ /* @__PURE__ */ h(S, { onFinish: x, size: "large", children: [
222
+ /* @__PURE__ */ r(S.Item, { name: "username", rules: [{ required: !0, message: "请输入用户名" }], children: /* @__PURE__ */ r(v, { prefix: /* @__PURE__ */ r(J, {}), placeholder: "用户名" }) }),
223
+ /* @__PURE__ */ r(S.Item, { name: "password", rules: [{ required: !0, message: "请输入密码" }], children: /* @__PURE__ */ r(v.Password, { prefix: /* @__PURE__ */ r(Q, {}), placeholder: "密码" }) }),
224
+ /* @__PURE__ */ r(S.Item, { children: /* @__PURE__ */ r(k, { type: "primary", htmlType: "submit", loading: n, block: !0, children: "登 录" }) })
225
+ ] })
226
+ ] }) });
227
+ }
228
+ const L = {
229
+ 1: { color: "green", text: "正常" },
230
+ 0: { color: "red", text: "禁用" },
231
+ pending: { color: "orange", text: "待处理" },
232
+ approved: { color: "blue", text: "已通过" },
233
+ rejected: { color: "red", text: "已拒绝" }
234
+ };
235
+ function ie({ status: t, map: e }) {
236
+ const o = (e == null ? void 0 : e[t]) || L[t] || { color: "default", text: String(t) };
237
+ return /* @__PURE__ */ r(q, { color: o.color, children: o.text });
238
+ }
239
+ class le extends _ {
240
+ constructor(e) {
241
+ super(e), this.state = { hasError: !1, error: null, errorInfo: null }, this.handleReset = () => {
242
+ this.setState({ hasError: !1, error: null, errorInfo: null }), typeof this.props.onReset == "function" && this.props.onReset();
243
+ };
244
+ }
245
+ static getDerivedStateFromError(e) {
246
+ return { hasError: !0, error: e };
247
+ }
248
+ componentDidCatch(e, o) {
249
+ console.error("[ErrorBoundary] caught error:", e, o), this.setState({ errorInfo: o });
250
+ }
251
+ render() {
252
+ var e;
253
+ return this.state.hasError ? /* @__PURE__ */ r(
254
+ F,
255
+ {
256
+ status: "error",
257
+ title: "页面出错了",
258
+ subTitle: String(((e = this.state.error) == null ? void 0 : e.message) || this.state.error),
259
+ extra: /* @__PURE__ */ r(k, { type: "primary", onClick: this.handleReset, children: "重试" })
260
+ }
261
+ ) : this.props.children;
262
+ }
263
+ }
264
+ const me = {
265
+ AppLayout: re,
266
+ StatusTag: ie,
267
+ defaultStatusMap: L,
268
+ LoginPage: ae,
269
+ ErrorBoundary: le,
270
+ request: M,
271
+ authRequest: se,
272
+ createRequest: b
273
+ };
274
+ export {
275
+ re as AppLayout,
276
+ xe as CategoryDot,
277
+ we as DarkBanner,
278
+ Ie as EmptyState,
279
+ le as ErrorBoundary,
280
+ ke as ErrorState,
281
+ be as FeatureCard,
282
+ Ce as GradientStatCard,
283
+ Re as LoadingState,
284
+ ae as LoginPage,
285
+ ve as PageHeader,
286
+ ze as PagedTable,
287
+ Me as RefreshButton,
288
+ Le as SearchInput,
289
+ Oe as SectionHeader,
290
+ Be as StatusBadge,
291
+ ie as StatusTag,
292
+ Ee as TableToolbar,
293
+ je as antdTheme,
294
+ se as authRequest,
295
+ Te as brand,
296
+ b as createRequest,
297
+ me as default,
298
+ L as defaultStatusMap,
299
+ Ke as fontSize,
300
+ $e as lift,
301
+ De as neutral,
302
+ Pe as palette,
303
+ qe as radius,
304
+ M as request,
305
+ oe as setupInterceptors,
306
+ Fe as shadow,
307
+ He as space,
308
+ ne as unwrapResponse
309
+ };
@@ -0,0 +1,54 @@
1
+ import { jsx as l } from "react/jsx-runtime";
2
+ import { useRef as s, useEffect as u } from "react";
3
+ import * as c from "echarts/core";
4
+ import { LineChart as d, PieChart as p, BarChart as v } from "echarts/charts";
5
+ import { GridComponent as C, TooltipComponent as h, LegendComponent as z, TitleComponent as R } from "echarts/components";
6
+ import { CanvasRenderer as w } from "echarts/renderers";
7
+ c.use([
8
+ d,
9
+ p,
10
+ v,
11
+ C,
12
+ h,
13
+ z,
14
+ R,
15
+ w
16
+ ]);
17
+ function x({
18
+ option: t,
19
+ height: f = 300,
20
+ className: a,
21
+ style: m
22
+ }) {
23
+ const r = s(null), e = s(null);
24
+ return u(() => {
25
+ if (!r.current) return;
26
+ e.current = c.init(r.current, null, { renderer: "canvas" });
27
+ let n;
28
+ const i = () => {
29
+ var o;
30
+ return (o = e.current) == null ? void 0 : o.resize();
31
+ };
32
+ return typeof ResizeObserver < "u" ? (n = new ResizeObserver(i), n.observe(r.current)) : window.addEventListener("resize", i), () => {
33
+ n ? n.disconnect() : window.removeEventListener("resize", i), e.current && (e.current.dispose(), e.current = null);
34
+ };
35
+ }, []), u(() => {
36
+ e.current && t && e.current.setOption(t, { notMerge: !0 });
37
+ }, [t]), /* @__PURE__ */ l(
38
+ "div",
39
+ {
40
+ ref: r,
41
+ className: a,
42
+ role: "img",
43
+ "aria-label": "数据可视化图表",
44
+ style: {
45
+ width: "100%",
46
+ height: f,
47
+ ...m
48
+ }
49
+ }
50
+ );
51
+ }
52
+ export {
53
+ x as EChartsChart
54
+ };
package/dist/ui.js ADDED
@@ -0,0 +1,26 @@
1
+ import { C as s, D as t, E as r, a as d, F as n, G as o, L as S, P as l, b as g, R as i, S as p, c as u, d as b, T as f, e as h, f as T, g as c, l as C, n as m, p as B, r as D, s as E, h as P } from "./PagedTable-D9Bw7uhG.js";
2
+ export {
3
+ s as CategoryDot,
4
+ t as DarkBanner,
5
+ r as EmptyState,
6
+ d as ErrorState,
7
+ n as FeatureCard,
8
+ o as GradientStatCard,
9
+ S as LoadingState,
10
+ l as PageHeader,
11
+ g as PagedTable,
12
+ i as RefreshButton,
13
+ p as SearchInput,
14
+ u as SectionHeader,
15
+ b as StatusBadge,
16
+ f as TableToolbar,
17
+ h as antdTheme,
18
+ T as brand,
19
+ c as fontSize,
20
+ C as lift,
21
+ m as neutral,
22
+ B as palette,
23
+ D as radius,
24
+ E as shadow,
25
+ P as space
26
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yuku123/z-frontend-common",
3
- "version": "1.0.0",
3
+ "version": "1.1.1",
4
4
  "description": "z-opc 全仓共享前端基座 — AppLayout(§1/§11/§12/§15/§16) + LoginPage(mockAuth 双模式) + EmptyState/StatusTag/ErrorBoundary + createRequest 工厂。lead 008 前端开发规范唯一承载仓",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -10,6 +10,12 @@
10
10
  ".": {
11
11
  "types": "./dist/index.d.ts",
12
12
  "default": "./dist/index.js"
13
+ },
14
+ "./ui/echarts": {
15
+ "default": "./dist/ui-echarts.js"
16
+ },
17
+ "./ui": {
18
+ "default": "./dist/ui.js"
13
19
  }
14
20
  },
15
21
  "files": [
@@ -0,0 +1,38 @@
1
+ import {palette} from './tokens'
2
+
3
+ /**
4
+ * 分类圆点 - 借鉴 wenming7 分类标识
5
+ *
6
+ * 用法:
7
+ * <CategoryDot color="pink" /> // 仅圆点
8
+ * <CategoryDot color="blue" label="对话" /> // 圆点 + 文字
9
+ * <CategoryDot color="green" size={10} /> // 自定义大小
10
+ *
11
+ * @param {Object} props
12
+ * @param {string} props.color - 配色 (pink|blue|green|orange|violet|cyan|red|yellow)
13
+ * @param {string} [props.label] - 可选标签文字
14
+ * @param {number} [props.size] - 圆点直径 (默认 8)
15
+ */
16
+ export default function CategoryDot({color = 'blue', label, size = 8}) {
17
+ const c = palette[color] || palette.blue
18
+ return (
19
+ <span style={{
20
+ display: 'inline-flex',
21
+ alignItems: 'center',
22
+ gap: 8,
23
+ fontSize: 14,
24
+ fontWeight: 600,
25
+ color: '#111827',
26
+ }}>
27
+ <span style={{
28
+ width: size,
29
+ height: size,
30
+ borderRadius: '50%',
31
+ background: c.bg,
32
+ boxShadow: `0 0 0 3px ${c.soft}`,
33
+ flexShrink: 0,
34
+ }}/>
35
+ {label && <span>{label}</span>}
36
+ </span>
37
+ )
38
+ }
@@ -0,0 +1,142 @@
1
+ import {radius, shadow} from './tokens'
2
+
3
+ /**
4
+ * 深色 CTA 横幅 - 借鉴 wenming7 "FOR DEVELOPERS" 区
5
+ *
6
+ * 视觉:
7
+ * ┌──────────────────────────────────────────────┐
8
+ * │ [标签] │
9
+ * │ 把你的想法做成产品 │ ← 深色渐变背景
10
+ * │ 副标题/描述文案 │
11
+ * │ [行动按钮 →] │
12
+ * └──────────────────────────────────────────────┘
13
+ *
14
+ * @param {Object} props
15
+ * @param {string} [props.tag] - 顶部小标签 (如 "FOR DEVELOPERS")
16
+ * @param {string} props.title - 主标题
17
+ * @param {string} [props.description] - 描述
18
+ * @param {string} [props.buttonText] - 按钮文案
19
+ * @param {string} [props.buttonHref] - 跳转路径
20
+ */
21
+ export default function DarkBanner({
22
+ tag,
23
+ title,
24
+ description,
25
+ buttonText,
26
+ buttonHref,
27
+ onButtonClick,
28
+ }) {
29
+ return (
30
+ <div style={{
31
+ position: 'relative',
32
+ borderRadius: radius.lg,
33
+ padding: '40px 48px',
34
+ background: 'linear-gradient(135deg, #0f172a 0%, #1e293b 50%, #312e81 100%)',
35
+ color: '#ffffff',
36
+ overflow: 'hidden',
37
+ boxShadow: shadow.lg,
38
+ }}>
39
+ {/* 装饰光晕 */}
40
+ <div style={{
41
+ position: 'absolute',
42
+ top: -64,
43
+ right: -64,
44
+ width: 200,
45
+ height: 200,
46
+ borderRadius: '50%',
47
+ background: 'radial-gradient(circle, rgba(139, 92, 246, 0.4) 0%, transparent 70%)',
48
+ pointerEvents: 'none',
49
+ }}/>
50
+ <div style={{
51
+ position: 'absolute',
52
+ bottom: -48,
53
+ left: '30%',
54
+ width: 160,
55
+ height: 160,
56
+ borderRadius: '50%',
57
+ background: 'radial-gradient(circle, rgba(59, 130, 246, 0.3) 0%, transparent 70%)',
58
+ pointerEvents: 'none',
59
+ }}/>
60
+
61
+ <div style={{
62
+ position: 'relative',
63
+ display: 'flex',
64
+ alignItems: 'center',
65
+ justifyContent: 'space-between',
66
+ gap: 32,
67
+ flexWrap: 'wrap',
68
+ }}>
69
+ <div style={{flex: 1, minWidth: 240}}>
70
+ {tag && (
71
+ <div style={{
72
+ fontSize: 11,
73
+ fontWeight: 600,
74
+ letterSpacing: '0.12em',
75
+ color: '#a5b4fc',
76
+ textTransform: 'uppercase',
77
+ marginBottom: 12,
78
+ }}>
79
+ {tag}
80
+ </div>
81
+ )}
82
+ <div style={{
83
+ fontSize: 24,
84
+ fontWeight: 700,
85
+ lineHeight: 1.3,
86
+ marginBottom: 8,
87
+ }}>
88
+ {title}
89
+ </div>
90
+ {description && (
91
+ <div style={{
92
+ fontSize: 14,
93
+ color: 'rgba(255, 255, 255, 0.7)',
94
+ lineHeight: 1.6,
95
+ maxWidth: 540,
96
+ }}>
97
+ {description}
98
+ </div>
99
+ )}
100
+ </div>
101
+
102
+ {(buttonText && (buttonHref || onButtonClick)) && (
103
+ <a
104
+ href={buttonHref || '#'}
105
+ onClick={(e) => {
106
+ if (onButtonClick) {
107
+ e.preventDefault()
108
+ onButtonClick()
109
+ }
110
+ }}
111
+ style={{
112
+ display: 'inline-flex',
113
+ alignItems: 'center',
114
+ gap: 8,
115
+ padding: '12px 24px',
116
+ background: 'linear-gradient(135deg, #10b981 0%, #059669 100%)',
117
+ color: '#ffffff',
118
+ borderRadius: 999,
119
+ fontSize: 14,
120
+ fontWeight: 600,
121
+ textDecoration: 'none',
122
+ boxShadow: '0 4px 12px rgba(16, 185, 129, 0.4)',
123
+ transition: 'transform 150ms ease, box-shadow 150ms ease',
124
+ whiteSpace: 'nowrap',
125
+ }}
126
+ onMouseEnter={(e) => {
127
+ e.currentTarget.style.transform = 'translateY(-1px)'
128
+ e.currentTarget.style.boxShadow = '0 6px 16px rgba(16, 185, 129, 0.5)'
129
+ }}
130
+ onMouseLeave={(e) => {
131
+ e.currentTarget.style.transform = 'translateY(0)'
132
+ e.currentTarget.style.boxShadow = '0 4px 12px rgba(16, 185, 129, 0.4)'
133
+ }}
134
+ >
135
+ {buttonText}
136
+ <span>→</span>
137
+ </a>
138
+ )}
139
+ </div>
140
+ </div>
141
+ )
142
+ }