├── .browserslistrc ├── .editorconfig ├── .eslintrc.js ├── .gitignore ├── README.md ├── babel.config.js ├── favicon.ico ├── jsconfig.json ├── package.json ├── public ├── favicon.ico └── index.html ├── src ├── App.vue ├── api.js ├── assets │ ├── iconfont │ │ ├── demo.css │ │ ├── demo_index.html │ │ ├── iconfont.css │ │ ├── iconfont.eot │ │ ├── iconfont.js │ │ ├── iconfont.json │ │ ├── iconfont.svg │ │ ├── iconfont.ttf │ │ ├── iconfont.woff │ │ └── iconfont.woff2 │ ├── img │ │ ├── 1.png │ │ ├── 2.png │ │ ├── 3.png │ │ ├── 4.png │ │ ├── 5.png │ │ ├── 6.png │ │ ├── 7.png │ │ ├── 8.png │ │ └── 9.png │ └── logo.png ├── background.js ├── components │ ├── DataSource.vue │ ├── FieldTable.vue │ ├── Generate.vue │ └── ViewFiles.vue ├── localstorage.js ├── main.js ├── mix │ ├── fileData.js │ └── tableData.js ├── router │ └── index.js ├── store │ └── index.js ├── style │ ├── element-variables.scss │ ├── main.css │ └── reset.css └── views │ ├── BuildCode.vue │ ├── DocumentText.vue │ ├── Home.vue │ └── TemplateManagement.vue ├── static ├── componentList.json ├── document │ └── frontCRUD.md └── ejs │ ├── bim │ ├── bimApi │ ├── bimCRUD-弹窗版 │ ├── bimCRUD-弹窗版Api │ ├── bim左右结构 │ ├── bim左右结构-弹窗版 │ ├── bim左右结构-弹窗版Api │ └── bim左右结构Api ├── vue.config.js ├── yarn.lock ├── 前端代码生成器使用说明.md └── 更换模板操作.md /.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | not dead 4 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | [*.{js,jsx,ts,tsx,vue}] 2 | indent_style = space 3 | indent_size = 2 4 | trim_trailing_whitespace = true 5 | insert_final_newline = true 6 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | node: true 5 | }, 6 | extends: [ 7 | 'plugin:vue/essential', 8 | '@vue/standard' 9 | ], 10 | parserOptions: { 11 | parser: 'babel-eslint' 12 | }, 13 | rules: { 14 | 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off', 15 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off' 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | 6 | # local env files 7 | .env.local 8 | .env.*.local 9 | 10 | # Log files 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | pnpm-debug.log* 15 | 16 | # Editor directories and files 17 | .idea 18 | .vscode 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw? 24 | 25 | #Electron-builder output 26 | /dist_electron 27 | 28 | # 生成的数据文件 29 | /static/localConfig.json 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # EasyCode For JavaScript 2 | 3 | # Feature 4 | 5 | - 使用Ejs作为模板, 简单易学 6 | 7 | - 此Ejs中已经内置了lodash.js 更灵活 8 | 9 | - 只要是关于数据库生成的 都能用 10 | 11 | # DevelopmentEnvironment 12 | 13 | - yarn 14 | ``` 15 | yarn 16 | ``` 17 | 18 | - 运行 19 | ``` 20 | yarn electron-serve 21 | ``` 22 | 23 | # ProductionEnvironment 24 | 25 | - github中有Releases可供下载 26 | 27 | - yarn electron-build 28 | 29 | # Use 30 | 31 | ctrl+n 连接数据库 32 | 33 | ctrl+alt+s 设置生成模板目录(默认是桌面,mac、linux生成时会报错,更改生成目录就好了。mac、linux用户生成时请确保权限ok) 34 | 35 | # TODO 36 | 37 | - 后台语言java等模板demo制作 38 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chendonming/easycode-javascript/656b7c777bc7e045f45b0d3365f3dced98b48f6d/favicon.ico -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["src/**/*"], 3 | "target": "es6", 4 | "exclude": ["node_modules"], 5 | "compilerOptions": { 6 | "baseUrl": ".", 7 | "paths": { 8 | "@/*": ["./src/*"] 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "easycode-javascript", 3 | "version": "1.0.21", 4 | "private": false, 5 | "author": "chendm<2283973011@qq.com>", 6 | "description": "一款前端代码生成器", 7 | "scripts": { 8 | "serve": "vue-cli-service serve", 9 | "build": "vue-cli-service build", 10 | "lint": "vue-cli-service lint", 11 | "electron:build": "vue-cli-service electron:build", 12 | "electron:serve": "vue-cli-service electron:serve", 13 | "postinstall": "electron-builder install-app-deps", 14 | "postuninstall": "electron-builder install-app-deps" 15 | }, 16 | "main": "background.js", 17 | "dependencies": { 18 | "core-js": "^3.6.5", 19 | "ejs": "^3.1.5", 20 | "electron-builder": "^22.14.13", 21 | "element-ui": "^2.13.2", 22 | "fs-extra": "^10.0.0", 23 | "github-markdown-css": "^4.0.0", 24 | "lodash": "^4.17.20", 25 | "marked": "^1.2.2", 26 | "monaco-editor": "^0.31.1", 27 | "mysql2": "^2.2.5", 28 | "sass": "^1.27.1", 29 | "sass-loader": "^10.0.4", 30 | "sortablejs": "^1.14.0", 31 | "uuid": "^8.3.1", 32 | "vue": "^2.6.11", 33 | "vue-router": "^3.2.0", 34 | "vuex": "^3.4.0" 35 | }, 36 | "devDependencies": { 37 | "@vue/cli-plugin-babel": "~4.5.0", 38 | "@vue/cli-plugin-eslint": "~4.5.0", 39 | "@vue/cli-plugin-router": "~4.5.0", 40 | "@vue/cli-plugin-vuex": "~4.5.0", 41 | "@vue/cli-service": "~4.5.0", 42 | "@vue/eslint-config-standard": "^5.1.2", 43 | "babel-eslint": "^10.1.0", 44 | "electron": "^9.0.0", 45 | "electron-devtools-installer": "^3.1.0", 46 | "eslint": "^6.7.2", 47 | "eslint-plugin-import": "^2.20.2", 48 | "eslint-plugin-node": "^11.1.0", 49 | "eslint-plugin-promise": "^4.2.1", 50 | "eslint-plugin-standard": "^4.0.0", 51 | "eslint-plugin-vue": "^6.2.2", 52 | "less": "^3.0.4", 53 | "less-loader": "^5.0.0", 54 | "vue-cli-plugin-electron-builder": "~2.0.0-rc.4", 55 | "vue-template-compiler": "^2.6.11" 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chendonming/easycode-javascript/656b7c777bc7e045f45b0d3365f3dced98b48f6d/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | <%= htmlWebpackPlugin.options.title %> 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 24 | 25 | 52 | -------------------------------------------------------------------------------- /src/api.js: -------------------------------------------------------------------------------- 1 | import { app, dialog, ipcMain } from 'electron' 2 | import fs from 'fs' 3 | import mysql from 'mysql2' 4 | import ejs from 'ejs' 5 | import { v4 as uuidv4 } from 'uuid' 6 | import { exec } from 'child_process' 7 | import localstorage from './localstorage' 8 | import path from 'path' 9 | import fsExtra from 'fs-extra' 10 | 11 | function queryAllTables (connection, db) { 12 | return new Promise((resolve, reject) => { 13 | const json = {} 14 | if (connection) { 15 | connection.query(`use \`${db}\``, err => { 16 | if (err) { 17 | json.code = -1 18 | json.msg = '查询数据库失败: ' + err.message 19 | reject(json) 20 | } else { 21 | connection.query('select TABLE_NAME,TABLE_COMMENT from information_schema.tables where TABLE_TYPE = \'BASE TABLE\'', (err, res) => { 22 | if (err) { 23 | json.code = -1 24 | json.msg = '查询数据库失败: ' + err.message 25 | reject(json) 26 | } else { 27 | json.code = 200 28 | json.data = res 29 | resolve(json) 30 | } 31 | }) 32 | } 33 | }) 34 | } else { 35 | json.code = -1 36 | json.msg = '请链接数据库再做此操作' 37 | reject(json) 38 | } 39 | }) 40 | } 41 | 42 | /** 43 | * 根据表名查询字段名称 44 | * @param connection 45 | * @param table 46 | */ 47 | function queryColumns (connection, table) { 48 | return new Promise((resolve, reject) => { 49 | const json = {} 50 | connection.query(`show full columns from \`${table}\``, (err, res) => { 51 | if (err) { 52 | json.code = -1 53 | json.msg = 'err: ' + err.message 54 | reject(json) 55 | } else { 56 | resolve(res) 57 | } 58 | }) 59 | }) 60 | } 61 | 62 | export default function (win, renderer) { 63 | let connection 64 | ipcMain.on('queryTemplateFile', () => { 65 | const path = app.getPath('userData') + '\\template' 66 | fs.access(path, err => { 67 | if (err) { 68 | // 创建文件夹再返回空数据 69 | fs.mkdir(path, err => { 70 | const json = {} 71 | if (err) { 72 | json.code = -1 73 | json.msg = '创建文件夹失败' 74 | } else { 75 | json.code = 200 76 | json.data = [] 77 | } 78 | renderer.send('queryTemplateFile', json) 79 | }) 80 | } else { 81 | fs.readdir(path, (err, fileList) => { 82 | if (err) { 83 | renderer.send('queryTemplateFile', { 84 | code: -1, 85 | msg: '读取文件失败!' 86 | }) 87 | } else { 88 | renderer.send('queryTemplateFile', { 89 | code: 200, 90 | data: fileList.map(v => ({ 91 | title: v, 92 | value: path + '\\' + v 93 | })) 94 | }) 95 | } 96 | }) 97 | } 98 | }) 99 | }) 100 | 101 | ipcMain.on('localTemplateFile', () => { 102 | const folder = path.join(__dirname, '../static/ejs/') 103 | fs.access(folder, err => { 104 | if (!err) { 105 | fs.readdir(folder, (err, fileList) => { 106 | if (!err) { 107 | renderer.send('localTemplateFile', fileList.map(v => ({ 108 | title: v, 109 | value: folder + v 110 | }))) 111 | } 112 | }) 113 | } 114 | }) 115 | }) 116 | 117 | ipcMain.on('loadComponentList', () => { 118 | const file = path.join(__dirname, '../static/componentList.json') 119 | fs.readFile(file, 'utf8', (err, data) => { 120 | if (!err) { 121 | renderer.send('loadComponentList', data) 122 | } 123 | }) 124 | }) 125 | 126 | ipcMain.on('connectToTheDatabase', (e, data) => { 127 | try { 128 | delete data.tryConnection 129 | if (connection) connection.destroy() 130 | connection = mysql.createConnection(data) 131 | connection.ping((err) => { 132 | if (err) { 133 | win.webContents.send('connection.failed', { msg: err.message }) 134 | } else { 135 | win.webContents.send('connection.success') 136 | } 137 | }) 138 | } catch (err) { 139 | win.webContents.send('connection.failed', { msg: err.message }) 140 | } 141 | }) 142 | 143 | ipcMain.on('showDatabase', () => { 144 | const json = {} 145 | if (connection) { 146 | connection.query('show databases', (err, res) => { 147 | if (err) { 148 | json.code = -1 149 | json.msg = '查询数据库失败: ' + err.message 150 | } else { 151 | json.code = 200 152 | json.data = res.map(v => v.Database).filter(v => ['information_schema', 'performance_schema', 'mysql'].indexOf(v) === -1) 153 | } 154 | renderer.send('showDatabase', json) 155 | }) 156 | } else { 157 | json.code = -1 158 | json.msg = '请链接数据库再做此操作' 159 | renderer.send('showDatabase', json) 160 | } 161 | }) 162 | 163 | ipcMain.on('queryAllTables', async (e, db) => { 164 | try { 165 | const data = await queryAllTables(connection, db) 166 | renderer.send('queryAllTables', data) 167 | } catch (err) { 168 | renderer.send('queryAllTables', err) 169 | } 170 | }) 171 | 172 | // 根据Ejs生成实体类文件 (Test) 173 | function generateEjsFile (data, tableName) { 174 | const newTableName = data.tableName ? data.tableName.toLocaleUpperCase() : tableName 175 | const newData = { 176 | ...data, 177 | table: newTableName, 178 | date: new Date().toLocaleDateString(), 179 | className: 'Test' 180 | } 181 | ejs.renderFile(data.templateName, newData, (err, str) => { 182 | if (err) { 183 | renderer.send('generateEntityFiles', { 184 | code: -1, 185 | msg: 'err: ' + err.message 186 | }) 187 | } else { 188 | const fileName = app.getPath('userData') + '\\files\\' + newTableName + '.java' 189 | fs.writeFile(fileName, str, { flag: 'a' }, (err) => { 190 | if (err) { 191 | renderer.send('generateEntityFiles', { 192 | code: -1, 193 | msg: 'err: ' + err.message 194 | }) 195 | } else { 196 | renderer.send('generateEntityFiles', { 197 | code: 200, 198 | data: fileName 199 | }) 200 | } 201 | }) 202 | } 203 | }) 204 | } 205 | 206 | // 生成实体类文件 207 | ipcMain.on('generateEntityFiles', (e, data) => { 208 | if (data.tableName) { 209 | generateEjsFile(data) 210 | } else { 211 | queryAllTables(connection, data.database).then(res => { 212 | if (res.code === 200) { 213 | res.data.forEach(v => { 214 | generateEjsFile(data, v.toLocaleUpperCase()) 215 | }) 216 | } 217 | }) 218 | } 219 | }) 220 | 221 | ipcMain.on('generateCustomFiles', (e, data) => { 222 | // 使用固定文件位置 223 | const setting = localstorage.getItem('setting') 224 | const name = data.name || uuidv4() 225 | let filepath 226 | if (setting && setting.fileGenerationDirectory) { 227 | filepath = setting.fileGenerationDirectory + '\\' + name 228 | } else { 229 | filepath = app.getPath('userData') + '\\' + name 230 | } 231 | ejs.renderFile(data.templateName, { 232 | ...data, 233 | _: require('lodash') 234 | }, (err, str) => { 235 | if (err) { 236 | renderer.send('generateCustomFiles', { 237 | code: -1, 238 | msg: 'err: ' + err.message, 239 | err: err 240 | }) 241 | } else { 242 | if (data.type === 'previewCode') { 243 | // 执行预览 244 | renderer.send('generateCustomFiles', { 245 | code: 200, 246 | data: str, 247 | type: 'previewCode' 248 | }) 249 | } else { 250 | fs.writeFile(filepath + '.' + data.suffix, str, { flag: 'ax' }, (err) => { 251 | if (err) { 252 | renderer.send('generateCustomFiles', { 253 | code: err.code, 254 | err: err 255 | }) 256 | } else { 257 | renderer.send('generateCustomFiles', { 258 | code: 200, 259 | data: filepath + '.' + data.suffix 260 | }) 261 | } 262 | }) 263 | } 264 | } 265 | }) 266 | }) 267 | 268 | // 显示表中所有字段 269 | ipcMain.on('displayField', (e, db, table) => { 270 | const json = {} 271 | if (connection) { 272 | connection.query(`use \`${db}\``, async (err) => { 273 | if (err) { 274 | json.code = -1 275 | json.msg = 'err: ' + err.message 276 | renderer.send('displayField', json) 277 | } else { 278 | if (Object.prototype.toString.call(table) === '[object Array]') { 279 | const jsonArray = [] 280 | for (let i = 0; i < table.length; i++) { 281 | try { 282 | const columns = await queryColumns(connection, table[i]) 283 | jsonArray.push(...columns) 284 | } catch (e) { 285 | renderer.send('displayField', e) 286 | break 287 | } 288 | } 289 | renderer.send('displayField', { 290 | code: 200, 291 | data: jsonArray 292 | }) 293 | } else { 294 | try { 295 | const tables = await queryColumns(connection, table) 296 | renderer.send('displayField', { 297 | code: 200, 298 | data: tables 299 | }) 300 | } catch (e) { 301 | renderer.send('displayField', e) 302 | } 303 | } 304 | } 305 | }) 306 | } else { 307 | json.code = -1 308 | json.msg = '请链接数据库再做此操作' 309 | renderer.send('displayField', json) 310 | } 311 | }) 312 | 313 | // 调用vscode 314 | ipcMain.on('transferCode', (e, data) => { 315 | exec(`code ${data}`) 316 | }) 317 | 318 | // 调用资源管理器 319 | ipcMain.on('transferExplorer', (e, data) => { 320 | exec(`explorer /select,${data}`) 321 | }) 322 | 323 | // 打开文件夹选择框 324 | ipcMain.on('openDirectory', (e, data) => { 325 | const json = dialog.showOpenDialog({ 326 | title: data.title, 327 | properties: ['openDirectory'], 328 | message: '输入框的信息测试' 329 | }) 330 | 331 | json.then(res => { 332 | renderer.send('openDirectory', res.filePaths) 333 | }) 334 | }) 335 | 336 | // 打开文件选择框 337 | ipcMain.on('openFile', (e, data) => { 338 | const json = dialog.showOpenDialog({ 339 | title: data.title, 340 | filters: data.filters, 341 | properties: ['openFile'], 342 | message: '输入框的信息测试' 343 | }) 344 | 345 | json.then(res => { 346 | renderer.send('openFile', res.filePaths) 347 | }) 348 | }) 349 | 350 | // 保存系统设置 351 | ipcMain.on('saveSetting', (e, json) => { 352 | localstorage.setItem('setting', json) 353 | renderer.send('saveSetting', { code: 200 }) 354 | }) 355 | 356 | ipcMain.on('getSetting', () => { 357 | renderer.send('getSetting', localstorage.getItem('setting')) 358 | }) 359 | 360 | ipcMain.on('getKeyValue', () => { 361 | renderer.send('getKeyValue', { 362 | code: 200, 363 | data: localstorage.getItem('keyValue') 364 | }) 365 | }) 366 | 367 | ipcMain.on('saveKeyValue', (e, json) => { 368 | localstorage.setItem('keyValue', json) 369 | }) 370 | 371 | // 保存数据源 372 | ipcMain.on('saveDataSource', (e, json) => { 373 | localstorage.setItem('dataSource', json) 374 | }) 375 | 376 | // 取出数据源 377 | ipcMain.on('getDataSource', () => { 378 | renderer.send('getDataSource', localstorage.getItem('dataSource')) 379 | }) 380 | 381 | // 查询文档 382 | ipcMain.on('consultYourDocumentation', (e, id, filePath) => { 383 | const file = path.join(__dirname, filePath || '../static/document', id) 384 | fs.access(file, err => { 385 | if (!err) { 386 | fs.readFile(file, 'utf8', (err, data) => { 387 | if (!err) { 388 | renderer.send('consultYourDocumentation', data) 389 | } 390 | }) 391 | } 392 | }) 393 | }) 394 | 395 | // 模板管理 - 新增 396 | ipcMain.on('TemplateManagementAdd', (e, data) => { 397 | const uuid = uuidv4() 398 | const picture = path.join(__dirname, '../static/picture', `${uuid}${path.extname(data.picture)}`) 399 | const ejs = path.join(__dirname, '../static/ejs', `${uuid}.ejs`) 400 | // 进行复制操作 401 | Promise.all([fsExtra.copy(data.picture, picture), fsExtra.copy(data.ejs, ejs)]).then(() => { 402 | let templates = localstorage.getItem('templates') 403 | if (!templates) { 404 | localstorage.setItem('templates', []) 405 | templates = [] 406 | } 407 | 408 | templates.push({ 409 | id: uuid, 410 | name: data.name, 411 | picture, 412 | ejs 413 | }) 414 | 415 | localstorage.setItem('templates', templates) 416 | renderer.send('TemplateManagementAdd:success') 417 | }).catch(err => { 418 | renderer.send('TemplateManagementAdd:error', err) 419 | }) 420 | }) 421 | 422 | // 模板管理 - 查询 423 | ipcMain.on('TemplateManagementQuery', () => { 424 | renderer.send('TemplateManagementQuery:success', localstorage.getItem('templates')) 425 | }) 426 | 427 | // 模板管理 - 设置当前模板 428 | ipcMain.on('setCurrentTemp', (e, data) => { 429 | localstorage.setItem('currentTemp', data) 430 | }) 431 | 432 | // 模板管理 - 获取当前模板 433 | ipcMain.on('getCurrentTemp', () => { 434 | renderer.send('getCurrentTemp:success', localstorage.getItem('currentTemp')) 435 | }) 436 | 437 | // 模板管理 - 删除模板 438 | ipcMain.on('TemplateManagementDel', (e, data) => { 439 | const temps = localstorage.getItem('templates').filter(v => v.id !== data.id) 440 | localstorage.setItem('templates', temps) 441 | renderer.send('TemplateManagementDel:success') 442 | }) 443 | 444 | ipcMain.on('close', () => { 445 | win.close() 446 | }) 447 | } 448 | -------------------------------------------------------------------------------- /src/assets/iconfont/demo.css: -------------------------------------------------------------------------------- 1 | /* Logo 字体 */ 2 | @font-face { 3 | font-family: "iconfont logo"; 4 | src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834'); 5 | src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'), 6 | url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'), 7 | url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'), 8 | url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg'); 9 | } 10 | 11 | .logo { 12 | font-family: "iconfont logo"; 13 | font-size: 160px; 14 | font-style: normal; 15 | -webkit-font-smoothing: antialiased; 16 | -moz-osx-font-smoothing: grayscale; 17 | } 18 | 19 | /* tabs */ 20 | .nav-tabs { 21 | position: relative; 22 | } 23 | 24 | .nav-tabs .nav-more { 25 | position: absolute; 26 | right: 0; 27 | bottom: 0; 28 | height: 42px; 29 | line-height: 42px; 30 | color: #666; 31 | } 32 | 33 | #tabs { 34 | border-bottom: 1px solid #eee; 35 | } 36 | 37 | #tabs li { 38 | cursor: pointer; 39 | width: 100px; 40 | height: 40px; 41 | line-height: 40px; 42 | text-align: center; 43 | font-size: 16px; 44 | border-bottom: 2px solid transparent; 45 | position: relative; 46 | z-index: 1; 47 | margin-bottom: -1px; 48 | color: #666; 49 | } 50 | 51 | 52 | #tabs .active { 53 | border-bottom-color: #f00; 54 | color: #222; 55 | } 56 | 57 | .tab-container .content { 58 | display: none; 59 | } 60 | 61 | /* 页面布局 */ 62 | .main { 63 | padding: 30px 100px; 64 | width: 960px; 65 | margin: 0 auto; 66 | } 67 | 68 | .main .logo { 69 | color: #333; 70 | text-align: left; 71 | margin-bottom: 30px; 72 | line-height: 1; 73 | height: 110px; 74 | margin-top: -50px; 75 | overflow: hidden; 76 | *zoom: 1; 77 | } 78 | 79 | .main .logo a { 80 | font-size: 160px; 81 | color: #333; 82 | } 83 | 84 | .helps { 85 | margin-top: 40px; 86 | } 87 | 88 | .helps pre { 89 | padding: 20px; 90 | margin: 10px 0; 91 | border: solid 1px #e7e1cd; 92 | background-color: #fffdef; 93 | overflow: auto; 94 | } 95 | 96 | .icon_lists { 97 | width: 100% !important; 98 | overflow: hidden; 99 | *zoom: 1; 100 | } 101 | 102 | .icon_lists li { 103 | width: 100px; 104 | margin-bottom: 10px; 105 | margin-right: 20px; 106 | text-align: center; 107 | list-style: none !important; 108 | cursor: default; 109 | } 110 | 111 | .icon_lists li .code-name { 112 | line-height: 1.2; 113 | } 114 | 115 | .icon_lists .icon { 116 | display: block; 117 | height: 100px; 118 | line-height: 100px; 119 | font-size: 42px; 120 | margin: 10px auto; 121 | color: #333; 122 | -webkit-transition: font-size 0.25s linear, width 0.25s linear; 123 | -moz-transition: font-size 0.25s linear, width 0.25s linear; 124 | transition: font-size 0.25s linear, width 0.25s linear; 125 | } 126 | 127 | .icon_lists .icon:hover { 128 | font-size: 100px; 129 | } 130 | 131 | .icon_lists .svg-icon { 132 | /* 通过设置 font-size 来改变图标大小 */ 133 | width: 1em; 134 | /* 图标和文字相邻时,垂直对齐 */ 135 | vertical-align: -0.15em; 136 | /* 通过设置 color 来改变 SVG 的颜色/fill */ 137 | fill: currentColor; 138 | /* path 和 stroke 溢出 viewBox 部分在 IE 下会显示 139 | normalize.css 中也包含这行 */ 140 | overflow: hidden; 141 | } 142 | 143 | .icon_lists li .name, 144 | .icon_lists li .code-name { 145 | color: #666; 146 | } 147 | 148 | /* markdown 样式 */ 149 | .markdown { 150 | color: #666; 151 | font-size: 14px; 152 | line-height: 1.8; 153 | } 154 | 155 | .highlight { 156 | line-height: 1.5; 157 | } 158 | 159 | .markdown img { 160 | vertical-align: middle; 161 | max-width: 100%; 162 | } 163 | 164 | .markdown h1 { 165 | color: #404040; 166 | font-weight: 500; 167 | line-height: 40px; 168 | margin-bottom: 24px; 169 | } 170 | 171 | .markdown h2, 172 | .markdown h3, 173 | .markdown h4, 174 | .markdown h5, 175 | .markdown h6 { 176 | color: #404040; 177 | margin: 1.6em 0 0.6em 0; 178 | font-weight: 500; 179 | clear: both; 180 | } 181 | 182 | .markdown h1 { 183 | font-size: 28px; 184 | } 185 | 186 | .markdown h2 { 187 | font-size: 22px; 188 | } 189 | 190 | .markdown h3 { 191 | font-size: 16px; 192 | } 193 | 194 | .markdown h4 { 195 | font-size: 14px; 196 | } 197 | 198 | .markdown h5 { 199 | font-size: 12px; 200 | } 201 | 202 | .markdown h6 { 203 | font-size: 12px; 204 | } 205 | 206 | .markdown hr { 207 | height: 1px; 208 | border: 0; 209 | background: #e9e9e9; 210 | margin: 16px 0; 211 | clear: both; 212 | } 213 | 214 | .markdown p { 215 | margin: 1em 0; 216 | } 217 | 218 | .markdown>p, 219 | .markdown>blockquote, 220 | .markdown>.highlight, 221 | .markdown>ol, 222 | .markdown>ul { 223 | width: 80%; 224 | } 225 | 226 | .markdown ul>li { 227 | list-style: circle; 228 | } 229 | 230 | .markdown>ul li, 231 | .markdown blockquote ul>li { 232 | margin-left: 20px; 233 | padding-left: 4px; 234 | } 235 | 236 | .markdown>ul li p, 237 | .markdown>ol li p { 238 | margin: 0.6em 0; 239 | } 240 | 241 | .markdown ol>li { 242 | list-style: decimal; 243 | } 244 | 245 | .markdown>ol li, 246 | .markdown blockquote ol>li { 247 | margin-left: 20px; 248 | padding-left: 4px; 249 | } 250 | 251 | .markdown code { 252 | margin: 0 3px; 253 | padding: 0 5px; 254 | background: #eee; 255 | border-radius: 3px; 256 | } 257 | 258 | .markdown strong, 259 | .markdown b { 260 | font-weight: 600; 261 | } 262 | 263 | .markdown>table { 264 | border-collapse: collapse; 265 | border-spacing: 0px; 266 | empty-cells: show; 267 | border: 1px solid #e9e9e9; 268 | width: 95%; 269 | margin-bottom: 24px; 270 | } 271 | 272 | .markdown>table th { 273 | white-space: nowrap; 274 | color: #333; 275 | font-weight: 600; 276 | } 277 | 278 | .markdown>table th, 279 | .markdown>table td { 280 | border: 1px solid #e9e9e9; 281 | padding: 8px 16px; 282 | text-align: left; 283 | } 284 | 285 | .markdown>table th { 286 | background: #F7F7F7; 287 | } 288 | 289 | .markdown blockquote { 290 | font-size: 90%; 291 | color: #999; 292 | border-left: 4px solid #e9e9e9; 293 | padding-left: 0.8em; 294 | margin: 1em 0; 295 | } 296 | 297 | .markdown blockquote p { 298 | margin: 0; 299 | } 300 | 301 | .markdown .anchor { 302 | opacity: 0; 303 | transition: opacity 0.3s ease; 304 | margin-left: 8px; 305 | } 306 | 307 | .markdown .waiting { 308 | color: #ccc; 309 | } 310 | 311 | .markdown h1:hover .anchor, 312 | .markdown h2:hover .anchor, 313 | .markdown h3:hover .anchor, 314 | .markdown h4:hover .anchor, 315 | .markdown h5:hover .anchor, 316 | .markdown h6:hover .anchor { 317 | opacity: 1; 318 | display: inline-block; 319 | } 320 | 321 | .markdown>br, 322 | .markdown>p>br { 323 | clear: both; 324 | } 325 | 326 | 327 | .hljs { 328 | display: block; 329 | background: white; 330 | padding: 0.5em; 331 | color: #333333; 332 | overflow-x: auto; 333 | } 334 | 335 | .hljs-comment, 336 | .hljs-meta { 337 | color: #969896; 338 | } 339 | 340 | .hljs-string, 341 | .hljs-variable, 342 | .hljs-template-variable, 343 | .hljs-strong, 344 | .hljs-emphasis, 345 | .hljs-quote { 346 | color: #df5000; 347 | } 348 | 349 | .hljs-keyword, 350 | .hljs-selector-tag, 351 | .hljs-type { 352 | color: #a71d5d; 353 | } 354 | 355 | .hljs-literal, 356 | .hljs-symbol, 357 | .hljs-bullet, 358 | .hljs-attribute { 359 | color: #0086b3; 360 | } 361 | 362 | .hljs-section, 363 | .hljs-name { 364 | color: #63a35c; 365 | } 366 | 367 | .hljs-tag { 368 | color: #333333; 369 | } 370 | 371 | .hljs-title, 372 | .hljs-attr, 373 | .hljs-selector-id, 374 | .hljs-selector-class, 375 | .hljs-selector-attr, 376 | .hljs-selector-pseudo { 377 | color: #795da3; 378 | } 379 | 380 | .hljs-addition { 381 | color: #55a532; 382 | background-color: #eaffea; 383 | } 384 | 385 | .hljs-deletion { 386 | color: #bd2c00; 387 | background-color: #ffecec; 388 | } 389 | 390 | .hljs-link { 391 | text-decoration: underline; 392 | } 393 | 394 | /* 代码高亮 */ 395 | /* PrismJS 1.15.0 396 | https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */ 397 | /** 398 | * prism.js default theme for JavaScript, CSS and HTML 399 | * Based on dabblet (http://dabblet.com) 400 | * @author Lea Verou 401 | */ 402 | code[class*="language-"], 403 | pre[class*="language-"] { 404 | color: black; 405 | background: none; 406 | text-shadow: 0 1px white; 407 | font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; 408 | text-align: left; 409 | white-space: pre; 410 | word-spacing: normal; 411 | word-break: normal; 412 | word-wrap: normal; 413 | line-height: 1.5; 414 | 415 | -moz-tab-size: 4; 416 | -o-tab-size: 4; 417 | tab-size: 4; 418 | 419 | -webkit-hyphens: none; 420 | -moz-hyphens: none; 421 | -ms-hyphens: none; 422 | hyphens: none; 423 | } 424 | 425 | pre[class*="language-"]::-moz-selection, 426 | pre[class*="language-"] ::-moz-selection, 427 | code[class*="language-"]::-moz-selection, 428 | code[class*="language-"] ::-moz-selection { 429 | text-shadow: none; 430 | background: #b3d4fc; 431 | } 432 | 433 | pre[class*="language-"]::selection, 434 | pre[class*="language-"] ::selection, 435 | code[class*="language-"]::selection, 436 | code[class*="language-"] ::selection { 437 | text-shadow: none; 438 | background: #b3d4fc; 439 | } 440 | 441 | @media print { 442 | 443 | code[class*="language-"], 444 | pre[class*="language-"] { 445 | text-shadow: none; 446 | } 447 | } 448 | 449 | /* Code blocks */ 450 | pre[class*="language-"] { 451 | padding: 1em; 452 | margin: .5em 0; 453 | overflow: auto; 454 | } 455 | 456 | :not(pre)>code[class*="language-"], 457 | pre[class*="language-"] { 458 | background: #f5f2f0; 459 | } 460 | 461 | /* Inline code */ 462 | :not(pre)>code[class*="language-"] { 463 | padding: .1em; 464 | border-radius: .3em; 465 | white-space: normal; 466 | } 467 | 468 | .token.comment, 469 | .token.prolog, 470 | .token.doctype, 471 | .token.cdata { 472 | color: slategray; 473 | } 474 | 475 | .token.punctuation { 476 | color: #999; 477 | } 478 | 479 | .namespace { 480 | opacity: .7; 481 | } 482 | 483 | .token.property, 484 | .token.tag, 485 | .token.boolean, 486 | .token.number, 487 | .token.constant, 488 | .token.symbol, 489 | .token.deleted { 490 | color: #905; 491 | } 492 | 493 | .token.selector, 494 | .token.attr-name, 495 | .token.string, 496 | .token.char, 497 | .token.builtin, 498 | .token.inserted { 499 | color: #690; 500 | } 501 | 502 | .token.operator, 503 | .token.entity, 504 | .token.url, 505 | .language-css .token.string, 506 | .style .token.string { 507 | color: #9a6e3a; 508 | background: hsla(0, 0%, 100%, .5); 509 | } 510 | 511 | .token.atrule, 512 | .token.attr-value, 513 | .token.keyword { 514 | color: #07a; 515 | } 516 | 517 | .token.function, 518 | .token.class-name { 519 | color: #DD4A68; 520 | } 521 | 522 | .token.regex, 523 | .token.important, 524 | .token.variable { 525 | color: #e90; 526 | } 527 | 528 | .token.important, 529 | .token.bold { 530 | font-weight: bold; 531 | } 532 | 533 | .token.italic { 534 | font-style: italic; 535 | } 536 | 537 | .token.entity { 538 | cursor: help; 539 | } 540 | -------------------------------------------------------------------------------- /src/assets/iconfont/demo_index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IconFont Demo 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 |

19 | 29 |
30 |
31 |
    32 | 33 |
  • 34 | 35 |
    关 闭
    36 |
    &#xe645;
    37 |
  • 38 | 39 |
40 |
41 |

Unicode 引用

42 |
43 | 44 |

Unicode 是字体在网页端最原始的应用方式,特点是:

45 |
    46 |
  • 兼容性最好,支持 IE6+,及所有现代浏览器。
  • 47 |
  • 支持按字体的方式去动态调整图标大小,颜色等等。
  • 48 |
  • 但是因为是字体,所以不支持多色。只能使用平台里单色的图标,就算项目里有多色图标也会自动去色。
  • 49 |
50 |
51 |

注意:新版 iconfont 支持多色图标,这些多色图标在 Unicode 模式下将不能使用,如果有需求建议使用symbol 的引用方式

52 |
53 |

Unicode 使用步骤如下:

54 |

第一步:拷贝项目下面生成的 @font-face

55 |
@font-face {
 57 |   font-family: 'iconfont';
 58 |   src: url('iconfont.eot');
 59 |   src: url('iconfont.eot?#iefix') format('embedded-opentype'),
 60 |       url('iconfont.woff2') format('woff2'),
 61 |       url('iconfont.woff') format('woff'),
 62 |       url('iconfont.ttf') format('truetype'),
 63 |       url('iconfont.svg#iconfont') format('svg');
 64 | }
 65 | 
66 |

第二步:定义使用 iconfont 的样式

67 |
.iconfont {
 69 |   font-family: "iconfont" !important;
 70 |   font-size: 16px;
 71 |   font-style: normal;
 72 |   -webkit-font-smoothing: antialiased;
 73 |   -moz-osx-font-smoothing: grayscale;
 74 | }
 75 | 
76 |

第三步:挑选相应图标并获取字体编码,应用于页面

77 |
 78 | <span class="iconfont">&#x33;</span>
 80 | 
81 |
82 |

"iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。

83 |
84 |
85 |
86 |
87 |
    88 | 89 |
  • 90 | 91 |
    92 | 关 闭 93 |
    94 |
    .icon-guanbi 95 |
    96 |
  • 97 | 98 |
99 |
100 |

font-class 引用

101 |
102 | 103 |

font-class 是 Unicode 使用方式的一种变种,主要是解决 Unicode 书写不直观,语意不明确的问题。

104 |

与 Unicode 使用方式相比,具有如下特点:

105 |
    106 |
  • 兼容性良好,支持 IE8+,及所有现代浏览器。
  • 107 |
  • 相比于 Unicode 语意明确,书写更直观。可以很容易分辨这个 icon 是什么。
  • 108 |
  • 因为使用 class 来定义图标,所以当要替换图标时,只需要修改 class 里面的 Unicode 引用。
  • 109 |
  • 不过因为本质上还是使用的字体,所以多色图标还是不支持的。
  • 110 |
111 |

使用步骤如下:

112 |

第一步:引入项目下面生成的 fontclass 代码:

113 |
<link rel="stylesheet" href="./iconfont.css">
114 | 
115 |

第二步:挑选相应图标并获取类名,应用于页面:

116 |
<span class="iconfont icon-xxx"></span>
117 | 
118 |
119 |

" 120 | iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。

121 |
122 |
123 |
124 |
125 |
    126 | 127 |
  • 128 | 131 |
    关 闭
    132 |
    #icon-guanbi
    133 |
  • 134 | 135 |
136 |
137 |

Symbol 引用

138 |
139 | 140 |

这是一种全新的使用方式,应该说这才是未来的主流,也是平台目前推荐的用法。相关介绍可以参考这篇文章 141 | 这种用法其实是做了一个 SVG 的集合,与另外两种相比具有如下特点:

142 |
    143 |
  • 支持多色图标了,不再受单色限制。
  • 144 |
  • 通过一些技巧,支持像字体那样,通过 font-size, color 来调整样式。
  • 145 |
  • 兼容性较差,支持 IE9+,及现代浏览器。
  • 146 |
  • 浏览器渲染 SVG 的性能一般,还不如 png。
  • 147 |
148 |

使用步骤如下:

149 |

第一步:引入项目下面生成的 symbol 代码:

150 |
<script src="./iconfont.js"></script>
151 | 
152 |

第二步:加入通用 CSS 代码(引入一次就行):

153 |
<style>
154 | .icon {
155 |   width: 1em;
156 |   height: 1em;
157 |   vertical-align: -0.15em;
158 |   fill: currentColor;
159 |   overflow: hidden;
160 | }
161 | </style>
162 | 
163 |

第三步:挑选相应图标并获取类名,应用于页面:

164 |
<svg class="icon" aria-hidden="true">
165 |   <use xlink:href="#icon-xxx"></use>
166 | </svg>
167 | 
168 |
169 |
170 | 171 |
172 |
173 | 192 | 193 | 194 | -------------------------------------------------------------------------------- /src/assets/iconfont/iconfont.css: -------------------------------------------------------------------------------- 1 | @font-face {font-family: "iconfont"; 2 | src: url('iconfont.eot?t=1603964335884'); /* IE9 */ 3 | src: url('iconfont.eot?t=1603964335884#iefix') format('embedded-opentype'), /* IE6-IE8 */ 4 | url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAK0AAsAAAAABlwAAAJpAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCCcApocwE2AiQDCAsGAAQgBYRtBzAbmQXILjF2bRABpltYSC4tKDJ5CgNKHhE87Uebt7tnqtWzaBJMQ7nQIEEikTopkPFM/vu/pimgMLV5viyrCBX6g/wDzuUKz8M2ZzajSchNuPUEzxCgZghRZAYbcIGuMKhvOmgT5xonJdkQSitstp1XUQW2Yf03eVH5ewMup78CCmQeUG5zDFwDMMEA98IoslLJG8YueIGPCTQa1ZQ7nm8PUFXYqwLx3rE0qBbCisJy9UJtw8EiPqtRnz6m8Sn6fvyzGfUkNZndcPZyZsLwZ05BvtptQIgQ0PEaZCwDhbhqTJ8oCMYuaEwXTYJj1QY/W1WBVRzVJNhfZ1c3g2EofiaJJ33U6gRK4h4CetOkH0JqaX14I85BueKZH0ce2pckJS9h1dmYePRHDR9+uGzq08OPa/+Df7JxfOaIaTzcXGAfoDJ/zcoh2F2r/fuozf/1TQV837xEwcpimBfU780T/BXJwKFiyGxLKpqk0ZsMTVqZ0KgRFdjf6W+qvucW8qFez41464xkyOpNk4W1jBpNtlGr3h4aLVkcb9KFFURpwKI7QGj3jqTVN2TtfsjC+kWNXv+o1R4ZjW6CC5vMxpt6TJqQibqFDhOFyrVJPa7dkZX5GudlEedEnDox7K2ul3MLComX2JLqVl9UhUqOApyD58j3I4zlyCVD2rYq8aCz9rLpTW1DCKDuCCMaQUxId4MchkhIBZNFvfL5HWLJ+DTc0VYXPiEs5UyPetq6A8iFOhzU9iivpM4sfUIoSGGRAJqDecTni6C4eZ6LGESbPSEZG+g449RQdXt7bfADRawL25DCmZXVvsq0UHcAAAA=') format('woff2'), 5 | url('iconfont.woff?t=1603964335884') format('woff'), 6 | url('iconfont.ttf?t=1603964335884') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */ 7 | url('iconfont.svg?t=1603964335884#iconfont') format('svg'); /* iOS 4.1- */ 8 | } 9 | 10 | .iconfont { 11 | font-family: "iconfont" !important; 12 | font-size: 16px; 13 | font-style: normal; 14 | -webkit-font-smoothing: antialiased; 15 | -moz-osx-font-smoothing: grayscale; 16 | } 17 | 18 | .icon-guanbi:before { 19 | content: "\e645"; 20 | } 21 | 22 | -------------------------------------------------------------------------------- /src/assets/iconfont/iconfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chendonming/easycode-javascript/656b7c777bc7e045f45b0d3365f3dced98b48f6d/src/assets/iconfont/iconfont.eot -------------------------------------------------------------------------------- /src/assets/iconfont/iconfont.js: -------------------------------------------------------------------------------- 1 | !function(e){var t,n,o,i,a,d,c='',l=(l=document.getElementsByTagName("script"))[l.length-1].getAttribute("data-injectcss");if(l&&!e.__iconfont__svg__cssinject__){e.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(e){console&&console.log(e)}}function s(){a||(a=!0,o())}t=function(){var e,t,n,o;(o=document.createElement("div")).innerHTML=c,c=null,(n=o.getElementsByTagName("svg")[0])&&(n.setAttribute("aria-hidden","true"),n.style.position="absolute",n.style.width=0,n.style.height=0,n.style.overflow="hidden",e=n,(t=document.body).firstChild?(o=e,(n=t.firstChild).parentNode.insertBefore(o,n)):t.appendChild(e))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(t,0):(n=function(){document.removeEventListener("DOMContentLoaded",n,!1),t()},document.addEventListener("DOMContentLoaded",n,!1)):document.attachEvent&&(o=t,i=e.document,a=!1,(d=function(){try{i.documentElement.doScroll("left")}catch(e){return void setTimeout(d,50)}s()})(),i.onreadystatechange=function(){"complete"==i.readyState&&(i.onreadystatechange=null,s())})}(window); -------------------------------------------------------------------------------- /src/assets/iconfont/iconfont.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "2166494", 3 | "name": "EasyCode", 4 | "font_family": "iconfont", 5 | "css_prefix_text": "icon-", 6 | "description": "", 7 | "glyphs": [ 8 | { 9 | "icon_id": "9255860", 10 | "name": "关 闭", 11 | "font_class": "guanbi", 12 | "unicode": "e645", 13 | "unicode_decimal": 58949 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /src/assets/iconfont/iconfont.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | Created by iconfont 9 | 10 | 11 | 12 | 13 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/assets/iconfont/iconfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chendonming/easycode-javascript/656b7c777bc7e045f45b0d3365f3dced98b48f6d/src/assets/iconfont/iconfont.ttf -------------------------------------------------------------------------------- /src/assets/iconfont/iconfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chendonming/easycode-javascript/656b7c777bc7e045f45b0d3365f3dced98b48f6d/src/assets/iconfont/iconfont.woff -------------------------------------------------------------------------------- /src/assets/iconfont/iconfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chendonming/easycode-javascript/656b7c777bc7e045f45b0d3365f3dced98b48f6d/src/assets/iconfont/iconfont.woff2 -------------------------------------------------------------------------------- /src/assets/img/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chendonming/easycode-javascript/656b7c777bc7e045f45b0d3365f3dced98b48f6d/src/assets/img/1.png -------------------------------------------------------------------------------- /src/assets/img/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chendonming/easycode-javascript/656b7c777bc7e045f45b0d3365f3dced98b48f6d/src/assets/img/2.png -------------------------------------------------------------------------------- /src/assets/img/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chendonming/easycode-javascript/656b7c777bc7e045f45b0d3365f3dced98b48f6d/src/assets/img/3.png -------------------------------------------------------------------------------- /src/assets/img/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chendonming/easycode-javascript/656b7c777bc7e045f45b0d3365f3dced98b48f6d/src/assets/img/4.png -------------------------------------------------------------------------------- /src/assets/img/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chendonming/easycode-javascript/656b7c777bc7e045f45b0d3365f3dced98b48f6d/src/assets/img/5.png -------------------------------------------------------------------------------- /src/assets/img/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chendonming/easycode-javascript/656b7c777bc7e045f45b0d3365f3dced98b48f6d/src/assets/img/6.png -------------------------------------------------------------------------------- /src/assets/img/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chendonming/easycode-javascript/656b7c777bc7e045f45b0d3365f3dced98b48f6d/src/assets/img/7.png -------------------------------------------------------------------------------- /src/assets/img/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chendonming/easycode-javascript/656b7c777bc7e045f45b0d3365f3dced98b48f6d/src/assets/img/8.png -------------------------------------------------------------------------------- /src/assets/img/9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chendonming/easycode-javascript/656b7c777bc7e045f45b0d3365f3dced98b48f6d/src/assets/img/9.png -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chendonming/easycode-javascript/656b7c777bc7e045f45b0d3365f3dced98b48f6d/src/assets/logo.png -------------------------------------------------------------------------------- /src/background.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | import { app, protocol, BrowserWindow, Menu } from 'electron' 4 | import { createProtocol } from 'vue-cli-plugin-electron-builder/lib' 5 | import api from './api' 6 | 7 | // import installExtension, { VUEJS_DEVTOOLS } from 'electron-devtools-installer' 8 | const isDevelopment = process.env.NODE_ENV !== 'production' 9 | 10 | // Keep a global reference of the window object, if you don't, the window will 11 | // be closed automatically when the JavaScript object is garbage collected. 12 | // eslint-disable-next-line no-unused-vars 13 | let win 14 | 15 | // Scheme must be registered before the app is ready 16 | protocol.registerSchemesAsPrivileged([ 17 | { 18 | scheme: 'app', 19 | privileges: { 20 | secure: true, 21 | standard: true 22 | } 23 | } 24 | ]) 25 | 26 | function createWindow () { 27 | // Create the browser window. 28 | win = new BrowserWindow({ 29 | width: 1320, 30 | height: 730, 31 | webPreferences: { 32 | // Use pluginOptions.nodeIntegration, leave this alone 33 | // See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration for more info 34 | nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION, 35 | webSecurity: false 36 | }, 37 | show: false, 38 | frame: false 39 | }) 40 | 41 | //= ==========自定义file:///协议的解析======================= 42 | protocol.interceptFileProtocol('file', (req, callback) => { 43 | const url = req.url.substr(8) 44 | callback(decodeURI(url)) 45 | }, (error) => { 46 | if (error) { 47 | console.error('Failed to register protocol') 48 | } 49 | }) 50 | 51 | if (process.env.WEBPACK_DEV_SERVER_URL) { 52 | // Load the url of the dev server if in development mode 53 | win.loadURL(process.env.WEBPACK_DEV_SERVER_URL) 54 | if (!process.env.IS_TEST) win.webContents.openDevTools() 55 | } else { 56 | createProtocol('app') 57 | // Load the index.html when not in development 58 | win.loadURL('app://./index.html') 59 | } 60 | 61 | win.on('closed', () => { 62 | win = null 63 | }) 64 | 65 | win.on('ready-to-show', () => { 66 | win.show() 67 | }) 68 | } 69 | 70 | // Quit when all windows are closed. 71 | app.on('window-all-closed', () => { 72 | // On macOS it is common for applications and their menu bar 73 | // to stay active until the user quits explicitly with Cmd + Q 74 | if (process.platform !== 'darwin') { 75 | app.quit() 76 | } 77 | }) 78 | 79 | app.on('activate', () => { 80 | // On macOS it's common to re-create a window in the app when the 81 | // dock icon is clicked and there are no other windows open. 82 | if (win === null) { 83 | createWindow() 84 | } 85 | }) 86 | 87 | // This method will be called when Electron has finished 88 | // initialization and is ready to create browser windows. 89 | // Some APIs can only be used after this event occurs. 90 | app.on('ready', async () => { 91 | if (isDevelopment && !process.env.IS_TEST) { 92 | // Install Vue Devtools 93 | // try { 94 | // await installExtension(VUEJS_DEVTOOLS) 95 | // } catch (e) { 96 | // console.error('Vue Devtools failed to install:', e.toString()) 97 | // } 98 | } 99 | const template = [ 100 | { 101 | label: '&Connection', 102 | submenu: [ 103 | { 104 | label: '连接数据库', 105 | accelerator: 'ctrl+n', 106 | click () { 107 | win.webContents.send('connection') 108 | } 109 | }, 110 | { 111 | label: '&Settings', 112 | accelerator: 'ctrl+alt+s', 113 | click () { 114 | win.webContents.send('settings') 115 | } 116 | } 117 | ] 118 | }, 119 | { 120 | label: '&Authority', 121 | submenu: [ 122 | { 123 | label: '创建账号', 124 | click () { 125 | win.webContents.send('openPermissions') 126 | } 127 | }, 128 | { 129 | label: '创建便签', 130 | click () { 131 | let newWin = new BrowserWindow({ 132 | webPreferences: { 133 | // Use pluginOptions.nodeIntegration, leave this alone 134 | // See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration for more info 135 | nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION 136 | }, 137 | width: 200, 138 | height: 300, 139 | frame: false, 140 | x: 1600, 141 | y: 100 142 | }) 143 | 144 | if (process.env.WEBPACK_DEV_SERVER_URL) { 145 | // Load the url of the dev server if in development mode 146 | newWin.loadURL(process.env.WEBPACK_DEV_SERVER_URL + '#/Note') 147 | } else { 148 | createProtocol('app') 149 | // Load the index.html when not in development 150 | newWin.loadURL('app://./index.html/#/Note') 151 | } 152 | 153 | newWin.on('closed', () => { 154 | newWin = null 155 | }) 156 | 157 | newWin.on('ready-to-show', () => { 158 | newWin.show() 159 | }) 160 | } 161 | } 162 | ] 163 | }, 164 | { 165 | label: '&Window', 166 | submenu: [{ role: 'minimize' }, { role: 'zoom' }, { role: 'close' }] 167 | }, 168 | { 169 | label: '&File', 170 | submenu: [{ role: 'quit' }] 171 | }, 172 | { 173 | label: '&About', 174 | submenu: [ 175 | { 176 | label: '前端CRUD', 177 | submenu: [ 178 | { 179 | label: '使用手册', 180 | click () { 181 | win.webContents.send('about', { 182 | id: 'frontCRUD.md', 183 | title: '前端CRUD手册' 184 | }) 185 | } 186 | } 187 | ] 188 | }, 189 | { 190 | role: 'about' 191 | } 192 | ] 193 | } 194 | ] 195 | 196 | const menu = Menu.buildFromTemplate(template) 197 | Menu.setApplicationMenu(menu) 198 | 199 | createWindow() 200 | api(win, win.webContents) 201 | }) 202 | 203 | // Exit cleanly on request from parent process in development mode. 204 | if (isDevelopment) { 205 | if (process.platform === 'win32') { 206 | process.on('message', data => { 207 | if (data === 'graceful-exit') { 208 | app.quit() 209 | } 210 | }) 211 | } else { 212 | process.on('SIGTERM', () => { 213 | app.quit() 214 | }) 215 | } 216 | } 217 | -------------------------------------------------------------------------------- /src/components/DataSource.vue: -------------------------------------------------------------------------------- 1 | 81 | 82 | 199 | 200 | 203 | -------------------------------------------------------------------------------- /src/components/FieldTable.vue: -------------------------------------------------------------------------------- 1 | 86 | 87 | 176 | 177 | 180 | -------------------------------------------------------------------------------- /src/components/Generate.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 142 | 143 | 173 | -------------------------------------------------------------------------------- /src/components/ViewFiles.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 68 | 69 | 74 | -------------------------------------------------------------------------------- /src/localstorage.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /** 4 | * 读取本地配置 5 | */ 6 | const fs = require('fs') 7 | const path = require('path') 8 | /** 9 | * 判断配置文件是否存在 10 | */ 11 | function isExit () { 12 | let success = true 13 | if (!(localConfig.config && typeof localConfig.config === 'object')) { 14 | success = initConfig() 15 | } 16 | return success 17 | } 18 | /** 19 | * 初始化config 20 | */ 21 | function initConfig () { 22 | try { 23 | const config = readConfig() 24 | if (config) { 25 | localConfig.config = JSON.parse(config) 26 | return true 27 | } 28 | const defaultConfig = {} 29 | const content = JSON.stringify(defaultConfig) 30 | fs.writeFileSync(localConfig.configUrl, content) 31 | localConfig.config = defaultConfig 32 | return true 33 | } catch (e) { 34 | return false 35 | } 36 | } 37 | /** 38 | * 读取文件 39 | */ 40 | function readConfig () { 41 | try { 42 | return fs.readFileSync(localConfig.configUrl) 43 | } catch (error) { 44 | return false 45 | } 46 | } 47 | /** 48 | * 写入文件 49 | */ 50 | function writeConfig (value) { 51 | try { 52 | const content = JSON.stringify(value) 53 | fs.writeFileSync(localConfig.configUrl, content) 54 | return true 55 | } catch (e) { 56 | return false 57 | } 58 | } 59 | 60 | const localConfig = { 61 | config: null, 62 | configUrl: path.join(__dirname, '../static/localConfig.json'), 63 | setStoragePath: (path) => { 64 | localConfig.configUrl = path 65 | }, 66 | getStoragePath: () => { 67 | return localConfig.configUrl 68 | }, 69 | getItem: (key) => { 70 | const success = isExit() 71 | if (success) { 72 | const result = localConfig.config[key] 73 | return result || '' 74 | } 75 | return null 76 | }, 77 | setItem: (key, value) => { 78 | const success = isExit() 79 | if (success) { 80 | const config = Object.assign({}, localConfig.config) 81 | config[key] = value 82 | const suc = writeConfig(config) 83 | if (suc) { 84 | localConfig.config = config 85 | return true 86 | } 87 | } 88 | return false 89 | }, 90 | getAll: () => { 91 | const success = isExit() 92 | if (success) { 93 | return localConfig.config 94 | } 95 | return null 96 | }, 97 | removeItem: (key) => { 98 | const value = localConfig.getItem(key) 99 | if (value) { 100 | const config = Object.assign({}, localConfig.config) 101 | delete config[key] 102 | const suc = writeConfig(config) 103 | if (suc) { 104 | localConfig.config = config 105 | return true 106 | } 107 | } 108 | return false 109 | }, 110 | clear: () => { 111 | const success = isExit() 112 | if (success) { 113 | const suc = writeConfig({}) 114 | if (suc) { 115 | localConfig.config = {} 116 | return true 117 | } 118 | } 119 | return false 120 | } 121 | } 122 | 123 | module.exports = localConfig 124 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | import router from './router' 4 | import store from './store' 5 | import ElementUI from 'element-ui' 6 | import '@/style/element-variables.scss' 7 | import '@/style/reset.css' 8 | import '@/assets/iconfont/iconfont.css' 9 | import '@/style/main.css' 10 | 11 | Vue.config.productionTip = false 12 | Vue.use(ElementUI, { 13 | size: 'small' 14 | }) 15 | 16 | new Vue({ 17 | router, 18 | store, 19 | render: h => h(App) 20 | }).$mount('#app') 21 | -------------------------------------------------------------------------------- /src/mix/fileData.js: -------------------------------------------------------------------------------- 1 | export default { 2 | computed: { 3 | fileList: { 4 | get () { return this.$store.state.fileList }, 5 | set (val) { this.$store.commit('setFileList', val) } 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/mix/tableData.js: -------------------------------------------------------------------------------- 1 | export default { 2 | computed: { 3 | tableDataHide: { 4 | get () { return this.$store.state.tableDataHide }, 5 | set (val) { this.$store.commit('setTableDataHide', val) } 6 | }, 7 | tableData: { 8 | get () { return this.$store.state.tableData }, 9 | set (val) { this.$store.commit('setTableData', val) } 10 | }, 11 | rememberKey: { 12 | get () { return this.$store.state.rememberKey }, 13 | set (val) { this.$store.commit('setRememberKey', val) } 14 | }, 15 | kdata: { 16 | get () { return this.$store.state.kdata }, 17 | set (val) { this.$store.commit('setKdata', val) } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import VueRouter from 'vue-router' 3 | import Home from '../views/Home.vue' 4 | 5 | Vue.use(VueRouter) 6 | 7 | const routes = [ 8 | { 9 | path: '/', 10 | component: Home, 11 | children: [ 12 | { 13 | path: '/BuildCode', 14 | component: () => import('@/views/BuildCode.vue') 15 | }, 16 | { 17 | path: '/TemplateManagement', 18 | component: () => import('@/views/TemplateManagement.vue') 19 | } 20 | ] 21 | }, 22 | { 23 | path: '/DocumentText', 24 | component: () => import('@/views/DocumentText') 25 | } 26 | ] 27 | 28 | const router = new VueRouter({ 29 | routes 30 | }) 31 | 32 | export default router 33 | -------------------------------------------------------------------------------- /src/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | 4 | Vue.use(Vuex) 5 | 6 | export default new Vuex.Store({ 7 | state: { 8 | // 是否连接数据库 9 | connection: false, 10 | primaryColor: '#409eff', 11 | successColor: '#67c23a', 12 | warningColor: '#e6a23c', 13 | dangerColor: '#f56c6c', 14 | infoColor: '#909399', 15 | title: 'EasyCode', 16 | 17 | tableDataHide: null, 18 | tableData: [], 19 | localFile: '', 20 | fileList: [], 21 | rememberKey: true, 22 | kdata: [], 23 | 24 | // 当前使用的模板<模板管理> 25 | currentTemplate: null 26 | }, 27 | mutations: { 28 | setCurrentTemplate (state, temp) { 29 | state.currentTemplate = temp 30 | }, 31 | setKdata (state, data) { 32 | state.kdata = data 33 | }, 34 | setRememberKey (state, key) { 35 | state.rememberKey = key 36 | }, 37 | setFileList (state, fileList) { 38 | state.fileList = fileList 39 | }, 40 | setLocalFile (state, localFile) { 41 | state.localFile = localFile 42 | }, 43 | setTableData (state, tableData) { 44 | state.tableData = tableData.map(v => { 45 | if (!v.component) { 46 | v.component = 'input' 47 | } 48 | return v 49 | }) 50 | }, 51 | setTableDataHide (state, tableDataHide) { 52 | state.tableDataHide = tableDataHide 53 | }, 54 | setTitle (state, title) { 55 | state.title = title 56 | }, 57 | setPrimaryColor (state, color) { 58 | state.primaryColor = color 59 | }, 60 | setSuccessColor (state, color) { 61 | state.successColor = color 62 | }, 63 | setWarningColor (state, color) { 64 | state.warningColor = color 65 | }, 66 | setDangerColor (state, color) { 67 | state.dangerColor = color 68 | }, 69 | setInfoColor (state, color) { 70 | state.infoColor = color 71 | }, 72 | setConnection (state, bool) { 73 | state.connection = bool 74 | } 75 | }, 76 | getters: { 77 | connection: state => state.connection, 78 | primaryColor: state => state.primaryColor, 79 | successColor: state => state.successColor, 80 | warningColor: state => state.warningColor, 81 | dangerColor: state => state.dangerColor, 82 | infoColor: state => state.infoColor, 83 | title: state => state.title, 84 | tableDataHide: state => state.tableDataHide, 85 | tableData: state => state.tableData 86 | }, 87 | actions: {}, 88 | modules: {} 89 | }) 90 | -------------------------------------------------------------------------------- /src/style/element-variables.scss: -------------------------------------------------------------------------------- 1 | :root { 2 | --primary: teal; 3 | --success: #67c23a; 4 | --warning: #e6a23c; 5 | --danger: #f56c6c; 6 | --info: #909399; 7 | } 8 | 9 | 10 | /* 改变主题色变量 */ 11 | $--color-primary: teal; 12 | 13 | $--color-success: #67c23a; 14 | 15 | $--color-warning: #e6a23c; 16 | 17 | $--color-danger: #f56c6c; 18 | 19 | $--color-info: #909399; 20 | 21 | 22 | /* 改变 icon 字体路径变量,必需 */ 23 | $--font-path: '~element-ui/lib/theme-chalk/fonts'; 24 | 25 | @import "~element-ui/packages/theme-chalk/src/index"; 26 | -------------------------------------------------------------------------------- /src/style/main.css: -------------------------------------------------------------------------------- 1 | .df { 2 | display: flex; 3 | } 4 | 5 | .tac { 6 | text-align: center; 7 | } 8 | 9 | .tal { 10 | text-align: left; 11 | } 12 | 13 | .center { 14 | justify-content: center; 15 | } 16 | 17 | .vcenter { 18 | align-items: center; 19 | } 20 | 21 | .p10 { 22 | padding: 10px; 23 | } 24 | 25 | .pt10 { 26 | padding-top: 10px; 27 | } 28 | 29 | .ptb10 { 30 | padding: 10px 0; 31 | } 32 | 33 | .lr10 { 34 | padding: 0 10px; 35 | } 36 | -------------------------------------------------------------------------------- /src/style/reset.css: -------------------------------------------------------------------------------- 1 | /* http://meyerweb.com/eric/tools/css/reset/ 2 | v2.0 | 20110126 3 | License: none (public domain) 4 | */ 5 | 6 | html, body, div, span, applet, object, iframe, 7 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 8 | a, abbr, acronym, address, big, cite, code, 9 | del, dfn, em, img, ins, kbd, q, s, samp, 10 | small, strike, strong, sub, sup, tt, var, 11 | b, u, i, center, 12 | dl, dt, dd, ol, ul, li, 13 | fieldset, form, label, legend, 14 | table, caption, tbody, tfoot, thead, tr, th, td, 15 | article, aside, canvas, details, embed, 16 | figure, figcaption, footer, header, hgroup, 17 | menu, nav, output, ruby, section, summary, 18 | time, mark, audio, video { 19 | margin: 0; 20 | padding: 0; 21 | border: 0; 22 | font-size: 100%; 23 | font: inherit; 24 | vertical-align: baseline; 25 | } 26 | 27 | /* HTML5 display-role reset for older browsers */ 28 | article, aside, details, figcaption, figure, 29 | footer, header, hgroup, menu, nav, section { 30 | display: block; 31 | } 32 | 33 | body { 34 | line-height: 1; 35 | } 36 | 37 | ol, ul { 38 | list-style: none; 39 | } 40 | 41 | blockquote, q { 42 | quotes: none; 43 | } 44 | 45 | blockquote:before, blockquote:after, 46 | q:before, q:after { 47 | content: ''; 48 | content: none; 49 | } 50 | 51 | table { 52 | border-collapse: collapse; 53 | border-spacing: 0; 54 | } 55 | 56 | .el-form-item__content { 57 | text-align: left; 58 | } 59 | 60 | .atag { 61 | color: #409EFF; 62 | cursor: pointer; 63 | } 64 | 65 | ::-webkit-scrollbar-track { 66 | border-radius: 10px; 67 | box-shadow: inset 0 0 6px rgba(0, 0, 0, 0); 68 | -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0); 69 | } 70 | 71 | ::-webkit-scrollbar-thumb { 72 | background-color: rgba(0, 0, 0, 0.05); 73 | border-radius: 10px; 74 | box-shadow: inset 1px 1px 0 rgba(0, 0, 0, 0.1); 75 | -webkit-box-shadow: inset 1px 1px 0 rgba(0, 0, 0, 0.1); 76 | } 77 | 78 | ::-webkit-scrollbar-thumb { 79 | background-color: rgba(0, 0, 0, 0.2); 80 | border-radius: 10px; 81 | box-shadow: inset 1px 1px 0 rgba(0, 0, 0, 0.1); 82 | -webkit-box-shadow: inset 1px 1px 0 rgba(0, 0, 0, 0.1); 83 | } 84 | 85 | ::-webkit-scrollbar { 86 | width: 16px; 87 | height: 16px; 88 | } 89 | 90 | ::-webkit-scrollbar-track, 91 | ::-webkit-scrollbar-thumb { 92 | border-radius: 999px; 93 | border: 5px solid transparent; 94 | } 95 | 96 | ::-webkit-scrollbar-track { 97 | box-shadow: 1px 1px 5px rgba(144, 146, 152, 0.3) inset; 98 | } 99 | 100 | ::-webkit-scrollbar-thumb { 101 | min-height: 20px; 102 | background-clip: content-box; 103 | box-shadow: 0 0 0 5px rgba(144, 146, 152, 0.3) inset; 104 | } 105 | 106 | ::-webkit-scrollbar-corner { 107 | background: transparent; 108 | } 109 | -------------------------------------------------------------------------------- /src/views/BuildCode.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 61 | 62 | 81 | -------------------------------------------------------------------------------- /src/views/DocumentText.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 56 | 57 | 75 | -------------------------------------------------------------------------------- /src/views/Home.vue: -------------------------------------------------------------------------------- 1 | 76 | 77 | 271 | 272 | 347 | -------------------------------------------------------------------------------- /src/views/TemplateManagement.vue: -------------------------------------------------------------------------------- 1 | 42 | 43 | 181 | 182 | 232 | -------------------------------------------------------------------------------- /static/componentList.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "1输入框", 4 | "value": "input" 5 | }, 6 | { 7 | "name": "2字典下拉框", 8 | "value": "select" 9 | }, 10 | { 11 | "name": "3文本框", 12 | "value": "text" 13 | }, 14 | { 15 | "name": "4数字框", 16 | "value": "number" 17 | }, 18 | { 19 | "name": "5日期选择器", 20 | "value": "date" 21 | }, 22 | { 23 | "name": "6日期时间选择器", 24 | "value": "datetime" 25 | }, 26 | { 27 | "name": "7附件上传", 28 | "value": "upload" 29 | }, 30 | { 31 | "name": "8选择树", 32 | "value": "treeselect" 33 | } 34 | ] 35 | -------------------------------------------------------------------------------- /static/document/frontCRUD.md: -------------------------------------------------------------------------------- 1 | # 前端 CRUD 使用手册 2 | 3 | ## 编写 ejs 4 | 5 | ejs 是一门 javascript 编写的高效模板引擎 6 | 7 | ejs 入门, 请看https://ejs.bootcss.com/#install 8 | 9 | ## 可使用变量 10 | 11 | ```ts 12 | interface CRUD { 13 | insertList: Array // 新增字段集合 14 | queryList: Array // 查询字段集合 15 | searchList: Array // 搜索字段集合 16 | suffix: string // 后缀 17 | templateName: string // 模板地址 18 | _: Object // lodash对象, 可以在ejs中使用lodash!! 19 | } 20 | 21 | // 字段信息 22 | interface Field { 23 | Collation: string, 24 | Comment: string, // 注释 25 | Default: string, // 默认值 26 | Field: string, // 字段名 27 | Key: string, // 键名 28 | Null: string, // 是否可为空 29 | Privileges: string, // 权限 30 | Type: string // 类型 31 | } 32 | ``` 33 | 34 | ## 可使用方法 35 | 36 | ### lodash 37 | 38 | lodash作为前端最受欢迎的工具库,里面有着许多方便的方法,而有的一些也已经成为了Javascript标准! 39 | 40 | lodash是一个一致性、模块化、高性能的 JavaScript 实用工具库! 41 | 42 | 在ejs里面可以使用lodash的所有方法! 43 | 44 | 比如: 把字符串转成驼峰命名: 45 | ```js 46 | _.camelCase(data.Field) 47 | ``` 48 | 49 | 首字母大写: 50 | ```js 51 | _.capitalize(data.Field) 52 | ``` 53 | 54 | 转为kebabCase写法: 55 | ```js 56 | _.kebabCase(data.Field) 57 | ``` 58 | 59 | 学习了解lodash https://www.lodashjs.com/ 60 | 61 | 62 | 还可以使用 JavaScript 的所有方法, 学习 JavaScript: 63 | 64 | https://developer.mozilla.org/zh-CN/docs/Learn/JavaScript 65 | -------------------------------------------------------------------------------- /static/ejs/bim: -------------------------------------------------------------------------------- 1 | <%# Bim工程前端生成模板 -%> 2 | <%# t: "新增项目" r: "必填字段 用英文逗号隔开" kp: "主键字段" -%> 3 | <%# 重置字典使用`code + 序号 : 字典值` -%> 4 | <%_ function getKey(key) { return kdata.filter(v => v.key === key)[0].value } -%> 5 | <%_ function getRequire(keys) { var arr = keys.split(','); var newArr = []; arr.forEach(v => { newArr.push(...insertList.filter(vv => vv.index==v)); }); return newArr; } -%> 6 | <%_ function filterSelect() { return insertList.filter(v => v.component === 'select').map(v => _.camelCase(v.Field) + 'List') } -%> 7 | <%_ function filterUpload() { return insertList.filter(v => v.component === 'upload') } -%> 8 | <%_ function filterTreeSelect() { return insertList.filter(v => v.component === 'treeselect').map(v => _.camelCase(v.Field) + 'Options') } -%> 9 | <%_ var getDicCode = (() => { var json = {}; kdata.filter(v => v.key.indexOf('code') === 0).forEach(v => { var serialNumber = v.key.substring(4); var key = insertList.filter(vv => vv.index == serialNumber)[0].Field; json[key] = v.value }); return json })() -%> 10 | <%_ function A(str) { return _.capitalize(str) } -%> 11 | <%_ function B(str) { return _.lowerFirst(str) } -%> 12 | <%_ var name = getKey('name'); -%> 13 | 275 | 276 | 414 | -------------------------------------------------------------------------------- /static/ejs/bimApi: -------------------------------------------------------------------------------- 1 | <%# 这是前端vue ejs模板 API文件生成 -%> 2 | <%# 具体参数要求: name: "当前页面名称", api: "api前缀 例如/pm/baseproject/" -%> 3 | <%# 将首写字母大写,其余小写 -%> 4 | <%_ function A(str) { return _.capitalize(str) } -%> 5 | <%_ function getKey(key) { return kdata.filter(v => v.key === key)[0].value } -%> 6 | <%_ var api = getKey('api');var name = getKey('name'); -%> 7 | import request from '@/utils/request' 8 | 9 | export function list<%=A(name) %>(query) { 10 | return request({ 11 | url: '<%=api -%>list', 12 | method: 'get', 13 | params: query 14 | }) 15 | } 16 | 17 | export function get<%=A(name) %>(<%=A(name) %>Id) { 18 | return request({ 19 | url: '<%=api -%>info/' + <%=A(name) %>Id, 20 | method: 'get' 21 | }) 22 | } 23 | 24 | 25 | export function add<%=A(name) %>(data) { 26 | return request({ 27 | url: '<%=api -%>save', 28 | method: 'post', 29 | data: data 30 | }) 31 | } 32 | 33 | export function update<%=A(name) %>(data) { 34 | return request({ 35 | url: '<%=api -%>update', 36 | method: 'put', 37 | data: data 38 | }) 39 | } 40 | 41 | export function del<%=A(name) %>(data) { 42 | return request({ 43 | url: '<%=api -%>delete', 44 | method: 'delete', 45 | data: data 46 | }) 47 | } 48 | -------------------------------------------------------------------------------- /static/ejs/bimCRUD-弹窗版: -------------------------------------------------------------------------------- 1 | <%# Bim工程前端生成模板 -%> 2 | <%# t: "新增项目" r: "必填字段 用英文逗号隔开" kp: "主键字段" -%> 3 | <%# 重置字典使用`code + 序号 : 字典值` -%> 4 | <%_ function getKey(key) { return kdata.filter(v => v.key === key)[0].value } -%> 5 | <%_ function getRequire(keys) { var arr = keys.split(','); var newArr = []; arr.forEach(v => { newArr.push(...insertList.filter(vv => vv.index==v)); }); return newArr; } -%> 6 | <%_ function filterSelect() { return insertList.filter(v => v.component === 'select').map(v => _.camelCase(v.Field) + 'List') } -%> 7 | <%_ function filterUpload() { return insertList.filter(v => v.component === 'upload') } -%> 8 | <%_ function filterTreeSelect() { return insertList.filter(v => v.component === 'treeselect').map(v => _.camelCase(v.Field) + 'Options') } -%> 9 | <%_ var getDicCode = (() => { var json = {}; kdata.filter(v => v.key.indexOf('code') === 0).forEach(v => { var serialNumber = v.key.substring(4); var key = insertList.filter(vv => vv.index == serialNumber)[0].Field; json[key] = v.value }); return json })() -%> 10 | <%_ function A(str) { return _.capitalize(str) } -%> 11 | <%_ function B(str) { return _.lowerFirst(str) } -%> 12 | <%_ var name = getKey('name'); -%> 13 | 145 | 146 | 284 | -------------------------------------------------------------------------------- /static/ejs/bimCRUD-弹窗版Api: -------------------------------------------------------------------------------- 1 | <%# 这是前端vue ejs模板 API文件生成 -%> 2 | <%# 具体参数要求: name: "当前页面名称", api: "api前缀 例如/pm/baseproject/" -%> 3 | <%# 将首写字母大写,其余小写 -%> 4 | <%_ function A(str) { return _.capitalize(str) } -%> 5 | <%_ function getKey(key) { return kdata.filter(v => v.key === key)[0].value } -%> 6 | <%_ var api = getKey('api');var name = getKey('name'); -%> 7 | import request from '@/utils/request' 8 | 9 | export function list<%=A(name) %>(query) { 10 | return request({ 11 | url: '<%=api -%>list', 12 | method: 'get', 13 | params: query 14 | }) 15 | } 16 | 17 | export function get<%=A(name) %>(<%=A(name) %>Id) { 18 | return request({ 19 | url: '<%=api -%>info/' + <%=A(name) %>Id, 20 | method: 'get' 21 | }) 22 | } 23 | 24 | 25 | export function add<%=A(name) %>(data) { 26 | return request({ 27 | url: '<%=api -%>save', 28 | method: 'post', 29 | data: data 30 | }) 31 | } 32 | 33 | export function update<%=A(name) %>(data) { 34 | return request({ 35 | url: '<%=api -%>update', 36 | method: 'put', 37 | data: data 38 | }) 39 | } 40 | 41 | export function del<%=A(name) %>(data) { 42 | return request({ 43 | url: '<%=api -%>delete', 44 | method: 'delete', 45 | data: data 46 | }) 47 | } 48 | -------------------------------------------------------------------------------- /static/ejs/bim左右结构: -------------------------------------------------------------------------------- 1 | <%# Bim工程前端生成模板 -%> 2 | <%# t: "新增项目" r: "必填字段 用英文逗号隔开" kp: "主键字段" -%> 3 | <%# 重置字典使用`code + 序号 : 字典值` -%> 4 | <%_ function getKey(key) { return kdata.filter(v => v.key === key)[0].value } -%> 5 | <%_ function getRequire(keys) { var arr = keys.split(','); var newArr = []; arr.forEach(v => { newArr.push(...insertList.filter(vv => vv.index==v)); }); return newArr; } -%> 6 | <%_ function filterSelect() { return insertList.filter(v => v.component === 'select').map(v => _.camelCase(v.Field) + 'List') } -%> 7 | <%_ function filterUpload() { return insertList.filter(v => v.component === 'upload') } -%> 8 | <%_ function filterTreeSelect() { return insertList.filter(v => v.component === 'treeselect').map(v => _.camelCase(v.Field) + 'Options') } -%> 9 | <%_ var getDicCode = (() => { var json = {}; kdata.filter(v => v.key.indexOf('code') === 0).forEach(v => { var serialNumber = v.key.substring(4); var key = insertList.filter(vv => vv.index == serialNumber)[0].Field; json[key] = v.value }); return json })() -%> 10 | <%_ function A(str) { return _.capitalize(str) } -%> 11 | <%_ function B(str) { return _.lowerFirst(str) } -%> 12 | <%_ var name = getKey('name'); -%> 13 | 288 | 289 | 444 | -------------------------------------------------------------------------------- /static/ejs/bim左右结构-弹窗版: -------------------------------------------------------------------------------- 1 | <%# Bim工程前端生成模板 -%> 2 | <%# t: "新增项目" r: "必填字段 用英文逗号隔开" kp: "主键字段" -%> 3 | <%# 重置字典使用`code + 序号 : 字典值` -%> 4 | <%_ function getKey(key) { return kdata.filter(v => v.key === key)[0].value } -%> 5 | <%_ function getRequire(keys) { var arr = keys.split(','); var newArr = []; arr.forEach(v => { newArr.push(...insertList.filter(vv => vv.index==v)); }); return newArr; } -%> 6 | <%_ function filterSelect() { return insertList.filter(v => v.component === 'select').map(v => _.camelCase(v.Field) + 'List') } -%> 7 | <%_ function filterUpload() { return insertList.filter(v => v.component === 'upload') } -%> 8 | <%_ function filterTreeSelect() { return insertList.filter(v => v.component === 'treeselect').map(v => _.camelCase(v.Field) + 'Options') } -%> 9 | <%_ var getDicCode = (() => { var json = {}; kdata.filter(v => v.key.indexOf('code') === 0).forEach(v => { var serialNumber = v.key.substring(4); var key = insertList.filter(vv => vv.index == serialNumber)[0].Field; json[key] = v.value }); return json })() -%> 10 | <%_ function A(str) { return _.capitalize(str) } -%> 11 | <%_ function B(str) { return _.lowerFirst(str) } -%> 12 | <%_ var name = getKey('name'); -%> 13 | 158 | 159 | 314 | -------------------------------------------------------------------------------- /static/ejs/bim左右结构-弹窗版Api: -------------------------------------------------------------------------------- 1 | <%# 这是前端vue ejs模板 API文件生成 -%> 2 | <%# 具体参数要求: name: "当前页面名称", api: "api前缀 例如/pm/baseproject/" -%> 3 | <%# 将首写字母大写,其余小写 -%> 4 | <%_ function A(str) { return _.capitalize(str) } -%> 5 | <%_ function getKey(key) { return kdata.filter(v => v.key === key)[0].value } -%> 6 | <%_ var api = getKey('api');var name = getKey('name'); -%> 7 | import request from '@/utils/request' 8 | 9 | export function list<%=A(name) %>(query) { 10 | return request({ 11 | url: '<%=api -%>list', 12 | method: 'get', 13 | params: query 14 | }) 15 | } 16 | 17 | export function get<%=A(name) %>(<%=A(name) %>Id) { 18 | return request({ 19 | url: '<%=api -%>info/' + <%=A(name) %>Id, 20 | method: 'get' 21 | }) 22 | } 23 | 24 | 25 | export function add<%=A(name) %>(data) { 26 | return request({ 27 | url: '<%=api -%>save', 28 | method: 'post', 29 | data: data 30 | }) 31 | } 32 | 33 | export function update<%=A(name) %>(data) { 34 | return request({ 35 | url: '<%=api -%>update', 36 | method: 'put', 37 | data: data 38 | }) 39 | } 40 | 41 | export function del<%=A(name) %>(data) { 42 | return request({ 43 | url: '<%=api -%>delete', 44 | method: 'delete', 45 | data: data 46 | }) 47 | } 48 | -------------------------------------------------------------------------------- /static/ejs/bim左右结构Api: -------------------------------------------------------------------------------- 1 | <%# 这是前端vue ejs模板 API文件生成 -%> 2 | <%# 具体参数要求: name: "当前页面名称", api: "api前缀 例如/pm/baseproject/" -%> 3 | <%# 将首写字母大写,其余小写 -%> 4 | <%_ function A(str) { return _.capitalize(str) } -%> 5 | <%_ function getKey(key) { return kdata.filter(v => v.key === key)[0].value } -%> 6 | <%_ var api = getKey('api');var name = getKey('name'); -%> 7 | import request from '@/utils/request' 8 | 9 | export function list<%=A(name) %>(query) { 10 | return request({ 11 | url: '<%=api -%>list', 12 | method: 'get', 13 | params: query 14 | }) 15 | } 16 | 17 | export function get<%=A(name) %>(<%=A(name) %>Id) { 18 | return request({ 19 | url: '<%=api -%>info/' + <%=A(name) %>Id, 20 | method: 'get' 21 | }) 22 | } 23 | 24 | 25 | export function add<%=A(name) %>(data) { 26 | return request({ 27 | url: '<%=api -%>save', 28 | method: 'post', 29 | data: data 30 | }) 31 | } 32 | 33 | export function update<%=A(name) %>(data) { 34 | return request({ 35 | url: '<%=api -%>update', 36 | method: 'put', 37 | data: data 38 | }) 39 | } 40 | 41 | export function del<%=A(name) %>(data) { 42 | return request({ 43 | url: '<%=api -%>delete', 44 | method: 'delete', 45 | data: data 46 | }) 47 | } 48 | -------------------------------------------------------------------------------- /vue.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | pluginOptions: { 3 | electronBuilder: { 4 | nodeIntegration: true, 5 | builderOptions: { 6 | appId: 'com.chendm.easycode-javascript.1.0.0', 7 | productName: 'EasyCode', 8 | copyright: 'Copyright © 2020', 9 | directories: { 10 | output: './dist' 11 | }, 12 | extraResources: ['./static/**'], 13 | buildVersion: '1.0.0', 14 | nsis: { 15 | createDesktopShortcut: true, 16 | createStartMenuShortcut: true 17 | }, 18 | win: { 19 | icon: 'favicon.ico', 20 | target: [ 21 | { 22 | target: 'nsis', 23 | arch: [ 24 | 'x64', 25 | 'ia32' 26 | ] 27 | } 28 | ] 29 | } 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /前端代码生成器使用说明.md: -------------------------------------------------------------------------------- 1 | # 前端代码生成器使用说明 2 | 3 | - 连接数据库 4 | 点击标题,选择`连接数据库` 5 | 6 | ![1](./src/assets/img/3.png) 7 | 8 | 输入相关信息, 点击确定, 点击`前端CRUD生成` 9 | 10 | ![1](./src/assets/img/4.png) 11 | 12 | - 选择数据库 13 | 14 | ![1](./src/assets/img/1.png) 15 | 16 | - 选择表 17 | 18 | ![2](./src/assets/img/2.png) 19 | 20 | 会自动出现表字段 21 | 22 | - 信息说明 23 | 24 | ![2](./src/assets/img/5.png) 25 | 26 | insert复选框代表新增时需要展示的字段 27 | search复选框代表搜索时需要的字段 28 | query复选框代表table需要展示的字段 29 | 上移和下移可以移动字段,新增和table的字段展示顺序和`序号`相关 30 | 31 | - 设置属性 32 | `设置属性`需要设置一些模板需要的属性,下面就以`bim`模板为例 33 | ``` 34 | t: "新增项目" ( 新增按钮的文字 ) 35 | r: "必填字段序号 用英文逗号隔开" 36 | kp: "主键字段" 37 | name: "当前页面名称", 38 | api: "api前缀 例如/pm/baseproject/" 39 | ``` 40 | > **这些参数可以是模板所需要的,而模板的参数是约定的,并不是软件**所要求的。 41 | 如图所示 42 | 43 | ![2](./src/assets/img/6.png) 44 | 45 | - 选择Ejs模板 46 | 47 | ![2](./src/assets/img/7.png) 48 | 49 | - 生成 50 | 51 | 文件名: 生成的文件名 52 | 53 | 其他地方和图片中一致即可 54 | 55 | ![2](./src/assets/img/8.png) 56 | 57 | - 模板存放位置 58 | 59 | `c:\用户名\appData\Local\Programs\easycode-javascript\resources\static\ejs` 60 | 61 | - Ejs模板学习 62 | 63 | ![2](./src/assets/img/9.png) 64 | 65 | -------------------------------------------------------------------------------- /更换模板操作.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chendonming/easycode-javascript/656b7c777bc7e045f45b0d3365f3dced98b48f6d/更换模板操作.md --------------------------------------------------------------------------------