提交代码

This commit is contained in:
code@server 2025-12-17 23:11:17 +08:00
parent c31c06c227
commit 8291c9c447
25 changed files with 96 additions and 18 deletions

View File

@ -1 +1 @@
VITE_API_BASE_URL=http://localhost:5159/api
VITE_API_BASE_URL=/api

View File

@ -6,6 +6,7 @@
"scripts": {
"dev": "vite",
"build": "vue-tsc -b && vite build",
"build:deploy": "npm run build && echo 'Admin项目已打包到BookmarkApi/wwwroot'",
"preview": "vite preview"
},
"dependencies": {

View File

@ -13,8 +13,6 @@ const form = reactive({
password: ''
})
const formRef = ref()
async function handleSubmit() {
loading.value = true
try {

View File

@ -3,12 +3,15 @@
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"types": ["vite/client"],
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
},
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"erasableSyntaxOnly": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
},

View File

@ -17,5 +17,11 @@ export default defineConfig({
changeOrigin: true
}
}
},
build: {
// 打包输出到 BookmarkApi 的 wwwroot 文件夹
outDir: '../backend/BookmarkApi/wwwroot',
// 清空输出目录
emptyOutDir: true
}
})

View File

@ -147,31 +147,40 @@ if (app.Environment.IsDevelopment())
app.UseSwaggerUI(options =>
{
options.SwaggerEndpoint("/swagger/v1/swagger.json", "Bookmark API v1");
options.RoutePrefix = string.Empty; // 设置 Swagger UI 为根路径
}); // 开发环境启用 CORS
app.UseCors("Development");
options.RoutePrefix = "swagger"; // 开发环境将 Swagger UI 移到 /swagger 路径
});
}
//else
//{
// app.UseCors();
//}
app.UseHttpsRedirection();
// 路由必须在 Authentication 和 Authorization 之前
app.UseRouting();
// CORS 配置
if (app.Environment.IsDevelopment())
{
app.UseCors("Development");
}
app.UseAuthentication();
app.UseAuthorization();
// 配置静态文件服务
app.UseDefaultFiles(); // 支持默认文件(如 index.html
app.UseStaticFiles(); // 启用静态文件服务
// 配置端点
app.MapControllers();
// 配置最小API端点
app.UseRouting();
app.UseEndpoints(endpoints =>
app.MapGet("/log", async context =>
{
endpoints.MapGet("/log", async context =>
{
await context.Response.WriteAsync("run success");
});
await context.Response.WriteAsync("run success");
});
// 配置 SPA 回退路由(必须放在最后)
app.MapFallbackToFile("index.html");
// 初始化数据库
using (var scope = app.Services.CreateScope())
{

View File

@ -0,0 +1 @@
.dashboard .page-title[data-v-9e5f3ec2]{color:#333;margin-bottom:24px;font-size:20px;font-weight:600}.stats-grid[data-v-9e5f3ec2]{grid-template-columns:repeat(4,1fr);gap:20px;margin-bottom:20px;display:grid}.stats-row[data-v-9e5f3ec2]{grid-template-columns:repeat(4,1fr);gap:20px;display:grid}.stat-card[data-v-9e5f3ec2]{background:#fff;border-radius:12px;align-items:center;gap:16px;padding:24px;display:flex;box-shadow:0 2px 8px #0000000f}.stat-card.small[data-v-9e5f3ec2]{flex-direction:column;align-items:flex-start;gap:8px}.stat-card.small .stat-label[data-v-9e5f3ec2]{color:#666;font-size:14px}.stat-card.small .stat-value[data-v-9e5f3ec2]{color:#333;font-size:28px;font-weight:700}.stat-card.small .stat-value.warning[data-v-9e5f3ec2]{color:#f56c6c}.stat-card .stat-icon[data-v-9e5f3ec2]{color:#fff;border-radius:12px;justify-content:center;align-items:center;width:56px;height:56px;display:flex}.stat-card .stat-icon.users[data-v-9e5f3ec2]{background:linear-gradient(135deg,#667eea,#764ba2)}.stat-card .stat-icon.active[data-v-9e5f3ec2]{background:linear-gradient(135deg,#11998e,#38ef7d)}.stat-card .stat-icon.bookmarks[data-v-9e5f3ec2]{background:linear-gradient(135deg,#f093fb,#f5576c)}.stat-card .stat-icon.devices[data-v-9e5f3ec2]{background:linear-gradient(135deg,#4facfe,#00f2fe)}.stat-card .stat-content .stat-value[data-v-9e5f3ec2]{color:#333;font-size:32px;font-weight:700;line-height:1}.stat-card .stat-content .stat-label[data-v-9e5f3ec2]{color:#999;margin-top:4px;font-size:14px}

View File

@ -0,0 +1 @@
import{A as e,D as t,M as n,O as r,S as i,T as a,_ as o,b as s,m as c,o as l,w as u,x as d,y as f}from"./index-jy40eMQa.js";import{t as p}from"./admin-CqpMrZ_s.js";var m={class:`dashboard`},h={class:`stats-grid`},g={class:`stat-card`},_={class:`stat-icon users`},v={class:`stat-content`},y={class:`stat-value`},b={class:`stat-card`},x={class:`stat-icon active`},S={class:`stat-content`},C={class:`stat-value`},w={class:`stat-card`},T={class:`stat-icon bookmarks`},E={class:`stat-content`},D={class:`stat-value`},O={class:`stat-card`},k={class:`stat-icon devices`},A={class:`stat-content`},j={class:`stat-value`},M={class:`stats-row`},N={class:`stat-card small`},P={class:`stat-value`},F={class:`stat-card small`},I={class:`stat-value`},L={class:`stat-card small`},R={class:`stat-value`},z={class:`stat-card small`},B={class:`stat-value warning`},V=l(s({__name:`DashboardView`,setup(s){let l=e(!0),V=e(null);return d(async()=>{try{let e=await p.getStatistics();e.success&&e.data&&(V.value=e.data)}finally{l.value=!1}}),(e,s)=>{let d=u(`User`),p=u(`el-icon`),H=u(`UserFilled`),U=u(`Collection`),W=u(`Monitor`),G=a(`loading`);return i(),o(`div`,m,[s[8]||=c(`h2`,{class:`page-title`},`仪表盘`,-1),r((i(),o(`div`,h,[c(`div`,g,[c(`div`,_,[f(p,{size:`28`},{default:t(()=>[f(d)]),_:1})]),c(`div`,v,[c(`div`,y,n(V.value?.totalUsers||0),1),s[0]||=c(`div`,{class:`stat-label`},`总用户数`,-1)])]),c(`div`,b,[c(`div`,x,[f(p,{size:`28`},{default:t(()=>[f(H)]),_:1})]),c(`div`,S,[c(`div`,C,n(V.value?.activeUsersLast7Days||0),1),s[1]||=c(`div`,{class:`stat-label`},`7日活跃用户`,-1)])]),c(`div`,w,[c(`div`,T,[f(p,{size:`28`},{default:t(()=>[f(U)]),_:1})]),c(`div`,E,[c(`div`,D,n(V.value?.totalBookmarks||0),1),s[2]||=c(`div`,{class:`stat-label`},`总书签数`,-1)])]),c(`div`,O,[c(`div`,k,[f(p,{size:`28`},{default:t(()=>[f(W)]),_:1})]),c(`div`,A,[c(`div`,j,n(V.value?.totalDevices||0),1),s[3]||=c(`div`,{class:`stat-label`},`总设备数`,-1)])])])),[[G,l.value]]),c(`div`,M,[c(`div`,N,[s[4]||=c(`div`,{class:`stat-label`},`今日新增用户`,-1),c(`div`,P,n(V.value?.newUsersToday||0),1)]),c(`div`,F,[s[5]||=c(`div`,{class:`stat-label`},`本周新增用户`,-1),c(`div`,I,n(V.value?.newUsersThisWeek||0),1)]),c(`div`,L,[s[6]||=c(`div`,{class:`stat-label`},`本月新增用户`,-1),c(`div`,R,n(V.value?.newUsersThisMonth||0),1)]),c(`div`,z,[s[7]||=c(`div`,{class:`stat-label`},`禁用用户数`,-1),c(`div`,B,n(V.value?.disabledUsers||0),1)])])])}}}),[[`__scopeId`,`data-v-9e5f3ec2`]]);export{V as default};

View File

@ -0,0 +1 @@
.layout-container[data-v-369082cb]{height:100vh}.layout-aside[data-v-369082cb]{background:#1a1a2e}.layout-aside .logo[data-v-369082cb]{color:#fff;border-bottom:1px solid #ffffff1a;justify-content:center;align-items:center;height:60px;font-size:18px;font-weight:600;display:flex}.layout-aside .aside-menu[data-v-369082cb]{border-right:none}.layout-aside .aside-menu .el-menu-item[data-v-369082cb]:hover{background:#ffffff0d!important}.layout-aside .aside-menu .el-menu-item.is-active[data-v-369082cb]{background:#409eff!important}.layout-header[data-v-369082cb]{background:#fff;justify-content:space-between;align-items:center;padding:0 20px;display:flex;box-shadow:0 1px 4px #00000014}.layout-header .user-info[data-v-369082cb]{cursor:pointer;border-radius:8px;align-items:center;gap:8px;padding:8px;display:flex}.layout-header .user-info[data-v-369082cb]:hover{background:#f5f5f5}.layout-main[data-v-369082cb]{background:#f0f2f5;padding:20px}

View File

@ -0,0 +1 @@
import{C as e,D as t,E as n,M as r,N as i,S as a,_ as o,a as s,b as c,f as l,g as u,h as d,i as f,j as p,m,o as h,p as g,s as _,v,w as y,y as b}from"./index-jy40eMQa.js";import"./admin-CqpMrZ_s.js";import"./types-WIP_Oieg.js";import{t as x}from"./auth-BtSAcF4e.js";var S={class:`header-left`},C={class:`header-right`},w={class:`user-info`},T=h(c({__name:`LayoutView`,setup(i){let c=s(),h=f(),T=x(),E=g(()=>T.user),D=[{path:`/`,title:`仪表盘`,icon:`DataAnalysis`},{path:`/users`,title:`用户管理`,icon:`User`}];async function O(){try{await _.confirm(`确定要退出登录吗?`,`提示`,{confirmButtonText:`确定`,cancelButtonText:`取消`,type:`warning`}),await T.logout(),c.push(`/login`)}catch{}}return(i,s)=>{let c=y(`el-icon`),f=y(`el-menu-item`),g=y(`el-menu`),_=y(`el-aside`),x=y(`el-breadcrumb-item`),T=y(`el-breadcrumb`),k=y(`el-avatar`),A=y(`ArrowDown`),j=y(`SwitchButton`),M=y(`el-dropdown-item`),N=y(`el-dropdown-menu`),P=y(`el-dropdown`),F=y(`el-header`),I=y(`router-view`),L=y(`el-main`),R=y(`el-container`);return a(),d(R,{class:`layout-container`},{default:t(()=>[b(_,{width:`220px`,class:`layout-aside`},{default:t(()=>[s[0]||=m(`div`,{class:`logo`},[m(`span`,null,`📊 管理后台`)],-1),b(g,{"default-active":p(h).path,router:``,class:`aside-menu`,"background-color":`#1a1a2e`,"text-color":`#b0b0b0`,"active-text-color":`#fff`},{default:t(()=>[(a(),o(l,null,e(D,e=>b(f,{key:e.path,index:e.path},{default:t(()=>[b(c,null,{default:t(()=>[(a(),d(n(e.icon)))]),_:2},1024),m(`span`,null,r(e.title),1)]),_:2},1032,[`index`])),64))]),_:1},8,[`default-active`])]),_:1}),b(R,null,{default:t(()=>[b(F,{class:`layout-header`},{default:t(()=>[m(`div`,S,[b(T,{separator:`/`},{default:t(()=>[b(x,{to:{path:`/`}},{default:t(()=>[...s[1]||=[v(`首页`,-1)]]),_:1}),p(h).meta.title?(a(),d(x,{key:0},{default:t(()=>[v(r(p(h).meta.title),1)]),_:1})):u(``,!0)]),_:1})]),m(`div`,C,[b(P,{trigger:`click`,onCommand:O},{dropdown:t(()=>[b(N,null,{default:t(()=>[b(M,{command:`logout`},{default:t(()=>[b(c,null,{default:t(()=>[b(j)]),_:1}),s[2]||=v(` 退出登录 `,-1)]),_:1})]),_:1})]),default:t(()=>[m(`div`,w,[b(k,{size:32},{default:t(()=>[v(r(E.value?.userName?.[0]||`A`),1)]),_:1}),m(`span`,null,r(E.value?.userName||`管理员`),1),b(c,null,{default:t(()=>[b(A)]),_:1})])]),_:1})])]),_:1}),b(L,{class:`layout-main`},{default:t(()=>[b(I)]),_:1})]),_:1})]),_:1})}}}),[[`__scopeId`,`data-v-369082cb`]]);export{T as default};

View File

@ -0,0 +1 @@
import{A as e,D as t,N as n,S as r,_ as i,a,b as o,c as s,d as c,k as l,m as u,o as d,v as f,w as p,y as m}from"./index-jy40eMQa.js";import"./admin-CqpMrZ_s.js";import"./types-WIP_Oieg.js";import{t as h}from"./auth-BtSAcF4e.js";var g={class:`login-container`},_={class:`login-card`},v=d(o({__name:`LoginView`,setup(n){let o=a(),d=h(),v=e(!1),y=l({email:``,password:``});async function b(){v.value=!0;try{let e=await d.login(y.email,y.password);e.success?(s.success(`登录成功`),o.push(`/`)):s.error(e.message||`登录失败`)}catch(e){s.error(e.response?.data?.message||`登录失败`)}finally{v.value=!1}}return(e,n)=>{let a=p(`el-input`),o=p(`el-form-item`),s=p(`el-button`),l=p(`el-form`);return r(),i(`div`,g,[u(`div`,_,[n[3]||=u(`div`,{class:`login-header`},[u(`h1`,null,`📊 书签管理后台`),u(`p`,null,`管理员登录`)],-1),m(l,{ref:`formRef`,model:y,class:`login-form`,onSubmit:c(b,[`prevent`])},{default:t(()=>[m(o,null,{default:t(()=>[m(a,{modelValue:y.email,"onUpdate:modelValue":n[0]||=e=>y.email=e,placeholder:`管理员邮箱`,size:`large`,"prefix-icon":`User`},null,8,[`modelValue`])]),_:1}),m(o,null,{default:t(()=>[m(a,{modelValue:y.password,"onUpdate:modelValue":n[1]||=e=>y.password=e,type:`password`,placeholder:`密码`,size:`large`,"show-password":``,"prefix-icon":`Lock`},null,8,[`modelValue`])]),_:1}),m(o,null,{default:t(()=>[m(s,{type:`primary`,size:`large`,loading:v.value,class:`submit-btn`,"native-type":`submit`},{default:t(()=>[...n[2]||=[f(` 登录 `,-1)]]),_:1},8,[`loading`])]),_:1})]),_:1},8,[`model`])])])}}}),[[`__scopeId`,`data-v-76df69c7`]]);export{v as default};

View File

@ -0,0 +1 @@
.login-container[data-v-76df69c7]{background:linear-gradient(135deg,#1a1a2e 0%,#16213e 100%);justify-content:center;align-items:center;min-height:100vh;display:flex}.login-card[data-v-76df69c7]{background:#fff;border-radius:16px;width:400px;padding:40px;box-shadow:0 20px 60px #0000004d}.login-header[data-v-76df69c7]{text-align:center;margin-bottom:32px}.login-header h1[data-v-76df69c7]{color:#333;margin-bottom:8px;font-size:24px}.login-header p[data-v-76df69c7]{color:#999;font-size:14px}.login-form .submit-btn[data-v-76df69c7]{width:100%;height:44px;font-size:16px}

View File

@ -0,0 +1 @@
.user-bookmarks .page-header[data-v-be59d845]{align-items:center;gap:16px;margin-bottom:20px;display:flex}.user-bookmarks .page-header h2[data-v-be59d845]{color:#333;margin:0;font-size:20px;font-weight:600}.user-bookmarks .search-bar[data-v-be59d845]{background:#fff;border-radius:8px;gap:12px;margin-bottom:20px;padding:16px;display:flex}.user-bookmarks .bookmark-table[data-v-be59d845]{background:#fff;border-radius:8px}.user-bookmarks .bookmark-cell[data-v-be59d845]{align-items:center;gap:12px;display:flex}.user-bookmarks .bookmark-cell .favicon[data-v-be59d845]{border-radius:4px;width:24px;height:24px}.user-bookmarks .bookmark-cell .bookmark-info .title[data-v-be59d845]{color:#333;font-weight:500}.user-bookmarks .bookmark-cell .bookmark-info .url[data-v-be59d845]{color:#999;text-overflow:ellipsis;white-space:nowrap;max-width:400px;font-size:12px;display:block;overflow:hidden}.user-bookmarks .tags[data-v-be59d845]{flex-wrap:wrap;gap:4px;display:flex}.user-bookmarks .pagination[data-v-be59d845]{justify-content:flex-end;margin-top:20px;display:flex}

View File

@ -0,0 +1 @@
import{A as e,C as t,D as n,M as r,N as i,O as a,S as o,T as s,_ as c,a as l,b as u,c as d,f,g as p,h as m,i as h,j as g,k as _,m as v,o as y,s as b,u as x,v as S,w as C,x as w,y as T}from"./index-jy40eMQa.js";import{t as E}from"./admin-CqpMrZ_s.js";import{i as D}from"./types-WIP_Oieg.js";var O={class:`user-bookmarks`},k={class:`page-header`},A={class:`search-bar`},j={class:`bookmark-cell`},M=[`src`],N={class:`bookmark-info`},P={class:`title`},F=[`href`],I={class:`tags`},L={class:`pagination`},R=y(u({__name:`UserBookmarksView`,setup(i){let u=h(),y=l(),R=e(!0),z=e([]),B=e(0),V=_({page:1,pageSize:20,search:``}),H=u.params.id;w(()=>{U()});async function U(){R.value=!0;try{let e=await E.getUserBookmarks(H,V);e.success&&e.data&&(z.value=e.data.items,B.value=e.data.total)}finally{R.value=!1}}function W(){V.page=1,U()}function G(e){V.page=e,U()}async function K(e){try{await b.confirm(`确定要删除书签 "${e.title}" 吗?`,`删除确认`,{confirmButtonText:`删除`,cancelButtonText:`取消`,type:`warning`}),(await E.deleteUserBookmark(H,e.id)).success&&(d.success(`删除成功`),U())}catch{}}function q(e){return{[D.Public]:`公开`,[D.Private]:`私密`,[D.Specified]:`指定设备`}[e]||`公开`}function J(e){return e?new Date(e).toLocaleString(`zh-CN`):`-`}return(e,i)=>{let l=C(`ArrowLeft`),u=C(`el-icon`),d=C(`el-button`),h=C(`Search`),_=C(`el-input`),b=C(`el-table-column`),w=C(`el-tag`),E=C(`el-table`),D=C(`el-pagination`),H=s(`loading`);return o(),c(`div`,O,[v(`div`,k,[T(d,{onClick:i[0]||=e=>g(y).back()},{default:n(()=>[T(u,null,{default:n(()=>[T(l)]),_:1}),i[4]||=S(` 返回 `,-1)]),_:1}),i[5]||=v(`h2`,null,`用户书签`,-1)]),v(`div`,A,[T(_,{modelValue:V.search,"onUpdate:modelValue":i[1]||=e=>V.search=e,placeholder:`搜索书签标题或URL`,clearable:``,style:{width:`300px`},onKeyup:x(W,[`enter`])},{prefix:n(()=>[T(u,null,{default:n(()=>[T(h)]),_:1})]),_:1},8,[`modelValue`]),T(d,{type:`primary`,onClick:W},{default:n(()=>[...i[6]||=[S(`搜索`,-1)]]),_:1})]),a((o(),m(E,{data:z.value,class:`bookmark-table`},{default:n(()=>[T(b,{label:`书签`,"min-width":`300`},{default:n(({row:e})=>[v(`div`,j,[e.icon?(o(),c(`img`,{key:0,src:e.icon,class:`favicon`,onError:i[2]||=e=>e.target.style.display=`none`},null,40,M)):p(``,!0),v(`div`,N,[v(`div`,P,r(e.title),1),v(`a`,{href:e.url,target:`_blank`,class:`url`},r(e.url),9,F)])])]),_:1}),T(b,{label:`标签`,width:`200`},{default:n(({row:e})=>[v(`div`,I,[(o(!0),c(f,null,t(e.tags.slice(0,3),e=>(o(),m(w,{key:e,size:`small`,type:`info`},{default:n(()=>[S(r(e),1)]),_:2},1024))),128))])]),_:1}),T(b,{label:`可见性`,width:`100`},{default:n(({row:e})=>[S(r(q(e.visibility)),1)]),_:1}),T(b,{label:`访问次数`,width:`100`,align:`center`,prop:`visitCount`}),T(b,{label:`创建时间`,width:`180`},{default:n(({row:e})=>[S(r(J(e.createdAt)),1)]),_:1}),T(b,{label:`操作`,width:`100`,fixed:`right`},{default:n(({row:e})=>[T(d,{size:`small`,type:`danger`,onClick:t=>K(e)},{default:n(()=>[...i[7]||=[S(` 删除 `,-1)]]),_:1},8,[`onClick`])]),_:1})]),_:1},8,[`data`])),[[H,R.value]]),v(`div`,L,[T(D,{"current-page":V.page,"onUpdate:currentPage":i[3]||=e=>V.page=e,"page-size":V.pageSize,total:B.value,layout:`total, prev, pager, next`,onCurrentChange:G},null,8,[`current-page`,`page-size`,`total`])])])}}}),[[`__scopeId`,`data-v-be59d845`]]);export{R as default};

View File

@ -0,0 +1 @@
.user-detail .page-header[data-v-d2de856f]{align-items:center;gap:16px;margin-bottom:20px;display:flex}.user-detail .page-header h2[data-v-d2de856f]{color:#333;margin:0;font-size:20px;font-weight:600}.user-detail .info-card[data-v-d2de856f]{background:#fff;border-radius:8px;margin-bottom:20px;padding:20px}.user-detail .info-card .card-header[data-v-d2de856f]{justify-content:space-between;align-items:center;margin-bottom:20px;display:flex}.user-detail .info-card .card-header h3[data-v-d2de856f]{color:#333;margin:0;font-size:16px;font-weight:600}.user-detail .info-grid[data-v-d2de856f]{grid-template-columns:repeat(3,1fr);gap:16px;display:grid}.user-detail .info-grid .info-item[data-v-d2de856f]{flex-direction:column;gap:4px;display:flex}.user-detail .info-grid .info-item label[data-v-d2de856f]{color:#999;font-size:12px}.user-detail .info-grid .info-item span[data-v-d2de856f]{color:#333;font-size:14px}.user-detail .device-table[data-v-d2de856f]{border-radius:8px}

View File

@ -0,0 +1 @@
import{A as e,D as t,M as n,N as r,O as i,S as a,T as o,_ as s,a as c,b as l,c as u,f as d,g as f,h as p,i as m,j as h,m as g,o as _,s as v,v as y,w as b,x,y as S}from"./index-jy40eMQa.js";import{t as C}from"./admin-CqpMrZ_s.js";import{n as w,r as T,t as E}from"./types-WIP_Oieg.js";var D={class:`user-detail`},O={class:`page-header`},k={class:`info-card`},A={class:`card-header`},j={class:`info-grid`},M={class:`info-item`},N={class:`info-item`},P={class:`info-item`},F={class:`info-item`},I={class:`info-item`},L={class:`info-item`},R={class:`info-item`},z={class:`info-card`},B={class:`card-header`},V={key:1},H=_(l({__name:`UserDetailView`,setup(r){let l=m(),_=c(),H=e(!0),U=e(null),W=l.params.id;x(async()=>{try{let e=await C.getUserDetail(W);e.success&&e.data&&(U.value=e.data)}finally{H.value=!1}});async function G(){try{await v.confirm(`确定要重置该用户的密码吗?新密码将显示一次,请妥善保存。`,`重置密码`,{confirmButtonText:`确定`,cancelButtonText:`取消`,type:`warning`});let e=await C.resetUserPassword(W);e.success&&e.data&&v.alert(`新密码: ${e.data}`,`密码已重置`,{confirmButtonText:`我已记录`})}catch{}}async function K(e){try{await v.confirm(`确定要强制设备 "${e.deviceName}" 下线吗?`,`强制下线`,{confirmButtonText:`确定`,cancelButtonText:`取消`,type:`warning`}),(await C.forceDeviceLogout(e.id)).success&&u.success(`已强制下线`)}catch{}}async function q(e){let t=e.status===w.Normal,n=t?`禁用`:`启用`;try{await v.confirm(`确定要${n}设备 "${e.deviceName}" 吗?`,`${n}设备`,{confirmButtonText:`确定`,cancelButtonText:`取消`,type:`warning`}),(await C.setDeviceStatus(e.id,t)).success&&(u.success(`${n}成功`),e.status=t?w.Disabled:w.Normal)}catch{}}function J(e){return e?new Date(e).toLocaleString(`zh-CN`):`-`}function Y(e){return{[E.User]:`普通用户`,[E.Admin]:`管理员`,[E.SuperAdmin]:`超级管理员`}[e]||`未知`}return(e,r)=>{let c=b(`ArrowLeft`),l=b(`el-icon`),u=b(`el-button`),m=b(`el-tag`),v=b(`el-table-column`),x=b(`el-table`),C=o(`loading`);return i((a(),s(`div`,D,[g(`div`,O,[S(u,{onClick:r[0]||=e=>h(_).back()},{default:t(()=>[S(l,null,{default:t(()=>[S(c)]),_:1}),r[1]||=y(` 返回 `,-1)]),_:1}),r[2]||=g(`h2`,null,`用户详情`,-1)]),U.value?(a(),s(d,{key:0},[g(`div`,k,[g(`div`,A,[r[4]||=g(`h3`,null,`基本信息`,-1),S(u,{type:`primary`,onClick:G},{default:t(()=>[...r[3]||=[y(`重置密码`,-1)]]),_:1})]),g(`div`,j,[g(`div`,M,[r[5]||=g(`label`,null,`用户名`,-1),g(`span`,null,n(U.value.userName),1)]),g(`div`,N,[r[6]||=g(`label`,null,`邮箱`,-1),g(`span`,null,n(U.value.email),1)]),g(`div`,P,[r[7]||=g(`label`,null,`角色`,-1),g(`span`,null,n(Y(U.value.role)),1)]),g(`div`,F,[r[8]||=g(`label`,null,`状态`,-1),S(m,{type:U.value.status===h(T).Normal?`success`:`danger`,size:`small`},{default:t(()=>[y(n(U.value.status===h(T).Normal?`正常`:`禁用`),1)]),_:1},8,[`type`])]),g(`div`,I,[r[9]||=g(`label`,null,`注册时间`,-1),g(`span`,null,n(J(U.value.createdAt)),1)]),g(`div`,L,[r[10]||=g(`label`,null,`最后登录`,-1),g(`span`,null,n(J(U.value.lastLoginAt)),1)]),g(`div`,R,[r[11]||=g(`label`,null,`书签数量`,-1),g(`span`,null,n(U.value.bookmarkCount),1)])])]),g(`div`,z,[g(`div`,B,[g(`h3`,null,`设备列表 (`+n(U.value.devices.length)+`)`,1)]),S(x,{data:U.value.devices,class:`device-table`},{default:t(()=>[S(v,{label:`设备名称`,prop:`deviceName`,"min-width":`150`}),S(v,{label:`设备类型`,prop:`deviceType`,"min-width":`150`}),S(v,{label:`管理员设备`,width:`100`,align:`center`},{default:t(({row:e})=>[e.isAdmin?(a(),p(m,{key:0,type:`warning`,size:`small`},{default:t(()=>[...r[12]||=[y(``,-1)]]),_:1})):(a(),s(`span`,V,`-`))]),_:1}),S(v,{label:`状态`,width:`100`},{default:t(({row:e})=>[S(m,{type:e.status===h(w).Normal?`success`:`danger`,size:`small`},{default:t(()=>[y(n(e.status===h(w).Normal?`正常`:`禁用`),1)]),_:2},1032,[`type`])]),_:1}),S(v,{label:`最后活跃`,width:`180`},{default:t(({row:e})=>[y(n(J(e.lastActiveAt)),1)]),_:1}),S(v,{label:`操作`,width:`180`},{default:t(({row:e})=>[S(u,{size:`small`,onClick:t=>K(e)},{default:t(()=>[...r[13]||=[y(` 强制下线 `,-1)]]),_:1},8,[`onClick`]),S(u,{size:`small`,type:e.status===h(w).Normal?`danger`:`success`,onClick:t=>q(e)},{default:t(()=>[y(n(e.status===h(w).Normal?`禁用`:`启用`),1)]),_:2},1032,[`type`,`onClick`])]),_:1})]),_:1},8,[`data`])])],64)):f(``,!0)])),[[C,H.value]])}}}),[[`__scopeId`,`data-v-d2de856f`]]);export{H as default};

View File

@ -0,0 +1 @@
import{A as e,D as t,M as n,N as r,O as i,S as a,T as o,_ as s,a as c,b as l,c as u,h as d,j as f,k as p,m,o as h,s as g,u as _,v,w as y,x as b,y as x}from"./index-jy40eMQa.js";import{t as S}from"./admin-CqpMrZ_s.js";import{r as C,t as w}from"./types-WIP_Oieg.js";var T={class:`user-list`},E={class:`search-bar`},D={class:`user-cell`},O={class:`user-info`},k={class:`user-name`},A={class:`user-email`},j={class:`pagination`},M=h(l({__name:`UserListView`,setup(r){let l=c(),h=e(!1),M=e([]),N=e(0),P=p({page:1,pageSize:20,search:``,status:void 0});b(()=>{F()});async function F(){h.value=!0;try{let e=await S.getUsers(P);e.success&&e.data&&(M.value=e.data.items,N.value=e.data.total)}finally{h.value=!1}}function I(){P.page=1,F()}function L(e){P.page=e,F()}function R(e){l.push(`/users/${e.id}`)}function z(e){l.push(`/users/${e.id}/bookmarks`)}async function B(e){let t=e.status===C.Normal,n=t?`禁用`:`启用`;try{await g.confirm(`确定要${n}用户 "${e.userName}" 吗?`,`${n}确认`,{confirmButtonText:`确定`,cancelButtonText:`取消`,type:`warning`}),(await S.setUserStatus(e.id,t)).success&&(u.success(`${n}成功`),F())}catch{}}function V(e){return e?new Date(e).toLocaleString(`zh-CN`):`-`}function H(e){return{[w.User]:`普通用户`,[w.Admin]:`管理员`,[w.SuperAdmin]:`超级管理员`}[e]||`未知`}function U(e){return{[w.User]:`info`,[w.Admin]:`warning`,[w.SuperAdmin]:`danger`}[e]||`info`}return(e,r)=>{let c=y(`Search`),l=y(`el-icon`),u=y(`el-input`),p=y(`el-option`),g=y(`el-select`),b=y(`el-button`),S=y(`el-avatar`),w=y(`el-table-column`),F=y(`el-tag`),W=y(`el-table`),G=y(`el-pagination`),K=o(`loading`);return a(),s(`div`,T,[r[6]||=m(`div`,{class:`page-header`},[m(`h2`,null,`用户管理`)],-1),m(`div`,E,[x(u,{modelValue:P.search,"onUpdate:modelValue":r[0]||=e=>P.search=e,placeholder:`搜索用户邮箱或用户名`,clearable:``,style:{width:`300px`},onKeyup:_(I,[`enter`])},{prefix:t(()=>[x(l,null,{default:t(()=>[x(c)]),_:1})]),_:1},8,[`modelValue`]),x(g,{modelValue:P.status,"onUpdate:modelValue":r[1]||=e=>P.status=e,placeholder:`用户状态`,clearable:``,style:{width:`150px`},onChange:I},{default:t(()=>[x(p,{label:`正常`,value:f(C).Normal},null,8,[`value`]),x(p,{label:`禁用`,value:f(C).Disabled},null,8,[`value`])]),_:1},8,[`modelValue`]),x(b,{type:`primary`,onClick:I},{default:t(()=>[...r[3]||=[v(`搜索`,-1)]]),_:1})]),i((a(),d(W,{data:M.value,class:`user-table`},{default:t(()=>[x(w,{label:`用户`,"min-width":`200`},{default:t(({row:e})=>[m(`div`,D,[x(S,{size:40,src:e.avatar},{default:t(()=>[v(n(e.userName?.[0]||`U`),1)]),_:2},1032,[`src`]),m(`div`,O,[m(`div`,k,n(e.userName),1),m(`div`,A,n(e.email),1)])])]),_:1}),x(w,{label:`角色`,width:`120`},{default:t(({row:e})=>[x(F,{type:U(e.role),size:`small`},{default:t(()=>[v(n(H(e.role)),1)]),_:2},1032,[`type`])]),_:1}),x(w,{label:`状态`,width:`100`},{default:t(({row:e})=>[x(F,{type:e.status===f(C).Normal?`success`:`danger`,size:`small`},{default:t(()=>[v(n(e.status===f(C).Normal?`正常`:`禁用`),1)]),_:2},1032,[`type`])]),_:1}),x(w,{label:`设备数`,width:`80`,align:`center`},{default:t(({row:e})=>[v(n(e.deviceCount),1)]),_:1}),x(w,{label:`书签数`,width:`80`,align:`center`},{default:t(({row:e})=>[v(n(e.bookmarkCount),1)]),_:1}),x(w,{label:`注册时间`,width:`180`},{default:t(({row:e})=>[v(n(V(e.createdAt)),1)]),_:1}),x(w,{label:`最后登录`,width:`180`},{default:t(({row:e})=>[v(n(V(e.lastLoginAt)),1)]),_:1}),x(w,{label:`操作`,width:`220`,fixed:`right`},{default:t(({row:e})=>[x(b,{size:`small`,onClick:t=>R(e)},{default:t(()=>[...r[4]||=[v(` 详情 `,-1)]]),_:1},8,[`onClick`]),x(b,{size:`small`,onClick:t=>z(e)},{default:t(()=>[...r[5]||=[v(` 书签 `,-1)]]),_:1},8,[`onClick`]),x(b,{size:`small`,type:e.status===f(C).Normal?`danger`:`success`,onClick:t=>B(e)},{default:t(()=>[v(n(e.status===f(C).Normal?`禁用`:`启用`),1)]),_:2},1032,[`type`,`onClick`])]),_:1})]),_:1},8,[`data`])),[[K,h.value]]),m(`div`,j,[x(G,{"current-page":P.page,"onUpdate:currentPage":r[2]||=e=>P.page=e,"page-size":P.pageSize,total:N.value,layout:`total, prev, pager, next`,onCurrentChange:L},null,8,[`current-page`,`page-size`,`total`])])])}}}),[[`__scopeId`,`data-v-a21164e0`]]);export{M as default};

View File

@ -0,0 +1 @@
.user-list .page-header[data-v-a21164e0]{margin-bottom:20px}.user-list .page-header h2[data-v-a21164e0]{color:#333;font-size:20px;font-weight:600}.user-list .search-bar[data-v-a21164e0]{background:#fff;border-radius:8px;gap:12px;margin-bottom:20px;padding:16px;display:flex}.user-list .user-table[data-v-a21164e0]{background:#fff;border-radius:8px}.user-list .user-cell[data-v-a21164e0]{align-items:center;gap:12px;display:flex}.user-list .user-cell .user-info .user-name[data-v-a21164e0]{color:#333;font-weight:500}.user-list .user-cell .user-info .user-email[data-v-a21164e0]{color:#999;font-size:12px}.user-list .pagination[data-v-a21164e0]{justify-content:flex-end;margin-top:20px;display:flex}

View File

@ -0,0 +1 @@
import{n as e,r as t,t as n}from"./index-jy40eMQa.js";var r=`/api`;const i={async login(n,i){let a=await t.post(`${r}/auth/login`,{email:n,password:i,deviceName:`Admin Panel`,deviceType:`Web Admin`});return a.data.success&&a.data.accessToken&&(e.setAccessToken(a.data.accessToken),e.setRefreshToken(a.data.refreshToken),e.setTokenExpires(a.data.expiresAt)),a.data},async logout(){try{let n=e.getAccessToken();n&&await t.post(`${r}/auth/logout`,{},{headers:{Authorization:`Bearer ${n}`}})}finally{e.clearTokens()}},async getStatistics(){return n.get(`/admin/statistics`)},async getUsers(e){return n.get(`/admin/users`,{params:e})},async getUserDetail(e){return n.get(`/admin/users/${e}`)},async setUserStatus(e,t){return n.put(`/admin/users/${e}/status`,{disabled:t})},async resetUserPassword(e){return n.post(`/admin/users/${e}/reset-password`)},async getUserBookmarks(e,t){return n.get(`/admin/users/${e}/bookmarks`,{params:t})},async deleteUserBookmark(e,t){return n.delete(`/admin/users/${e}/bookmarks/${t}`)},async forceDeviceLogout(e){return n.post(`/admin/devices/${e}/force-logout`)},async setDeviceStatus(e,t){return n.put(`/admin/devices/${e}/status`,{disabled:t})}};export{i as t};

View File

@ -0,0 +1 @@
import{A as e,l as t,n,p as r}from"./index-jy40eMQa.js";import{t as i}from"./admin-CqpMrZ_s.js";import{t as a}from"./types-WIP_Oieg.js";const o=t(`auth`,()=>{let t=e(null),o=e(!1),s=r(()=>!!n.getAccessToken()&&!n.isTokenExpired()),c=r(()=>t.value&&t.value.role>=a.Admin),l=r(()=>t.value?.role===a.SuperAdmin);async function u(e,r){o.value=!0;try{let o=await i.login(e,r);if(o.success&&o.user){if(o.user.role<a.Admin)return n.clearTokens(),{success:!1,message:`您没有管理员权限`};t.value=o.user}return o}finally{o.value=!1}}async function d(){o.value=!0;try{await i.logout()}finally{t.value=null,o.value=!1}}function f(e){t.value=e}return{user:t,loading:o,isLoggedIn:s,isAdmin:c,isSuperAdmin:l,login:u,logout:d,setUser:f}});export{o as t};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
let e=function(e){return e[e.Normal=0]=`Normal`,e[e.Disabled=1]=`Disabled`,e}({}),t=function(e){return e[e.Normal=0]=`Normal`,e[e.Disabled=1]=`Disabled`,e}({}),n=function(e){return e[e.Public=0]=`Public`,e[e.Private=1]=`Private`,e[e.Specified=2]=`Specified`,e}({}),r=function(e){return e[e.User=0]=`User`,e[e.Admin=1]=`Admin`,e[e.SuperAdmin=2]=`SuperAdmin`,e}({});export{n as i,t as n,e as r,r as t};

View File

@ -0,0 +1,14 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>admin</title>
<script type="module" crossorigin src="/assets/index-jy40eMQa.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-m6f-7ssD.css">
</head>
<body>
<div id="app"></div>
</body>
</html>

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB