chore: 同步主分支本地改动与个人开发工具链

纳入 personal-dev/OpenSpec 配置、管理端与教育 Demo 界面调整、工作人员 JWT 默认 7 天,以及参考资料与代理文档更新。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
wuzilongandCursor committed 2026-11-10 17:14:52 +08:00
1 parent e8060287e0
commit 608afb88ea
217 files changed
+15370 -5890

No files matched your search

+26
View File
@@ -32,6 +32,32 @@
line-height: var(--el-component-custom-height) !important;
}
// 提高 Tabs 标签文字对比度,避免浅灰难辨认
.el-tabs__item {
color: var(--art-gray-800) !important;
&.is-active {
color: var(--el-color-primary) !important;
}
&:hover {
color: var(--el-color-primary) !important;
}
}
// 列表列头默认走 secondary 灰,对比不足(需盖过 Element Plus 后载变量)
.el-table {
--el-table-header-text-color: var(--art-gray-800) !important;
thead {
color: var(--art-gray-800) !important;
}
th.el-table__cell > .cell {
color: var(--art-gray-800) !important;
}
}
// 日期选择器
.el-date-range-picker {
--el-datepicker-inrange-bg-color: var(--art-gray-200) !important;
+2 -1
View File
@@ -1,5 +1,5 @@
<template>
<div class="mb-3 flex flex-wrap items-center gap-2">
<div class="list-keyword-search-bar mb-3 flex flex-wrap items-center gap-2">
<ElInput
v-model="draft"
clearable
@@ -8,6 +8,7 @@
@keyup.enter="submit"
@clear="submit"
/>
<slot />
<ElButton type="primary" @click="submit">检索</ElButton>
<ElButton @click="reset">重置</ElButton>
</div>
@@ -10,19 +10,19 @@
<div
:class="
isClickable(item, index)
? 'c-p py-1 rounded tad-200 hover:bg-active-color hover:[&_span]:text-g-600'
? 'c-p py-1 rounded tad-200 hover:bg-active-color hover:[&_span]:text-g-900'
: ''
"
@click="handleBreadcrumbClick(item, index)"
>
<span
class="block max-w-46 overflow-hidden text-ellipsis whitespace-nowrap px-1.5 text-sm text-g-600 dark:text-g-800"
class="block max-w-46 overflow-hidden text-ellipsis whitespace-nowrap px-1.5 text-sm text-g-800 dark:text-g-800"
>{{ formatMenuTitle(item.meta?.title as string) }}</span
>
</div>
<div
v-if="!isLastItem(index) && item.meta?.title"
class="mx-1 text-sm not-italic text-g-500"
class="mx-1 text-sm not-italic text-g-600"
aria-hidden="true"
>
/
@@ -68,10 +68,10 @@
@click="openSearchDialog"
>
<div class="flex-c">
<ArtSvgIcon icon="ri:search-line" class="text-sm text-g-500" />
<span class="ml-1 text-xs font-normal text-g-500">{{ $t('topBar.search.title') }}</span>
<ArtSvgIcon icon="ri:search-line" class="text-sm text-g-700" />
<span class="ml-1 text-xs font-normal text-g-700">{{ $t('topBar.search.title') }}</span>
</div>
<div class="flex-c h-5 px-1.5 text-g-500/80 border border-g-400 rounded">
<div class="flex-c h-5 px-1.5 text-g-700 border border-g-400 rounded">
<ArtSvgIcon v-if="isWindows" icon="vaadin:ctrl-a" class="text-sm" />
<ArtSvgIcon v-else icon="ri:command-fill" class="text-xs" />
<span class="ml-0.5 text-xs">k</span>
@@ -21,7 +21,7 @@
<li
class="art-card-xs inline-flex flex-cc h-8 mr-1.5 text-xs c-p hover:text-theme group"
:class="[
item.path === activeTab ? 'activ-tab !text-theme' : 'text-g-600 dark:text-g-800',
item.path === activeTab ? 'activ-tab !text-theme' : 'text-g-800 dark:text-g-800',
tabStyle === 'tab-google' ? 'google-tab relative !h-8 !leading-8 !border-none' : ''
]"
:style="{
@@ -42,7 +42,7 @@
v-show="item.icon"
:icon="item.icon"
class="text-base mr-1 group-hover:text-theme"
:class="item.path === activeTab ? 'text-theme' : 'text-g-600'"
:class="item.path === activeTab ? 'text-theme' : 'text-g-800'"
/>
{{ item.customTitle || formatMenuTitle(item.title) }}
<span
@@ -50,7 +50,7 @@
class="inline-flex flex-cc relative ml-0.5 p-1 rounded-full tad-200 hover:bg-g-200"
@click.stop="closeWorktab('current', item.path)"
>
<ArtSvgIcon icon="ri:close-large-fill" class="text-[10px] text-g-600" />
<ArtSvgIcon icon="ri:close-large-fill" class="text-[10px] text-g-700" />
</span>
<div
v-if="tabStyle === 'tab-google'"
@@ -521,7 +521,7 @@
.google-tab:not(.activ-tab):hover {
box-sizing: border-box;
color: var(--art-gray-600) !important;
color: var(--art-gray-800) !important;
background-color: var(--art-gray-200) !important;
border-bottom: 1px solid var(--default-box-color) !important;
border-radius: calc(var(--custom-radius) / 2.5 + 4px) !important;
@@ -1,7 +1,7 @@
<!-- 按钮组件 -->
<template>
<div
class="size-8.5 inline-flex flex-cc c-p text-g-600 dark:text-g-800 text-xl rounded tad-300 hover:bg-hover-color"
class="size-8.5 inline-flex flex-cc c-p text-g-800 dark:text-g-800 text-xl rounded tad-300 hover:bg-hover-color"
:class="{ 'rounded-full': circle }"
>
<ArtSvgIcon :icon="icon"></ArtSvgIcon>
+105 -40
View File
@@ -2,52 +2,58 @@
<template>
<div class="file-page art-full-height">
<ElCard class="art-table-card">
<div class="flex flex-wrap items-center gap-3 mb-4">
<ElRadioGroup v-model="bucket">
<ElRadioButton value="public">公开</ElRadioButton>
<ElRadioButton value="private">私有</ElRadioButton>
</ElRadioGroup>
<ElButton v-auth="'file:upload'" type="primary" @click="pickFiles">选择文件</ElButton>
<span class="text-sm text-g-600">可多选,也可在本页粘贴图片</span>
<input ref="fileInput" class="hidden" type="file" multiple @change="onPick" />
</div>
<div class="file-toolbar">
<div class="file-toolbar__upload">
<span class="file-toolbar__label">上传到</span>
<ElRadioGroup v-model="bucket">
<ElRadioButton value="public">公开</ElRadioButton>
<ElRadioButton value="private">私有</ElRadioButton>
</ElRadioGroup>
<ElButton v-auth="'file:upload'" type="primary" @click="pickFiles">选择文件</ElButton>
<span class="file-toolbar__hint">可多选,也可在本页粘贴图片</span>
<input ref="fileInput" class="hidden" type="file" multiple @change="onPick" />
</div>
<div v-if="tasks.length" class="mb-4">
<div v-for="task in tasks" :key="task.id" class="mb-2">
<div class="flex justify-between text-sm mb-1">
<span>{{ task.name }}</span>
<span>{{ task.status === 'error' ? task.message : `${task.percent}%` }}</span>
<div v-if="tasks.length" class="file-toolbar__tasks">
<div v-for="task in tasks" :key="task.id" class="file-toolbar__task">
<div class="file-toolbar__task-meta">
<span>{{ task.name }}</span>
<span>{{ task.status === 'error' ? task.message : `${task.percent}%` }}</span>
</div>
<ElProgress
:percentage="task.percent"
:status="
task.status === 'error'
? 'exception'
: task.status === 'success'
? 'success'
: undefined
"
/>
</div>
<ElProgress
:percentage="task.percent"
:status="
task.status === 'error'
? 'exception'
: task.status === 'success'
? 'success'
: undefined
"
</div>
<div class="file-toolbar__filters">
<ListKeywordSearch v-model="keyword" placeholder="检索文件名" @search="searchFiles">
<ElSelect
v-model="listBucket"
clearable
placeholder="全部桶"
class="file-toolbar__bucket"
@change="reload"
>
<ElOption label="公开" value="public" />
<ElOption label="私有" value="private" />
</ElSelect>
</ListKeywordSearch>
<ArtTableHeader
v-model:columns="columnChecks"
:loading="loading"
@refresh="refreshData"
/>
</div>
</div>
<ListKeywordSearch v-model="keyword" placeholder="检索文件名" @search="searchFiles" />
<ArtTableHeader v-model:columns="columnChecks" :loading="loading" @refresh="refreshData">
<template #left>
<ElSelect
v-model="listBucket"
clearable
placeholder="全部桶"
style="width: 140px"
@change="reload"
>
<ElOption label="公开" value="public" />
<ElOption label="私有" value="private" />
</ElSelect>
</template>
</ArtTableHeader>
<ArtTable
:loading="loading"
:data="data"
@@ -277,3 +283,62 @@
}
}
</script>
<style scoped>
.file-toolbar {
display: flex;
flex-direction: column;
gap: 14px;
margin-bottom: 12px;
padding-bottom: 16px;
border-bottom: 1px solid var(--el-border-color-lighter);
}
.file-toolbar__upload {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 10px 12px;
}
.file-toolbar__label,
.file-toolbar__hint {
color: var(--el-text-color-secondary);
font-size: 13px;
line-height: 1.4;
}
.file-toolbar__tasks {
display: flex;
flex-direction: column;
gap: 8px;
}
.file-toolbar__task-meta {
display: flex;
justify-content: space-between;
gap: 12px;
margin-bottom: 4px;
font-size: 13px;
}
.file-toolbar__filters {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 8px 12px;
}
.file-toolbar__filters :deep(.list-keyword-search-bar) {
margin-bottom: 0;
}
.file-toolbar__filters :deep(#art-table-header) {
flex: 1 1 220px;
min-width: 0;
}
.file-toolbar__bucket {
width: 140px;
}
</style>
+26 -24
View File
@@ -3,30 +3,32 @@
<div class="flex flex-col gap-3">
<ElCard>
<template #header>登录锁定</template>
<ElForm v-loading="loading" label-width="120px" class="max-w-lg">
<ElFormItem label="失败次数">
<ElInputNumber
v-model="form.loginMaxFailures"
:min="1"
:precision="0"
:step="1"
controls-position="right"
/>
</ElFormItem>
<ElFormItem label="锁定分钟数">
<ElInputNumber
v-model="form.loginLockMinutes"
:min="1"
:precision="0"
:step="1"
controls-position="right"
/>
</ElFormItem>
<ElFormItem>
<ElButton v-auth="'security:edit'" type="primary" :loading="saving" @click="save">
保存
</ElButton>
</ElFormItem>
<ElForm v-loading="loading" label-width="auto">
<div class="flex flex-wrap items-center gap-x-4 gap-y-2">
<ElFormItem label="失败次数" class="!mb-0">
<ElInputNumber
v-model="form.loginMaxFailures"
:min="1"
:precision="0"
:step="1"
controls-position="right"
/>
</ElFormItem>
<ElFormItem label="锁定分钟数" class="!mb-0">
<ElInputNumber
v-model="form.loginLockMinutes"
:min="1"
:precision="0"
:step="1"
controls-position="right"
/>
</ElFormItem>
<ElFormItem class="!mb-0">
<ElButton v-auth="'security:edit'" type="primary" :loading="saving" @click="save">
保存
</ElButton>
</ElFormItem>
</div>
</ElForm>
</ElCard>