2.31.2 • Published 3 years ago

@yishitec/web v2.31.2

Weekly downloads
53
License
MIT
Repository
github
Last release
3 years ago

@yishitec/web

Install

echo "dist\node_modules" > .gitignore
cnpm i -S @yishitec/web
cnpm i nodemon @vue/cli-service less less-loader sass-loader node-sass vue-template-compiler vue-cli-plugin-style-resources-loader style-resources-loader -D
mkdir server
mkdir server/clients
touch server/clients/index.js
touch server/clients/db.js
mkdir server/services
touch server/services/index.js
mkdir server/apis
touch server/apis/index.js
touch server/index.js
mkdir public
touch public/index.html
touch public/favicon.ico
mkdir src
touch src/main.js
mkdir src/views
touch src/views/Home.vue
mkdir src/assets
mkdir src/assets/images
mkdir src/assets/images/logo
touch src/assets/images/logo/logo-horizontal.png
mkdir src/assets/styles
touch src/assets/styles/app-mixins.scss
touch src/assets/styles/app.scss
mkdir src/components
touch web.d.ts
touch vue.config.js
echo "OK"

Configure eslint

cnpm i -D @vue/cli-plugin-eslint @vue/eslint-config-airbnb babel-eslint eslint eslint-plugin-vue
touch .eslintrc.js

eslintrc.js

module.exports = {
  env: {
    browser: true,
    es6: true,
    node: true,
  },
  extends: ['eslint:recommended', 'plugin:vue/essential'],
  globals: {
    Atomics: 'readonly',
    SharedArrayBuffer: 'readonly',
  },
  parserOptions: {
    ecmaVersion: 2018,
    sourceType: 'module',
  },
  plugins: ['vue'],
  rules: {},
};

package.json

scripts

    "dev:server": "nodemon -w server server/index.js",
    "dev": "npm run dev:server & npm run serve",
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint",
    "start": "node server/index.js"

vue.config.js

const paths = require('path');

module.exports = {
  devServer: {
    proxy: 'http://localhost:3000',
  },
  pluginOptions: {
    'style-resources-loader': {
      preProcessor: 'scss',
      patterns: [
        paths.resolve(__dirname, './src/assets/styles/app-mixins.scss'),
      ],
    },
  },
};

Public/index.html

public/index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width,initial-scale=1.0" />
    <link rel="icon" href="<%= BASE_URL %>favicon.ico" />
    <title>欢迎使用</title>
  </head>
  <body>
    <noscript>
      <strong>
        We're sorry but workspace-chris doesn't work properly without JavaScript
        enabled. Please enable it to continue.
      </strong>
    </noscript>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>

Main

src/main.js

import { main } from '@yishitec/web';
import './assets/styles/app-mixins.scss';
import './assets/styles/app.scss';

import Home from './views/Home.vue';

main({
  routes: [
    {
      component: Home,
      name: 'home',
      path: '/',
      children: [],
    },
  ],
  componentsConfig: {
    common: {
      appName: '欢迎使用',
      appLogo: require('./assets/images/logo/logo-horizontal.png'),
    },
    container: {
      maxWidth: '1100px',
    },
  },
});
  • 修改 appName

放入 Logo 文件 assets/images/logo/logo-horizontal.png

/server/clients/db.js

Variables:

  • {DB_NAME}
const { _, Sequelize, initDb, consts } = require('@yishitec/web/server');

const { Op } = Sequelize;

const ex = {
  Sequelize,
  Op,
  db: {
    db: {},
    models: {},
  },
};

const models = {};

ex.initDb = async () => {
  const res = initDb(
    {
      ...consts.dbConfig,
      constraints: false,
    },
    {
      models,
      associations: [],
    },
  );
  _.extend(ex.db, res);

  await ex.db.db.sync();

  consts.db = ex.db;

  return ex;
};

module.exports = ex;

/server/index.js

const { _, main, consts, utils, moment } = require('@yishitec/web/server');
const services = require('./services');
const { initDb, db, Op } = require('./clients/db');
const apis = require('./apis');

consts.dbConfig = {
  host: consts.env.DB_HOST || 'localhost',
  port: consts.env.DB_PORT || 3306,
  username: consts.env.DB_USERNAME || 'yschris',
  password: consts.env.DB_PASSWORD || 'Welcome@888',
  database: consts.env.DB_DATABASE || 'zeba66',
  debug: false,
};

let requestIndex = 0;

main({
  appName: 'Zeba66Admin',
  port: consts.env.PORT || 3000,
  serverStartup: async () => {
    await utils.withTry(async () => {
      await initDb();
      console.log('DB ready');
    });
    await Promise.all([]);
  },
  routers: router => {
    router.use(async (ctx, next) => {
      const startTime = Date.now();
      requestIndex += 1;
      console.log('req', {
        requestIndex,
        url: ctx.path, // todo
        params: ctx.params,
        query: ctx.request.query,
        body: ctx.request.body,
        time: moment().format('YYYY-MM-DD HH:mm:ss'),
      });
      await next();
      console.log('res', {
        requestIndex,
        duration: Date.now() - startTime,
      });
    });

    router.post('/login', async ctx => {
      const { username, password, appId = 1 } = ctx.request.body;
      if (!username) throw new Error('请输入用户名');
      if (!password) throw new Error('请输入密码');
      const findUser = await db.models.User.findOne({
        where: {
          username,
          password: utils.encodePassword(password),
          appId,
        },
      });
      if (!findUser) throw new Error('账号或密码错误');
      const user = findUser.toJSON();
      delete user.password;
      // eslint-disable-next-line no-param-reassign
      ctx.session.user = user;
      ctx.jsonOk(ctx.session.user);
    });

    const sessionAuth = async (ctx, next) => {
      if (!ctx.session.user) {
        ctx.jsonFail('请先登录', undefined, 401);
        return;
      }
      await next();
    };

    router.post('/whoami', sessionAuth, async ctx => {
      const findUser = await db.models.User.findOne({
        where: {
          id: ctx.session.user.id,
        },
        include: [],
      });
      if (!findUser) {
        // eslint-disable-next-line no-param-reassign
        delete ctx.session.user;
        throw new Error('找不到指定的用户');
      }
      const user = findUser.toJSON();
      // eslint-disable-next-line no-param-reassign
      delete user.password;
      ctx.jsonOk(user);
    });

    router.post('/change-password', sessionAuth, async ctx => {
      const { oldPassword, newPassword, newPassword2 } = ctx.request.body;
      if (!oldPassword) throw new Error('请输入旧密码');
      if (newPassword !== newPassword2) throw new Error('两次新密码输入不一致');
      if (!newPassword) throw new Error('请输入新密码');
      if (newPassword.length < 4)
        throw new Error('为了您的账号安全,密码长度应大于4位');
      await db.db.transaction(async transaction => {
        await db.models.User.update(
          {
            password: utils.encodePassword(newPassword),
          },
          {
            where: {
              id: ctx.session.user.id,
            },
            transaction,
          },
        );
      });
      ctx.jsonOk('OK');
    });

    router.post('/logout', async ctx => {
      // eslint-disable-next-line no-param-reassign
      delete ctx.session.user;
      ctx.jsonOk();
    });

    const syncDb = async () => {
      await db.db.sync({ alter: true });
      console.log('DML synced. ');
    };

    router.get('/migrate/sync', async ctx => {
      await syncDb();
      ctx.jsonOk('OK');
    });

    router.get('/migrate/seed', async ctx => {
      await db.models.User.findOrCreate({
        where: {
          username: 'admin',
          appId: 1,
        },
        defaults: {
          username: 'admin',
          password: utils.encodePassword('admin'),
          appId: 1,
        },
      });
      ctx.jsonOk('OK');
    });
  },
});

Server export dir modules

const { requireDir } = require('@yishitec/web/server');

module.exports = requireDir(__dirname);
  • server/clients/index.j
  • server/services/index.js
  • server/apis/index.js

Verify

npm run dev

Front-end

Exported:

import {
  Vue,
  _, // async-dash
  lodash, // async-dash
  axios,
  moment,
  numeral,
  main,
  views, // see below
  G, // an empty object for global data storage
  formatPrice // numeral: 0,0.00
  containsText, // moment: YYYY-MM-DD HH:mm:ss
  flattenedValues, // flatten, uniq, can apply to object
} from '@yishitec/web';

const {
  LoginView,
  ContainerView,
  PageHeaderView,
  ErrorView,
} = views;

Available components

  • ...element-ui components (available by el- or ui-)
  • ui-page-header
  • ui-media-box
  • ui-placeholder
  • ui-stage
  • ui-container
  • ui-flex
  • ui-admin-table
  • ui-admin-form
  • ui-data-select
  • ui-sub-list
  • ui-datetime-picker
  • ui-logo

Core logics (as Vue mixin)

import { login } from '@yishitec/web/core';

Back-end

Exports:

const {
  main, // uses Koajs
  Logger, // uses pino
  requireDir,
  lodash,
  axios,
  moment,
  numeral,
  _: lodash,
  utils,
  Router, // uses koa-joi-router
  consts, // an object for global data storage with preset properties; see below
  Sequelize,

  initDb, // uses Sequelize
  ensureSeedData,

  useCustomFields,
  useSubList,
  useComments,
} = require('@yishitec/web');

const {
  db = null,
  env, // = process.env
} = consts;

DB model types

    string: 'string',
    datetime: 'datetime',
    int: 'number',
    integer: 'number',
    tag: 'tag',
    select: 'tag',
    password: 'password',
    bool: 'tag',
    hidden: 'hidden',
    file: 'hidden',
2.31.2

3 years ago

2.30.0

3 years ago

2.31.1

3 years ago

2.29.0

3 years ago

2.27.2

3 years ago

2.27.1

3 years ago

2.27.0

3 years ago

2.26.2

3 years ago

2.26.1

3 years ago

2.25.2

3 years ago

2.26.0

3 years ago

2.25.1

3 years ago

2.25.0

4 years ago

2.24.0

4 years ago

2.22.0

4 years ago

2.23.0

4 years ago

2.21.3

4 years ago

2.21.2

4 years ago

2.21.0

4 years ago

2.21.1

4 years ago

2.20.1

4 years ago

2.20.0

4 years ago

2.19.4

4 years ago

2.19.2

4 years ago

2.19.3

4 years ago

2.19.1

4 years ago

2.19.0

4 years ago

2.18.5

4 years ago

2.18.4

4 years ago

2.18.3

4 years ago

1.0.0

4 years ago

2.18.2

4 years ago

2.18.1

4 years ago

2.17.1

4 years ago

2.17.0

4 years ago

2.16.9

4 years ago

2.16.11

4 years ago

2.16.10

4 years ago

2.16.8

4 years ago

2.16.7

4 years ago

2.16.6

4 years ago

2.16.5

4 years ago

2.16.4

4 years ago

2.16.3

4 years ago

2.16.2

4 years ago

2.16.1

4 years ago

2.16.0

4 years ago

2.15.0

4 years ago

2.14.0

4 years ago

2.13.1

4 years ago

2.13.0

4 years ago

2.12.0

4 years ago

2.11.0

4 years ago

2.10.0

4 years ago

2.9.0

4 years ago

2.8.0

4 years ago

2.7.1

4 years ago

2.6.2

4 years ago

2.6.1

4 years ago

2.6.0

4 years ago

2.5.0

4 years ago

2.2.1

4 years ago

2.2.0

4 years ago

2.1.2

4 years ago

2.1.1

4 years ago

2.1.0

4 years ago