chore: 同步主分支本地改动与个人开发工具链
纳入 personal-dev/OpenSpec 配置、管理端与教育 Demo 界面调整、工作人员 JWT 默认 7 天,以及参考资料与代理文档更新。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
e8060287e0
commit
608afb88ea
217 files changed
+15370
-5890
No files matched your search
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
|
||||
Reference in new issue
Block a user