diff --git a/WATCHDOG.yml b/WATCHDOG.yml
new file mode 100644
index 0000000..a641236
--- /dev/null
+++ b/WATCHDOG.yml
@@ -0,0 +1,3 @@
+advisors:
+ - name: default
+ model: deepseek/deepseek-v4-flash:xhigh
diff --git a/apps/admin/src/pages/Classrooms/index.tsx b/apps/admin/src/pages/Classrooms/index.tsx
index 515ebf7..bd8485c 100644
--- a/apps/admin/src/pages/Classrooms/index.tsx
+++ b/apps/admin/src/pages/Classrooms/index.tsx
@@ -226,29 +226,27 @@ const ClassroomsPage: React.FC = () => {
>
添加教室
-
- {
- const formData = new FormData();
- formData.append('file', file);
- try {
- const res: any = await api.post('/classrooms/import', formData, {
- headers: { 'Content-Type': 'multipart/form-data' },
- });
- message.success(res.message);
- onSuccess?.(res);
- fetchData();
- } catch (e: any) {
- message.error(e?.message || '导入失败');
- onError?.(e);
- }
- }}
- >
- }>导入Excel
-
-
+ {
+ const formData = new FormData();
+ formData.append('file', file);
+ try {
+ const res: any = await api.post('/classrooms/import', formData, {
+ headers: { 'Content-Type': 'multipart/form-data' },
+ });
+ message.success(res.message);
+ onSuccess?.(res);
+ fetchData();
+ } catch (e: any) {
+ message.error(e?.message || '导入失败');
+ onError?.(e);
+ }
+ }}
+ >
+ }>导入Excel
+
}
diff --git a/apps/admin/src/pages/Expenses/index.tsx b/apps/admin/src/pages/Expenses/index.tsx
index 849c63f..1bce84b 100644
--- a/apps/admin/src/pages/Expenses/index.tsx
+++ b/apps/admin/src/pages/Expenses/index.tsx
@@ -349,37 +349,35 @@ const ExpensesPage: React.FC = () => {
onChange={(v) => setRoomTypeFilter(v)}
options={expenseTypeOptions}
/>
-
- {
- const formData = new FormData();
- formData.append('file', file);
- try {
- const res: any = await api.post('/expenses/utility/import', formData, {
- headers: { 'Content-Type': 'multipart/form-data' },
+ {
+ const formData = new FormData();
+ formData.append('file', file);
+ try {
+ const res: any = await api.post('/expenses/utility/import', formData, {
+ headers: { 'Content-Type': 'multipart/form-data' },
+ });
+ if (res.errors?.length > 0) {
+ Modal.warning({
+ title: res.message,
+ content: res.errors.join('\n'),
+ width: 500,
});
- if (res.errors?.length > 0) {
- Modal.warning({
- title: res.message,
- content: res.errors.join('\n'),
- width: 500,
- });
- } else {
- message.success(res.message);
- }
- onSuccess?.(res);
- fetchData();
- } catch (e: any) {
- message.error(e?.message || '导入失败');
- onError?.(e);
+ } else {
+ message.success(res.message);
}
- }}
- >
- }>导入水电费Excel
-
-
+ onSuccess?.(res);
+ fetchData();
+ } catch (e: any) {
+ message.error(e?.message || '导入失败');
+ onError?.(e);
+ }
+ }}
+ >
+ }>导入水电费Excel
+
}
@@ -484,29 +482,27 @@ const ExpensesPage: React.FC = () => {
onChange={(v) => setPersonalTypeFilter(v)}
options={personalExpenseTypeOptions}
/>
-
- {
- try {
- const formData = new FormData();
- formData.append('file', file);
- const res: any = await api.post('/expenses/personal/import', formData);
- message.success(res.message || '导入完成');
- if (res.errors?.length)
- res.errors.forEach((e: string) => message.warning(e));
- fetchData();
- onSuccess?.(res);
- } catch (e: any) {
- message.error(e?.message || '导入失败');
- onError?.(e);
- }
- }}
- >
- }>导入个人附加费
-
-
+ {
+ try {
+ const formData = new FormData();
+ formData.append('file', file);
+ const res: any = await api.post('/expenses/personal/import', formData);
+ message.success(res.message || '导入完成');
+ if (res.errors?.length)
+ res.errors.forEach((e: string) => message.warning(e));
+ fetchData();
+ onSuccess?.(res);
+ } catch (e: any) {
+ message.error(e?.message || '导入失败');
+ onError?.(e);
+ }
+ }}
+ >
+ }>导入个人附加费
+
}
diff --git a/apps/admin/src/pages/Occupancies/index.tsx b/apps/admin/src/pages/Occupancies/index.tsx
index 9e9bb42..6bbd2c9 100644
--- a/apps/admin/src/pages/Occupancies/index.tsx
+++ b/apps/admin/src/pages/Occupancies/index.tsx
@@ -287,48 +287,46 @@ const OccupanciesPage: React.FC = () => {
>
入住登记
-
- {
- const formData = new FormData();
- formData.append('file', file);
- const params = new URLSearchParams();
- if (autoDeposit) {
- params.set('autoDeposit', 'true');
- params.set('depositAmount', String(depositAmount));
+ {
+ const formData = new FormData();
+ formData.append('file', file);
+ const params = new URLSearchParams();
+ if (autoDeposit) {
+ params.set('autoDeposit', 'true');
+ params.set('depositAmount', String(depositAmount));
+ }
+ try {
+ const res: any = await api.post(
+ `/occupancies/import?${params.toString()}`,
+ formData,
+ { headers: { 'Content-Type': 'multipart/form-data' } },
+ );
+ if (res.errors?.length > 0) {
+ Modal.warning({
+ title: res.message,
+ content: res.errors.join('\n'),
+ width: 500,
+ });
+ } else {
+ message.success(res.message);
}
- try {
- const res: any = await api.post(
- `/occupancies/import?${params.toString()}`,
- formData,
- { headers: { 'Content-Type': 'multipart/form-data' } },
- );
- if (res.errors?.length > 0) {
- Modal.warning({
- title: res.message,
- content: res.errors.join('\n'),
- width: 500,
- });
- } else {
- message.success(res.message);
- }
- onSuccess?.(res);
- fetchData();
- } catch (e: any) {
- message.error(e?.message || '导入失败');
- onError?.(e);
- }
- }}
- >
-
- }>
- 导入入住名单
-
-
-
-
+ onSuccess?.(res);
+ fetchData();
+ } catch (e: any) {
+ message.error(e?.message || '导入失败');
+ onError?.(e);
+ }
+ }}
+ >
+
+ }>
+ 导入入住名单
+
+
+
}
diff --git a/apps/admin/src/pages/Rooms/index.tsx b/apps/admin/src/pages/Rooms/index.tsx
index 30ba5af..e35a3c0 100644
--- a/apps/admin/src/pages/Rooms/index.tsx
+++ b/apps/admin/src/pages/Rooms/index.tsx
@@ -330,27 +330,25 @@ const RoomsPage: React.FC = () => {
>
添加宿舍
-
- {
- try {
- const res: any = await api.post('/rooms/import', formData, {
- headers: { 'Content-Type': 'multipart/form-data' },
- });
- message.success(res.message);
- onSuccess?.(res);
- fetchData();
- } catch (e: any) {
- message.error(e?.message || '导入失败');
- onError?.(e);
- }
- }}
- >
- }>导入Excel
-
-
+ {
+ try {
+ const res: any = await api.post('/rooms/import', formData, {
+ headers: { 'Content-Type': 'multipart/form-data' },
+ });
+ message.success(res.message);
+ onSuccess?.(res);
+ fetchData();
+ } catch (e: any) {
+ message.error(e?.message || '导入失败');
+ onError?.(e);
+ }
+ }}
+ >
+ }>导入Excel
+
}
diff --git a/apps/admin/src/pages/Students/index.tsx b/apps/admin/src/pages/Students/index.tsx
index f7fb748..8d84422 100644
--- a/apps/admin/src/pages/Students/index.tsx
+++ b/apps/admin/src/pages/Students/index.tsx
@@ -275,29 +275,27 @@ const StudentsPage: React.FC = () => {
>
添加学生
-
- {
- const formData = new FormData();
- formData.append('file', file);
- try {
- const res: any = await api.post('/students/import', formData, {
- headers: { 'Content-Type': 'multipart/form-data' },
- });
- message.success(res.message);
- onSuccess?.(res);
- fetchData();
- } catch (e: any) {
- message.error(e?.message || '导入失败');
- onError?.(e);
- }
- }}
- >
- }>导入Excel
-
-
+ {
+ const formData = new FormData();
+ formData.append('file', file);
+ try {
+ const res: any = await api.post('/students/import', formData, {
+ headers: { 'Content-Type': 'multipart/form-data' },
+ });
+ message.success(res.message);
+ onSuccess?.(res);
+ fetchData();
+ } catch (e: any) {
+ message.error(e?.message || '导入失败');
+ onError?.(e);
+ }
+ }}
+ >
+ }>导入Excel
+
}
diff --git a/package-lock.json b/package-lock.json
index e2542f0..f0d8509 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -54,6 +54,7 @@
"@nestjs/jwt": "^11.0.2",
"@nestjs/passport": "^11.0.5",
"@nestjs/platform-express": "^11.1.19",
+ "@nestjs/schedule": "^6.1.3",
"@nestjs/throttler": "^6.5.0",
"@nestjs/typeorm": "^11.0.1",
"@types/multer": "^2.1.0",
@@ -3086,6 +3087,19 @@
"node": ">= 0.6"
}
},
+ "node_modules/@nestjs/schedule": {
+ "version": "6.1.3",
+ "resolved": "https://registry.npmmirror.com/@nestjs/schedule/-/schedule-6.1.3.tgz",
+ "integrity": "sha512-RflMFOpR16Dwd1jAUbeB4mfGTCh65fvEdL4mSjQPJChpkRGRjIXjb+6YQcK2faQrVT60c9DmLmoVR7/ONCtuYQ==",
+ "license": "MIT",
+ "dependencies": {
+ "cron": "4.4.0"
+ },
+ "peerDependencies": {
+ "@nestjs/common": "^10.0.0 || ^11.0.0",
+ "@nestjs/core": "^10.0.0 || ^11.0.0"
+ }
+ },
"node_modules/@nestjs/schematics": {
"version": "11.1.0",
"resolved": "https://registry.npmmirror.com/@nestjs/schematics/-/schematics-11.1.0.tgz",
@@ -3605,9 +3619,6 @@
"arm64"
],
"dev": true,
- "libc": [
- "glibc"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -3625,9 +3636,6 @@
"arm64"
],
"dev": true,
- "libc": [
- "musl"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -3645,9 +3653,6 @@
"ppc64"
],
"dev": true,
- "libc": [
- "glibc"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -3665,9 +3670,6 @@
"riscv64"
],
"dev": true,
- "libc": [
- "glibc"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -3685,9 +3687,6 @@
"riscv64"
],
"dev": true,
- "libc": [
- "musl"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -3705,9 +3704,6 @@
"s390x"
],
"dev": true,
- "libc": [
- "glibc"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -3725,9 +3721,6 @@
"x64"
],
"dev": true,
- "libc": [
- "glibc"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -3745,9 +3738,6 @@
"x64"
],
"dev": true,
- "libc": [
- "musl"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -3952,9 +3942,6 @@
"arm64"
],
"dev": true,
- "libc": [
- "glibc"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -3972,9 +3959,6 @@
"arm64"
],
"dev": true,
- "libc": [
- "musl"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -3992,9 +3976,6 @@
"ppc64"
],
"dev": true,
- "libc": [
- "glibc"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -4012,9 +3993,6 @@
"riscv64"
],
"dev": true,
- "libc": [
- "glibc"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -4032,9 +4010,6 @@
"riscv64"
],
"dev": true,
- "libc": [
- "musl"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -4052,9 +4027,6 @@
"s390x"
],
"dev": true,
- "libc": [
- "glibc"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -4072,9 +4044,6 @@
"x64"
],
"dev": true,
- "libc": [
- "glibc"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -4092,9 +4061,6 @@
"x64"
],
"dev": true,
- "libc": [
- "musl"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -5010,9 +4976,6 @@
"arm64"
],
"dev": true,
- "libc": [
- "glibc"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -5030,9 +4993,6 @@
"arm64"
],
"dev": true,
- "libc": [
- "musl"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -5050,9 +5010,6 @@
"ppc64"
],
"dev": true,
- "libc": [
- "glibc"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -5070,9 +5027,6 @@
"s390x"
],
"dev": true,
- "libc": [
- "glibc"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -5090,9 +5044,6 @@
"x64"
],
"dev": true,
- "libc": [
- "glibc"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -5110,9 +5061,6 @@
"x64"
],
"dev": true,
- "libc": [
- "musl"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -5622,6 +5570,12 @@
"@types/node": "*"
}
},
+ "node_modules/@types/luxon": {
+ "version": "3.7.2",
+ "resolved": "https://registry.npmmirror.com/@types/luxon/-/luxon-3.7.2.tgz",
+ "integrity": "sha512-gW+Oib+vUtGJBtNC8V9Reww0oIpusw+4m81uncg9REGZAJfqOQHfo/nkabnc7w0QReXyPqjrbWMJk6NuAkiX3Q==",
+ "license": "MIT"
+ },
"node_modules/@types/methods": {
"version": "1.1.4",
"resolved": "https://registry.npmmirror.com/@types/methods/-/methods-1.1.4.tgz",
@@ -6210,9 +6164,6 @@
"arm64"
],
"dev": true,
- "libc": [
- "glibc"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -6227,9 +6178,6 @@
"arm64"
],
"dev": true,
- "libc": [
- "musl"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -6244,9 +6192,6 @@
"loong64"
],
"dev": true,
- "libc": [
- "glibc"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -6261,9 +6206,6 @@
"loong64"
],
"dev": true,
- "libc": [
- "musl"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -6278,9 +6220,6 @@
"ppc64"
],
"dev": true,
- "libc": [
- "glibc"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -6295,9 +6234,6 @@
"riscv64"
],
"dev": true,
- "libc": [
- "glibc"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -6312,9 +6248,6 @@
"riscv64"
],
"dev": true,
- "libc": [
- "musl"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -6329,9 +6262,6 @@
"s390x"
],
"dev": true,
- "libc": [
- "glibc"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -6346,9 +6276,6 @@
"x64"
],
"dev": true,
- "libc": [
- "glibc"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -6363,9 +6290,6 @@
"x64"
],
"dev": true,
- "libc": [
- "musl"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -8205,6 +8129,23 @@
"devOptional": true,
"license": "MIT"
},
+ "node_modules/cron": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmmirror.com/cron/-/cron-4.4.0.tgz",
+ "integrity": "sha512-fkdfq+b+AHI4cKdhZlppHveI/mgz2qpiYxcm+t5E5TsxX7QrLS1VE0+7GENEk9z0EeGPcpSciGv6ez24duWhwQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/luxon": "~3.7.0",
+ "luxon": "~3.7.0"
+ },
+ "engines": {
+ "node": ">=18.x"
+ },
+ "funding": {
+ "type": "ko-fi",
+ "url": "https://ko-fi.com/intcreator"
+ }
+ },
"node_modules/cross-spawn": {
"version": "7.0.6",
"resolved": "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.6.tgz",
@@ -11791,9 +11732,6 @@
"arm64"
],
"dev": true,
- "libc": [
- "glibc"
- ],
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -11815,9 +11753,6 @@
"arm64"
],
"dev": true,
- "libc": [
- "musl"
- ],
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -11839,9 +11774,6 @@
"x64"
],
"dev": true,
- "libc": [
- "glibc"
- ],
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -11863,9 +11795,6 @@
"x64"
],
"dev": true,
- "libc": [
- "musl"
- ],
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -12190,6 +12119,15 @@
"url": "https://github.com/sponsors/wellwelwel"
}
},
+ "node_modules/luxon": {
+ "version": "3.7.2",
+ "resolved": "https://registry.npmmirror.com/luxon/-/luxon-3.7.2.tgz",
+ "integrity": "sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ }
+ },
"node_modules/magic-string": {
"version": "0.30.17",
"resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.17.tgz",