feat: admin add user

This commit is contained in:
archer
2023-07-20 10:56:57 +08:00
parent 82e7776a77
commit 6d358ef3e6
8 changed files with 1411 additions and 2279 deletions

View File

@@ -25,7 +25,7 @@
"react-admin": "^4.11.0", "react-admin": "^4.11.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-i18next": "^12.3.1", "react-i18next": "^12.3.1",
"tushan": "^0.2.30" "tushan": "^0.3.1"
}, },
"devDependencies": { "devDependencies": {
"@types/jsonexport": "^3.0.2", "@types/jsonexport": "^3.0.2",

3521
admin/pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -16,14 +16,21 @@ useKbRoute(app);
useSystemRoute(app); useSystemRoute(app);
app.get('/*', (req, res) => { app.get('/*', (req, res) => {
res.sendFile(new URL('dist/index.html', import.meta.url).pathname); try {
res.sendFile(new URL('dist/index.html', import.meta.url).pathname);
} catch (error) {
res.end();
}
}); });
app.use((err, req, res, next) => { app.use((err, req, res, next) => {
res.sendFile(new URL('dist/index.html', import.meta.url).pathname); try {
res.sendFile(new URL('dist/index.html', import.meta.url).pathname);
} catch (error) {
res.end();
}
}); });
const PORT = process.env.PORT || 3001; const PORT = process.env.PORT || 3001;
app.listen(PORT, () => { app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`); console.log(`Server is running on port ${PORT}`);

View File

@@ -46,63 +46,6 @@ export const useSystemRoute = (app) => {
res.status(401).end('username or password incorrect'); res.status(401).end('username or password incorrect');
} }
}); });
app.get('/system', auth(), async (req, res) => {
try {
const data = await System.find();
const totalCount = await System.countDocuments();
res.header('Access-Control-Expose-Headers', 'X-Total-Count');
res.header('X-Total-Count', totalCount);
res.json(
data.map((item) => {
const obj = item.toObject();
return {
...obj,
id: obj._id
};
})
);
} catch (error) {
console.log(error);
res.status(500).json({ error: 'Error creating system env' });
}
});
app.post('/system', auth(), async (req, res) => {
try {
await System.create({
...req.body,
sensitiveCheck: req.body.sensitiveCheck === 'true'
});
postParent();
res.json({});
} catch (error) {
res.status(500).json({ error: 'Error creating system env' });
}
});
app.put('/system/:id', auth(), async (req, res) => {
try {
const _id = req.params.id;
await System.findByIdAndUpdate(_id, {
...req.body,
sensitiveCheck: req.body.sensitiveCheck === 'true'
});
postParent();
res.json({});
} catch (error) {
res.status(500).json({ error: 'Error updating system env' });
}
});
app.delete('/system/:id', auth(), async (req, res) => {
try {
const _id = req.params.id;
await System.findByIdAndDelete(_id);
res.json({});
} catch (error) {
res.status(500).json({ error: 'Error updating system env' });
}
});
}; };
export const auth = () => { export const auth = () => {
@@ -110,7 +53,7 @@ export const auth = () => {
try { try {
const authorization = req.headers.authorization; const authorization = req.headers.authorization;
if (!authorization) { if (!authorization) {
return next(new Error("unAuthorization")) return next(new Error('unAuthorization'));
} }
const token = authorization.slice('Bearer '.length); const token = authorization.slice('Bearer '.length);

View File

@@ -2,6 +2,11 @@ import { User, Pay } from '../schema.js';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { auth } from './system.js'; import { auth } from './system.js';
import crypto from 'crypto'; import crypto from 'crypto';
export const PRICE_SCALE = 100000;
export const formatPrice = (val = 0, multiple = 1) => {
return Number(((val / PRICE_SCALE) * multiple).toFixed(10));
};
// 加密 // 加密
const hashPassword = (psw) => { const hashPassword = (psw) => {
@@ -78,6 +83,7 @@ export const useUserRoute = (app) => {
return { return {
...obj, ...obj,
id: obj._id, id: obj._id,
balance: formatPrice(obj.balance),
createTime: dayjs(obj.createTime).format('YYYY/MM/DD HH:mm'), createTime: dayjs(obj.createTime).format('YYYY/MM/DD HH:mm'),
password: '' password: ''
}; };
@@ -107,8 +113,8 @@ export const useUserRoute = (app) => {
const result = await User.create({ const result = await User.create({
username, username,
password, password: hashPassword(hashPassword(password)),
balance balance: balance * PRICE_SCALE
}); });
res.json(result); res.json(result);
} catch (err) { } catch (err) {
@@ -116,17 +122,17 @@ export const useUserRoute = (app) => {
res.status(500).json({ error: 'Error creating user' }); res.status(500).json({ error: 'Error creating user' });
} }
}); });
// 修改用户信息 // 修改用户信息
app.put('/users/:id', auth(), async (req, res) => { app.put('/users/:id', auth(), async (req, res) => {
try { try {
const _id = req.params.id; const _id = req.params.id;
let { password, balance = 0 } = req.body; let { username, password, balance = 0 } = req.body;
const result = await User.findByIdAndUpdate(_id, { const result = await User.findByIdAndUpdate(_id, {
...(username && { username }),
...(password && { password: hashPassword(hashPassword(password)) }), ...(password && { password: hashPassword(hashPassword(password)) }),
...(balance && { balance }) ...(balance && { balance: balance * PRICE_SCALE })
}); });
res.json(result); res.json(result);
} catch (err) { } catch (err) {
@@ -134,6 +140,7 @@ export const useUserRoute = (app) => {
res.status(500).json({ error: 'Error updating user' }); res.status(500).json({ error: 'Error updating user' });
} }
}); });
// 新增: 获取 pays 列表 // 新增: 获取 pays 列表
app.get('/pays', auth(), async (req, res) => { app.get('/pays', auth(), async (req, res) => {
try { try {

View File

@@ -21,22 +21,39 @@ mongoose
.then(() => console.log('Connected to MongoDB successfully!')) .then(() => console.log('Connected to MongoDB successfully!'))
.catch((err) => console.log(`Error connecting to MongoDB: ${err}`)); .catch((err) => console.log(`Error connecting to MongoDB: ${err}`));
const userSchema = new mongoose.Schema({ const UserSchema = new mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId, username: {
username: String, type: String,
password: String, required: true,
balance: Number, unique: true
promotion: {
rate: Number
}, },
openaiKey: String, password: {
avatar: String, type: String,
createTime: Date required: true,
select: false
},
createTime: {
type: Date,
default: () => new Date()
},
avatar: {
type: String,
default: '/icon/human.png'
},
balance: {
type: Number,
default: 0
},
limit: {
exportKbTime: {
// Every half hour
type: Date
}
}
}); });
// 新增: 定义 pays 模型 // 新增: 定义 pays 模型
const paySchema = new mongoose.Schema({ const paySchema = new mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
userId: mongoose.Schema.Types.ObjectId, userId: mongoose.Schema.Types.ObjectId,
price: Number, price: Number,
orderId: String, orderId: String,
@@ -47,7 +64,6 @@ const paySchema = new mongoose.Schema({
// 新增: 定义 kb 模型 // 新增: 定义 kb 模型
const kbSchema = new mongoose.Schema({ const kbSchema = new mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
userId: mongoose.Schema.Types.ObjectId, userId: mongoose.Schema.Types.ObjectId,
avatar: String, avatar: String,
name: String, name: String,
@@ -98,8 +114,8 @@ const SystemSchema = new mongoose.Schema({
} }
}); });
export const App = mongoose.models['app'] || mongoose.model('app', appSchema); export const App = mongoose.models['model'] || mongoose.model('model', appSchema);
export const Kb = mongoose.models['kb'] || mongoose.model('kb', kbSchema); export const Kb = mongoose.models['kb'] || mongoose.model('kb', kbSchema);
export const User = mongoose.models['user'] || mongoose.model('user', userSchema); export const User = mongoose.models['user'] || mongoose.model('user', UserSchema);
export const Pay = mongoose.models['pay'] || mongoose.model('pay', paySchema); export const Pay = mongoose.models['pay'] || mongoose.model('pay', paySchema);
export const System = mongoose.models['system'] || mongoose.model('system', SystemSchema); export const System = mongoose.models['system'] || mongoose.model('system', SystemSchema);

View File

@@ -9,7 +9,7 @@ import {
HTTPClient HTTPClient
} from 'tushan'; } from 'tushan';
import { authProvider } from './auth'; import { authProvider } from './auth';
import { userFields, payFields, kbFields, AppFields, SystemFields } from './fields'; import { userFields, payFields, kbFields, AppFields } from './fields';
import { Dashboard } from './Dashboard'; import { Dashboard } from './Dashboard';
import { IconUser, IconApps, IconBook, IconStamp } from 'tushan/icon'; import { IconUser, IconApps, IconBook, IconStamp } from 'tushan/icon';
import { i18nZhTranslation } from 'tushan/client/i18n/resources/zh'; import { i18nZhTranslation } from 'tushan/client/i18n/resources/zh';
@@ -64,7 +64,7 @@ function App() {
}) })
]} ]}
fields={userFields} fields={userFields}
action={{ detail: true, edit: true }} action={{ create: true, detail: true, edit: true }}
/> />
} }
/> />
@@ -122,17 +122,6 @@ function App() {
/> />
} }
/> />
<Resource
name="system"
label="系统"
list={
<ListTable
fields={SystemFields}
action={{ detail: true, edit: true, create: true, delete: true }}
/>
}
/>
</Tushan> </Tushan>
); );
} }

View File

@@ -2,9 +2,13 @@ import { createTextField, createNumberField } from 'tushan';
export const userFields = [ export const userFields = [
createTextField('id', { label: 'ID' }), createTextField('id', { label: 'ID' }),
createTextField('username', { label: '用户名', edit: { hidden: true } }), createTextField('username', { label: '用户名' }),
createNumberField('balance', { label: '余额', list: { sort: true } }), createNumberField('balance', { label: '余额(元)', list: { sort: true } }),
createTextField('createTime', { label: 'Create Time', list: { sort: true } }), createTextField('createTime', {
label: '创建时间',
list: { sort: true },
edit: { hidden: true }
}),
createTextField('password', { label: '密码', list: { hidden: true } }) createTextField('password', { label: '密码', list: { hidden: true } })
]; ];
@@ -14,7 +18,7 @@ export const payFields = [
createNumberField('price', { label: '支付金额' }), createNumberField('price', { label: '支付金额' }),
createTextField('orderId', { label: 'orderId' }), createTextField('orderId', { label: 'orderId' }),
createTextField('status', { label: '状态' }), createTextField('status', { label: '状态' }),
createTextField('createTime', { label: 'Create Time', list: { sort: true } }) createTextField('createTime', { label: '创建时间', list: { sort: true } })
]; ];
export const kbFields = [ export const kbFields = [
@@ -43,10 +47,3 @@ export const AppFields = [
} }
}) })
]; ];
export const SystemFields = [
createTextField('vectorMaxProcess', { label: '向量最大进程' }),
createTextField('qaMaxProcess', { label: 'qa最大进程' }),
createTextField('pgIvfflatProbe', { label: 'pg 探针数量' }),
createTextField('sensitiveCheck', { label: '敏感词校验(true,false)' })
];