feat: 升级stylelint依赖并修复相关问题

- 更新stylelint到16.x版本
- 修复postcss版本冲突
- 解决循环依赖问题
- 优化代码类型定义
This commit is contained in:
2025-06-24 19:46:34 +08:00
parent d1c2d332ab
commit 4d66f8baa7
30 changed files with 2190 additions and 2424 deletions
+123 -79
View File
@@ -1,71 +1,119 @@
<template>
<div class="business_project_wrap">
<Breadcrumb :items="['menu.business', 'menu.business.project']" />
<a-card class="general-card">
<template #title>
<div class="card-title_between">
<p class="title">{{ $t('menu.business.project') }}</p>
<div class="flex_center_between">
<a-space>
<a-input-search :style="{ width: '320px' }" :placeholder="$t('search.placeholder')" />
<a-button>
<template #icon>
<icon-filter />
</template>
{{ $t('table.filter') }}
</a-button>
<a-button>
<template #icon>
<icon-download />
</template>
{{ $t('table.export') }}
</a-button>
<a-button type="primary">
<template #icon>
<icon-plus />
</template>
{{ $t('add-project') }}
</a-button>
</a-space>
</div>
</div>
</template>
<a-table row-key="id" :loading="loading" :pagination="pagination" :columns="projectColumn"
:data="renderData" :bordered="false" @page-change="onPageChange">
<template #type="{ record }">
<a-tag checkable :color="getTypeColor(record.type)">{{ getTypeText(record.type) }}</a-tag>
<div class="business_project_wrap">
<Breadcrumb :items="['menu.business', 'menu.business.project']" />
<a-card class="general-card">
<template #title>
<div class="card-title_between">
<p class="title">{{ $t('menu.business.project') }}</p>
<div class="flex_center_between">
<a-space>
<a-input-search
:style="{ width: '320px' }"
:placeholder="$t('search.placeholder')"
/>
<a-button>
<template #icon>
<icon-filter />
</template>
<template #rate="{ record }">
<a-progress :percent="record.rate" color="green" :style="{ width: '100px' }" />
{{ $t('table.filter') }}
</a-button>
<a-button>
<template #icon>
<icon-download />
</template>
<template #operate>
<a-space>
<a-button>查看</a-button>
<a-button type="primary">编辑</a-button>
<a-button>更多</a-button>
</a-space>
{{ $t('table.export') }}
</a-button>
<a-button type="primary">
<template #icon>
<icon-plus />
</template>
</a-table>
</a-card>
</div>
{{ $t('add-project') }}
</a-button>
</a-space>
</div>
</div>
</template>
<a-table
row-key="id"
:loading="loading"
:pagination="pagination"
:columns="projectColumn"
:data="renderData"
:bordered="false"
@page-change="onPageChange"
>
<template #type="{ record }">
<a-tag checkable :color="getTypeColor(record.type)">{{
getTypeText(record.type)
}}</a-tag>
</template>
<template #rate="{ record }">
<a-progress
:percent="record.rate"
color="green"
:style="{ width: '100px' }"
/>
</template>
<template #operate>
<a-space>
<a-button>查看</a-button>
<a-button type="primary">编辑</a-button>
<a-button>更多</a-button>
</a-space>
</template>
</a-table>
</a-card>
</div>
</template>
<script lang="ts" setup>
import { computed, ref, reactive, watch, nextTick } from 'vue';
import useLoading from '@/hooks/loading';
import { Pagination } from '@/types/global';
const { loading, setLoading } = useLoading(false);
const renderData = ref<any[]>([
{ name: '星河商务中心', type: '1', size: '1200m²', kezu: '1000m²', rate: 0.2, count: '90', create_time: '2025-06-24 00:51' },
{ name: '南山科学科学院', type: '2', size: '120m²', kezu: '100m²', rate: 0.6, count: '10', create_time: '2025-06-24 00:58' },
{ name: '前海科学科学院', type: '3', size: '1520m²', kezu: '1500m²', rate: 0.91, count: '120', create_time: '2025-06-24 01:16' },
]);
const basePagination: Pagination = {
<script lang="ts" setup>
import { computed, ref, reactive, watch, nextTick } from 'vue';
import useLoading from '@/hooks/loading';
import { Pagination } from '@/types/global';
import {
ProjectRecord,
ProjectType,
PROJECT_TYPE,
PROJECT_TYPE_COLORS,
PROJECT_TYPE_LABELS,
} from '@/types/business';
const { loading, setLoading } = useLoading(false);
const renderData = ref<ProjectRecord[]>([
{
name: '星河商务中心',
type: PROJECT_TYPE.COMMERCIAL_COMPLEX,
size: '1200m²',
kezu: '1000m²',
rate: 0.2,
count: '90',
create_time: '2025-06-24 00:51',
},
{
name: '南山科学科学院',
type: PROJECT_TYPE.OFFICE_BUILDING,
size: '120m²',
kezu: '100m²',
rate: 0.6,
count: '10',
create_time: '2025-06-24 00:58',
},
{
name: '前海科学科学院',
type: PROJECT_TYPE.INDUSTRIAL_PARK,
size: '1520m²',
kezu: '1500m²',
rate: 0.91,
count: '120',
create_time: '2025-06-24 01:16',
},
]);
const basePagination: Pagination = {
current: 1,
pageSize: 20,
total:3,
};
const projectColumn = [
total: 3,
};
const projectColumn = [
{ title: '项目信息', dataIndex: 'name' },
{ title: '项目类型', dataIndex: 'type', slotName: 'type' },
{ title: '管理面积', dataIndex: 'size' },
@@ -74,24 +122,20 @@ const projectColumn = [
{ title: '房源数量', dataIndex: 'count' },
{ title: '创建时间', dataIndex: 'create_time' },
{ title: '操作', dataIndex: 'operate', slotName: 'operate' },
];
const pagination = reactive({
];
const pagination = reactive({
...basePagination,
});
});
const getTypeColor = (type: number | string) => {
const projectMap: any = {
1: 'orangered', 2: 'green', 3: 'gold'
}
return projectMap[type]
}
const getTypeText = (type: number | string) => {
const projectMap: any = {
1: '商业综合体', 2: '写字楼', 3: '园区'
}
return projectMap[type]
}
const onPageChange = (current: number) => {
console.log(current, 'current');
};
</script>
const getTypeColor = (type: ProjectType): string => {
return PROJECT_TYPE_COLORS[type] || 'default';
};
const getTypeText = (type: ProjectType): string => {
return PROJECT_TYPE_LABELS[type] || '未知';
};
const onPageChange = (current: number) => {
pagination.current = current;
// TODO: 这里应该调用API获取对应页码的数据
};
</script>
+191 -40
View File
@@ -1,8 +1,9 @@
<template>
<div class="login-form-wrapper">
<div class="login-form-title">{{ $t('login.form.title') }}</div>
<div class="login-form-sub-title">{{ $t('login.form.slogan') }}</div>
<div class="login-form-error-msg">{{ errorMessage }}</div>
<div v-if="errorMessage" class="login-form-error-msg">
<icon-exclamation-circle-fill />
{{ errorMessage }}
</div>
<a-form
ref="loginForm"
:model="userInfo"
@@ -15,51 +16,86 @@
:rules="[{ required: true, message: $t('login.form.userName.errMsg') }]"
:validate-trigger="['change', 'blur']"
hide-label
class="form-item"
>
<a-input
v-model="userInfo.username"
:placeholder="$t('login.form.userName.placeholder')"
class="input-field"
size="large"
>
<template #prefix>
<icon-user />
<icon-user class="input-icon" />
</template>
</a-input>
</a-form-item>
<a-form-item
field="password"
:rules="[{ required: true, message: $t('login.form.password.errMsg') }]"
:validate-trigger="['change', 'blur']"
hide-label
class="form-item"
>
<a-input-password
v-model="userInfo.password"
:placeholder="$t('login.form.password.placeholder')"
allow-clear
class="input-field"
size="large"
>
<template #prefix>
<icon-lock />
<icon-lock class="input-icon" />
</template>
</a-input-password>
</a-form-item>
<a-space :size="16" direction="vertical">
<div class="login-form-password-actions">
<div class="form-actions">
<div class="form-options">
<a-checkbox
checked="rememberPassword"
:model-value="loginConfig.rememberPassword"
v-model="loginConfig.rememberPassword"
class="remember-checkbox"
@change="setRememberPassword as any"
>
{{ $t('login.form.rememberPassword') }}
</a-checkbox>
<a-link>{{ $t('login.form.forgetPassword') }}</a-link>
<a-link class="forgot-link">{{
$t('login.form.forgetPassword')
}}</a-link>
</div>
<a-button type="primary" html-type="submit" long :loading="loading">
<a-button
type="primary"
html-type="submit"
long
size="large"
:loading="loading"
class="login-button"
>
{{ $t('login.form.login') }}
</a-button>
<!-- <a-button type="text" long class="login-form-register-btn">
{{ $t('login.form.register') }}
</a-button> -->
</a-space>
</div>
</a-form>
<!-- 分隔线和其他登录方式 -->
<div class="divider">
<span class="divider-text">或者</span>
</div>
<div class="alternative-login">
<a-button class="alt-login-btn" size="large">
<template #icon>
<svg width="20" height="20" viewBox="0 0 24 24" fill="none">
<rect width="24" height="24" rx="4" fill="#1AAD19" />
<path
d="M8.5 7.5c-.8 0-1.5.7-1.5 1.5s.7 1.5 1.5 1.5 1.5-.7 1.5-1.5-.7-1.5-1.5-1.5zm7 0c-.8 0-1.5.7-1.5 1.5s.7 1.5 1.5 1.5 1.5-.7 1.5-1.5-.7-1.5-1.5-1.5zm-3.5 6c-1.4 0-2.6.9-3 2.2h6c-.4-1.3-1.6-2.2-3-2.2z"
fill="white"
/>
</svg>
</template>
使用微信登录
</a-button>
</div>
</div>
</template>
@@ -82,8 +118,8 @@
const loginConfig = useStorage('login-config', {
rememberPassword: true,
username: 'admin', // 演示默认值
password: 'admin', // demo default value
username: '13666666666', // 演示默认值
password: '13666666666', // demo default value
});
const userInfo = reactive({
username: loginConfig.value.username,
@@ -129,39 +165,154 @@
</script>
<style lang="less" scoped>
.login-form-wrapper {
width: 100%;
max-width: 380px;
}
.login-form-error-msg {
display: flex;
align-items: center;
gap: 8px;
padding: 12px 16px;
margin-bottom: 20px;
background-color: var(--color-danger-light-1);
border: 1px solid var(--color-danger-light-3);
border-radius: 6px;
color: var(--color-danger-6);
font-size: 14px;
line-height: 1.4;
}
.login-form {
&-wrapper {
width: 320px;
.form-item {
margin-bottom: 20px;
}
&-title {
color: var(--color-text-1);
font-weight: 500;
font-size: 24px;
line-height: 32px;
text-align: center;
}
.input-field {
:deep(.arco-input-wrapper) {
border-radius: 6px;
transition: all 0.2s ease;
&-sub-title {
color: var(--color-text-3);
font-size: 16px;
line-height: 24px;
text-align: center;
}
&:hover {
border-color: var(--color-primary-light-4);
}
&-error-msg {
height: 32px;
color: rgb(var(--red-6));
line-height: 32px;
}
&.arco-input-focus {
border-color: var(--color-primary-6);
box-shadow: 0 0 0 2px var(--color-primary-light-1);
}
}
&-password-actions {
.input-icon {
color: var(--color-text-3);
font-size: 16px;
}
}
}
.form-actions {
.form-options {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 24px;
.remember-checkbox {
:deep(.arco-checkbox-label) {
color: var(--color-text-2);
font-size: 14px;
}
}
.forgot-link {
font-size: 14px;
text-decoration: none;
&:hover {
text-decoration: underline;
}
}
}
&-register-btn {
color: var(--color-text-3) !important;
.login-button {
height: 44px;
border-radius: 6px;
font-size: 16px;
font-weight: 500;
transition: all 0.2s ease;
&:hover:not(:disabled) {
transform: translateY(-1px);
box-shadow: 0 4px 12px var(--color-primary-light-1);
}
}
}
.divider {
position: relative;
margin: 24px 0;
text-align: center;
&::before {
content: '';
position: absolute;
top: 50%;
left: 0;
right: 0;
height: 1px;
background-color: var(--color-border-2);
}
.divider-text {
display: inline-block;
padding: 0 16px;
background-color: var(--color-bg-1);
color: var(--color-text-3);
font-size: 14px;
}
}
.alternative-login {
.alt-login-btn {
width: 100%;
height: 44px;
border-radius: 6px;
font-size: 14px;
font-weight: 500;
border: 1px solid var(--color-border-2);
background-color: var(--color-bg-1);
color: var(--color-text-1);
transition: all 0.2s ease;
&:hover {
border-color: var(--color-border-3);
background-color: var(--color-bg-2);
transform: translateY(-1px);
box-shadow: 0 2px 8px var(--color-bg-3);
}
:deep(.arco-btn-icon) {
margin-right: 8px;
}
}
}
// 响应式适配
@media (max-width: 480px) {
.form-actions {
.form-options {
margin-bottom: 20px;
}
.login-button {
height: 40px;
font-size: 15px;
}
}
.alternative-login .alt-login-btn {
height: 40px;
font-size: 13px;
}
}
</style>
+171 -58
View File
@@ -1,84 +1,197 @@
<template>
<div class="container">
<!-- <div class="logo">
<img
alt="logo"
src="//p3-armor.byteimg.com/tos-cn-i-49unhts6dw/dfdba5317c0c20ce20e64fac803d52bc.svg~tplv-49unhts6dw-image.image"
/>
<div class="logo-text">Arco Design Pro</div>
</div> -->
<!-- <LoginBanner /> -->
<div class="content">
<div class="content-inner">
<div class="login-container">
<!-- 背景装饰 -->
<div class="bg-pattern"></div>
<!-- 主要内容区域 -->
<div class="content-wrapper">
<!-- Logo 区域 -->
<div class="logo-section">
<div class="logo-icon">
<svg
width="48"
height="48"
viewBox="0 0 48 48"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<rect
width="48"
height="48"
rx="12"
fill="var(--color-primary-6)"
/>
<path
d="M14 24L22 32L34 20"
stroke="white"
stroke-width="3"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</div>
<h1 class="logo-title">租赁管理系统</h1>
<p class="logo-subtitle">简单高效的房屋租赁管理平台</p>
</div>
<!-- 登录表单卡片 -->
<div class="login-card">
<LoginForm />
</div>
<div class="footer">
<Footer />
</div>
</div>
<!-- 页脚 -->
<div class="footer-wrapper">
<Footer />
</div>
</div>
</template>
<script lang="ts" setup>
import { useI18n } from 'vue-i18n';
import Footer from '@/components/footer/index.vue';
// import LoginBanner from './components/banner.vue';
import LoginForm from './components/login-form.vue';
const { t } = useI18n();
</script>
<style lang="less" scoped>
.container {
.login-container {
position: relative;
display: flex;
height: 100vh;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
.banner {
width: 550px;
background: linear-gradient(163.85deg, #1d2129 0%, #00308f 100%);
}
.content {
position: relative;
display: flex;
flex: 1;
flex-direction: column;
align-items: center;
justify-content: center;
.content-inner{
background-color: #fff;
padding: 60px 40px;
border-radius: 10px;
}
}
.footer {
position: absolute;
right: 0;
bottom: 0;
width: 100%;
}
min-height: 100vh;
padding: 20px;
background-color: var(--color-bg-2);
overflow: hidden;
}
.logo {
position: fixed;
top: 24px;
left: 22px;
z-index: 1;
display: inline-flex;
// 简化的背景装饰
.bg-pattern {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image: radial-gradient(
circle at 20% 80%,
var(--color-primary-light-1) 0%,
transparent 50%
),
radial-gradient(
circle at 80% 20%,
var(--color-primary-light-2) 0%,
transparent 50%
);
opacity: 0.6;
pointer-events: none;
}
// 主要内容区域
.content-wrapper {
position: relative;
z-index: 2;
display: flex;
flex-direction: column;
align-items: center;
max-width: 420px;
width: 100%;
}
&-text {
margin-right: 4px;
margin-left: 4px;
color: var(--color-fill-1);
font-size: 20px;
// Logo 区域
.logo-section {
text-align: center;
margin-bottom: 32px;
.logo-icon {
margin-bottom: 16px;
filter: drop-shadow(0 2px 8px var(--color-primary-light-2));
}
.logo-title {
margin: 0 0 8px 0;
color: var(--color-text-1);
font-size: 28px;
font-weight: 600;
letter-spacing: -0.5px;
}
.logo-subtitle {
margin: 0;
color: var(--color-text-3);
font-size: 16px;
font-weight: 400;
line-height: 1.5;
}
}
</style>
<style lang="less" scoped>
// responsive
@media (max-width: @screen-lg) {
.container {
.banner {
width: 25%;
// 登录卡片
.login-card {
width: 100%;
background: var(--color-bg-1);
border-radius: 12px;
padding: 32px;
box-shadow: var(--shadow-2);
border: 1px solid var(--color-border-1);
transition: all 0.2s ease;
&:hover {
box-shadow: var(--shadow-3);
}
}
// 页脚
.footer-wrapper {
position: absolute;
bottom: 16px;
left: 50%;
transform: translateX(-50%);
z-index: 2;
:deep(.footer) {
background: transparent;
color: var(--color-text-4);
}
}
// 响应式设计
@media (max-width: 768px) {
.login-container {
padding: 16px;
}
.logo-section {
margin-bottom: 24px;
.logo-title {
font-size: 24px;
}
.logo-subtitle {
font-size: 14px;
}
}
.login-card {
padding: 24px;
border-radius: 8px;
}
}
@media (max-width: 480px) {
.content-wrapper {
max-width: 100%;
}
.login-card {
padding: 20px;
}
.logo-section {
.logo-title {
font-size: 22px;
}
}
}