ljr-cli 1.0.8 → 1.0.10

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.
Files changed (69) hide show
  1. package/bin/commands/demo1.js +1 -1
  2. package/bin/commands/init.js +3 -1
  3. package/bin/commands/sync.js +120 -16
  4. package/bin/templates/vue2.7.16/README.md +15 -13
  5. package/bin/templates/vue2.7.16/public/index.html +5 -5
  6. package/bin/templates/vue3.5.25-2025.12.4/.vscode/settings.json +1 -0
  7. package/bin/templates/vue3.5.25-2025.12.4/README.md +28 -17
  8. package/bin/templates/vue3.5.25-2025.12.4/auto-imports.d.ts +229 -0
  9. package/bin/templates/vue3.5.25-2025.12.4/components.d.ts +49 -0
  10. package/bin/templates/vue3.5.25-2025.12.4/eslint.config.ts +1 -0
  11. package/bin/templates/vue3.5.25-2025.12.4/index.html +2 -2
  12. package/bin/templates/vue3.5.25-2025.12.4/package.json +3 -1
  13. package/bin/templates/vue3.5.25-2025.12.4/pnpm-lock.yaml +480 -11
  14. package/bin/templates/vue3.5.25-2025.12.4/src/assets/images/login_bg.jpg +0 -0
  15. package/bin/templates/vue3.5.25-2025.12.4/src/assets/images/login_bg_black.jpg +0 -0
  16. package/bin/templates/vue3.5.25-2025.12.4/src/assets/images/sc_login_icon.png +0 -0
  17. package/bin/templates/vue3.5.25-2025.12.4/src/boot/el-icon.ts +9 -0
  18. package/bin/templates/vue3.5.25-2025.12.4/src/boot/index.ts +2 -0
  19. package/bin/templates/vue3.5.25-2025.12.4/src/boot/pinia.ts +8 -3
  20. package/bin/templates/vue3.5.25-2025.12.4/src/boot/style.ts +2 -1
  21. package/bin/templates/vue3.5.25-2025.12.4/src/components/layout/header.ts +97 -0
  22. package/bin/templates/vue3.5.25-2025.12.4/src/components/layout/header.vue +37 -13
  23. package/bin/templates/vue3.5.25-2025.12.4/src/components/layout/left-right.vue +3 -7
  24. package/bin/templates/vue3.5.25-2025.12.4/src/components/layout/menu.ts +19 -0
  25. package/bin/templates/vue3.5.25-2025.12.4/src/components/layout/menu.vue +89 -5
  26. package/bin/templates/vue3.5.25-2025.12.4/src/components/layout/up-down.vue +24 -0
  27. package/bin/templates/vue3.5.25-2025.12.4/src/components/login/change-password.vue +111 -0
  28. package/bin/templates/vue3.5.25-2025.12.4/src/components/login/user-login.vue +61 -0
  29. package/bin/templates/vue3.5.25-2025.12.4/src/css/base.css +204 -0
  30. package/bin/templates/vue3.5.25-2025.12.4/src/css/global.css +1596 -0
  31. package/bin/templates/vue3.5.25-2025.12.4/src/css/index.css +3 -0
  32. package/bin/templates/vue3.5.25-2025.12.4/src/css/theme.css +61 -0
  33. package/bin/templates/vue3.5.25-2025.12.4/src/dialogs/device/index.ts +1 -0
  34. package/bin/templates/vue3.5.25-2025.12.4/src/dialogs/dialog.vue +66 -0
  35. package/bin/templates/vue3.5.25-2025.12.4/src/dialogs/helper.ts +90 -0
  36. package/bin/templates/vue3.5.25-2025.12.4/src/dialogs/index.ts +2 -0
  37. package/bin/templates/vue3.5.25-2025.12.4/src/dialogs/template.ts +41 -0
  38. package/bin/templates/vue3.5.25-2025.12.4/src/dialogs/template.vue +29 -0
  39. package/bin/templates/vue3.5.25-2025.12.4/src/dialogs/user-info/index.ts +31 -0
  40. package/bin/templates/vue3.5.25-2025.12.4/src/dialogs/user-info/layout.ts +47 -0
  41. package/bin/templates/vue3.5.25-2025.12.4/src/dialogs/user-info/layout.vue +51 -0
  42. package/bin/templates/vue3.5.25-2025.12.4/src/dialogs/user-info/notification.ts +27 -0
  43. package/bin/templates/vue3.5.25-2025.12.4/src/dialogs/user-info/notification.vue +29 -0
  44. package/bin/templates/vue3.5.25-2025.12.4/src/dialogs/user-info/permission.ts +22 -0
  45. package/bin/templates/vue3.5.25-2025.12.4/src/dialogs/user-info/permission.vue +23 -0
  46. package/bin/templates/vue3.5.25-2025.12.4/src/directive/rememberScrollPosition.ts +1 -1
  47. package/bin/templates/vue3.5.25-2025.12.4/src/enums/device.ts +42 -0
  48. package/bin/templates/vue3.5.25-2025.12.4/src/enums/index.ts +2 -0
  49. package/bin/templates/vue3.5.25-2025.12.4/src/enums/status.ts +23 -0
  50. package/bin/templates/vue3.5.25-2025.12.4/src/pages/index/permission/role.ts +40 -0
  51. package/bin/templates/vue3.5.25-2025.12.4/src/pages/index/permission/role.vue +39 -0
  52. package/bin/templates/vue3.5.25-2025.12.4/src/pages/index/permission/user.vue +10 -0
  53. package/bin/templates/vue3.5.25-2025.12.4/src/pages/index/template/base-info.vue +5 -0
  54. package/bin/templates/vue3.5.25-2025.12.4/src/pages/index/template/base-info2.vue +5 -0
  55. package/bin/templates/vue3.5.25-2025.12.4/src/pages/index/template/list.ts +40 -0
  56. package/bin/templates/vue3.5.25-2025.12.4/src/pages/index/template/list.vue +39 -0
  57. package/bin/templates/vue3.5.25-2025.12.4/src/pages/index/template/store.vue +89 -0
  58. package/bin/templates/vue3.5.25-2025.12.4/src/pages/index.vue +7 -2
  59. package/bin/templates/vue3.5.25-2025.12.4/src/pages/login.vue +34 -64
  60. package/bin/templates/vue3.5.25-2025.12.4/src/stores/account(/351/200/211/351/241/271/345/274/217api/345/206/231/346/263/225/347/244/272/344/276/213).ts +49 -0
  61. package/bin/templates/vue3.5.25-2025.12.4/src/stores/account.ts +46 -28
  62. package/bin/templates/vue3.5.25-2025.12.4/src/stores/dd.ts +85 -29
  63. package/bin/templates/vue3.5.25-2025.12.4/src/stores/layout.ts +99 -21
  64. package/bin/templates/vue3.5.25-2025.12.4/typed-router.d.ts +90 -0
  65. package/bin/templates/vue3.5.25-2025.12.4/uno.config.ts +53 -0
  66. package/bin/templates/vue3.5.25-2025.12.4/vite.config.ts +12 -1
  67. package/package.json +2 -2
  68. package/bin/templates/vue3.5.25-2025.12.4/src/stores//347/273/204/345/220/210/345/274/217pinia/345/206/231/346/263/225(/344/273/245account/344/270/272/344/276/213).ts +0 -28
  69. /package/bin/templates/vue3.5.25-2025.12.4/{public → src/assets}/favicon.svg +0 -0
@@ -1,6 +1,6 @@
1
1
  export default function registerDemo1(program) {
2
2
  program
3
- .command("demo1 <name>")
3
+ .command("demo1 [name]")
4
4
  .description("demo1演示")
5
5
  .option("-l, --local", "从本地模板创建目录")
6
6
  .option("-g, --git", "从git地址创建目录")
@@ -29,7 +29,9 @@ export default function registerInit(program, { currentRunningDirPath, cwdPath,
29
29
  placeholder: "项目名称",
30
30
  validate: (value) => {
31
31
  if (!value.trim().length) return "请输入项目名称"
32
- if (/[^a-z-_]+/i.test(value)) return "英文开头或下划线开头,且只能包含英文、数字、下划线或中划线"
32
+ if (!/^[a-zA-Z_][a-zA-Z0-9_\-]*$/.test(value)) {
33
+ return "英文开头或下划线开头,且只能包含英文、数字、下划线或中划线"
34
+ }
33
35
  },
34
36
  }),
35
37
  templateName: () =>
@@ -10,28 +10,132 @@ export default function registerSync(program, { currentRunningDirPath, cwdPath,
10
10
  .action(async () => {
11
11
  prompts.intro(gradientString("开始同步"))
12
12
 
13
+ const destPath = await prompts.text({
14
+ message: "输出的文件夹路径:",
15
+ placeholder: "输出的文件夹路径",
16
+ initialValue: "src",
17
+ validate: (value) => {
18
+ if (!value.trim().length) return "请输入输出的文件夹路径"
19
+ },
20
+ })
21
+
22
+ /** 选择同步的文件夹 */
23
+ const syncFolder = await prompts.multiselect({
24
+ message: "请选择需要同步的文件夹",
25
+ options: [
26
+ { label: "css", value: "css" },
27
+ { label: "less", value: "less" },
28
+ { label: "utils", value: "utils" },
29
+ ],
30
+ required: true,
31
+ initialValues: ["css", "utils"],
32
+ })
33
+ if (prompts.isCancel(syncFolder)) {
34
+ prompts.cancel("取消操作!")
35
+ process.exit(0)
36
+ }
37
+
38
+ /** 选择同步的css文件 */
39
+ let cssFiles = []
40
+ if (syncFolder.includes("css")) {
41
+ cssFiles = await prompts.multiselect({
42
+ message: `请选择需要同步的css文件${gradientString("(未选择的情况下,同步整个文件夹)", ["red", "red"])}`,
43
+ options: [
44
+ { label: "index.css", value: "index.css" },
45
+ { label: "base.css", value: "base.css" },
46
+ { label: "theme.css", value: "theme.css" },
47
+ { label: "global.css", value: "global.css" },
48
+ ],
49
+ required: false,
50
+ initialValues: ["index.css", "base.css", "theme.css", "global.css"],
51
+ })
52
+ if (prompts.isCancel(syncFolder)) {
53
+ prompts.cancel("取消操作!")
54
+ process.exit(0)
55
+ }
56
+ }
57
+
58
+ /** 选择同步的util文件 */
59
+ let utilFiles = []
60
+ if (syncFolder.includes("utils")) {
61
+ utilFiles = await prompts.multiselect({
62
+ message: `请选择需要同步的util文件${gradientString("(未选择的情况下,同步整个文件夹)", ["red", "red"])}`,
63
+ options: [
64
+ { label: "arr.js", value: "arr.js" },
65
+ { label: "city.js", value: "city.js" },
66
+ { label: "date.js", value: "date.js" },
67
+ { label: "file.ts", value: "file.ts" },
68
+ { label: "file.js", value: "file.js" },
69
+ { label: "index.js", value: "index.js" },
70
+ ],
71
+ required: false,
72
+ initialValues: ["arr.js", "city.js", "date.js", "file.js", "index.js"],
73
+ })
74
+ if (prompts.isCancel(syncFolder)) {
75
+ prompts.cancel("取消操作!")
76
+ process.exit(0)
77
+ }
78
+ }
79
+
13
80
  try {
81
+ // 模块路径
14
82
  const moduleBase = path.join(currentRunningDirPath, "../node_modules/l-global")
15
- const cssSrc = path.join(moduleBase, "css")
16
- const utilsSrc = path.join(moduleBase, "utils")
17
- const destBase = path.join(cwdPath, "src")
18
-
19
- if (existsSync(cssSrc)) {
20
- copySync(cssSrc, path.join(destBase, "css"), { recursive: true, overwrite: true })
21
- console.log("已复制:l-global/css -> src/css")
22
- } else {
23
- console.warn("未找到 l-global/css:", cssSrc)
83
+ // 输出路径
84
+ const destBase = path.join(cwdPath, destPath)
85
+
86
+ const s = prompts.spinner({ indicator: "timer" })
87
+
88
+ // 通用复制函数:若 selectedFiles 有值,则只复制这些文件(文件名包含扩展名),否则复制整个文件夹
89
+ const copyFolderOrFiles = (moduleBasePath, folderName, destBasePath, selectedFiles = []) => {
90
+ const folderSrc = path.join(moduleBasePath, folderName)
91
+ const folderDest = path.join(destBasePath, folderName)
92
+
93
+ // 如果选中了具体文件,逐个复制
94
+ if (selectedFiles && selectedFiles.length) {
95
+ for (const fname of selectedFiles) {
96
+ const srcFile = path.join(folderSrc, fname)
97
+ const destFile = path.join(folderDest, fname)
98
+ s.start(`复制 ${folderName}/${fname} ...`)
99
+ if (!existsSync(srcFile)) {
100
+ s.stop()
101
+ throw new Error(`未找到文件:${srcFile}`)
102
+ }
103
+ // 确保目标目录存在,copySync 会自动创建父目录
104
+ copySync(srcFile, destFile, { overwrite: true })
105
+ s.stop(`已复制:l-global/${folderName}/${fname} -> src/${folderName}/${fname}`)
106
+ }
107
+ return
108
+ }
109
+
110
+ // 否则复制整个文件夹
111
+ s.start(`复制 ${folderName} 文件夹...`)
112
+ if (!existsSync(folderSrc)) {
113
+ s.stop()
114
+ throw new Error(`未找到 l-global/${folderName}:${folderSrc}`)
115
+ }
116
+ copySync(folderSrc, folderDest, { recursive: true, overwrite: true })
117
+ s.stop(`已复制:l-global/${folderName} -> src/${folderName}`)
24
118
  }
25
119
 
26
- if (existsSync(utilsSrc)) {
27
- copySync(utilsSrc, path.join(destBase, "utils"), { recursive: true, overwrite: true })
28
- console.log("已复制:l-global/utils -> src/utils")
29
- } else {
30
- console.warn("未找到 l-global/utils:", utilsSrc)
120
+ // 输出的文件夹
121
+ if (syncFolder.length) {
122
+ for (const e of syncFolder) {
123
+ if (e === "css") {
124
+ // 使用通用函数:传入 cssFiles(可能为空)
125
+ copyFolderOrFiles(moduleBase, "css", destBase, cssFiles)
126
+ continue
127
+ }
128
+ if (e === "utils") {
129
+ // 使用通用函数:传入 utilFiles(可能为空)
130
+ copyFolderOrFiles(moduleBase, "utils", destBase, utilFiles)
131
+ continue
132
+ }
133
+ // less / utils 等按整体复制
134
+ copyFolderOrFiles(moduleBase, e, destBase)
135
+ }
31
136
  }
32
137
  } catch (err) {
33
- console.error("同步出错:", err)
34
- prompts.cancel("同步失败")
138
+ prompts.cancel(`同步失败:${err}`)
35
139
  process.exit(1)
36
140
  }
37
141
 
@@ -44,28 +44,30 @@ pnpm install
44
44
  ### 项目运行
45
45
 
46
46
  ```sh
47
- pnpm run dev || pnpm run serve
47
+ pnpm dev || pnpm serve
48
48
  ```
49
49
 
50
50
  ### 项目打包
51
51
 
52
52
  ```sh
53
- pnpm run build
53
+ pnpm build
54
54
  ```
55
55
 
56
56
  ### 检查和修复文件
57
57
 
58
58
  ```sh
59
- pnpm run lint
59
+ pnpm lint
60
60
  ```
61
61
 
62
- ### 命名规范
63
-
64
- | 类别 | 推荐命名方式 | 示例 | 关键点/例外情况 |
65
- | ------------------ | ----------------------------------------------- | ----------------- | ---------------------- |
66
- | 通用 | kebab-case | package-lock.json | 没有特别说明尽量用这个 |
67
- | 变量 | camelCase | userProfile | |
68
- | 路由名称 | camelCase 或者 PascalCase | userProfile | |
69
- | App.vue | PascalCase | | |
70
- | Vue 组件里的组件名 | PascalCase | | |
71
- | Vue 组件里的 Props | 在声明时使用 camelCase,在模板中使用 kebab-case | | |
62
+ ## 命名规范
63
+
64
+ | 类别 | 推荐命名方式 | 示例 | 关键点/例外情况 |
65
+ | ------------------ | ----------------------------------------------- | -------------------------- | ---------------------- |
66
+ | 通用 | kebab-case | package-lock.json | 没有特别说明尽量用这个 |
67
+ | 路由名称 | kebab-case | user-info | 最通用、最推荐路径命名 |
68
+ | Vue 组件里的组件名 | kebab-case | user-info.vue | |
69
+ | Vue 组件里的 Props | 在声明时使用 camelCase,在模板中使用 kebab-case | | |
70
+ | 方法 / 函数 / 变量 | camelCase | getUserInfo | |
71
+ | 构造函数 / 类 | PascalCase | UserInfo | |
72
+ | 常量 | UPPER_SNAKE_CASE(全大写 + 下划线分隔) | const BASE_API_URL = "xxx" | |
73
+ | 私有属性 / 方法 | \_camelCase(下划线开头 + 小驼峰) | \_userInfo | |
@@ -1,5 +1,5 @@
1
1
  <!DOCTYPE html>
2
- <html lang="">
2
+ <html lang="zh">
3
3
  <head>
4
4
  <meta charset="utf-8" />
5
5
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
@@ -9,10 +9,10 @@
9
9
  </head>
10
10
  <body>
11
11
  <noscript>
12
- <strong
13
- >We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please
14
- enable it to continue.</strong
15
- >
12
+ <strong>
13
+ We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please
14
+ enable it to continue.
15
+ </strong>
16
16
  </noscript>
17
17
  <div id="app"></div>
18
18
  <!-- built files will be auto injected -->
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "explorer.fileNesting.enabled": true,
3
3
  "explorer.fileNesting.patterns": {
4
+ "*.vue": "$(capture).ts, $(capture).*.ts, $(capture).*.js, $(capture).css, $(capture).scss, $(capture).less",
4
5
  "tsconfig.json": "tsconfig.*.json, env.d.ts",
5
6
  "vite.config.*": "jsconfig*, vitest.config.*, cypress.config.*, playwright.config.*",
6
7
  "package.json": "*.env, .env.*, env.d.ts, package-lock.json, pnpm*, .yarnrc*, yarn*, .eslint*, eslint*, .oxlint*, oxlint*, .prettier*, prettier*, .editorconfig, .gitignore, .gitattributes, index.html, .browserslistrc, babel.config.js, jsconfig.json, auto-imports.d.ts, components.d.ts, typed-router.d.ts"
@@ -29,34 +29,35 @@ pnpm install
29
29
  ### 编译和热重载开发
30
30
 
31
31
  ```sh
32
- pnpm run dev || pnpm run serve
32
+ pnpm dev || pnpm serve
33
33
  ```
34
34
 
35
35
  ### 为生产进行类型检查、编译和最小化
36
36
 
37
37
  ```sh
38
- pnpm run build
38
+ pnpm build
39
39
  ```
40
40
 
41
41
  ### eslint检查
42
42
 
43
43
  ```sh
44
- pnpm run lint
44
+ pnpm lint
45
45
  ```
46
46
 
47
47
  ### prettier格式化
48
48
 
49
49
  ```sh
50
- pnpm run format
50
+ pnpm format
51
51
  ```
52
52
 
53
- # 全局
53
+ # 样式
54
54
 
55
- 全局引入 l-global 包,包括 variable.cssbase.cssglobal.css 和 utils 工具类
55
+ 全局 `@/css/index.css` 里面包含了 `theme.css`、`base.css`、`global.css`
56
+ 集成 `unocss` 原子化css
56
57
 
57
58
  # 自动导入
58
59
 
59
- 使用 `unplugin-auto-import` 插件自动导入vuevue-route
60
+ 使用 `unplugin-auto-import` 插件自动导入 `vue`、`vue-route`、`pinia`、`vueuse`
60
61
  使用 `unplugin-auto-import`、`unplugin-vue-components` 插件按需导入element-plus组件
61
62
 
62
63
  # 路由
@@ -65,12 +66,21 @@ pnpm run format
65
66
  加入页面过渡动画
66
67
  封装了全局登录判断的路由卫士
67
68
 
69
+ # 左侧菜单
70
+
71
+ 未整理
72
+
73
+ # 函数式弹窗
74
+
75
+ 未整理
76
+
68
77
  # store仓库
69
78
 
70
79
  使用 `pinia-plugin-persistedstate` 做持久化,默认全部 store 都持久化
71
80
  持久化储存的 `key` 默认加上 `pinia` 前缀
72
81
  默认都存到 `sessionStorage` ,account 的 store 默认改成 `localStorage` 存储
73
82
  如果需要关闭持久化,为单个 store 配置
83
+ 此项目统一采用组合式 `pinia` 写法,选项式 `pinia` 写法也有示例,请自行选择
74
84
 
75
85
  # 布局
76
86
 
@@ -78,7 +88,6 @@ pnpm run format
78
88
 
79
89
  - 上下布局:顶部信息,下左菜单,下右页面
80
90
  - 左右布局:左侧菜单,右上顶部信息,右下页面
81
- - 全屏页面(隐藏顶部信息和菜单):只有页面,没有顶部信息和菜单,可通过快捷键退出全屏页面
82
91
 
83
92
  # 其他
84
93
 
@@ -109,16 +118,18 @@ axios 封装
109
118
  ├── stores # stores
110
119
  ├── views # 页面
111
120
  ├── package.json
112
- ├── package-lock.json
121
+ ├── pnpm-lock.yaml
113
122
  ```
114
123
 
115
124
  ## 命名规范
116
125
 
117
- | 类别 | 推荐命名方式 | 示例 | 关键点/例外情况 |
118
- | ------------------ | ----------------------------------------------- | ----------------- | ---------------------- |
119
- | 通用 | kebab-case | package-lock.json | 没有特别说明尽量用这个 |
120
- | 变量 | camelCase | userProfile | |
121
- | 路由名称 | camelCase 或者 PascalCase | userProfile | |
122
- | App.vue | PascalCase | | |
123
- | Vue 组件里的组件名 | PascalCase | | |
124
- | Vue 组件里的 Props | 在声明时使用 camelCase,在模板中使用 kebab-case | | |
126
+ | 类别 | 推荐命名方式 | 示例 | 关键点/例外情况 |
127
+ | ------------------ | ----------------------------------------------- | -------------------------- | ---------------------- |
128
+ | 通用 | kebab-case | package-lock.json | 没有特别说明尽量用这个 |
129
+ | 路由名称 | kebab-case | user-info | 最通用、最推荐路径命名 |
130
+ | Vue 组件里的组件名 | kebab-case | user-info.vue | |
131
+ | Vue 组件里的 Props | 在声明时使用 camelCase,在模板中使用 kebab-case | | |
132
+ | 方法 / 函数 / 变量 | camelCase | getUserInfo | |
133
+ | 构造函数 / 类 | PascalCase | UserInfo | |
134
+ | 常量 | UPPER_SNAKE_CASE(全大写 + 下划线分隔) | const BASE_API_URL = "xxx" | |
135
+ | 私有属性 / 方法 | \_camelCase(下划线开头 + 小驼峰) | \_userInfo | |