# 一、 user表字段设计

字段名 数据类型及描述

默认值

字段含义

id INTEGER(20).UNSIGNED
主键、自增长、UNSIGNED无符号
主键id
uuid string(36)唯一用户标识 用户ID(UUID)
username STRING(50)唯一登录账号 登录账号
password STRING(255) 加密密码
nickname STRING(50) '' 用户昵称
avatar STRING(1000) 如:https://docs-51yrc-com.oss-cn-hangzhou.aliyuncs.com/
chat/user.jpg
头像地址(本地、网络图片地址)
... 随着业务需求增加字段
devicefingeruuid STRING(200) '' 设备标识(游客标识)
uniplatform STRING(100) '' 平台类型(web/mp-weixin/app))
devicemodel STRING(100) '' 设备型号(统计用)
deviceos STRING(100) '' 操作系统(统计用)
devicebrand STRING(100) '' 设备品牌(统计用)
userset text '' 用户设置
invite_confirm TINYINT(1) 0 是否需要用户确认才能加为好友(0-不需要 1- 需要用户确认 2-其他情况)
... 随着业务需求增加字段
mobile STRING(20) NULL 手机号
email STRING(100) NULL 邮箱
last_login DATE NULL 最后登录时间
last_login_ip STRING(45) NULL 最后登录IP
register_time DATE CURRENT_TIMESTAMP 注册时间
register_ip STRING(45) NULL 注册IP
is_deleted TINYINT(1) 0 软删除标记
wechat_openid STRING(128) NULL 微信OpenID
qq_openid STRING(128) NULL QQ OpenID
weibo_uid STRING(128) NULL 微博UID
role STRING(20) 'user' 用户角色
is_email_verified TINYINT(1) 0 邮箱验证状态
is_mobile_verified TINYINT(1) 0 手机验证状态
status TINYINT(1) 1 用户状态(0-禁用 1-正常 2-锁定)
order int(11) 50 排序,默认50
create_time DATE CURRENT_TIMESTAMP 数据创建时间
update_time DATE CURRENT_TIMESTAMP 更新时间
  1. 直接在phpMyAdmin中根据表字段设计创建表,或者通过数据库插件写sql语句创建表。
  2. 通过迁移命名创建user表:
  1. 创建迁移文件 命令:
npx sequelize migration:generate --name=user
  1. 创建迁移文件 user.js,内容如下:
'use strict';

module.exports = {
  async up(queryInterface, Sequelize) {
    const { INTEGER, STRING, DATE, TINYINT, ENUM, TEXT } = Sequelize;
    await queryInterface.createTable('user', {
      id: {
        type: INTEGER(20).UNSIGNED,
        primaryKey: true,
        autoIncrement: true,
        comment: '主键ID'
      },
      uuid: {
        type: STRING(36),
        allowNull: false,
        unique: true,
        comment: '用户UUID'
      },
      username: {
        type: STRING(50),
        allowNull: false,
        unique: true,
        comment: '登录账号'
      },
      password: { 
        type: STRING(255),
        allowNull: false,
        comment: '加密密码'
      },
      nickname: {
        type: STRING(50),
        allowNull: false,
        defaultValue: '',
        comment: '用户昵称'
      },
      avatar : { 
        type: STRING(1000), 
        allowNull: true, 
        defaultValue: 'https://docs-51yrc-com.oss-cn-hangzhou.aliyuncs.com/chat/user.jpg', 
        comment: '用户头像(本地、网络图片地址)' 
      },
      devicefingeruuid: {
        type: STRING(200),
        unique: true,
        allowNull: false,
        defaultValue: '',
        comment: '设备标识(游客标识)'
      },
      uniplatform: {
        type: STRING(100),
        allowNull: false,
        defaultValue: '',
        comment: '平台类型(web/mp-weixin/app)等'
      },
      devicemodel: {
        type: STRING(100),
        allowNull: false,
        defaultValue: '',
        comment: '设备型号'
      },
      deviceos: {
        type: STRING(100),
        allowNull: false,
        defaultValue: '',
        comment: '操作系统'
      },
      devicebrand: {
        type: STRING(100),
        allowNull: false,
        defaultValue: '',
        comment: '设备品牌'
      },
      userset: {
        type: TEXT,
        allowNull: false,
        defaultValue: '',
        comment: '用户设置'
      },
      invite_confirm: {
        type: TINYINT(1),
        allowNull: false,
        defaultValue: 0,
        comment: '是否需要用户确认才能加为好友(0-不需要 1- 需要用户确认 2-其他情况)'
      },
      mobile: {
        type: STRING(20),
        unique: true,
        comment: '手机号'
      },
      email: {
        type: STRING(100),
        unique: true,
        comment: '邮箱'
      },
      status: {
        type: TINYINT(1),
        allowNull: false,
        defaultValue: 1,
        comment: '用户状态 1:启用,0:禁用'
      },
      last_login: {
        type: DATE,
        comment: '最后登录时间'
      },
      last_login_ip: {
        type: STRING(45),
        comment: '最后登录IP'
      },
      register_time: {
        type: DATE,
        allowNull: false,
        defaultValue: Sequelize.literal('CURRENT_TIMESTAMP'),
        comment: '注册时间'
      },
      register_ip: {
        type: STRING(45),
        comment: '注册IP'
      },
      is_deleted: {
        type: TINYINT(1),
        allowNull: false,
        defaultValue: 0,
        comment: '软删除标记'
      },
      wechat_openid: {
        type: STRING(128),
        unique: true,
        comment: '微信OpenID'
      },
      qq_openid: {
        type: STRING(128),
        unique: true,
        comment: 'QQ OpenID'
      },
      weibo_uid: {
        type: STRING(128),
        unique: true,
        comment: '微博UID'
      },
      role: {
        type: STRING(20),
        allowNull: false,
        defaultValue: 'user',
        comment: '用户角色'
      },
      is_email_verified: {
        type: TINYINT(1),
        allowNull: false,
        defaultValue: 0,
        comment: '邮箱验证'
      },
      is_mobile_verified: {
        type: TINYINT(1),
        allowNull: false,
        defaultValue: 0,
        comment: '手机验证'
      },
      order: {
        type: INTEGER,//不限定长度.默认int(11)
        allowNull: true,
        defaultValue: 50,
        comment: '排序,默认50'
      },
      // sex: { type: ENUM, values: ['男','女','保密'], allowNull: true, defaultValue: '保密', comment: '留言用户性别'},
      create_time: {type: DATE, allowNull: false, defaultValue:Sequelize.fn('NOW')},
      update_time: {
        type: DATE,
        allowNull: false,
        defaultValue: Sequelize.literal('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'),
        comment: '更新时间'
      },
    });

    // 添加索引优化查询
    await queryInterface.addIndex('user', ['uuid']);
    await queryInterface.addIndex('user', ['username']);
    await queryInterface.addIndex('user', ['devicefingeruuid']);
    await queryInterface.addIndex('user', ['mobile']);
    await queryInterface.addIndex('user', ['email']);
  },

  async down(queryInterface) {
    await queryInterface.dropTable('user');
  }
};
  1. 执行迁移文件命令生成数据库表:
// 创建数据库
npx sequelize db:migrate
// 如果有问题需要回滚,可以通过 `db:migrate:undo` 回退一个变更
npx sequelize db:migrate:undo
// 可以通过 `db:migrate:undo:all` 回退到初始状态
npx sequelize db:migrate:undo:all

# user表模型

app/model/user.js

'use strict';
//哈希函数 
const crypto = require('node:crypto');
// 引入 uuid 库 `npm install uuid`
const { v4: uuidv4 } = require('uuid'); 

module.exports = app => {
    const { INTEGER, STRING, DATE, TINYINT, ENUM, TEXT } = app.Sequelize;

    const User = app.model.define('user', {
        id: {
            type: INTEGER(20).UNSIGNED,
            primaryKey: true,
            autoIncrement: true,
            comment: '主键ID'
        },
        uuid: {
            type: STRING(36),
            allowNull: false,
            unique: true,
            comment: '用户UUID',
            defaultValue: () => uuidv4(), // 自动生成 UUID
        },
        username: {
            type: STRING(50),
            allowNull: false,
            unique: true,
            comment: '登录账号'
        },
        password: {
            type: STRING(255),
            allowNull: false,
            comment: '加密密码',
            set(val) {
                //'sha256'加密
                let hash = crypto.createHash('sha256', app.config.crypto.secret); //或者md5
                hash.update(val);
                let result = hash.digest('hex');
                // console.log(result);
                this.setDataValue('password', result);
            }
        },
        nickname: {
            type: STRING(50),
            allowNull: false,
            defaultValue: '',
            comment: '用户昵称'
        },
        avatar: {
            type: STRING(1000),
            allowNull: true,
            defaultValue: 'https://docs-51yrc-com.oss-cn-hangzhou.aliyuncs.com/chat/user.jpg',
            comment: '用户头像(本地、网络图片地址)'
        },
        devicefingeruuid: {
          type: STRING(200),
          unique: true,
          allowNull: false,
          defaultValue: '',
          comment: '设备标识(游客标识)'
        },
        uniplatform: {
          type: STRING(100),
          allowNull: false,
          defaultValue: '',
          comment: '平台类型(web/mp-weixin/app)等'
        },
        devicemodel: {
          type: STRING(100),
          allowNull: false,
          defaultValue: '',
          comment: '设备型号'
        },
        deviceos: {
          type: STRING(100),
          allowNull: false,
          defaultValue: '',
          comment: '操作系统'
        },
        devicebrand: {
          type: STRING(100),
          allowNull: false,
          defaultValue: '',
          comment: '设备品牌'
        },
        userset: {
          type: TEXT,
          allowNull: false,
          defaultValue: '',
          comment: '用户设置'
        },
        invite_confirm: {
          type: TINYINT(1),
          allowNull: false,
          defaultValue: 0,
          comment: '是否需要用户确认才能加为好友(0-不需要 1- 需要用户确认 2-其他情况)'
        },
        mobile: {
            type: STRING(20),
            unique: true,
            comment: '手机号'
        },
        email: {
            type: STRING(100),
            unique: true,
            comment: '邮箱'
        },
        status: {
            type: TINYINT(1),
            allowNull: false,
            defaultValue: 1,
            comment: '用户状态 1:启用,0:禁用'
        },
        last_login: {
            type: DATE,
            comment: '最后登录时间'
        },
        last_login_ip: {
            type: STRING(45),
            comment: '最后登录IP'
        },
        register_time: {
            type: DATE,
            allowNull: false,
            defaultValue: app.Sequelize.literal('CURRENT_TIMESTAMP'),
            comment: '注册时间'
        },
        register_ip: {
            type: STRING(45),
            comment: '注册IP'
        },
        is_deleted: {
            type: TINYINT(1),
            allowNull: false,
            defaultValue: 0,
            comment: '软删除标记'
        },
        wechat_openid: {
            type: STRING(128),
            unique: true,
            comment: '微信OpenID'
        },
        qq_openid: {
            type: STRING(128),
            unique: true,
            comment: 'QQ OpenID'
        },
        weibo_uid: {
            type: STRING(128),
            unique: true,
            comment: '微博UID'
        },
        role: {
            type: STRING(20),
            allowNull: false,
            defaultValue: 'user',
            comment: '用户角色'
        },
        is_email_verified: {
            type: TINYINT(1),
            allowNull: false,
            defaultValue: 0,
            comment: '邮箱验证'
        },
        is_mobile_verified: {
            type: TINYINT(1),
            allowNull: false,
            defaultValue: 0,
            comment: '手机验证'
        },
        order: {
            type: INTEGER,//不限定长度.默认int(11)
            allowNull: true,
            defaultValue: 50,
            comment: '排序,默认50'
        },
        // sex: { type: ENUM, values: ['男','女','保密'], allowNull: true, defaultValue: '保密', comment: '留言用户性别'},
        create_time: {
            type: DATE,
            allowNull: false,
            defaultValue: app.Sequelize.fn('NOW'),
            get() {
                return app.formatTime(this.getDataValue('create_time'));
            }
        },
        update_time: { type: DATE, allowNull: false, defaultValue: app.Sequelize.fn('NOW') },
    });

    return User;
}

# 二、 user_info表字段设计

字段名 数据类型及描述

默认值

字段含义

id INTEGER(20).UNSIGNED
主键、自增长、UNSIGNED无符号
主键id
user_id INTEGER(20).UNSIGNED 外键关联user.id 用户ID
gender ENUM('male','female','unknown') 'unknown' 性别
birthday DATE NULL 出生日期
bio STRING(200) NULL 个人简介
location STRING(100) NULL 所在地
website STRING(255) NULL 个人网站
order int(11) 50 排序,默认50
create_time DATE CURRENT_TIMESTAMP 数据创建时间
update_time DATE CURRENT_TIMESTAMP 更新时间
  1. 直接在phpMyAdmin中根据表字段设计创建表,或者通过数据库插件写sql语句创建表。
  2. 通过迁移命名创建user_info表:
  1. 创建迁移文件 命令:
npx sequelize migration:generate --name=user_info
  1. 创建迁移文件 user_info.js,内容如下:
'use strict';

module.exports = {
  async up(queryInterface, Sequelize) {
    const { INTEGER, STRING, DATE, ENUM } = Sequelize;
    await queryInterface.createTable('user_info', {
      id: { 
        type: INTEGER(20).UNSIGNED, 
        primaryKey: true, 
        autoIncrement: true,
        comment: '主键id'
      },
      user_id:{
        type: INTEGER(20).UNSIGNED, 
        allowNull: true, 
        defaultValue:0,
        comment: '用户ID',
        references: { //关联关系
          model: 'user', //关联的表
          key: 'id' //关联表的主键
        },
        onDelete: 'cascade', //删除时操作
        onUpdate: 'restrict', // 更新时操作
      },
      gender: {
        type: ENUM('male', 'female', 'unknown'),
        allowNull: false,
        defaultValue: 'unknown',
        comment: '性别'
      },
      birthday: {
        type: DATE,
        comment: '出生日期'
      },
      bio: {
        type: STRING(200),
        comment: '个人简介'
      },
      location: {
        type: STRING(100),
        comment: '所在地'
      },
      website: {
        type: STRING(255),
        comment: '个人网站'
      },
      order: {
        type: INTEGER,//不限定长度.默认int(11)
        allowNull: true,
        defaultValue: 50,
        comment: '排序,默认50'
      },
      // sex: { type: ENUM, values: ['男','女','保密'], allowNull: true, defaultValue: '保密', comment: '留言用户性别'},
      create_time: {type: DATE, allowNull: false, defaultValue:Sequelize.fn('NOW')},
      update_time: {
        type: DATE,
        allowNull: false,
        defaultValue: Sequelize.literal('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'),
        comment: '更新时间'
      }
    });
  },

  async down(queryInterface) {
    await queryInterface.dropTable('user_info');
  }
};
  1. 执行迁移文件命令生成数据库表:
// 创建数据库
npx sequelize db:migrate
// 如果有问题需要回滚,可以通过 `db:migrate:undo` 回退一个变更
npx sequelize db:migrate:undo
// 可以通过 `db:migrate:undo:all` 回退到初始状态
npx sequelize db:migrate:undo:all

# user_info表模型

app/model/user_info.js

'use strict';

module.exports = app => {
    const { INTEGER, STRING, DATE, ENUM } = app.Sequelize;

    const UserInfo = app.model.define('user_info', {
        id: {
            type: INTEGER(20).UNSIGNED,
            primaryKey: true,
            autoIncrement: true,
            comment: '主键id'
        },
        user_id: {
            type: INTEGER(20).UNSIGNED,
            allowNull: true,
            defaultValue: 0,
            comment: '用户ID',
            references: { //关联关系
                model: 'user', //关联的表
                key: 'id' //关联表的主键
            },
            onDelete: 'cascade', //删除时操作
            onUpdate: 'restrict', // 更新时操作
        },
        gender: {
            type: ENUM('male', 'female', 'unknown'),
            allowNull: false,
            defaultValue: 'unknown',
            comment: '性别'
        },
        birthday: {
            type: DATE,
            comment: '出生日期'
        },
        bio: {
            type: STRING(200),
            comment: '个人简介'
        },
        location: {
            type: STRING(100),
            comment: '所在地'
        },
        website: {
            type: STRING(255),
            comment: '个人网站'
        },
        order: {
            type: INTEGER,//不限定长度.默认int(11)
            allowNull: true,
            defaultValue: 50,
            comment: '排序,默认50'
        },
        // sex: { type: ENUM, values: ['男','女','保密'], allowNull: true, defaultValue: '保密', comment: '留言用户性别'},
        create_time: {
            type: DATE,
            allowNull: false,
            defaultValue: app.Sequelize.fn('NOW'),
            get() {
                return app.formatTime(this.getDataValue('create_time'));
            }
        },
        update_time: { type: DATE, allowNull: false, defaultValue: app.Sequelize.fn('NOW') },
    });

    // 模型关联关系
    UserInfo.associate = function (models) {
        // 关联user 
        this.belongsTo(app.model.User, {
            foreignKey: 'user_id',  // 关联外键
            // as: 'UserInfo', // 别名(可选)
            
        });
    }

    return UserInfo;
}
更新时间: 2025年9月19日星期五晚上7点44分