fix: 🧩 移动文件位置

This commit is contained in:
Bunny 2025-02-26 08:05:20 +08:00
parent 51156fb489
commit 4da932a3f5
16 changed files with 121 additions and 216 deletions

View File

@ -1,6 +1,6 @@
{
"name": "financial-admin",
"version": "1.0.0",
"version": "5.8.2",
"private": true,
"type": "module",
"license": "MIT",

View File

@ -52,6 +52,7 @@ export const useUserStore = defineStore({
/** 前端登出 */
async logOut() {
const result = await fetchLogout();
if (result.code == 200) {
this.username = '';
this.roles = [];
@ -64,6 +65,7 @@ export const useUserStore = defineStore({
return true;
}
localStorage.clear();
message(result.message, { type: 'error' });
},

View File

@ -1,6 +1,6 @@
<script lang="tsx" setup>
import { reactive, ref } from 'vue';
import { deviceDetection } from '@pureadmin/utils';
import { debounce, deviceDetection } from '@pureadmin/utils';
import { $t } from '@/plugins/i18n';
import { addDialog } from '@/components/BaseDialog/index';
import { useAdminUserStore } from '@/store/system/adminUser';
@ -47,6 +47,12 @@ const onResetPassword = () => {
},
});
};
/* 发送周邮箱测试*/
const sendWeekTest = debounce(() => billUserStore.sendBillReport('week'), 1000, true);
/* 发送月邮箱测试*/
const sendMouthTest = debounce(() => billUserStore.sendBillReport('mouth'), 1000, true);
</script>
<template>
@ -81,7 +87,7 @@ const onResetPassword = () => {
@click="updateUserReportStatusByWeek(0)"
/>
<el-divider direction="vertical" />
<el-link :underline="false" type="primary" @click="billUserStore.sendBillReport('week')">接受测试</el-link>
<el-link :underline="false" type="primary" @click="sendWeekTest"> 接受测试</el-link>
</li>
<el-divider />
@ -103,7 +109,7 @@ const onResetPassword = () => {
@click="updateUserReportStatusByMouth(1)"
/>
<el-divider direction="vertical" />
<el-link :underline="false" type="primary" @click="billUserStore.sendBillReport('mouth')">接受测试</el-link>
<el-link :underline="false" type="primary" @click="sendMouthTest">接受测试</el-link>
</li>
<el-divider />
</ul>

View File

@ -37,7 +37,34 @@ export const form = ref({
export const onSearch = async () => {
const result = await fetchGetWebConfig();
if (result.code !== 200) return;
form.value = result.data;
const data = result.data;
form.value.version = data.Version;
form.value.title = data.Title;
form.value.copyright = data.Copyright;
form.value.fixedHeader = data.FixedHeader;
form.value.hiddenSideBar = data.HiddenSideBar;
form.value.multiTagsCache = data.MultiTagsCache;
form.value.keepAlive = data.KeepAlive;
form.value.locale = data.Locale;
form.value.layout = data.Layout;
form.value.theme = data.Theme;
form.value.darkMode = data.DarkMode;
form.value.overallStyle = data.OverallStyle;
form.value.grey = data.Grey;
form.value.weak = data.Weak;
form.value.hideTabs = data.HideTabs;
form.value.hideFooter = data.HideFooter;
form.value.stretch = data.Stretch;
form.value.sidebarStatus = data.SidebarStatus;
form.value.epThemeColor = data.EpThemeColor;
form.value.showLogo = data.ShowLogo;
form.value.showModel = data.ShowModel;
form.value.menuArrowIconNoTransition = data.MenuArrowIconNoTransition;
form.value.cachingAsyncRoutes = data.CachingAsyncRoutes;
form.value.tooltipEffect = data.TooltipEffect;
form.value.responsiveStorageNameSpace = data.ResponsiveStorageNameSpace;
form.value.menuSearchHistory = data.MenuSearchHistory;
};
/** 提交表单 */

View File

@ -22,9 +22,9 @@ const timer = ref(null);
const { t } = useI18n();
const ruleForm = reactive({
username: '1319900154@qq.com',
password: 'admin123',
emailCode: '1',
username: '',
password: '',
emailCode: '',
type: currentPage.value,
});
@ -122,7 +122,13 @@ onBeforeUnmount(() => {
<Motion :delay="150">
<el-form-item prop="emailCode">
<el-input v-model="ruleForm.emailCode" :placeholder="t('login.emailCode')" :prefix-icon="useRenderIcon('ic:outline-email')" clearable @keydown.enter="onLogin(ruleFormRef)">
<el-input
v-model="ruleForm.emailCode"
:placeholder="t('login.emailCode')"
:prefix-icon="useRenderIcon('ic:outline-email')"
clearable
@keydown.enter="onLogin(ruleFormRef)"
>
<template v-slot:append>
<el-link v-if="sendSecond === 60" :underline="false" class="px-2" type="primary" @click="onSendEmailCode">
{{ t('login.getEmailCode') }}
@ -134,7 +140,7 @@ onBeforeUnmount(() => {
</template>
</el-input>
<el-checkbox v-model="userStore.isRemembered">
<el-text size="small" type="primary">{{ userStore.readMeDay }}天免登录(邮箱验证码随便输入,后端校验验证码已注释) </el-text>
<el-text size="small" type="primary">{{ userStore.readMeDay }}天免登录</el-text>
</el-checkbox>
</el-form-item>
</Motion>

View File

@ -3,11 +3,12 @@ import type { FormRules } from 'element-plus';
import { $t } from '@/plugins/i18n';
/** 密码正则密码格式应为8-18位数字、字母、符号的任意两种组合 */
export const REGEXP_PWD = /^(?![0-9]+$)(?![a-z]+$)(?![A-Z]+$)(?!([^(0-9a-zA-Z)]|[()])+$)(?!^.*[\u4E00-\u9FA5].*$)([^(0-9a-zA-Z)]|[()]|[a-z]|[A-Z]|[0-9]){8,18}$/;
export const REGEXP_PWD =
/^(?![0-9]+$)(?![a-z]+$)(?![A-Z]+$)(?!([^(0-9a-zA-Z)]|[()])+$)(?!^.*[\u4E00-\u9FA5].*$)([^(0-9a-zA-Z)]|[()]|[a-z]|[A-Z]|[0-9]){8,18}$/;
/** 邮箱登录校验 */
export const emailRules = reactive(<FormRules>{
username: [{ required: true, message: $t('login.usernameRegex'), trigger: 'blur' }],
username: [{ required: true, message: $t('email') + $t('formatError'), trigger: 'blur', type: 'email' }],
password: [
{
validator: (rule, value, callback) => {

View File

@ -1,8 +1,8 @@
<script lang="ts" setup>
import { onMounted, ref } from 'vue';
import { FormInstance, genFileId, UploadProps, UploadRawFile } from 'element-plus';
import { addRules, uploadRules } from '@/views/system/files/utils/columns';
import { FormProps } from '@/views/system/files/utils/types';
import { addRules, uploadRules } from '@/views/monitor/files/utils/columns';
import { FormProps } from '@/views/monitor/files/utils/types';
import { $t } from '@/plugins/i18n';
import { useFilesStore } from '@/store/monitor/files';
import { UploadFilled } from '@element-plus/icons-vue';
@ -77,7 +77,16 @@ defineExpose({ formRef });
<!-- 文件列表---上传不显示 -->
<el-form-item :label="$t('files')" prop="files">
<el-upload v-if="form.isUpload" ref="upload" v-model:file-list="form.files" :auto-upload="false" :limit="1" :on-exceed="handleExceed" class="w-full" drag>
<el-upload
v-if="form.isUpload"
ref="upload"
v-model:file-list="form.files"
:auto-upload="false"
:limit="1"
:on-exceed="handleExceed"
class="w-full"
drag
>
<el-icon class="el-icon--upload">
<UploadFilled />
</el-icon>

View File

@ -1,10 +1,10 @@
<script lang="ts" setup>
import { onMounted, ref } from 'vue';
import { columns } from '@/views/system/files/utils/columns';
import { columns } from '@/views/monitor/files/utils/columns';
import PureTableBar from '@/components/TableBar/src/bar';
import AddFill from '@iconify-icons/ri/add-circle-line';
import PureTable from '@pureadmin/table';
import { onAdd, onDelete, onDeleteBatch, onDownload, onDownloadBatch, onSearch, onUpdate, selectRows } from '@/views/system/files/utils/hooks';
import { onAdd, onDelete, onDeleteBatch, onDownload, onDownloadBatch, onSearch, onUpdate, selectRows } from '@/views/monitor/files/utils/hooks';
import Delete from '@iconify-icons/ep/delete';
import Download from '@iconify-icons/ep/download';
import EditPen from '@iconify-icons/ep/edit-pen';
@ -14,7 +14,7 @@ import { $t } from '@/plugins/i18n';
import { useFilesStore } from '@/store/monitor/files';
import { useRenderIcon } from '@/components/CommonIcon/src/hooks';
import { FormInstance } from 'element-plus';
import { auth } from '@/views/system/files/utils/auth';
import { auth } from '@/views/monitor/files/utils/auth';
import { hasAuth } from '@/router/utils';
const tableRef = ref();
@ -64,10 +64,19 @@ onMounted(() => {
<el-input v-model="filesStore.form.fileType" :placeholder="`${$t('input')}${$t('files_fileType')}`" class="!w-[180px]" clearable />
</el-form-item>
<el-form-item :label="$t('files_downloadCount')" prop="downloadCount">
<el-input v-model="filesStore.form.downloadCount" :placeholder="`${$t('input')}${$t('files_downloadCount')}`" class="!w-[180px]" clearable min="0" type="number" />
<el-input
v-model="filesStore.form.downloadCount"
:placeholder="`${$t('input')}${$t('files_downloadCount')}`"
class="!w-[180px]"
clearable
min="0"
type="number"
/>
</el-form-item>
<el-form-item>
<el-button :icon="useRenderIcon('ri:search-line')" :loading="filesStore.loading" type="primary" @click="onSearch"> {{ $t('search') }} </el-button>
<el-button :icon="useRenderIcon('ri:search-line')" :loading="filesStore.loading" type="primary" @click="onSearch">
{{ $t('search') }}
</el-button>
<el-button :icon="useRenderIcon(Refresh)" @click="resetForm(formRef)"> {{ $t('buttons.reset') }}</el-button>
</el-form-item>
</el-form>
@ -80,7 +89,13 @@ onMounted(() => {
</el-button>
<!-- 批量下载 -->
<el-button v-if="hasAuth(auth.downloadFilesByFileId)" :disabled="!(selectRows.length > 0)" :icon="useRenderIcon(Download)" type="success" @click="onDownloadBatch">
<el-button
v-if="hasAuth(auth.downloadFilesByFileId)"
:disabled="!(selectRows.length > 0)"
:icon="useRenderIcon(Download)"
type="success"
@click="onDownloadBatch"
>
{{ $t('download_batch') }}
</el-button>
@ -124,8 +139,26 @@ onMounted(() => {
</template>
<template #operation="{ row }">
<el-button v-if="hasAuth(auth.update)" :icon="useRenderIcon(EditPen)" :size="size" class="reset-margin" link type="primary" @click="onUpdate(row)"> {{ $t('modify') }} </el-button>
<el-button v-if="hasAuth(auth.downloadFilesByFileId)" :icon="useRenderIcon(EditPen)" :size="size" class="reset-margin" link type="primary" @click="onDownload(row)">
<el-button
v-if="hasAuth(auth.update)"
:icon="useRenderIcon(EditPen)"
:size="size"
class="reset-margin"
link
type="primary"
@click="onUpdate(row)"
>
{{ $t('modify') }}
</el-button>
<el-button
v-if="hasAuth(auth.downloadFilesByFileId)"
:icon="useRenderIcon(EditPen)"
:size="size"
class="reset-margin"
link
type="primary"
@click="onDownload(row)"
>
{{ $t('download') }}
</el-button>
<el-popconfirm v-if="hasAuth(auth.deleted)" :title="`${$t('delete')} ${row.filename}?`" @confirm="onDelete(row)">

View File

@ -1,9 +1,9 @@
import { addDialog } from '@/components/BaseDialog/index';
import FilesDialog from '@/views/system/files/files-dialog.vue';
import FilesDialog from '@/views/monitor/files/files-dialog.vue';
import { useFilesStore } from '@/store/monitor/files';
import { h, ref } from 'vue';
import { message, messageBox } from '@/utils/message';
import type { FormItemProps } from '@/views/system/files/utils/types';
import type { FormItemProps } from '@/views/monitor/files/utils/types';
import { $t } from '@/plugins/i18n';
import { downloadFilesByFileId } from '@/api/v1/files';
import { download } from '@/utils/sso';

View File

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" class="empty-icon" viewBox="0 0 1024 1024"><path d="M855.6 427.2H168.5c-12.7 0-24.4 6.9-30.6 18L4.4 684.7C1.5 689.9 0 695.8 0 701.8v287.1c0 19.4 15.7 35.1 35.1 35.1H989c19.4 0 35.1-15.7 35.1-35.1V701.8c0-6-1.5-11.8-4.4-17.1L886.2 445.2c-6.2-11.1-17.9-18-30.6-18M673.4 695.6c-16.5 0-30.8 11.5-34.3 27.7-12.7 58.5-64.8 102.3-127.2 102.3s-114.5-43.8-127.2-102.3c-3.5-16.1-17.8-27.7-34.3-27.7H119c-26.4 0-43.3-28-31.1-51.4l81.7-155.8c6.1-11.6 18-18.8 31.1-18.8h622.4c13 0 25 7.2 31.1 18.8l81.7 155.8c12.2 23.4-4.7 51.4-31.1 51.4zm146.5-486.1c-1-1.8-2.1-3.7-3.2-5.5-9.8-16.6-31.1-22.2-47.8-12.6L648.5 261c-17 9.8-22.7 31.6-12.6 48.4.9 1.4 1.7 2.9 2.5 4.4 9.5 17 31.2 22.8 48 13L807 257.3c16.7-9.7 22.4-31 12.9-47.8m-444.5 51.6L255 191.6c-16.7-9.6-38-4-47.8 12.6-1.1 1.8-2.1 3.6-3.2 5.5-9.5 16.8-3.8 38.1 12.9 47.8L337.3 327c16.9 9.7 38.6 4 48-13.1.8-1.5 1.7-2.9 2.5-4.4 10.2-16.8 4.5-38.6-12.4-48.4M512 239.3h2.5c19.5.3 35.5-15.5 35.5-35.1v-139c0-19.3-15.6-34.9-34.8-35.1h-6.4C489.6 30.3 474 46 474 65.2v139c0 19.5 15.9 35.4 35.5 35.1z"/></svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -1,180 +0,0 @@
<script lang="tsx" setup>
import { useRenderIcon } from '@/components/CommonIcon/src/hooks';
import PureTable from '@pureadmin/table';
import { $t } from '@/plugins/i18n';
import { ElTag, ElText } from 'element-plus';
import { onMounted, reactive, ref, watch } from 'vue';
import { fetchGetUserBillList } from '@/api/v1/financial/user/billUser';
import Empty from './empty.svg?component';
import dayjs from 'dayjs';
const props = defineProps({
financialType: { type: Number as PropType<any>, default: undefined },
startDate: { type: String as PropType<any>, default: undefined },
endDate: { type: String as PropType<any>, default: undefined },
});
const columns: TableColumnList = [
{ type: 'index', index: (index: number) => index + 1, label: '序号', width: 60 },
//
{
label: $t('amount'),
prop: 'amount',
sortable: true,
width: 200,
formatter({ type, amount }) {
return type === -1 ? (
<ElText size={'large'} type={'danger'} style={{ fontWeight: 800 }}>
- {amount}
</ElText>
) : (
<ElText size={'large'} type={'success'} style={{ fontWeight: 800 }}>
+ {amount}
</ElText>
);
},
filterMultiple: false,
filterClassName: 'pure-table-filter',
filters: [
{ text: '≥1000', value: 'more' },
{ text: '<1000', value: 'less' },
],
filterMethod: (value, { amount }) => {
return value === 'more' ? amount >= 1000 : amount < 1000;
},
},
//
{
label: $t('categoryName'),
prop: 'categoryName',
width: 150,
formatter({ categoryName }) {
return <ElTag effect={'plain'}>{categoryName}</ElTag>;
},
},
//
{ label: $t('description'), prop: 'description' },
//
{
label: $t('transactionDate'),
prop: 'transactionDate',
width: 190,
sortable: true,
formatter({ transactionDate }) {
return (
<ElText type={'success'} style={{ fontWeight: 800 }}>
{transactionDate}
</ElText>
);
},
},
];
const form = reactive({
// 1 - -1 -
type: props.financialType,
//
startDate: props.startDate,
//
endDate: props.endDate,
pagination: {
pageSize: 15,
currentPage: 1,
layout: 'prev, pager, next',
total: 1,
align: 'center',
hideOnSinglePage: true,
},
});
const dataList = ref([]);
const loading = ref(false);
/* 初始化数据 */
async function onSearch() {
loading.value = true;
form.startDate = dayjs(form.startDate).format('YYYY-MM-DD');
form.endDate = dayjs(form.endDate).format('YYYY-MM-DD');
const result = await fetchGetUserBillList({ ...form, ...form.pagination });
dataList.value = result.data?.list;
form.pagination.currentPage = result.data.pageNo;
form.pagination.pageSize = result.data.pageSize;
form.pagination.total = result.data.total;
loading.value = false;
}
/* 修改分页 */
async function onCurrentChange(page: number) {
form.pagination.currentPage = page;
await onSearch();
}
onMounted(() => {
watch(
() => props,
async () => {
form.startDate = props.startDate;
form.endDate = props.endDate;
await onSearch();
},
{ immediate: true, deep: true },
);
});
</script>
<template>
<pure-table
:columns="columns"
:data="dataList"
:loading="loading"
:loading-config="{ background: 'transparent' }"
:pagination="form.pagination"
alignWhole="center"
row-key="id"
showOverflowTooltip
@page-current-change="onCurrentChange"
>
<template #empty>
<el-empty :image-size="60" description="暂无数据" style="height: 430px">
<template #image>
<Empty />
</template>
</el-empty>
</template>
<template #operation="{ row }">
<el-button :icon="useRenderIcon('ri:search-line')" :title="`查看序号为${row.id}的详情`" circle plain size="small" />
</template>
</pure-table>
</template>
<style lang="scss">
.pure-table-filter {
.el-table-filter__list {
min-width: 80px;
padding: 0;
li {
line-height: 28px;
}
}
}
</style>
<style lang="scss" scoped>
:deep(.el-table) {
--el-table-border: none;
--el-table-border-color: transparent;
.el-empty__description {
margin: 0;
}
.el-scrollbar__bar {
display: none;
}
}
</style>

View File

@ -2,7 +2,6 @@
import { markRaw, onMounted } from 'vue';
import ReCol from '@/components/MyCol';
import { randomGradient, useDark } from '@pureadmin/utils';
import WelcomeTable from './components/home-table.vue';
import { ReNormalCountTo } from '@/components/CountTo';
import { useRenderFlicker } from '@/components/Flicker';
import ChartBar from '@/views/welcome/components/chart-bar.vue';
@ -10,11 +9,12 @@ import ChartLine from '@/views/welcome/components/chart-line.vue';
import { chartData, expendData, expendPercent, form, homeRanks, incomeData, onSearch, xAxis } from '@/views/welcome/utils/hooks';
import ChartRound from '@/views/welcome/components/chart-round.vue';
import { $t } from '@/plugins/i18n';
import { currentMouth, currentYear, shortcutsAllMouth } from '@/enums/dateEnums';
import { currentMouth, currentWeek, currentYear, shortcutsAllMouth } from '@/enums/dateEnums';
const { isDark } = useDark();
//
const shortcuts = [
{ text: $t('thisWeek'), value: currentWeek() },
{ text: $t('thisMonth'), value: currentMouth },
{
text: $t('thisYear'),
@ -31,6 +31,7 @@ onMounted(() => {
<template>
<div>
<el-row :gutter="24" justify="space-around">
<!-- 包含总支出总收入盈利金额-->
<re-col
v-for="(item, index) in chartData"
:key="index"
@ -92,6 +93,7 @@ onMounted(() => {
</el-card>
</re-col>
<!-- 双轴图数据 -->
<re-col
v-motion
:enter="{ opacity: 1, y: 0, transition: { delay: 400 } }"
@ -158,12 +160,12 @@ onMounted(() => {
:xs="24"
class="mb-[18px]"
>
<el-card class="h-[100%]" shadow="never">
<div class="flex justify-between">
<span class="text-md font-medium">{{ $t('dataStatistics') }}</span>
</div>
<WelcomeTable :end-date="form.endDate" :start-date="form.startDate" class="mt-3" />
</el-card>
<!--<el-card class="h-[100%]" shadow="never">-->
<!-- <div class="flex justify-between">-->
<!-- <span class="text-md font-medium">{{ $t('dataStatistics') }}</span>-->
<!-- </div>-->
<!-- <WelcomeTable :end-date="form.endDate" :start-date="form.startDate" class="mt-3" />-->
<!--</el-card>-->
</re-col>
</el-row>
</div>

View File

@ -75,7 +75,7 @@ function homeCardFun(income, expend) {
bgColor: '#effaff',
color: '#67C23A',
duration: 2200,
name: $t('totalIncomeOfTheMonth'),
name: $t('totalIncome'),
value: income,
percent: <p class='font-medium text-green-500'>{`+ ${income}`}</p>,
data: incomeData.value,
@ -88,7 +88,7 @@ function homeCardFun(income, expend) {
bgColor: '#fff5f4',
color: '#F56C6C',
duration: 2200,
name: $t('totalExpendituresOfTheMonth'),
name: $t('totalExpend'),
value: expend,
percent: <p class='font-medium text-red-500'>{`- ${expend}`}</p>,
data: expendData.value,