初次提交
This commit is contained in:
17
config/config.js
Normal file
17
config/config.js
Normal file
@@ -0,0 +1,17 @@
|
||||
const mysql = require('mysql2')
|
||||
|
||||
const sql = {
|
||||
createConnection() {
|
||||
return mysql.createPool({
|
||||
connectionLimit: 10,
|
||||
host: '114.55.111.44',
|
||||
user: 'test_mao',
|
||||
password: 'nK2mPbWriBp25BRd',
|
||||
database: 'test_mao',
|
||||
charset: 'utf8mb4',
|
||||
multipleStatements: true
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
module.exports = sql
|
||||
70
config/constants.js
Normal file
70
config/constants.js
Normal file
@@ -0,0 +1,70 @@
|
||||
// 系统常量配置
|
||||
module.exports = {
|
||||
// 转账类型
|
||||
TRANSFER_TYPES: {
|
||||
USER_TO_USER: 'user_to_user',
|
||||
SYSTEM_TO_USER: 'system_to_user',
|
||||
USER_TO_SYSTEM: 'user_to_system'
|
||||
},
|
||||
|
||||
// 转账状态
|
||||
TRANSFER_STATUS: {
|
||||
PENDING: 'pending',
|
||||
CONFIRMED: 'confirmed',
|
||||
RECEIVED: 'received',
|
||||
REJECTED: 'rejected',
|
||||
CANCELLED: 'cancelled',
|
||||
NOT_RECEIVED: 'not_received',
|
||||
FAILED: 'failed'
|
||||
},
|
||||
|
||||
// 用户角色
|
||||
USER_ROLES: {
|
||||
ADMIN: 'admin',
|
||||
USER: 'user'
|
||||
},
|
||||
|
||||
// 订单状态
|
||||
ORDER_STATUS: {
|
||||
PENDING: 'pending',
|
||||
PAID: 'paid',
|
||||
SHIPPED: 'shipped',
|
||||
DELIVERED: 'delivered',
|
||||
CANCELLED: 'cancelled'
|
||||
},
|
||||
|
||||
// 错误代码
|
||||
ERROR_CODES: {
|
||||
VALIDATION_ERROR: 'VALIDATION_ERROR',
|
||||
AUTHENTICATION_ERROR: 'AUTHENTICATION_ERROR',
|
||||
AUTHORIZATION_ERROR: 'AUTHORIZATION_ERROR',
|
||||
NOT_FOUND: 'NOT_FOUND',
|
||||
DUPLICATE_ENTRY: 'DUPLICATE_ENTRY',
|
||||
DATABASE_ERROR: 'DATABASE_ERROR',
|
||||
INTERNAL_ERROR: 'INTERNAL_ERROR'
|
||||
},
|
||||
|
||||
// HTTP状态码
|
||||
HTTP_STATUS: {
|
||||
OK: 200,
|
||||
CREATED: 201,
|
||||
BAD_REQUEST: 400,
|
||||
UNAUTHORIZED: 401,
|
||||
FORBIDDEN: 403,
|
||||
NOT_FOUND: 404,
|
||||
CONFLICT: 409,
|
||||
INTERNAL_SERVER_ERROR: 500
|
||||
},
|
||||
|
||||
// 分页默认值
|
||||
PAGINATION: {
|
||||
DEFAULT_PAGE: 1,
|
||||
DEFAULT_LIMIT: 10,
|
||||
MAX_LIMIT: 100
|
||||
},
|
||||
|
||||
// JWT配置
|
||||
JWT: {
|
||||
EXPIRES_IN: '24h'
|
||||
}
|
||||
};
|
||||
26
config/database-init.js
Normal file
26
config/database-init.js
Normal file
@@ -0,0 +1,26 @@
|
||||
|
||||
const { initDB, } = require('../database');
|
||||
|
||||
/**
|
||||
* 数据库初始化函数
|
||||
* 创建所有必要的表结构和初始数据
|
||||
*/
|
||||
async function initDatabase() {
|
||||
try {
|
||||
|
||||
|
||||
// 初始化数据库连接池
|
||||
await initDB();
|
||||
console.log('数据库连接池初始化成功');
|
||||
} catch (error) {
|
||||
console.error('数据库初始化失败:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
module.exports = {
|
||||
initDatabase
|
||||
};
|
||||
363
config/dbv2.js
Normal file
363
config/dbv2.js
Normal file
@@ -0,0 +1,363 @@
|
||||
class QueryBuilder {
|
||||
constructor() {
|
||||
this.conditions = {};
|
||||
this.limit = null;
|
||||
this.offset = null;
|
||||
this.groupBy = null;
|
||||
}
|
||||
|
||||
where(condition, ...params) {
|
||||
this.conditions[condition] = params;
|
||||
return this;
|
||||
}
|
||||
|
||||
setLimit(limit) {
|
||||
this.limit = limit;
|
||||
return this;
|
||||
}
|
||||
|
||||
setOffset(offset) {
|
||||
this.offset = offset;
|
||||
return this;
|
||||
}
|
||||
|
||||
setGroupBy(groupBy) {
|
||||
this.groupBy = groupBy;
|
||||
return this;
|
||||
}
|
||||
|
||||
sqdata(sql, params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
global.sqlReq.query(sql, params, (err, result) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
resolve(result);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
getParams() {
|
||||
return Object.values(this.conditions).flat();
|
||||
}
|
||||
|
||||
buildConditions() {
|
||||
return Object.keys(this.conditions).map(condition => `${condition}`).join(' AND ');
|
||||
}
|
||||
}
|
||||
|
||||
class SelectBuilder extends QueryBuilder {
|
||||
constructor() {
|
||||
super();
|
||||
this.selectFields = [];
|
||||
this.tables = [];
|
||||
this.orderByField = '';
|
||||
this.orderByDirection = 'ASC';
|
||||
this.subQueries = []; // 用于存储子查询
|
||||
this.unions = []; // 存储UNION查询
|
||||
}
|
||||
// 添加UNION查询
|
||||
union(queryBuilder, type = 'UNION') {
|
||||
this.unions.push({queryBuilder, type});
|
||||
return this;
|
||||
}
|
||||
|
||||
// 添加UNION ALL查询
|
||||
unionAll(queryBuilder) {
|
||||
this.union(queryBuilder, 'UNION ALL');
|
||||
return this;
|
||||
}
|
||||
|
||||
// 构建主查询部分(不含ORDER BY/LIMIT/OFFSET)
|
||||
buildMainQuery() {
|
||||
const subQuerySQL = this.subQueries.map(({alias, subQuery}) => `(${subQuery}) AS ${alias}`);
|
||||
const selectClause = this.selectFields.concat(subQuerySQL).join(', ');
|
||||
|
||||
let sql = `SELECT ${selectClause}
|
||||
FROM ${this.tables.join(' ')}`;
|
||||
|
||||
const conditionClauses = this.buildConditions();
|
||||
if (conditionClauses) {
|
||||
sql += ` WHERE ${conditionClauses}`;
|
||||
}
|
||||
|
||||
if (this.groupBy) {
|
||||
sql += ` GROUP BY ${this.groupBy}`;
|
||||
}
|
||||
|
||||
const params = this.getParams();
|
||||
return {sql, params};
|
||||
}
|
||||
|
||||
// 供UNION查询调用的构建方法
|
||||
buildForUnion() {
|
||||
return this.buildMainQuery();
|
||||
}
|
||||
|
||||
select(fields) {
|
||||
this.selectFields = fields.split(',').map(field => field.trim());
|
||||
return this;
|
||||
}
|
||||
|
||||
// 添加子查询
|
||||
addSubQuery(alias, subQuery) {
|
||||
this.subQueries.push({alias, subQuery});
|
||||
return this;
|
||||
}
|
||||
|
||||
whereLike(fields, keyword) {
|
||||
const likeConditions = fields.map(field => `${field} LIKE ?`).join(' OR ');
|
||||
this.conditions[likeConditions] = fields.map(() => `%${keyword}%`);
|
||||
return this;
|
||||
}
|
||||
|
||||
from(table) {
|
||||
this.tables.push(table);
|
||||
return this;
|
||||
}
|
||||
|
||||
leftJoin(table, condition) {
|
||||
this.tables.push(`LEFT JOIN ${table} ON ${condition}`);
|
||||
return this;
|
||||
}
|
||||
|
||||
orderBy(field, direction = 'ASC') {
|
||||
this.orderByField = field;
|
||||
this.orderByDirection = direction.toUpperCase();
|
||||
return this;
|
||||
}
|
||||
|
||||
paginate(page, pageSize) {
|
||||
if (page <= 0 || pageSize <= 0) {
|
||||
throw new Error('分页参数必须大于0');
|
||||
}
|
||||
this.limit = pageSize;
|
||||
this.offset = (page - 1) * pageSize;
|
||||
return this;
|
||||
}
|
||||
|
||||
async chidBuild() {
|
||||
|
||||
let sql = `SELECT ${this.selectFields.join(', ')}
|
||||
FROM ${this.tables.join(' ')}`;
|
||||
let conditionClauses = this.buildConditions();
|
||||
if (conditionClauses) {
|
||||
sql += ` WHERE ${conditionClauses}`;
|
||||
}
|
||||
if (this.orderByField) {
|
||||
sql += ` ORDER BY ${this.orderByField} ${this.orderByDirection}`;
|
||||
}
|
||||
if (this.limit !== null) {
|
||||
sql += ` LIMIT ${this.limit}`;
|
||||
}
|
||||
if (this.offset !== null) {
|
||||
sql += ` OFFSET ${this.offset}`;
|
||||
}
|
||||
return sql;
|
||||
}
|
||||
|
||||
async build() {
|
||||
const main = this.buildMainQuery();
|
||||
let fullSql = `(${main.sql})`;
|
||||
const allParams = [...main.params];
|
||||
|
||||
// 处理UNION部分
|
||||
for (const union of this.unions) {
|
||||
const unionBuilder = union.queryBuilder;
|
||||
if (!(unionBuilder instanceof SelectBuilder)) {
|
||||
throw new Error('UNION query must be a SelectBuilder instance');
|
||||
}
|
||||
const unionResult = unionBuilder.buildForUnion();
|
||||
fullSql += ` ${union.type} (${unionResult.sql})`;
|
||||
allParams.push(...unionResult.params);
|
||||
}
|
||||
|
||||
// 添加ORDER BY、LIMIT、OFFSET
|
||||
if (this.orderByField) {
|
||||
fullSql += ` ORDER BY ${this.orderByField} ${this.orderByDirection}`;
|
||||
}
|
||||
if (this.limit !== null) {
|
||||
fullSql += ` LIMIT ${this.limit}`;
|
||||
}
|
||||
if (this.offset !== null) {
|
||||
fullSql += ` OFFSET ${this.offset}`;
|
||||
}
|
||||
console.log(fullSql,allParams);
|
||||
return await this.sqdata(fullSql, allParams);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class UpdateBuilder extends QueryBuilder {
|
||||
constructor() {
|
||||
super();
|
||||
this.table = '';
|
||||
this.updateFields = {};
|
||||
}
|
||||
|
||||
update(table) {
|
||||
this.table = table;
|
||||
return this;
|
||||
}
|
||||
|
||||
set(field, value) {
|
||||
if (value && value.increment && typeof value === 'object' ) {
|
||||
this.updateFields[field] = {increment: value.increment};
|
||||
} else {
|
||||
this.updateFields[field] = value;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
async build() {
|
||||
let sql = `UPDATE ${this.table}
|
||||
SET `;
|
||||
let updateClauses = Object.keys(this.updateFields).map(field => {
|
||||
const value = this.updateFields[field];
|
||||
if (value && value.increment && typeof value === 'object' ) {
|
||||
return `${field} = ${field} + ?`;
|
||||
}
|
||||
return `${field} = ?`;
|
||||
}).join(', ');
|
||||
|
||||
sql += updateClauses;
|
||||
|
||||
let conditionClauses = this.buildConditions();
|
||||
if (conditionClauses) {
|
||||
sql += ` WHERE ${conditionClauses}`;
|
||||
}
|
||||
// 处理参数,确保自增字段也传入增量值
|
||||
const params = [
|
||||
...Object.values(this.updateFields).map(value =>
|
||||
(value && value.increment && typeof value === 'object' ) ? value.increment : value
|
||||
),
|
||||
...this.getParams()
|
||||
];
|
||||
return await this.sqdata(sql, params);
|
||||
}
|
||||
}
|
||||
|
||||
class InsertBuilder extends QueryBuilder {
|
||||
constructor() {
|
||||
super();
|
||||
this.table = '';
|
||||
this.insertValues = [];
|
||||
this.updateValues = {};
|
||||
}
|
||||
|
||||
insertInto(table) {
|
||||
this.table = table;
|
||||
return this;
|
||||
}
|
||||
|
||||
// 仍然保留单条记录的插入
|
||||
values(values) {
|
||||
if (Array.isArray(values)) {
|
||||
this.insertValues = values;
|
||||
} else {
|
||||
this.insertValues = [values]; // 将单条记录包装成数组
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
// 新增方法,支持一次插入多条记录
|
||||
valuesMultiple(records) {
|
||||
if (!Array.isArray(records) || records.length === 0) {
|
||||
throw new Error('Values must be a non-empty array');
|
||||
}
|
||||
|
||||
// 确保每一条记录都是对象
|
||||
records.forEach(record => {
|
||||
if (typeof record !== 'object') {
|
||||
throw new Error('Each record must be an object');
|
||||
}
|
||||
});
|
||||
|
||||
this.insertValues = records;
|
||||
return this;
|
||||
}
|
||||
|
||||
// 新增 upsert 方法,支持更新或插入
|
||||
upsert(values, updateFields) {
|
||||
// values: 要插入的记录
|
||||
// updateFields: 如果记录存在时,需要更新的字段
|
||||
if (!Array.isArray(values) || values.length === 0) {
|
||||
throw new Error('Values must be a non-empty array');
|
||||
}
|
||||
|
||||
// 检查每条记录是否是对象
|
||||
values.forEach(record => {
|
||||
if (typeof record !== 'object') {
|
||||
throw new Error('Each record must be an object');
|
||||
}
|
||||
});
|
||||
|
||||
this.insertValues = values;
|
||||
this.updateValues = updateFields || {};
|
||||
return this;
|
||||
}
|
||||
|
||||
async build() {
|
||||
if (this.insertValues.length === 0) {
|
||||
throw new Error("No values to insert");
|
||||
}
|
||||
|
||||
// 获取表单列名,假设所有记录有相同的字段
|
||||
const columns = Object.keys(this.insertValues[0]);
|
||||
|
||||
// 构建 VALUES 子句,支持批量插入
|
||||
const valuePlaceholders = this.insertValues.map(() =>
|
||||
`(${columns.map(() => '?').join(', ')})`
|
||||
).join(', ');
|
||||
|
||||
// 展平所有的插入值
|
||||
const params = this.insertValues.flatMap(record =>
|
||||
columns.map(column => record[column])
|
||||
);
|
||||
|
||||
// 如果有 updateFields,构建 ON DUPLICATE KEY UPDATE 子句
|
||||
let updateClause = '';
|
||||
if (Object.keys(this.updateValues).length > 0) {
|
||||
updateClause = ' ON DUPLICATE KEY UPDATE ' +
|
||||
Object.keys(this.updateValues).map(field => {
|
||||
return `${field} = VALUES(${field})`;
|
||||
}).join(', ');
|
||||
}
|
||||
|
||||
// 生成 SQL 语句
|
||||
const sql = `INSERT INTO ${this.table} (${columns.join(', ')})
|
||||
VALUES ${valuePlaceholders} ${updateClause}`;
|
||||
// 执行查询
|
||||
return await this.sqdata(sql, params);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class DeleteBuilder extends QueryBuilder {
|
||||
constructor() {
|
||||
super();
|
||||
this.table = '';
|
||||
}
|
||||
|
||||
deleteFrom(table) {
|
||||
this.table = table;
|
||||
return this;
|
||||
}
|
||||
|
||||
async build() {
|
||||
let sql = `DELETE
|
||||
FROM ${this.table}`;
|
||||
let conditionClauses = this.buildConditions();
|
||||
if (conditionClauses) {
|
||||
sql += ` WHERE ${conditionClauses}`;
|
||||
}
|
||||
return await this.sqdata(sql, this.getParams());
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
SelectBuilder,
|
||||
UpdateBuilder,
|
||||
InsertBuilder,
|
||||
DeleteBuilder,
|
||||
};
|
||||
73
config/logger.js
Normal file
73
config/logger.js
Normal file
@@ -0,0 +1,73 @@
|
||||
const winston = require('winston');
|
||||
const path = require('path');
|
||||
|
||||
// 创建日志目录
|
||||
const logDir = path.join(__dirname, '../logs');
|
||||
|
||||
// 日志格式配置
|
||||
const logFormat = winston.format.combine(
|
||||
winston.format.timestamp({
|
||||
format: 'YYYY-MM-DD HH:mm:ss'
|
||||
}),
|
||||
winston.format.errors({ stack: true }),
|
||||
winston.format.json()
|
||||
);
|
||||
|
||||
// 控制台日志格式
|
||||
const consoleFormat = winston.format.combine(
|
||||
winston.format.colorize(),
|
||||
winston.format.timestamp({
|
||||
format: 'YYYY-MM-DD HH:mm:ss'
|
||||
}),
|
||||
winston.format.printf(({ timestamp, level, message, ...meta }) => {
|
||||
return `${timestamp} [${level}]: ${message} ${Object.keys(meta).length ? JSON.stringify(meta, null, 2) : ''}`;
|
||||
})
|
||||
);
|
||||
|
||||
// 创建logger实例
|
||||
const logger = winston.createLogger({
|
||||
level: process.env.LOG_LEVEL || 'info',
|
||||
format: logFormat,
|
||||
defaultMeta: { service: 'integrated-system' },
|
||||
transports: [
|
||||
// 错误日志文件
|
||||
new winston.transports.File({
|
||||
filename: path.join(logDir, 'error.log'),
|
||||
level: 'error',
|
||||
maxsize: 5242880, // 5MB
|
||||
maxFiles: 5
|
||||
}),
|
||||
// 所有日志文件
|
||||
new winston.transports.File({
|
||||
filename: path.join(logDir, 'combined.log'),
|
||||
maxsize: 5242880, // 5MB
|
||||
maxFiles: 5
|
||||
})
|
||||
]
|
||||
});
|
||||
|
||||
// 开发环境添加控制台输出
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
logger.add(new winston.transports.Console({
|
||||
format: consoleFormat
|
||||
}));
|
||||
}
|
||||
|
||||
// 审计日志记录器
|
||||
const auditLogger = winston.createLogger({
|
||||
level: 'info',
|
||||
format: logFormat,
|
||||
defaultMeta: { service: 'audit' },
|
||||
transports: [
|
||||
new winston.transports.File({
|
||||
filename: path.join(logDir, 'audit.log'),
|
||||
maxsize: 5242880, // 5MB
|
||||
maxFiles: 10
|
||||
})
|
||||
]
|
||||
});
|
||||
|
||||
module.exports = {
|
||||
logger,
|
||||
auditLogger
|
||||
};
|
||||
97
config/minio.js
Normal file
97
config/minio.js
Normal file
@@ -0,0 +1,97 @@
|
||||
const Minio = require('minio');
|
||||
require('dotenv').config();
|
||||
|
||||
/**
|
||||
* MinIO 配置
|
||||
* 用于对象存储服务配置
|
||||
*/
|
||||
const minioConfig = {
|
||||
// MinIO 服务器配置
|
||||
endPoint: process.env.MINIO_ENDPOINT || 'localhost',
|
||||
port: parseInt(process.env.MINIO_PORT) || 9000,
|
||||
useSSL: process.env.MINIO_USE_SSL === 'true' || false,
|
||||
accessKey: process.env.MINIO_ACCESS_KEY || 'minioadmin',
|
||||
secretKey: process.env.MINIO_SECRET_KEY || 'minioadmin',
|
||||
|
||||
// 存储桶配置
|
||||
buckets: {
|
||||
uploads: process.env.MINIO_BUCKET_UPLOADS || 'uploads',
|
||||
avatars: process.env.MINIO_BUCKET_AVATARS || 'avatars',
|
||||
products: process.env.MINIO_BUCKET_PRODUCTS || 'products',
|
||||
documents: process.env.MINIO_BUCKET_DOCUMENTS || 'documents'
|
||||
},
|
||||
|
||||
// 文件访问配置
|
||||
publicUrl: process.env.MINIO_PUBLIC_URL || `http://localhost:9000`
|
||||
};
|
||||
|
||||
/**
|
||||
* 创建 MinIO 客户端实例
|
||||
*/
|
||||
const createMinioClient = () => {
|
||||
return new Minio.Client({
|
||||
endPoint: minioConfig.endPoint,
|
||||
port: minioConfig.port,
|
||||
useSSL: minioConfig.useSSL,
|
||||
accessKey: minioConfig.accessKey,
|
||||
secretKey: minioConfig.secretKey
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 初始化存储桶
|
||||
* 确保所有需要的存储桶都存在
|
||||
*/
|
||||
const initializeBuckets = async () => {
|
||||
const minioClient = createMinioClient();
|
||||
|
||||
try {
|
||||
// 检查并创建存储桶
|
||||
for (const [key, bucketName] of Object.entries(minioConfig.buckets)) {
|
||||
const exists = await minioClient.bucketExists(bucketName);
|
||||
if (!exists) {
|
||||
await minioClient.makeBucket(bucketName, 'us-east-1');
|
||||
console.log(`✅ 存储桶 '${bucketName}' 创建成功`);
|
||||
|
||||
// 设置存储桶策略为公开读取(可选)
|
||||
const policy = {
|
||||
Version: '2012-10-17',
|
||||
Statement: [
|
||||
{
|
||||
Effect: 'Allow',
|
||||
Principal: { AWS: ['*'] },
|
||||
Action: ['s3:GetObject'],
|
||||
Resource: [`arn:aws:s3:::${bucketName}/*`]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
try {
|
||||
await minioClient.setBucketPolicy(bucketName, JSON.stringify(policy));
|
||||
console.log(`✅ 存储桶 '${bucketName}' 策略设置成功`);
|
||||
} catch (policyError) {
|
||||
console.warn(`⚠️ 存储桶 '${bucketName}' 策略设置失败:`, policyError.message);
|
||||
}
|
||||
} else {
|
||||
console.log(`✅ 存储桶 '${bucketName}' 已存在`);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ 初始化存储桶失败:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取文件的公开访问URL
|
||||
*/
|
||||
const getPublicUrl = (bucketName, objectName) => {
|
||||
return `${minioConfig.publicUrl}/${bucketName}/${objectName}`;
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
minioConfig,
|
||||
createMinioClient,
|
||||
initializeBuckets,
|
||||
getPublicUrl
|
||||
};
|
||||
24
config/wechatPay.js
Normal file
24
config/wechatPay.js
Normal file
@@ -0,0 +1,24 @@
|
||||
// 微信支付配置
|
||||
module.exports = {
|
||||
// 微信支付配置
|
||||
wechatPay: {
|
||||
appId: process.env.WECHAT_APP_ID || '', // 微信公众号AppID
|
||||
mchId: process.env.WECHAT_MCH_ID || '', // 商户号
|
||||
apiKey: process.env.WECHAT_API_KEY || '', // API密钥
|
||||
apiV3Key: process.env.WECHAT_API_V3_KEY || '', // APIv3密钥
|
||||
notifyUrl: process.env.WECHAT_NOTIFY_URL || 'https://your-domain.com/api/wechat/notify', // 支付回调地址
|
||||
|
||||
// 证书路径(生产环境需要配置)
|
||||
certPath: process.env.WECHAT_CERT_PATH || '',
|
||||
keyPath: process.env.WECHAT_KEY_PATH || '',
|
||||
|
||||
// 支付相关配置
|
||||
tradeType: {
|
||||
h5: 'MWEB', // H5支付
|
||||
jsapi: 'JSAPI' // 公众号支付
|
||||
},
|
||||
|
||||
// 注册费用配置(单位:分)
|
||||
registrationFee: 100 // 1元注册费
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user