moyan-mfw-cli 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -181,7 +181,10 @@ Use --force to overwrite.`));
181
181
  process.exit(1);
182
182
  }
183
183
  }
184
- const answers = opts.yes ? defaultExtensionAnswers(name, className) : await import_inquirer.default.prompt([
184
+ if (!process.stdin.isTTY && !opts.yes) {
185
+ console.log(import_chalk.default.yellow("\u26A0 \u975E\u4EA4\u4E92\u5F0F\u7EC8\u7AEF\uFF0C\u5C06\u4F7F\u7528\u9ED8\u8BA4\u503C\u521B\u5EFA\uFF08\u4F7F\u7528 -y \u53EF\u8DF3\u8FC7\u6B64\u63D0\u793A\uFF09"));
186
+ }
187
+ const answers = opts.yes || !process.stdin.isTTY ? defaultExtensionAnswers(name, className) : await import_inquirer.default.prompt([
185
188
  { name: "displayName", message: "\u663E\u793A\u540D\u79F0:", default: className },
186
189
  { name: "description", message: "\u63CF\u8FF0:", default: "" },
187
190
  { name: "routePrefix", message: "\u8DEF\u7531\u524D\u7F00:", default: `/ext/${name}` },
@@ -259,7 +262,10 @@ Use --force to overwrite.`));
259
262
  process.exit(1);
260
263
  }
261
264
  }
262
- const answers = opts.yes ? defaultBusinessAnswers(className) : await import_inquirer2.default.prompt([
265
+ if (!process.stdin.isTTY && !opts.yes) {
266
+ console.log(import_chalk2.default.yellow("\u26A0 \u975E\u4EA4\u4E92\u5F0F\u7EC8\u7AEF\uFF0C\u5C06\u4F7F\u7528\u9ED8\u8BA4\u503C\u521B\u5EFA\uFF08\u4F7F\u7528 -y \u53EF\u8DF3\u8FC7\u6B64\u63D0\u793A\uFF09"));
267
+ }
268
+ const answers = opts.yes || !process.stdin.isTTY ? defaultBusinessAnswers(className) : await import_inquirer2.default.prompt([
263
269
  {
264
270
  name: "displayName",
265
271
  message: "\u663E\u793A\u540D\u79F0:",
@@ -318,11 +324,13 @@ Use --force to overwrite.`));
318
324
  ${import_chalk2.default.bold("\u{1F4CB} \u540E\u7EED\u6B65\u9AA4:")}`);
319
325
  console.log(` 1. cd ${path4.relative(process.cwd(), targetDir)}`);
320
326
  console.log(` 2. \u7F16\u8F91 backend/.env \u914D\u7F6E\u6570\u636E\u5E93\u8FDE\u63A5`);
321
- console.log(` 3. pnpm install && pnpm build`);
322
- console.log(` 4. pnpm --filter ${name}-backend dev # \u542F\u52A8\u540E\u7AEF`);
323
- console.log(` 5. pnpm --filter ${name}-frontend dev # \u542F\u52A8\u524D\u7AEF`);
327
+ console.log(` 3. \u5728 MySQL \u4E2D\u521B\u5EFA\u6570\u636E\u5E93\uFF08\u9ED8\u8BA4 DB_NAME \u89C1 backend/.env\uFF09`);
328
+ console.log(` 4. pnpm install --no-frozen-lockfile && pnpm build`);
329
+ console.log(` 5. pnpm --filter ${name}-backend dev # \u542F\u52A8\u540E\u7AEF`);
330
+ console.log(` 6. pnpm --filter ${name}-frontend dev # \u542F\u52A8\u524D\u7AEF`);
324
331
  console.log(`
325
- ${import_chalk2.default.gray("\u{1F4A1} \u6DFB\u52A0\u6269\u5C55\u6A21\u5757: \u5728 backend/src/app.modules.ts \u4E2D\u5F15\u5165\u6269\u5C55 Module")}`);
332
+ ${import_chalk2.default.yellow("\u26A0 \u9996\u6B21\u5B89\u88C5\u8BF7\u4F7F\u7528 --no-frozen-lockfile\uFF0C\u5426\u5219\u4F1A\u56E0\u7F3A\u5C11 lock \u6587\u4EF6\u62A5\u9519")}`);
333
+ console.log(`${import_chalk2.default.gray("\u{1F4A1} \u6DFB\u52A0\u6269\u5C55\u6A21\u5757: \u5728 backend/src/app.modules.ts \u4E2D\u5F15\u5165\u6269\u5C55 Module")}`);
326
334
  console.log(`${import_chalk2.default.gray("\u{1F4A1} \u6DFB\u52A0\u4E1A\u52A1\u6A21\u5757: \u5728 backend/src/modules/ \u4E0B\u521B\u5EFA\u65B0\u7684 NestJS \u6A21\u5757")}`);
327
335
  });
328
336
 
package/dist/index.js CHANGED
@@ -157,7 +157,10 @@ Use --force to overwrite.`));
157
157
  process.exit(1);
158
158
  }
159
159
  }
160
- const answers = opts.yes ? defaultExtensionAnswers(name, className) : await inquirer.prompt([
160
+ if (!process.stdin.isTTY && !opts.yes) {
161
+ console.log(chalk.yellow("\u26A0 \u975E\u4EA4\u4E92\u5F0F\u7EC8\u7AEF\uFF0C\u5C06\u4F7F\u7528\u9ED8\u8BA4\u503C\u521B\u5EFA\uFF08\u4F7F\u7528 -y \u53EF\u8DF3\u8FC7\u6B64\u63D0\u793A\uFF09"));
162
+ }
163
+ const answers = opts.yes || !process.stdin.isTTY ? defaultExtensionAnswers(name, className) : await inquirer.prompt([
161
164
  { name: "displayName", message: "\u663E\u793A\u540D\u79F0:", default: className },
162
165
  { name: "description", message: "\u63CF\u8FF0:", default: "" },
163
166
  { name: "routePrefix", message: "\u8DEF\u7531\u524D\u7F00:", default: `/ext/${name}` },
@@ -235,7 +238,10 @@ Use --force to overwrite.`));
235
238
  process.exit(1);
236
239
  }
237
240
  }
238
- const answers = opts.yes ? defaultBusinessAnswers(className) : await inquirer2.prompt([
241
+ if (!process.stdin.isTTY && !opts.yes) {
242
+ console.log(chalk2.yellow("\u26A0 \u975E\u4EA4\u4E92\u5F0F\u7EC8\u7AEF\uFF0C\u5C06\u4F7F\u7528\u9ED8\u8BA4\u503C\u521B\u5EFA\uFF08\u4F7F\u7528 -y \u53EF\u8DF3\u8FC7\u6B64\u63D0\u793A\uFF09"));
243
+ }
244
+ const answers = opts.yes || !process.stdin.isTTY ? defaultBusinessAnswers(className) : await inquirer2.prompt([
239
245
  {
240
246
  name: "displayName",
241
247
  message: "\u663E\u793A\u540D\u79F0:",
@@ -294,11 +300,13 @@ Use --force to overwrite.`));
294
300
  ${chalk2.bold("\u{1F4CB} \u540E\u7EED\u6B65\u9AA4:")}`);
295
301
  console.log(` 1. cd ${path4.relative(process.cwd(), targetDir)}`);
296
302
  console.log(` 2. \u7F16\u8F91 backend/.env \u914D\u7F6E\u6570\u636E\u5E93\u8FDE\u63A5`);
297
- console.log(` 3. pnpm install && pnpm build`);
298
- console.log(` 4. pnpm --filter ${name}-backend dev # \u542F\u52A8\u540E\u7AEF`);
299
- console.log(` 5. pnpm --filter ${name}-frontend dev # \u542F\u52A8\u524D\u7AEF`);
303
+ console.log(` 3. \u5728 MySQL \u4E2D\u521B\u5EFA\u6570\u636E\u5E93\uFF08\u9ED8\u8BA4 DB_NAME \u89C1 backend/.env\uFF09`);
304
+ console.log(` 4. pnpm install --no-frozen-lockfile && pnpm build`);
305
+ console.log(` 5. pnpm --filter ${name}-backend dev # \u542F\u52A8\u540E\u7AEF`);
306
+ console.log(` 6. pnpm --filter ${name}-frontend dev # \u542F\u52A8\u524D\u7AEF`);
300
307
  console.log(`
301
- ${chalk2.gray("\u{1F4A1} \u6DFB\u52A0\u6269\u5C55\u6A21\u5757: \u5728 backend/src/app.modules.ts \u4E2D\u5F15\u5165\u6269\u5C55 Module")}`);
308
+ ${chalk2.yellow("\u26A0 \u9996\u6B21\u5B89\u88C5\u8BF7\u4F7F\u7528 --no-frozen-lockfile\uFF0C\u5426\u5219\u4F1A\u56E0\u7F3A\u5C11 lock \u6587\u4EF6\u62A5\u9519")}`);
309
+ console.log(`${chalk2.gray("\u{1F4A1} \u6DFB\u52A0\u6269\u5C55\u6A21\u5757: \u5728 backend/src/app.modules.ts \u4E2D\u5F15\u5165\u6269\u5C55 Module")}`);
302
310
  console.log(`${chalk2.gray("\u{1F4A1} \u6DFB\u52A0\u4E1A\u52A1\u6A21\u5757: \u5728 backend/src/modules/ \u4E0B\u521B\u5EFA\u65B0\u7684 NestJS \u6A21\u5757")}`);
303
311
  });
304
312
 
@@ -3,7 +3,7 @@
3
3
  "version": "0.1.0",
4
4
  "private": true,
5
5
  "scripts": {
6
- "prebuild": "pnpm --filter {{name}}-shared build && pnpm --filter moyan-mfw-base build",
6
+ "prebuild": "pnpm --filter {{name}}-shared build",
7
7
  "dev": "pnpm run prebuild && nest start --watch",
8
8
  "build": "nest build",
9
9
  "typecheck": "tsc --noEmit -p tsconfig.json",
@@ -12,25 +12,35 @@
12
12
  },
13
13
  "dependencies": {
14
14
  "@nestjs/common": "catalog:",
15
+ "@nestjs/config": "catalog:",
15
16
  "@nestjs/core": "catalog:",
17
+ "@nestjs/jwt": "catalog:",
16
18
  "@nestjs/platform-express": "catalog:",
17
- "@nestjs/typeorm": "catalog:",
18
19
  "@nestjs/swagger": "catalog:",
19
- "typeorm": "catalog:",
20
+ "@nestjs/typeorm": "catalog:",
21
+ "bcryptjs": "catalog:",
20
22
  "class-transformer": "catalog:",
21
23
  "class-validator": "catalog:",
24
+ "dotenv": "catalog:",
25
+ "multer": "catalog:",
26
+ "mysql2": "catalog:",
27
+ "redis": "catalog:",
22
28
  "reflect-metadata": "catalog:",
23
29
  "rxjs": "catalog:",
24
- "mysql2": "catalog:",
25
- "dotenv": "catalog:",
26
- "moyan-mfw-base": "workspace:*",
30
+ "typeorm": "catalog:",
31
+ "moyan-mfw-base": "^1.0.0",
32
+ "moyan-mfw-extension-ad": "^0.1.0",
27
33
  "{{name}}-shared": "workspace:*"
28
34
  },
29
35
  "devDependencies": {
30
36
  "@nestjs/cli": "catalog:",
31
37
  "@nestjs/schematics": "catalog:",
32
- "typescript": "catalog:",
38
+ "@types/bcryptjs": "catalog:",
39
+ "@types/express": "catalog:",
40
+ "@types/multer": "catalog:",
41
+ "@types/node": "catalog:",
33
42
  "ts-node": "catalog:",
34
- "tsconfig-paths": "catalog:"
43
+ "tsconfig-paths": "catalog:",
44
+ "typescript": "catalog:"
35
45
  }
36
46
  }
@@ -1,6 +1,7 @@
1
1
  import { Module } from '@nestjs/common'
2
+ import AdModule from 'moyan-mfw-extension-ad/backend'
2
3
 
3
4
  @Module({
4
- imports: [],
5
+ imports: [AdModule],
5
6
  })
6
7
  export class AppModule {}
@@ -2,8 +2,16 @@ import 'dotenv/config'
2
2
  import { createBaseBackendApp, SwaggerGroupConfig } from 'moyan-mfw-base/backend'
3
3
  import { appTypesConfig } from './app-types.config'
4
4
  import { AppModule } from './app.modules'
5
+ import { AdModule, AD_EXTENSION_PERMISSION_VALUES } from 'moyan-mfw-extension-ad/backend'
5
6
 
6
- const swaggerGroups: SwaggerGroupConfig[] = []
7
+ const swaggerGroups: SwaggerGroupConfig[] = [
8
+ {
9
+ name: 'ad-extension',
10
+ title: '广告管理API文档',
11
+ description: '广告位类型、广告位、广告内容管理 API',
12
+ include: [AdModule],
13
+ },
14
+ ]
7
15
 
8
16
  async function bootstrap() {
9
17
  const startTime = Date.now()
@@ -16,7 +24,7 @@ async function bootstrap() {
16
24
  syncAppTypes: true,
17
25
  modules: [AppModule],
18
26
  swagger: swaggerGroups,
19
- permissionValues: [],
27
+ permissionValues: [...AD_EXTENSION_PERMISSION_VALUES],
20
28
  hooks: {
21
29
  onAppInit: async (ctx) => {
22
30
  console.log('[{{displayName}}] 应用初始化完成')
@@ -1,35 +1,394 @@
1
1
  <!doctype html>
2
- <html lang="zh-CN">
2
+ <html lang="en">
3
3
  <head>
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title>{{displayName}}</title>
7
+ <script>
8
+ (function() {
9
+ try {
10
+ var raw = localStorage.getItem('mfw:base-frontend:layout-preferences');
11
+ if (raw) {
12
+ var prefs = JSON.parse(raw);
13
+ if (prefs && prefs.styleConfig) {
14
+ var styleConfig = prefs.styleConfig;
15
+ if (styleConfig.colorMode === 'dark') {
16
+ document.documentElement.classList.add('dark');
17
+ var placeholder = document.getElementById('loading-placeholder');
18
+ if (placeholder) {
19
+ placeholder.setAttribute('data-dark', 'true');
20
+ }
21
+ }
22
+ var themeThemes = {
23
+ default: { primary: '#409eff', success: '#67c23a', warning: '#e6a23c', danger: '#f56c6c', info: '#909399' },
24
+ ocean: { primary: '#00a8cc', success: '#52c41a', warning: '#faad14', danger: '#ff4d4f', info: '#8c8c8c' },
25
+ graphite: { primary: '#5a5a5a', success: '#4a9c6d', warning: '#c9a227', danger: '#c45656', info: '#73767a' },
26
+ fintech: { primary: '#F59E0B', success: '#22C55E', warning: '#FBBF24', danger: '#EF4444', info: '#8B5CF6' },
27
+ tech: { primary: '#8B5CF6', success: '#10B981', warning: '#FBBF24', danger: '#F43F5E', info: '#6366F1' },
28
+ luxury: { primary: '#CA8A04', success: '#4ADE80', warning: '#FBBF24', danger: '#F87171', info: '#A8A29E' },
29
+ nature: { primary: '#059669', success: '#22C55E', warning: '#FBBF24', danger: '#EF4444', info: '#14B8A6' },
30
+ aurora: { primary: '#7c3aed', success: '#10b981', warning: '#f59e0b', danger: '#ef4444', info: '#6b7280', gradient: 'linear-gradient(135deg, #3b82f6 0%, #7c3aed 50%, #ec4899 100%)' },
31
+ sunset: { primary: '#f97316', success: '#22c55e', warning: '#eab308', danger: '#dc2626', info: '#78716c', gradient: 'linear-gradient(135deg, #fbbf24 0%, #f97316 50%, #dc2626 100%)' }
32
+ };
33
+ var themeName = styleConfig.themePackage || 'default';
34
+ var colors = themeThemes[themeName] || themeThemes['default'];
35
+ if (colors) {
36
+ var root = document.documentElement;
37
+ function hexToRgb(hex) {
38
+ var c = hex.replace('#', '');
39
+ return [parseInt(c.substring(0,2),16), parseInt(c.substring(2,4),16), parseInt(c.substring(4,6),16)];
40
+ }
41
+ function rgbToHex(r, g, b) {
42
+ var h = function(n) { var s = Math.round(Math.max(0,Math.min(255,n))).toString(16); return s.length===1?'0'+s:s; };
43
+ return '#'+h(r)+h(g)+h(b);
44
+ }
45
+ function mixWhite(color, level) {
46
+ var rgb = hexToRgb(color); var ratio = level / 10;
47
+ return rgbToHex(Math.round(255*ratio+rgb[0]*(1-ratio)), Math.round(255*ratio+rgb[1]*(1-ratio)), Math.round(255*ratio+rgb[2]*(1-ratio)));
48
+ }
49
+ function mixBlack(color, level) {
50
+ var rgb = hexToRgb(color); var ratio = level / 10;
51
+ return rgbToHex(Math.round(rgb[0]*(1-ratio)), Math.round(rgb[1]*(1-ratio)), Math.round(rgb[2]*(1-ratio)));
52
+ }
53
+ var lightLevels = [3, 5, 7, 8, 9];
54
+ var darkLevels = [2];
55
+ Object.keys(colors).forEach(function(key) {
56
+ var value = colors[key];
57
+ if (key === 'gradient') {
58
+ root.style.setProperty('--el-color-primary-gradient', value);
59
+ root.style.setProperty('--mfw-gradient-primary', value);
60
+ root.classList.add('mfw-theme-gradient');
61
+ return;
62
+ }
63
+ root.style.setProperty('--el-color-' + key, value);
64
+ lightLevels.forEach(function(level) {
65
+ root.style.setProperty('--el-color-' + key + '-light-' + level, mixWhite(value, level));
66
+ });
67
+ darkLevels.forEach(function(level) {
68
+ root.style.setProperty('--el-color-' + key + '-dark-' + level, mixBlack(value, level));
69
+ });
70
+ });
71
+ }
72
+ }
73
+ }
74
+ } catch (e) {
75
+ console.warn('[Loading] Failed to read preferences:', e);
76
+ }
77
+ })();
78
+ </script>
7
79
  <style>
8
- * { margin: 0; padding: 0; box-sizing: border-box; }
80
+ * {
81
+ margin: 0;
82
+ padding: 0;
83
+ box-sizing: border-box;
84
+ }
85
+
9
86
  #loading-placeholder {
10
- position: fixed; top: 0; left: 0; width: 100%; height: 100%;
11
- display: flex; flex-direction: column; align-items: center; justify-content: center;
87
+ position: fixed;
88
+ top: 0;
89
+ left: 0;
90
+ width: 100%;
91
+ height: 100%;
92
+ display: flex;
93
+ flex-direction: column;
94
+ align-items: center;
95
+ justify-content: center;
12
96
  background: linear-gradient(135deg, #ffffff 0%, #f8fafc 50%, #ffffff 100%);
13
- z-index: 9999; transition: opacity 0.4s ease;
97
+ z-index: 9999;
98
+ transition: opacity 0.5s ease, visibility 0.5s ease;
99
+ overflow: hidden;
100
+ }
101
+
102
+ #loading-placeholder[data-dark="true"] {
103
+ background: linear-gradient(135deg, #0f172a 0%, #1e293b 50%, #0f172a 100%);
104
+ }
105
+
106
+ #loading-placeholder.hidden {
107
+ opacity: 0;
108
+ visibility: hidden;
109
+ }
110
+
111
+ .loading-particles {
112
+ position: absolute;
113
+ width: 100%;
114
+ height: 100%;
115
+ overflow: hidden;
116
+ }
117
+
118
+ .particle {
119
+ position: absolute;
120
+ width: 4px;
121
+ height: 4px;
122
+ background: rgba(59, 130, 246, 0.4);
123
+ border-radius: 50%;
124
+ animation: float-particle linear infinite;
125
+ }
126
+
127
+ #loading-placeholder[data-dark="true"] .particle {
128
+ background: rgba(59, 130, 246, 0.6);
129
+ }
130
+
131
+ .particle:nth-child(1) { left: 10%; animation-duration: 8s; animation-delay: 0s; }
132
+ .particle:nth-child(2) { left: 20%; animation-duration: 10s; animation-delay: 1s; }
133
+ .particle:nth-child(3) { left: 30%; animation-duration: 7s; animation-delay: 2s; }
134
+ .particle:nth-child(4) { left: 40%; animation-duration: 9s; animation-delay: 0.5s; }
135
+ .particle:nth-child(5) { left: 50%; animation-duration: 11s; animation-delay: 1.5s; }
136
+ .particle:nth-child(6) { left: 60%; animation-duration: 8s; animation-delay: 3s; }
137
+ .particle:nth-child(7) { left: 70%; animation-duration: 10s; animation-delay: 2.5s; }
138
+ .particle:nth-child(8) { left: 80%; animation-duration: 7s; animation-delay: 0.8s; }
139
+ .particle:nth-child(9) { left: 90%; animation-duration: 9s; animation-delay: 1.2s; }
140
+ .particle:nth-child(10) { left: 15%; animation-duration: 12s; animation-delay: 2.2s; }
141
+ .particle:nth-child(11) { left: 25%; animation-duration: 8s; animation-delay: 0.3s; }
142
+ .particle:nth-child(12) { left: 35%; animation-duration: 10s; animation-delay: 1.8s; }
143
+ .particle:nth-child(13) { left: 45%; animation-duration: 7s; animation-delay: 3.5s; }
144
+ .particle:nth-child(14) { left: 55%; animation-duration: 9s; animation-delay: 0.7s; }
145
+ .particle:nth-child(15) { left: 65%; animation-duration: 11s; animation-delay: 2.8s; }
146
+ .particle:nth-child(16) { left: 75%; animation-duration: 8s; animation-delay: 1.1s; }
147
+ .particle:nth-child(17) { left: 85%; animation-duration: 10s; animation-delay: 3.2s; }
148
+ .particle:nth-child(18) { left: 95%; animation-duration: 7s; animation-delay: 0.4s; }
149
+
150
+ @keyframes float-particle {
151
+ 0% {
152
+ transform: translateY(100vh) scale(0);
153
+ opacity: 0;
154
+ }
155
+ 10% {
156
+ opacity: 1;
157
+ }
158
+ 90% {
159
+ opacity: 1;
160
+ }
161
+ 100% {
162
+ transform: translateY(-100px) scale(1);
163
+ opacity: 0;
164
+ }
14
165
  }
15
- #loading-placeholder.hidden { opacity: 0; pointer-events: none; }
16
- .loader {
17
- width: 48px; height: 48px;
18
- border: 4px solid #e5e7eb;
166
+
167
+ .loading-core {
168
+ position: relative;
169
+ width: 120px;
170
+ height: 120px;
171
+ display: flex;
172
+ align-items: center;
173
+ justify-content: center;
174
+ }
175
+
176
+ .loading-ring {
177
+ position: absolute;
178
+ border-radius: 50%;
179
+ border: 2px solid transparent;
180
+ }
181
+
182
+ .loading-ring-1 {
183
+ width: 120px;
184
+ height: 120px;
19
185
  border-top-color: #3b82f6;
186
+ border-right-color: #3b82f6;
187
+ animation: spin-clockwise 1.5s linear infinite;
188
+ }
189
+
190
+ .loading-ring-2 {
191
+ width: 90px;
192
+ height: 90px;
193
+ border-bottom-color: #8b5cf6;
194
+ border-left-color: #8b5cf6;
195
+ animation: spin-counter-clockwise 1.2s linear infinite;
196
+ }
197
+
198
+ .loading-ring-3 {
199
+ width: 60px;
200
+ height: 60px;
201
+ border-top-color: #06b6d4;
202
+ border-right-color: #06b6d4;
203
+ animation: spin-clockwise 0.9s linear infinite;
204
+ }
205
+
206
+ .loading-center {
207
+ width: 30px;
208
+ height: 30px;
209
+ background: linear-gradient(135deg, #3b82f6, #8b5cf6, #06b6d4);
210
+ border-radius: 50%;
211
+ animation: pulse-glow 1.5s ease-in-out infinite;
212
+ box-shadow: 0 0 20px rgba(59, 130, 246, 0.5),
213
+ 0 0 40px rgba(139, 92, 246, 0.3),
214
+ 0 0 60px rgba(6, 182, 212, 0.2);
215
+ }
216
+
217
+ @keyframes spin-clockwise {
218
+ to { transform: rotate(360deg); }
219
+ }
220
+
221
+ @keyframes spin-counter-clockwise {
222
+ to { transform: rotate(-360deg); }
223
+ }
224
+
225
+ @keyframes pulse-glow {
226
+ 0%, 100% {
227
+ transform: scale(0.8);
228
+ opacity: 0.8;
229
+ }
230
+ 50% {
231
+ transform: scale(1.2);
232
+ opacity: 1;
233
+ }
234
+ }
235
+
236
+ .loading-text-container {
237
+ margin-top: 40px;
238
+ text-align: center;
239
+ }
240
+
241
+ .loading-text {
242
+ font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
243
+ font-size: 16px;
244
+ font-weight: 500;
245
+ color: #1e293b;
246
+ letter-spacing: 2px;
247
+ animation: text-fade 2s ease-in-out infinite;
248
+ }
249
+
250
+ #loading-placeholder[data-dark="true"] .loading-text {
251
+ color: #e2e8f0;
252
+ }
253
+
254
+ .loading-dots {
255
+ display: inline-block;
256
+ margin-left: 4px;
257
+ }
258
+
259
+ .loading-dots span {
260
+ display: inline-block;
261
+ width: 6px;
262
+ height: 6px;
263
+ margin: 0 2px;
264
+ background: #3b82f6;
20
265
  border-radius: 50%;
21
- animation: spin 0.8s linear infinite;
266
+ animation: dot-bounce 1.4s ease-in-out infinite;
267
+ }
268
+
269
+ .loading-dots span:nth-child(1) { animation-delay: 0s; }
270
+ .loading-dots span:nth-child(2) { animation-delay: 0.2s; }
271
+ .loading-dots span:nth-child(3) { animation-delay: 0.4s; }
272
+
273
+ @keyframes text-fade {
274
+ 0%, 100% { opacity: 0.6; }
275
+ 50% { opacity: 1; }
276
+ }
277
+
278
+ @keyframes dot-bounce {
279
+ 0%, 80%, 100% {
280
+ transform: translateY(0);
281
+ }
282
+ 40% {
283
+ transform: translateY(-10px);
284
+ }
285
+ }
286
+
287
+ .loading-progress {
288
+ margin-top: 30px;
289
+ width: 200px;
290
+ height: 3px;
291
+ background: rgba(0, 0, 0, 0.1);
292
+ border-radius: 2px;
293
+ overflow: hidden;
294
+ }
295
+
296
+ #loading-placeholder[data-dark="true"] .loading-progress {
297
+ background: rgba(255, 255, 255, 0.1);
298
+ }
299
+
300
+ .loading-progress-bar {
301
+ height: 100%;
302
+ width: 0%;
303
+ background: linear-gradient(90deg, #3b82f6, #8b5cf6, #06b6d4);
304
+ border-radius: 2px;
305
+ animation: progress-fill 2s ease-in-out infinite;
306
+ }
307
+
308
+ @keyframes progress-fill {
309
+ 0% { width: 0%; }
310
+ 50% { width: 70%; }
311
+ 100% { width: 100%; }
312
+ }
313
+
314
+ @media (prefers-reduced-motion: reduce) {
315
+ .particle,
316
+ .loading-ring,
317
+ .loading-center,
318
+ .loading-text,
319
+ .loading-dots span,
320
+ .loading-progress-bar {
321
+ animation: none;
322
+ }
323
+
324
+ .loading-center {
325
+ transform: scale(1);
326
+ opacity: 1;
327
+ }
22
328
  }
23
- @keyframes spin { to { transform: rotate(360deg); } }
24
- .loading-text { margin-top: 16px; font-family: system-ui, sans-serif; font-size: 14px; color: #6b7280; }
25
329
  </style>
26
330
  </head>
27
331
  <body>
28
332
  <div id="app"></div>
29
333
  <div id="loading-placeholder">
30
- <div class="loader"></div>
31
- <div class="loading-text">正在加载...</div>
334
+ <div class="loading-particles">
335
+ <div class="particle"></div>
336
+ <div class="particle"></div>
337
+ <div class="particle"></div>
338
+ <div class="particle"></div>
339
+ <div class="particle"></div>
340
+ <div class="particle"></div>
341
+ <div class="particle"></div>
342
+ <div class="particle"></div>
343
+ <div class="particle"></div>
344
+ <div class="particle"></div>
345
+ <div class="particle"></div>
346
+ <div class="particle"></div>
347
+ <div class="particle"></div>
348
+ <div class="particle"></div>
349
+ <div class="particle"></div>
350
+ <div class="particle"></div>
351
+ <div class="particle"></div>
352
+ <div class="particle"></div>
353
+ </div>
354
+ <div class="loading-core">
355
+ <div class="loading-ring loading-ring-1"></div>
356
+ <div class="loading-ring loading-ring-2"></div>
357
+ <div class="loading-ring loading-ring-3"></div>
358
+ <div class="loading-center"></div>
359
+ </div>
360
+ <div class="loading-text-container">
361
+ <div class="loading-text">
362
+ 正在加载
363
+ <span class="loading-dots">
364
+ <span></span>
365
+ <span></span>
366
+ <span></span>
367
+ </span>
368
+ </div>
369
+ </div>
370
+ <div class="loading-progress">
371
+ <div class="loading-progress-bar"></div>
372
+ </div>
32
373
  </div>
374
+ <script>
375
+ (function() {
376
+ try {
377
+ var raw = localStorage.getItem('mfw:base-frontend:layout-preferences');
378
+ if (raw) {
379
+ var prefs = JSON.parse(raw);
380
+ if (prefs && prefs.styleConfig && prefs.styleConfig.colorMode === 'dark') {
381
+ var placeholder = document.getElementById('loading-placeholder');
382
+ if (placeholder) {
383
+ placeholder.setAttribute('data-dark', 'true');
384
+ }
385
+ }
386
+ }
387
+ } catch (e) {
388
+ console.warn('[Loading] Failed to read color mode preference:', e);
389
+ }
390
+ })();
391
+ </script>
33
392
  <script type="module" src="/src/main.ts"></script>
34
393
  </body>
35
394
  </html>
@@ -10,22 +10,27 @@
10
10
  "typecheck": "vue-tsc --noEmit -p tsconfig.json"
11
11
  },
12
12
  "dependencies": {
13
- "vue": "catalog:",
14
- "vue-router": "catalog:",
15
- "element-plus": "catalog:",
16
13
  "@element-plus/icons-vue": "catalog:",
17
- "pinia": "catalog:",
18
14
  "@vueuse/core": "catalog:",
19
15
  "axios": "catalog:",
20
- "moyan-mfw-base": "workspace:*",
16
+ "element-plus": "catalog:",
17
+ "md-editor-v3": "catalog:",
18
+ "moyan-mfw-base": "^1.0.0",
19
+ "moyan-mfw-extension-ad": "^0.1.0",
20
+ "pinia": "catalog:",
21
+ "quill": "catalog:",
22
+ "vue": "catalog:",
23
+ "vue-advanced-cropper": "catalog:",
24
+ "vue-router": "catalog:",
21
25
  "{{name}}-shared": "workspace:*"
22
26
  },
23
27
  "devDependencies": {
24
- "vite": "catalog:",
28
+ "@types/node": "catalog:",
25
29
  "@vitejs/plugin-vue": "catalog:",
26
30
  "@vitejs/plugin-vue-jsx": "catalog:",
27
- "vue-tsc": "catalog:",
28
31
  "sass": "catalog:",
29
- "typescript": "catalog:"
32
+ "typescript": "catalog:",
33
+ "vite": "catalog:",
34
+ "vue-tsc": "catalog:"
30
35
  }
31
36
  }
@@ -1,4 +1,4 @@
1
- import { createBaseAdminApp, registerPermissionValues } from 'moyan-mfw-base/frontend'
1
+ import { createBaseAdminApp } from 'moyan-mfw-base/frontend'
2
2
  import { businessRoutes } from './router'
3
3
  import './permissions'
4
4
 
@@ -0,0 +1,46 @@
1
+ packages:
2
+ - 'backend'
3
+ - 'frontend'
4
+ - 'shared'
5
+ catalog:
6
+ '@element-plus/icons-vue': ^2.3.2
7
+ '@nestjs/cli': ^10.4.9
8
+ '@nestjs/common': ^10.4.22
9
+ '@nestjs/config': ^3.3.0
10
+ '@nestjs/core': ^10.4.22
11
+ '@nestjs/jwt': ^10.2.0
12
+ '@nestjs/platform-express': ^10.4.22
13
+ '@nestjs/schematics': ^10.1.4
14
+ '@nestjs/swagger': ^7.4.2
15
+ '@nestjs/typeorm': ^10.0.2
16
+ '@types/bcryptjs': ^2.4.6
17
+ '@types/express': ^4.17.25
18
+ '@types/multer': ^2.1.0
19
+ '@types/node': ^22.19.15
20
+ '@vitejs/plugin-vue': ^5.2.4
21
+ '@vitejs/plugin-vue-jsx': ^5.1.5
22
+ '@vueuse/core': ^14.2.1
23
+ axios: ^1.6.5
24
+ bcryptjs: ^2.4.3
25
+ class-transformer: ^0.5.1
26
+ class-validator: ^0.14.4
27
+ dotenv: ^17.3.1
28
+ element-plus: ^2.13.5
29
+ md-editor-v3: ^6.4.2
30
+ multer: ^2.1.1
31
+ mysql2: ^3.11.5
32
+ pinia: ^2.3.0
33
+ quill: ^2.0.3
34
+ redis: ^4.7.0
35
+ reflect-metadata: ^0.1.14
36
+ rxjs: ^7.8.2
37
+ sass: ^1.70.0
38
+ ts-node: ^10.9.2
39
+ tsconfig-paths: ^4.2.0
40
+ typeorm: ^0.3.28
41
+ typescript: ^5.7.3
42
+ vite: ^5.4.21
43
+ vue: ^3.5.30
44
+ vue-advanced-cropper: ^2.8.8
45
+ vue-router: ^4.5.1
46
+ vue-tsc: ^2.2.12
@@ -26,7 +26,7 @@
26
26
  },
27
27
  "dependencies": {
28
28
  "reflect-metadata": "catalog:",
29
- "moyan-mfw-base": "workspace:*"
29
+ "moyan-mfw-base": "^1.0.0"
30
30
  },
31
31
  "devDependencies": {
32
32
  "typescript": "catalog:"
@@ -20,7 +20,7 @@ export default defineConfig({
20
20
  lib: {
21
21
  entry: resolve(__dirname, 'src/index.ts'),
22
22
  formats: ['es'],
23
- fileName: () => 'index.js',
23
+ fileName: () => 'index.mjs',
24
24
  },
25
25
  rollupOptions: {
26
26
  external: ['vue', 'vue-router', 'element-plus', '@element-plus/icons-vue', 'moyan-mfw-base/frontend', 'moyan-mfw-base/shared'],
@@ -1 +1 @@
1
- {"name": "moyan-mfw-extension-{{name}}", "version": "{{version}}", "description": "{{description}}", "private": true, "type": "module", "exports": {"./backend": {"import": "./src/backend/dist/index.js", "require": "./src/backend/dist/index.js", "types": "./src/backend/dist/index.d.ts"}, "./backend/*": {"import": "./src/backend/dist/*.js", "require": "./src/backend/dist/*", "types": "./src/backend/dist/*.d.ts"}, "./frontend": {"import": "./src/frontend/dist/index.mjs", "require": "./src/frontend/dist/index.js", "types": "./src/frontend/dist/index.d.ts"}, "./frontend/*": {"import": "./src/frontend/dist/*", "require": "./src/frontend/dist/*", "types": "./src/frontend/dist/*.d.ts"}, "./shared": {"import": "./src/shared/dist/index.js", "require": "./src/shared/dist/index.js", "types": "./src/shared/dist/index.d.ts"}, "./shared/*": {"import": "./src/shared/dist/*", "require": "./src/shared/dist/*", "types": "./src/shared/dist/*.d.ts"}}, "typesVersions": {"*": {"*": ["./src/*/dist/*.d.ts", "./src/*/dist/index.d.ts"]}}, "scripts": {"build:shared": "pnpm --filter @internal/{{name}}-shared build", "build:backend": "pnpm --filter moyan-mfw-base run build:shared && pnpm --filter moyan-mfw-base run build:backend && pnpm --filter @internal/{{name}}-backend build", "build:frontend": "pnpm --filter @internal/{{name}}-frontend build", "build": "pnpm run build:shared && pnpm run build:backend && pnpm run build:frontend", "dev:backend": "pnpm --filter @internal/{{name}}-backend dev", "dev:frontend": "pnpm --filter @internal/{{name}}-frontend dev", "typecheck:shared": "pnpm --filter @internal/{{name}}-shared typecheck", "typecheck:backend": "pnpm --filter @internal/{{name}}-backend typecheck", "typecheck:frontend": "pnpm --filter @internal/{{name}}-frontend typecheck", "typecheck": "pnpm run typecheck:shared && pnpm run typecheck:backend && pnpm run typecheck:frontend"}, "devDependencies": {"@internal/{{name}}-backend": "workspace:*", "@internal/{{name}}-frontend": "workspace:*", "@internal/{{name}}-shared": "workspace:*", "moyan-mfw-base": "workspace:*", "typescript": "catalog:"}}
1
+ {"name": "moyan-mfw-extension-{{name}}", "version": "{{version}}", "description": "{{description}}", "private": true, "type": "module", "exports": {"./backend": {"import": "./src/backend/dist/index.js", "require": "./src/backend/dist/index.js", "types": "./src/backend/dist/index.d.ts"}, "./backend/*": {"import": "./src/backend/dist/*.js", "require": "./src/backend/dist/*", "types": "./src/backend/dist/*.d.ts"}, "./frontend": {"import": "./src/frontend/dist/index.mjs", "require": "./src/frontend/dist/index.mjs", "types": "./src/frontend/dist/index.d.ts"}, "./frontend/*": {"import": "./src/frontend/dist/*", "require": "./src/frontend/dist/*", "types": "./src/frontend/dist/*.d.ts"}, "./shared": {"import": "./src/shared/dist/index.js", "require": "./src/shared/dist/index.js", "types": "./src/shared/dist/index.d.ts"}, "./shared/*": {"import": "./src/shared/dist/*", "require": "./src/shared/dist/*", "types": "./src/shared/dist/*.d.ts"}}, "typesVersions": {"*": {"*": ["./src/*/dist/*.d.ts", "./src/*/dist/index.d.ts"]}}, "scripts": {"build:shared": "pnpm --filter @internal/{{name}}-shared build", "build:backend": "pnpm --filter moyan-mfw-base run build:shared && pnpm --filter moyan-mfw-base run build:backend && pnpm --filter @internal/{{name}}-backend build", "build:frontend": "pnpm --filter @internal/{{name}}-frontend build", "build": "pnpm run build:shared && pnpm run build:backend && pnpm run build:frontend", "dev:backend": "pnpm --filter @internal/{{name}}-backend dev", "dev:frontend": "pnpm --filter @internal/{{name}}-frontend dev", "typecheck:shared": "pnpm --filter @internal/{{name}}-shared typecheck", "typecheck:backend": "pnpm --filter @internal/{{name}}-backend typecheck", "typecheck:frontend": "pnpm --filter @internal/{{name}}-frontend typecheck", "typecheck": "pnpm run typecheck:shared && pnpm run typecheck:backend && pnpm run typecheck:frontend"}, "devDependencies": {"@internal/{{name}}-backend": "workspace:*", "@internal/{{name}}-frontend": "workspace:*", "@internal/{{name}}-shared": "workspace:*", "moyan-mfw-base": "workspace:*", "typescript": "catalog:"}}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "moyan-mfw-cli",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "MFW framework CLI — extension scaffolding, validation, and publishing tools",
5
5
  "type": "module",
6
6
  "bin": {