Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in / Register
Toggle navigation
Q
qiyouxue
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
xuchentao
qiyouxue
Commits
a1cfaaed
Commit
a1cfaaed
authored
Aug 13, 2026
by
tao355667
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: refine admin data tables
parent
3d8d4534
Changes
3
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
138 additions
and
126 deletions
+138
-126
app.js
public/admin/app.js
+89
-79
style.css
public/admin/style.css
+34
-27
index.astro
src/pages/admin/index.astro
+15
-20
No files found.
public/admin/app.js
View file @
a1cfaaed
This diff is collapsed.
Click to expand it.
public/admin/style.css
View file @
a1cfaaed
...
...
@@ -42,6 +42,7 @@ input:focus, textarea:focus, select:focus { outline: 2px solid rgba(20,115,230,.
.pending-badge
{
padding
:
5px
10px
;
color
:
#cfe2ff
;
background
:
rgba
(
20
,
115
,
230
,
.12
);
border
:
1px
solid
rgba
(
20
,
115
,
230
,
.3
);
border-radius
:
999px
;
}
.view
{
width
:
min
(
1120px
,
calc
(
100%
-
40px
));
margin
:
0
auto
;
padding
:
44px
0
70px
;
}
.view-head
{
margin-bottom
:
26px
;
display
:
flex
;
align-items
:
center
;
justify-content
:
space-between
;
gap
:
18px
;
}
.view-toolbar
{
min-height
:
40px
;
margin-bottom
:
18px
;
display
:
flex
;
justify-content
:
flex-end
;
}
.view-head
p
{
margin
:
0
0
5px
;
color
:
var
(
--primary-dark
);
font-size
:
11px
;
font-weight
:
700
;
letter-spacing
:
.16em
;
}
.view-head
h1
{
margin
:
0
;
font-size
:
30px
;
}
.view-actions
{
display
:
flex
;
gap
:
9px
;
}
...
...
@@ -185,12 +186,17 @@ input:focus, textarea:focus, select:focus { outline: 2px solid rgba(20,115,230,.
.table-card
::-webkit-scrollbar
{
height
:
9px
;
}
.table-card
::-webkit-scrollbar-track
{
background
:
#f2f5f8
;
}
.table-card
::-webkit-scrollbar-thumb
{
background
:
#b8c7d8
;
border
:
2px
solid
#f2f5f8
;
border-radius
:
999px
;
}
.data-list
{
min-width
:
1320px
;
}
.data-list
{
min-width
:
0
;
}
.data-row
{
display
:
grid
;
align-items
:
center
;
gap
:
10px
;
padding
:
11px
14px
;
border-bottom
:
1px
solid
var
(
--border
);
font-size
:
12px
;
}
.data-row
:last-child
{
border-bottom
:
0
;
}
.data-head
{
min-height
:
44px
;
padding-block
:
11px
;
color
:
var
(
--muted
);
background
:
#f7f9fb
;
font-size
:
12px
;
font-weight
:
600
;
}
.consultation-row
{
grid-template-columns
:
44px
76px
108px
76px
82px
66px
112px
150px
68px
102px
214px
;
}
.teacher-row
{
grid-template-columns
:
1.45
fr
.85
fr
.45
fr
.65
fr
.55
fr
.9
fr
;
}
.data-head
{
min-height
:
61px
;
padding-block
:
8px
;
color
:
var
(
--muted
);
background
:
#f7f9fb
;
font-size
:
12px
;
font-weight
:
600
;
}
.column-filter
{
min-width
:
0
;
display
:
grid
;
gap
:
4px
;
}
.column-filter
>
span
{
overflow
:
hidden
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
}
.column-filter
select
{
min-height
:
24px
;
padding
:
2px
19px
2px
5px
;
color
:
#657587
;
background-color
:
#fff
;
border-color
:
#d9e1e9
;
border-radius
:
5px
;
font-size
:
10px
;
}
#consultation-list
{
min-width
:
1100px
;
}
.consultation-row
{
grid-template-columns
:
44px
76px
108px
76px
82px
66px
112px
minmax
(
150px
,
1
fr
)
68px
102px
86px
;
}
#teacher-list
{
min-width
:
1050px
;
}
.teacher-row
{
grid-template-columns
:
.75
fr
.9
fr
.55
fr
1.35
fr
1
fr
.65
fr
.75
fr
.65
fr
86px
;
}
.data-row
small
{
display
:
block
;
margin-top
:
4px
;
color
:
var
(
--muted
);
font-size
:
11px
;
}
.phone-link
{
color
:
var
(
--text
);
font-size
:
12px
;
font-weight
:
600
;
text-decoration
:
none
;
}
.page
{
max-width
:
180px
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
}
...
...
@@ -198,10 +204,16 @@ input:focus, textarea:focus, select:focus { outline: 2px solid rgba(20,115,230,.
.created
{
color
:
var
(
--muted
);
}
.sequence
,
.call-count
{
color
:
var
(
--muted
);
font-size
:
12px
;
}
.user-name
,
.location
,
.unadded-reason
,
.note-summary
,
.consultation-status
{
min-width
:
0
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
font-size
:
12px
;
}
.consultation-row
>
:last-child
{
position
:
sticky
;
right
:
0
;
z-index
:
2
;
min-height
:
100%
;
align-content
:
center
;
background
:
#fff
;
box-shadow
:
-10px
0
14px
-14px
rgba
(
19
,
48
,
79
,
.75
);
}
.consultation-row.data-head
>
:last-child
{
z-index
:
3
;
background
:
#f7f9fb
;
}
.consultation-row
.row-actions
{
gap
:
5px
;
flex-wrap
:
nowrap
;
}
.consultation-row
.row-actions
button
{
min-height
:
29px
;
padding-inline
:
9px
;
font-size
:
11px
;
}
.consultation-status
{
font-weight
:
700
;
}
.consultation-status--unprocessed
{
color
:
#1769aa
;
}
.consultation-status--added
{
color
:
#0b805b
;
}
.consultation-status--not_added
{
color
:
#bd4141
;
}
.consultation-row
>
:last-child
,
.teacher-row
>
:last-child
{
position
:
sticky
;
right
:
0
;
z-index
:
2
;
min-height
:
100%
;
align-content
:
center
;
justify-content
:
flex-end
;
background
:
#fff
;
box-shadow
:
-10px
0
14px
-14px
rgba
(
19
,
48
,
79
,
.75
);
}
.consultation-row.data-head
>
:last-child
,
.teacher-row.data-head
>
:last-child
{
z-index
:
3
;
background
:
#f7f9fb
;
}
.consultation-row
.row-actions
,
.teacher-row
.row-actions
{
gap
:
12px
;
flex-wrap
:
nowrap
;
}
.consultation-row
.row-actions
.text-action
,
.teacher-row
.row-actions
.text-action
{
min-height
:
auto
;
padding
:
2px
0
;
color
:
var
(
--primary-dark
);
background
:
transparent
;
border
:
0
;
border-radius
:
0
;
font-size
:
12px
;
line-height
:
1.4
;
}
.consultation-row
.row-actions
.text-action
:hover
,
.teacher-row
.row-actions
.text-action
:hover
{
color
:
var
(
--deep
);
text-decoration
:
underline
;
transform
:
none
;
}
.consultation-row
.row-actions
.text-action.danger
,
.teacher-row
.row-actions
.text-action.danger
{
color
:
var
(
--danger
);
}
.inline-follow-form
{
display
:
contents
;
}
.inline-follow-form
select
{
padding
:
8px
10px
;
font-size
:
13px
;
}
.inline-note
{
min-width
:
0
;
display
:
grid
;
gap
:
4px
;
}
...
...
@@ -210,20 +222,8 @@ input:focus, textarea:focus, select:focus { outline: 2px solid rgba(20,115,230,.
.note-toggle
:hover
{
text-decoration
:
underline
;
}
.inline-follow-actions
{
display
:
grid
;
justify-items
:
start
;
gap
:
2px
;
}
.inline-follow-actions
.save-state
{
min-height
:
14px
;
margin
:
0
;
white-space
:
nowrap
;
}
.consultation-note-card
{
width
:
min
(
680px
,
100%
);
}
.consultation-note-form
{
padding
:
22px
;
display
:
grid
;
gap
:
18px
;
}
.note-card-summary
{
display
:
grid
;
grid-template-columns
:
1
fr
1
fr
;
gap
:
12px
;
}
.note-card-summary
>
div
{
padding
:
14px
16px
;
display
:
grid
;
gap
:
5px
;
background
:
#f5f9fd
;
border-radius
:
9px
;
}
.note-card-summary
small
{
color
:
var
(
--muted
);
font-size
:
11px
;
}
.note-card-summary
strong
{
font-size
:
15px
;
}
.consultation-note-form
>
label
{
display
:
grid
;
gap
:
7px
;
color
:
var
(
--muted
);
font-size
:
13px
;
}
.consultation-note-form
select
{
max-width
:
180px
;
}
.consultation-note-form
textarea
{
min-height
:
230px
;
resize
:
vertical
;
line-height
:
1.7
;
}
.note-card-footer
{
display
:
grid
;
grid-template-columns
:
auto
1
fr
auto
auto
;
gap
:
9px
;
align-items
:
center
;
}
.note-card-footer
>
span
{
color
:
var
(
--muted
);
font-size
:
11px
;
}
.note-card-footer
>
p
{
margin
:
0
;
color
:
var
(
--danger
);
font-size
:
12px
;
}
.teacher-identity
{
display
:
flex
;
align-items
:
center
;
gap
:
12px
;
}
.teacher-identity
img
{
width
:
48px
;
height
:
48px
;
object-fit
:
cover
;
border
:
1px
solid
var
(
--border
);
border-radius
:
8px
;
}
.staff-name
{
overflow
:
hidden
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
font-size
:
12px
;
}
.staff-title
,
.staff-wechat
,
.username
{
overflow
:
hidden
;
color
:
var
(
--muted
);
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
font-size
:
12px
;
}
.teacher-state
{
width
:
max-content
;
padding
:
4px
9px
;
border-radius
:
999px
;
font-size
:
12px
;
}
.teacher-state.enabled
{
color
:
#087a56
;
background
:
#dff8ee
;
}
.teacher-state.disabled
{
color
:
#7b8190
;
background
:
#edf0f4
;
}
...
...
@@ -235,7 +235,14 @@ input:focus, textarea:focus, select:focus { outline: 2px solid rgba(20,115,230,.
.teacher-form
::-webkit-scrollbar
{
width
:
8px
;
}
.teacher-form
::-webkit-scrollbar-track
{
background
:
#f3f6f9
;
}
.teacher-form
::-webkit-scrollbar-thumb
{
background
:
#bdc9d6
;
border
:
2px
solid
#f3f6f9
;
border-radius
:
999px
;
}
.teacher-form
>
.password-actions
{
margin
:
0
-4px
-4px
;
padding
:
12px
4px
4px
;
position
:
sticky
;
bottom
:
0
;
z-index
:
2
;
background
:
linear-gradient
(
180deg
,
rgba
(
255
,
255
,
255
,
0
),
#fff
24%
);
}
.teacher-form
>
.password-actions
{
margin-top
:
2px
;
}
.consultation-edit-section
{
padding
:
17px
;
display
:
grid
;
gap
:
15px
;
border
:
1px
solid
var
(
--border
);
border-radius
:
12px
;
background
:
#fbfcfe
;
}
.consultation-edit-heading
{
display
:
flex
;
align-items
:
baseline
;
justify-content
:
space-between
;
gap
:
16px
;
}
.consultation-edit-heading
strong
{
color
:
#203a57
;
font-size
:
14px
;
}
.consultation-edit-heading
span
{
color
:
var
(
--muted
);
font-size
:
11px
;
}
.consultation-note-field
{
display
:
grid
;
gap
:
7px
;
color
:
var
(
--muted
);
font-size
:
13px
;
}
.consultation-note-field
textarea
{
min-height
:
170px
;
resize
:
vertical
;
line-height
:
1.7
;
}
.consultation-note-field
small
{
justify-self
:
end
;
color
:
var
(
--muted
);
font-size
:
11px
;
}
.form-grid
{
display
:
grid
;
grid-template-columns
:
1
fr
1
fr
;
gap
:
15px
;
}
.teacher-form
label
,
.qr-field
{
display
:
grid
;
gap
:
7px
;
color
:
var
(
--muted
);
font-size
:
13px
;
}
.teacher-form
label
small
{
font-size
:
11px
;
}
...
...
@@ -277,9 +284,9 @@ input:focus, textarea:focus, select:focus { outline: 2px solid rgba(20,115,230,.
.modal
{
padding
:
10px
;
place-items
:
start
center
;
}
.modal-card
{
max-height
:
calc
(
100
dvh
-
20px
);
}
.teacher-form
{
padding
:
17px
;
}
.consultation-row
{
grid-template-columns
:
44px
76px
108px
76px
82px
66px
112px
150px
68px
102px
214
px
;
}
.
note-card-summary
{
grid-template-columns
:
1
fr
;
}
.
note-card-footer
{
grid-template-columns
:
1
fr
1
fr
;
}
.
note-card-footer
>
p
{
grid-column
:
1
/
-1
;
grid-row
:
2
;
}
.consultation-row
{
grid-template-columns
:
44px
76px
108px
76px
82px
66px
112px
minmax
(
150px
,
1
fr
)
68px
102px
86
px
;
}
.
teacher-row
{
grid-template-columns
:
.75
fr
.9
fr
.55
fr
1.35
fr
1
fr
.65
fr
.75
fr
.65
fr
86px
;
}
.
consultation-edit-section
{
padding
:
14px
;
}
.
consultation-edit-heading
{
align-items
:
flex-start
;
flex-direction
:
column
;
gap
:
3px
;
}
.settings-panel
{
align-items
:
stretch
;
flex-direction
:
column
;
}
}
src/pages/admin/index.astro
View file @
a1cfaaed
...
...
@@ -50,7 +50,7 @@
</header>
<main
id=
"consultations-view"
class=
"view consultation-view consultation-role"
>
<div
class=
"view-
head"
><div><h1>
用户线索列表
</h1><span
id=
"consultation-scope"
>
管理员可查看全部客服的用户线索
</span></div
><div
class=
"view-actions"
><button
id=
"refresh-consultations"
class=
"ghost"
type=
"button"
>
刷新记录
</button><button
id=
"new-consultation"
class=
"primary admin-only"
type=
"button"
>
录入用户
</button></div></div>
<div
class=
"view-
toolbar"
><div
class=
"view-actions"
><button
id=
"refresh-consultations"
class=
"ghost"
type=
"button"
>
刷新记录
</button><button
id=
"new-consultation"
class=
"primary admin-only"
type=
"button"
>
录入用户
</button></div></div>
<div
class=
"metric-grid"
>
<article><small>
未处理
</small><strong
id=
"metric-unprocessed"
>
0
</strong></article>
<article><small>
已添加
</small><strong
id=
"metric-added"
>
0
</strong></article>
...
...
@@ -61,19 +61,18 @@
</main>
<main
id=
"teachers-view"
class=
"view hidden admin-only"
>
<div
class=
"view-
head"
><div><p>
STAFF ACCOUNTS
</p><h1>
后台账号管理
</h1><span>
客服负责用户咨询并参与轮询;运营负责学习资讯发布。
</span></div
><button
id=
"new-teacher"
class=
"primary"
type=
"button"
>
添加账号
</button></div>
<div
class=
"view-
toolbar"
><button
id=
"new-teacher"
class=
"primary"
type=
"button"
>
添加账号
</button></div>
<div
class=
"table-card"
><div
id=
"teacher-list"
class=
"data-list"
></div></div>
</main>
<main
id=
"list-view"
class=
"view hidden content-role"
>
<div
class=
"view-
head"
><div><p>
CONTENT
</p><h1>
学习资讯
</h1></div
><div
class=
"view-actions"
><button
id=
"manage-categories"
class=
"ghost"
>
管理分类
</button><button
id=
"import-article"
class=
"ghost"
>
导入文件
</button><button
id=
"new-article"
class=
"primary"
>
+ 新建文章
</button></div></div>
<div
class=
"view-
toolbar"
><div
class=
"view-actions"
><button
id=
"manage-categories"
class=
"ghost"
>
管理分类
</button><button
id=
"import-article"
class=
"ghost"
>
导入文件
</button><button
id=
"new-article"
class=
"primary"
>
+ 新建文章
</button></div></div>
<input
id=
"article-file"
class=
"hidden"
type=
"file"
accept=
".md,.docx,text/markdown,application/vnd.openxmlformats-officedocument.wordprocessingml.document"
/>
<p
id=
"import-status"
class=
"import-status"
aria-live=
"polite"
></p>
<div
id=
"article-list"
class=
"article-list"
></div>
</main>
<main
id=
"settings-view"
class=
"view hidden admin-only"
>
<div
class=
"view-head"
><div><h1>
账号设置
</h1><span>
管理后台管理员账号的登录安全
</span></div></div>
<section
class=
"settings-panel"
>
<div><strong>
登录密码
</strong><p>
修改管理员账号 admin 的登录密码。环境变量中的主密码仍可用于登录和恢复。
</p></div>
<button
id=
"change-password"
class=
"ghost"
type=
"button"
>
修改密码
</button>
...
...
@@ -157,33 +156,29 @@
</div>
</div>
<div
id=
"consultation-note-modal"
class=
"modal hidden"
>
<div
class=
"modal-card consultation-note-card"
>
<div
class=
"modal-head"
><div><strong>
全部跟进备注
</strong><small
id=
"note-card-meta"
></small></div><button
id=
"close-note-modal"
class=
"ghost small"
type=
"button"
>
关闭
</button></div>
<form
id=
"consultation-note-form"
class=
"consultation-note-form"
>
<div
class=
"note-card-summary"
><div><small>
家长手机号
</small><strong
id=
"note-card-phone"
></strong></div><div><small>
分配客服
</small><strong
id=
"note-card-teacher"
></strong></div></div>
<label>
咨询状态
<select
id=
"note-card-status"
><option
value=
"unprocessed"
>
未处理
</option><option
value=
"added"
>
已添加
</option><option
value=
"not_added"
>
未添加
</option></select></label>
<label>
完整备注
<textarea
id=
"note-card-content"
maxlength=
"500"
rows=
"10"
placeholder=
"记录沟通结果、家长需求或下次跟进时间"
></textarea></label>
<div
class=
"note-card-footer"
><span><strong
id=
"note-card-count"
>
0
</strong>
/ 500
</span><p
id=
"note-card-message"
></p><button
id=
"cancel-note-modal"
class=
"ghost"
type=
"button"
>
取消
</button><button
class=
"primary"
type=
"submit"
>
保存备注
</button></div>
</form>
</div>
</div>
<div
id=
"consultation-user-modal"
class=
"modal hidden"
>
<div
class=
"modal-card consultation-user-card"
>
<div
class=
"modal-head"
><div><strong
id=
"consultation-user-title"
>
录入用户
</strong><small
>
完善用户线索并分配客服
</small></div><button
id=
"close-consultation-user-modal"
class=
"ghost small"
type=
"button"
>
关闭
</button></div>
<div
class=
"modal-head"
><div><strong
id=
"consultation-user-title"
>
录入用户
</strong><small
id=
"consultation-user-description"
>
一次完成用户信息、咨询状态和跟进备注录入
</small></div><button
id=
"close-consultation-user-modal"
class=
"ghost small"
type=
"button"
>
关闭
</button></div>
<form
id=
"consultation-user-form"
class=
"teacher-form"
>
<input
id=
"consultation-user-id"
type=
"hidden"
/>
<div
class=
"form-grid"
>
<section
class=
"consultation-edit-section"
>
<div
class=
"consultation-edit-heading"
><strong>
用户信息
</strong><span>
联系方式与归属信息
</span></div>
<div
class=
"form-grid"
>
<label>
姓名
<input
id=
"consultation-user-name"
maxlength=
"30"
/></label>
<label>
手机号
<input
id=
"consultation-user-phone"
inputmode=
"numeric"
maxlength=
"11"
required
/></label>
<label>
归属地
<input
id=
"consultation-user-location"
maxlength=
"80"
/></label>
<label>
分配客服
<select
id=
"consultation-user-teacher"
required
></select></label>
</div>
</section>
<section
class=
"consultation-edit-section"
>
<div
class=
"consultation-edit-heading"
><strong>
咨询处理
</strong><span>
状态与本次联系结果
</span></div>
<div
class=
"form-grid"
>
<label>
状态
<select
id=
"consultation-user-status"
><option
value=
"unprocessed"
>
未处理
</option><option
value=
"added"
>
已添加
</option><option
value=
"not_added"
>
未添加
</option></select></label>
<label>
未添加原因
<input
id=
"consultation-user-reason"
maxlength=
"200"
/></label>
<label>
打电话次数
<input
id=
"consultation-user-calls"
type=
"number"
min=
"0"
max=
"9999"
value=
"0"
required
/></label>
</div>
<label>
跟进备注
<textarea
id=
"consultation-user-note"
maxlength=
"500"
rows=
"5"
></textarea></label>
</div>
<label
class=
"consultation-note-field"
>
完整跟进备注
<textarea
id=
"consultation-user-note"
maxlength=
"500"
rows=
"8"
placeholder=
"记录沟通结果、家长需求或下次跟进时间"
></textarea><small><strong
id=
"consultation-user-note-count"
>
0
</strong>
/ 500
</small></label>
</section>
<p
id=
"consultation-user-error"
class=
"error"
></p>
<div
class=
"password-actions"
><button
id=
"cancel-consultation-user"
class=
"ghost"
type=
"button"
>
取消
</button><button
class=
"primary"
type=
"submit"
>
保存用户
</button></div>
</form>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment