Browse Source

1111

master
wenlele 2 years ago
parent
commit
60a9093880
  1. 201
      api/config.js
  2. 29
      api/log/development.log
  3. 4
      script/1.0.0/schema/2.create.project.sql
  4. BIN
      web/client/assets/images/login/login_a.png
  5. BIN
      web/client/assets/images/login/login_b.png
  6. 341
      web/client/src/sections/auth/containers/login.js
  7. 4
      web/client/src/sections/projectRegime/containers/information.js
  8. 2
      web/client/src/sections/projectRegime/containers/qrCode.js
  9. 6
      web/log/development.txt

201
api/config.js

@ -37,118 +37,119 @@ const ALI_OSS_SECRETKET = process.env.ALI_OSS_SECRETKET || flags.aliOssSecretKey
const ALI_OSS_BUCKET = process.env.ALI_OSS_BUCKET || flags.aliOssBucket; const ALI_OSS_BUCKET = process.env.ALI_OSS_BUCKET || flags.aliOssBucket;
const ALI_OSS_REGION = process.env.ALI_OSS_REGION || flags.aliOssRegion; const ALI_OSS_REGION = process.env.ALI_OSS_REGION || flags.aliOssRegion;
if (!XUNJIAN_DB || !QINIU_DOMAIN_QNDMN_RESOURCE || !QINIU_BUCKET_RESOURCE || !QINIU_AK || !QINIU_SK) { if (!XUNJIAN_DB || !QINIU_DOMAIN_QNDMN_RESOURCE || !QINIU_BUCKET_RESOURCE || !QINIU_AK || !QINIU_SK) {
console.log('缺少启动参数,异常退出'); console.log('缺少启动参数,异常退出');
args.showHelp(); args.showHelp();
process.exit(-1); process.exit(-1);
} }
const product = { const product = {
port: flags.port || 8080, port: flags.port || 8080,
staticDirs: ['static'], staticDirs: ['static'],
mws: [ mws: [
{ {
entry: require('@fs/attachment').entry, entry: require('@fs/attachment').entry,
opts: { opts: {
qiniu: { qiniu: {
domain: QINIU_DOMAIN_QNDMN_RESOURCE, domain: QINIU_DOMAIN_QNDMN_RESOURCE,
bucket: QINIU_BUCKET_RESOURCE, bucket: QINIU_BUCKET_RESOURCE,
accessKey: QINIU_AK, accessKey: QINIU_AK,
secretKey: QINIU_SK secretKey: QINIU_SK
}, },
maxSize: 104857600, // 100M maxSize: 104857600, // 100M
} }
}, { }, {
entry: require('./app').entry, entry: require('./app').entry,
opts: { opts: {
dev, dev,
exclude: [ exclude: [
// "*" // "*"
], // 不做认证的路由,也可以使用 exclude: ["*"] 跳过所有路由 ], // 不做认证的路由,也可以使用 exclude: ["*"] 跳过所有路由
qiniu: { qiniu: {
domain: QINIU_DOMAIN_QNDMN_RESOURCE, domain: QINIU_DOMAIN_QNDMN_RESOURCE,
bucket: QINIU_BUCKET_RESOURCE, bucket: QINIU_BUCKET_RESOURCE,
accessKey: QINIU_AK, accessKey: QINIU_AK,
secretKey: QINIU_SK secretKey: QINIU_SK
}, },
aliOss: { aliOss: {
accessKey: ALI_OSS_ACCESSKEY, accessKey: ALI_OSS_ACCESSKEY,
secretKey: ALI_OSS_SECRETKET, secretKey: ALI_OSS_SECRETKET,
bucket: ALI_OSS_BUCKET, bucket: ALI_OSS_BUCKET,
region: ALI_OSS_REGION region: ALI_OSS_REGION
}, },
sms: { sms: {
///阿里云-安心云 ///阿里云-安心云
accessKey: 'LTAI5tAFdjz7j38aNF2C9Qe8', accessKey: 'LTAI5tAFdjz7j38aNF2C9Qe8',
accessSecret: '1trYkmiqfBtvZL6BxkNH2uQcQQPs0S' accessSecret: '1trYkmiqfBtvZL6BxkNH2uQcQQPs0S'
},
email: {
enabled: true,
host: 'smtp.exmail.qq.com',
port: 465,
sender: {
name: '中鼎服务',
address: 'fsiot@free-sun.com.cn',
password: 'Fs2689'
}
},
}
}
],
dc: {
url: XUNJIAN_DB,
opts: {
pool: {
max: 80,
min: 10,
idle: 10000
}, },
define: { email: {
freezeTableName: true, // 固定表名 enabled: true,
timestamps: false // 不含列 "createAt"/"updateAt"/"DeleteAt" host: 'smtp.exmail.qq.com',
port: 465,
sender: {
name: '中鼎服务',
address: 'fsiot@free-sun.com.cn',
password: 'Fs2689'
}
}, },
timezone: '+08:00', }
logging: false }
}, ],
models: [require('./app').models] dc: {
}, url: XUNJIAN_DB,
logger: { opts: {
level: 'info', pool: {
json: false, max: 80,
filename: path.join(__dirname, 'log', 'runtime.log'), min: 10,
colorize: false, idle: 10000
maxsize: 1024 * 1024 * 5, },
rotationFormat: false, define: {
zippedArchive: true, freezeTableName: true, // 固定表名
maxFiles: 10, timestamps: false // 不含列 "createAt"/"updateAt"/"DeleteAt"
prettyPrint: true, },
label: '', timezone: '+08:00',
timestamp: () => moment().format('YYYY-MM-DD HH:mm:ss.SSS'), logging: false
eol: os.EOL, },
tailable: true, models: [require('./app').models]
depth: null, },
showLevel: true, logger: {
maxRetries: 1 level: 'info',
} json: false,
filename: path.join(__dirname, 'log', 'runtime.log'),
colorize: false,
maxsize: 1024 * 1024 * 5,
rotationFormat: false,
zippedArchive: true,
maxFiles: 10,
prettyPrint: true,
label: '',
timestamp: () => moment().format('YYYY-MM-DD HH:mm:ss.SSS'),
eol: os.EOL,
tailable: true,
depth: null,
showLevel: true,
maxRetries: 1
}
}; };
const development = { const development = {
port: product.port, port: product.port,
staticDirs: product.staticDirs, staticDirs: product.staticDirs,
mws: product.mws, mws: product.mws,
dc: product.dc, dc: product.dc,
logger: product.logger logger: product.logger
}; };
if (dev) { if (dev) {
// mws // mws
for (let mw of development.mws) { for (let mw of development.mws) {
// if (mw.opts.exclude) mw.opts.exclude = ['*']; // 使用 ['*'] 跳过所有路由 // if (mw.opts.exclude) mw.opts.exclude = ['*']; // 使用 ['*'] 跳过所有路由
} }
// logger // logger
development.logger.filename = path.join(__dirname, 'log', 'development.log'); development.logger.filename = path.join(__dirname, 'log', 'development.log');
development.logger.level = 'debug'; development.logger.level = 'debug';
development.dc.opts.logging = console.log; development.dc.opts.logging = console.log;
} }
module.exports = dev ? development : product; module.exports = dev ? development : product;

29
api/log/development.log

@ -3865,3 +3865,32 @@ notNull Violation: project.describe cannot be null
2023-01-17 11:00:49.835 - debug: [FS-LOGGER] Init. 2023-01-17 11:00:49.835 - debug: [FS-LOGGER] Init.
2023-01-17 11:00:50.799 - info: [FS-ATTACHMENT] Inject attachment mw into router. 2023-01-17 11:00:50.799 - info: [FS-ATTACHMENT] Inject attachment mw into router.
2023-01-17 11:00:50.799 - info: [FS-AUTH] Inject auth and api mv into router. 2023-01-17 11:00:50.799 - info: [FS-AUTH] Inject auth and api mv into router.
2023-01-17 16:24:18.099 - debug: [FS-LOGGER] Init.
2023-01-17 16:24:19.169 - info: [FS-ATTACHMENT] Inject attachment mw into router.
2023-01-17 16:24:19.169 - info: [FS-AUTH] Inject auth and api mv into router.
2023-01-17 16:29:24.545 - error: path: /patrolPlan, error: SequelizeDatabaseError: relation "patrol_plan" does not exist
2023-01-17 16:30:55.708 - error: path: /patrolPlan, error: SequelizeDatabaseError: relation "patrol_plan" does not exist
2023-01-17 17:04:11.489 - error: path: /patrolPlan, error: SequelizeDatabaseError: relation "patrol_plan" does not exist
2023-01-17 17:34:08.720 - debug: [FS-LOGGER] Init.
2023-01-17 17:34:09.424 - info: [FS-ATTACHMENT] Inject attachment mw into router.
2023-01-17 17:34:09.425 - info: [FS-AUTH] Inject auth and api mv into router.
2023-01-17 17:54:21.406 - error: [FS-ERRHD]
{
message: 'transaction is not defined',
stack: 'ReferenceError: transaction is not defined\n' +
' at login (C:\\Users\\方式、\\Desktop\\Inspection\\api\\app\\lib\\controllers\\auth\\index.js:78:9)\n' +
' at async auth (C:\\Users\\方式、\\Desktop\\Inspection\\api\\app\\lib\\middlewares\\authenticator.js:144:13)'
}
2023-01-17 17:54:32.256 - error: [FS-ERRHD]
{
message: 'transaction is not defined',
stack: 'ReferenceError: transaction is not defined\n' +
' at login (C:\\Users\\方式、\\Desktop\\Inspection\\api\\app\\lib\\controllers\\auth\\index.js:78:9)\n' +
' at async auth (C:\\Users\\方式、\\Desktop\\Inspection\\api\\app\\lib\\middlewares\\authenticator.js:144:13)'
}
2023-01-17 17:54:56.524 - debug: [FS-LOGGER] Init.
2023-01-17 17:54:57.554 - info: [FS-ATTACHMENT] Inject attachment mw into router.
2023-01-17 17:54:57.555 - info: [FS-AUTH] Inject auth and api mv into router.
2023-01-17 17:55:16.799 - debug: [FS-LOGGER] Init.
2023-01-17 17:55:16.964 - info: [FS-ATTACHMENT] Inject attachment mw into router.
2023-01-17 17:55:16.965 - info: [FS-AUTH] Inject auth and api mv into router.

4
script/1.0.0/schema/2.create.project.sql

@ -10,7 +10,7 @@ create table project
describe varchar(255), describe varchar(255),
user_id integer, user_id integer,
img character varying[], img character varying[],
qr_code varchar(255) qr_code varchar
); );
create table point create table point
@ -22,6 +22,6 @@ create table point
longitude integer, longitude integer,
latitude integer, latitude integer,
describe varchar(255), describe varchar(255),
qr_code varchar(255), qr_code varchar,
project_id integer project_id integer
) )

BIN
web/client/assets/images/login/login_a.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

BIN
web/client/assets/images/login/login_b.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 MiB

341
web/client/src/sections/auth/containers/login.js

@ -16,246 +16,137 @@ const FormItem = Form.Item;
let codCountDownInterval = null let codCountDownInterval = null
const Login = props => { const Login = props => {
const { dispatch, user, error, isRequesting } = props const { dispatch, user, error, isRequesting } = props
const [username, setUserName] = useState('') const [username, setUserName] = useState('')
const [password, setPassword] = useState('') const [password, setPassword] = useState('')
const [phone, setPhone] = useState('') const [phone, setPhone] = useState('')
const [code, setCode] = useState('') const [code, setCode] = useState('')
const [inputChanged, setInputChanged] = useState(false) const [inputChanged, setInputChanged] = useState(false)
const [curTabKey, setCurTabKey] = useState(1) const [curTabKey, setCurTabKey] = useState(1)
const [codSending, setCodSending] = useState(false) const [codSending, setCodSending] = useState(false)
const [codCountDown, setCodeCountDown] = useState(60) const [codCountDown, setCodeCountDown] = useState(60)
const codCountDownRef = useRef(0) const codCountDownRef = useRef(0)
const [form] = Form.useForm();
useEffect(() => {
useEffect(() => { }, [])
}, [])
useEffect(() => {
if (user && user.authorized) {
dispatch(push('/projectRegime/information'));
}
}, [user])
useEffect(() => { useEffect(() => {
if (user && user.authorized) { if (codSending) {
dispatch(push('/projectRegime/information')); setCodeCountDown(59)
} codCountDownRef.current = 59
}, [user]) codCountDownInterval = setInterval(() => {
codCountDownRef.current -= 1
useEffect(() => { if (codCountDownRef.current == 0) {
if (codSending) { setCodSending(false)
setCodeCountDown(59) setCodeCountDown(60)
codCountDownRef.current = 59 clearInterval(codCountDownInterval)
codCountDownInterval = setInterval(() => { codCountDownInterval = null
codCountDownRef.current -= 1 } else {
if (codCountDownRef.current == 0) { setCodeCountDown(codCountDownRef.current)
setCodSending(false)
setCodeCountDown(60)
clearInterval(codCountDownInterval)
codCountDownInterval = null
} else {
setCodeCountDown(codCountDownRef.current)
}
}, 1000);
} else {
if (codCountDownInterval) {
clearInterval(codCountDownInterval)
codCountDownInterval = null
setCodeCountDown(60)
} }
} }, 1000);
}, [codSending]) } else {
if (codCountDownInterval) {
clearInterval(codCountDownInterval)
codCountDownInterval = null
setCodeCountDown(60)
}
}
}, [codSending])
const doLogin = () => {
}
return (
<div
id='loginContainer'
style={{
height: '100vh',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
color: 'aliceblue',
backgroundImage: 'url(/assets/images/login/login_b.png)',
backgroundSize: 'cover',
position: 'relative',
}}
>
{/* <img src='/assets/images/logo.png' style={{ height: 42, borderRadius: 4, position: 'fixed', top: 32, left: 32 }} /> */}
const doLogin = () => { <div style={{
if (curTabKey == 1) { width: 556, height: 434, backgroundColor: '#rgba(255,255,255,0.50)',
if (!username || !password) borderRadius: '2px 2px 0 0', boxShadow: 'inset 0 0 8px 0 rgba(50,131,255,0.25)',
dispatch({ display: 'flex', alignItems: 'center', justifyContent: 'center', position: 'absolute', right: 150, top: 'calc(50% - 217px)'
type: LOGIN_ERROR, }}>
payload: { error: '请输入账号名和密码' } <div style={{
}); width: 410,
setInputChanged(false) height: 322,
dispatch(login({ username, password })); backgroundColor: ''
} else { }}>
if (!phone || !code) <img src={'/assets/images/login/login_a.png'} style={{ width: 124, height: 37, display: 'inline-block', marginBottom: 40 }} />
dispatch({
type: LOGIN_ERROR,
payload: { error: '请输入手机号和验证码' }
});
dispatch(login({ phone, code }));
}
}
const enterHandler = e => { <Form
if (e.key === 'Enter') { form={form}
doLogin() onFinish={r => {
} // console.log(r);
}; form.validateFields().then(r => {
dispatch(login({ username: r.username, password: r.password }));
})
.catch(err => {
dispatch({
type: LOGIN_ERROR,
payload: { error: '请输入账号名和密码' }
})
})
}}
>
<Form.Item label='' name="username" rules={[{ required: true, message: '请输入点位名称' },]}>
<Input placeholder="用户名" />
</Form.Item>
<Form.Item label='' name="password" rules={[{ required: true, message: '请输入点位名称' },]}>
<Input placeholder="密码" />
</Form.Item>
<Form.Item
>
<Button type="primary" htmlType="submit" style={{ width: 410, height: 50 }}>
登录
</Button>
</Form.Item>
</Form>
return (
<div
id='loginContainer'
style={{
height: '100vh',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
color: 'aliceblue',
backgroundImage: 'url(/assets/images/login_bg.png)'
}}
>
<img src='/assets/images/logo.png' style={{ height: 42, borderRadius: 4, position: 'fixed', top: 32, left: 32 }} />
<div style={{ width: 1000, backgroundColor: '#01316d', borderRadius: 24 }}>
<Row>
<Col span={12} style={{}}>
<img src='/assets/images/login.png' width={'100%'} />
</Col>
<Col span={12}>
<div style={{
width: '100%',
height: '100%',
padding: 30,
display: 'flex',
flexDirection: 'column',
justifyContent: 'space-around'
}}>
<p style={{ fontSize: 30, fontWeight: 'bold', textAlign: 'center' }}>
中鼎国际工程项目指挥调度系统
</p>
<Tabs defaultActiveKey="1" animated={true} onChange={(k) => {
setCurTabKey(k)
}}>
<Tabs.TabPane tab="用户名登录" key="1">
<Form onKeyDown={enterHandler}>
<div style={{ fontSize: 10, fontWeight: 'bold' }}>
用户名
</div>
<FormItem name="username">
<Input
type="text"
size="large"
value={username}
placeholder="用户名"
onChange={e => {
setUserName(e.target.value)
setInputChanged(true)
}}
/>
</FormItem>
<div style={{ fontSize: 10, fontWeight: 'bold' }}>
密码
</div>
<FormItem name="password">
<Input
type="password"
size="large"
value={password}
placeholder="密码"
onChange={e => {
setPassword(e.target.value)
setInputChanged(true)
}}
/>
</FormItem>
</Form>
</Tabs.TabPane>
<Tabs.TabPane tab="手机登录" key="2" disabled>
<Form onKeyDown={enterHandler}>
<div style={{ fontSize: 10, fontWeight: 'bold' }}>
手机号
</div>
<FormItem name="phone" rules={[{ pattern: /^1[3|4|5|7|8|9]\d{9}$/, message: '请输入正确的手机号码' }]}>
<Input
type="text"
size="large"
value={username}
onChange={e => {
setPhone(e.target.value)
setInputChanged(true)
}}
/>
</FormItem>
<div style={{ fontSize: 10, fontWeight: 'bold' }}>
验证码
</div>
<FormItem name="code">
<Input.Group compact>
<Input
size="large"
style={{ width: 'calc(100% - 112px)' }}
onChange={e => {
setCode(e.target.value)
setInputChanged(true)
}}
/>
<Button
size="large"
onClick={() => {
setCodSending(true)
const random = Math.floor(Math.random() * Math.pow(10, 4));
const sig = Hex.stringify(SHA1(phone + random));
setInputChanged(false)
Request.post(ApiTable.validatePhone, {
phone: phone,
r: random,
sig: sig
}).then(res => {
}, err => {
let message = err.response.body?.message
console.log(message);
dispatch({
type: LOGIN_ERROR,
payload: { error: message || '获取验证码失败' }
});
setCodSending(false)
});
}}
loading={codSending}
style={{ width: 112 }}
>
{codSending ? codCountDown + ' s' : '发送验证码'}
</Button>
</Input.Group>
</FormItem>
</Form>
</Tabs.TabPane>
</Tabs>
<Row style={{
textAlign: 'left'
}}>
{
inputChanged || !error ?
<span style={{
visibility: 'hidden'
}}>-</span> :
<span>
<ExclamationCircleOutlined style={{ color: 'red' }} />{error}
</span>
}
</Row>
<Button
shape="round"
size="large"
style={{ width: '100%' }}
loading={isRequesting}
onClick={doLogin}
>
登录
</Button>
</div>
</Col>
</Row>
</div> </div>
</div >
); </div>
</div >
);
} }
function mapStateToProps (state) { function mapStateToProps (state) {
const { auth } = state; const { auth } = state;
console.log(auth.error); console.log(auth.error);
return { return {
user: auth.user, user: auth.user,
error: auth.error, error: auth.error,
isRequesting: auth.isRequesting isRequesting: auth.isRequesting
} }
} }
export default connect(mapStateToProps)(Login); export default connect(mapStateToProps)(Login);

4
web/client/src/sections/projectRegime/containers/information.js

@ -144,11 +144,11 @@ const Information = (props) => {
}} }}
> >
<Form.Item <Form.Item
label='项目名称' label='结构物名称'
name="name" name="name"
style={{ marginRight: 16, minWidth: 180 }} style={{ marginRight: 16, minWidth: 180 }}
> >
<Input placeholder="请输入项目名称" allowClear /> <Input placeholder="请输入结构物名称" allowClear />
</Form.Item> </Form.Item>
<Form.Item wrapperCol={{}}> <Form.Item wrapperCol={{}}>
<Button type="primary" htmlType="submit"> <Button type="primary" htmlType="submit">

2
web/client/src/sections/projectRegime/containers/qrCode.js

@ -87,7 +87,7 @@ const QrCode = (props) => {
marginLeft: 20, width: 220, borderBottom: '1px solid #3c383824' marginLeft: 20, width: 220, borderBottom: '1px solid #3c383824'
}}> }}>
<span>结构物名称{firmList?.filter(u => u.value == v.projectId)[0]?.label}</span> <span>结构物名称{firmList?.filter(u => u.value == v.projectId)[0]?.label}</span>
<span>结构物名称{v.name}</span> <span>点位名称{v.name}</span>
</div> </div>
<img src={v.qrCode} style={{ display: 'inline-block', width: 260 }} /> <img src={v.qrCode} style={{ display: 'inline-block', width: 260 }} />
<div style={{ <div style={{

6
web/log/development.txt

@ -4301,3 +4301,9 @@
'/_file-server/project/e0bd9eaf-e4b9-4e85-aed9-77c668dbb92a/1', '/_file-server/project/e0bd9eaf-e4b9-4e85-aed9-77c668dbb92a/1',
'jpg' 'jpg'
] ]
2023-01-17 16:24:43.098 - debug: [FS-LOGGER] Init.
2023-01-17 16:24:43.101 - debug: init fs.attachment and inject it into app(app.fs.attachment) and runtime ctx(ctx.fs.attachment)
2023-01-17 16:24:45.513 - info: [Router] Inject api: attachment/index
2023-01-17 17:35:01.801 - debug: [FS-LOGGER] Init.
2023-01-17 17:35:01.805 - debug: init fs.attachment and inject it into app(app.fs.attachment) and runtime ctx(ctx.fs.attachment)
2023-01-17 17:35:04.036 - info: [Router] Inject api: attachment/index

Loading…
Cancel
Save