# 一、 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 | 手机号 |
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 | 更新时间 |
- 直接在
phpMyAdmin中根据表字段设计创建表,或者通过数据库插件写sql语句创建表。- 通过迁移命名创建
user表:
- 创建迁移文件 命令:
npx sequelize migration:generate --name=user
- 创建迁移文件
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');
}
};
- 执行迁移文件命令生成数据库表:
// 创建数据库 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 | 更新时间 |
- 直接在
phpMyAdmin中根据表字段设计创建表,或者通过数据库插件写sql语句创建表。- 通过迁移命名创建
user_info表:
- 创建迁移文件 命令:
npx sequelize migration:generate --name=user_info
- 创建迁移文件
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');
}
};
- 执行迁移文件命令生成数据库表:
// 创建数据库 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;
}