提交 4775e8c6 编写于 作者: uuai's avatar uuai

sqlite 数字令牌

上级 37c3c167
const express = require('express')
const path = require('path')
const config = require('./config')
const bodyParser =require('body-parser')
const app = express()
//允许接收x-www-form-urlencoede 格式
app.use(express.urlencoded({extended:true}))
// extended: false:表示使用系统模块querystring来处理,也是官方推荐的
// extended: true:表示使用第三方模块qs来处理
//允许接收json格式
app.use(express.json())
const messageBoards = require('./router/messageBoards')
app.use(express.static(path.join(__dirname, './public')))
app.get('/', (req, res) => {
res.send('Welcome')
})
app.use('/messageBoards',messageBoards)
app.listen(config.PORT,()=>{
console.log(`http://localhost:${config.PORT}`);
})
\ No newline at end of file
module.exports = {
PORT: 8080
}
\ No newline at end of file
{
"name": "serve-vite",
"version": "1.0.0",
"description": "",
"main": "app.js",
"scripts": {
"dev": "nodemon app.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"body-parser": "^1.20.2",
"express": "^4.18.2",
"nodemon": "^2.0.21",
"otplib": "^12.0.1",
"qrcode": "^1.5.1",
"sqlite3": "^5.1.4"
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>node - html</div>
</body>
</html>
\ No newline at end of file
const express = require('express')
const {db} = require('../utlis/dbutil')
const router = express.Router()
router.get('/test', (req, res) => {
db.all("select * from message", [], (err, rows) => {
res.send(rows)
})
})
router.get('/list', (req, res) => {
db.all("select * from `message`", (err, rows) => {
res.send({
code: 200,
data: rows,
message: 'success'
})
})
})
router.get('/del', (req, res) => {
const {id} = req.query;
db.all("delete from `message` where `id`=?", [id], (err, rows) => {
res.send({
code: 200,
data: rows,
message: 'success'
})
})
})
router.post('/update', (req, res) => {
const {title, content, id} = req.body;
// console.log('a',req.body,title,content);
// UPDATE `message` SET `title`=344,`content`=122,`update_time`=111 WHERE `id`=1;
db.all("UPDATE `message` SET `title`=?,`content`=?,`update_time`=? WHERE `id`=?",[title,content,new Date().getTime(),id], (err, rows) => {
res.send({
code: 200,
data: rows,
message: 'success'
})
})
})
router.post('/save', (req, res) => {
const addSql = "INSERT INTO `message` (`id`,`title`,`content`,`create_time`) VALUES(?,?,?,?)";
// res.setHeader('Content-Type', 'application/json')
const {title, content} = req.body;
console.log('req.body', req.body)
db.run(addSql, [new Date().getTime(), title, content, new Date().getTime()], (err, rows) => {
if (!err) {
res.send({
code: 200,
message: 'success'
})
}
})
})
const {createSeedSecret} = require('../utlis/digitalTokens')
router.get('/seedSecret', (req, res) => {
createSeedSecret('uuqi','app').then(resSecret => {
res.send({
code: 200,
data: resSecret,
message: 'success'
})
})
})
module.exports = router
\ No newline at end of file
const path = require('path')
const sqlite3 = require('sqlite3').verbose()
const storehouse = '../db/messageBoards/messageBoards.sqlite3'
const db = new sqlite3.Database(path.join(__dirname,storehouse))
module.exports = {
db
}
const {authenticator} = require('otplib')
const QRCode = require('qrcode')
/**
* 初始化 OTP 令牌
*
* @param userName 唯一的用户名
* @param appName 项目名称
* @returns secret 需要临时缓存的种子密钥
* @returns qrcodeUrl 展示给用户的二维码 base64
*/
const createSeedSecret = async (userName, appName) => {
console.log(userName, appName);
const secret = authenticator.generateSecret()
const googleKeyuri = authenticator.keyuri(userName, appName, secret)
const qrcodeUrl = await QRCode.toDataURL(googleKeyuri)
return { secret, qrcodeUrl }
}
/**
* 判断令牌是否正确
*
* @param code 用户输入的一次性令牌
* @param secret 用户对应的种子密钥
* @returns {boolean} 一次性令牌是否正确
*/
const isCodeCorrect = (code, secret) => {
return authenticator.check(code, secret)
}
module.exports = {
createSeedSecret,
isCodeCorrect
}
......@@ -16,7 +16,9 @@
"less": "^4.1.2",
"mavon-editor": "^2.10.4",
"md-editor-v3": "^1.11.9",
"otplib": "^12.0.1",
"pako": "^2.0.4",
"qrcode": "^1.5.1",
"sass": "^1.50.0",
"scss": "^0.2.4",
"vue": "^3.2.25",
......@@ -25,6 +27,7 @@
},
"devDependencies": {
"@vitejs/plugin-vue": "^2.3.0",
"crypto-js": "^4.1.1",
"mockjs": "^1.1.0",
"vite": "^2.9.0",
"vite-plugin-mock": "^2.9.6"
......
import request from '@/utils/request'
export function tabelAll(data) {
console.log(data);
return request({
url: '/api/table/all',
method: 'get',
......
import request from '@/utils/request'
export function messageSave(data) {
return request({
url: '/Api/messageBoards/save',
method: 'post',
data
})
}
export function messageList(data) {
return request({
url: '/Api/messageBoards/list',
method: 'get'
})
}
export function messageDel(id) {
return request({
url: '/Api/messageBoards/del',
method: 'get',
params:id
})
}
export function messageUpdate(data) {
return request({
url: '/Api/messageBoards/update',
method: 'post',
data
})
}
\ No newline at end of file
export const accessControl = {
source: 'back' // 前端 and 后端 back 控制
source: 'and' // 前端 and 后端 back 控制
}
\ No newline at end of file
......@@ -128,6 +128,15 @@ export default [
},
component: '/views/tool/mdEditor.vue',
},
{
path: 'digitalTokens',
name: 'digitalTokens',
title: '数字令牌',
meta: {
title: '数字令牌',
},
component: '/views/tool/digitalTokens/index.vue',
},
{
path: 'ui',
name: 'ui',
......@@ -196,5 +205,24 @@ export default [
},
]
},
{
path: '/node',
name: 'node',
meta: {
title: 'sqlite',
},
component: 'Layout',
children: [
{
path: 'sqlite',
name: 'sqlite',
title: 'sqlite',
meta: {
title: 'sqlite',
},
component: '/views/node/sqlite3/index.vue',
}
]
},
{path: '/:pathMatch(.*)', hidden: true, redirect: '/'} //当用户输入页面链接错误或者没有该页面时,显示该路径页面
]
......@@ -8,7 +8,7 @@ import {getToken} from '@/utils/auth'
const service = axios.create({
baseURL: import.meta.env.BASE_API, // url = base url + request url
// withCredentials: true, // send cookies when cross-domain requests
timeout: 5000 // request timeout
// timeout: 5000 // request timeout
})
// request interceptor
......@@ -42,7 +42,7 @@ service.interceptors.response.use(
if (res.code !== 200) {
message.error({
content: res.message || 'Error',
duration: 5 * 1000
duration: 3 * 1000
})
if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
......@@ -70,7 +70,7 @@ service.interceptors.response.use(
console.log('err' + error) // for debug
message.error({
content: error.message,
duration: 5 * 1000
duration: 3 * 1000
})
return Promise.reject(error)
}
......
......@@ -22,6 +22,7 @@ fields.forEach(field => {
const showMessageBox = (app, {resolve, reject}) => {
const oFragment = document.createDocumentFragment();
const vm = app.mount(oFragment) // 返回的组件实例 oFragment(节点)
console.log('vm',vm);
document.body.appendChild(oFragment)
vm.setVisibil(true)
watch(vm.state, (state) => {
......
<template>
<a-form>
<a-form-item label="标题">
<a-input v-model:value="formState.title"/>
</a-form-item>
<a-form-item label="内容">
<a-textarea v-model:value="formState.content" :auto-size="{ minRows: 2, maxRows: 5 }"/>
</a-form-item>
<a-form-item :wrapper-col="{ span: 14, offset: 4 }">
<a-button type="primary" @click="onSubmit">提交</a-button>
<a-button style="margin-left: 10px">Cancel</a-button>
</a-form-item>
</a-form>
<a-table :dataSource="dataSource" :columns="columns" :rowKey="(row)=>row.id">
<template #operate="{ record }">
<a-button @click="onDel(record.id)">删除</a-button>
<a-button @click="onUpdate(record,'edit')">修改</a-button>
</template>
</a-table>
</template>
<script>
import {ref, reactive} from 'vue'
import {messageSave, messageList, messageDel, messageUpdate} from '@/api/message'
export default {
name: "index",
setup() {
const formState = reactive({
title: '',
content: ''
})
const formType = ref('add')
let dataSource = ref([])
let rowId = ref('')
const columns = [
{
title: '标题',
dataIndex: 'title',
key: 'title',
},
{
title: '内容',
dataIndex: 'content',
key: 'content',
},
{
title: '时间',
dataIndex: 'create_time',
key: 'create_time',
},
{
title: '操作',
dataIndex: 'operate',
key: 'operate',
slots: {customRender: 'operate'},
},
]
const onSubmit = () => {
console.log('formState', formState);
if(formType.value==='add'){
messageSave(formState).then(res => {
if (res.code === 200) {
getList()
}
}).catch(err => {
console.log('----', err);
})
}else {
updateRow()
}
}
const onDel = (id) => {
console.log('formState', id);
messageDel({id}).then(res => {
if (res.code === 200) {
getList()
}
})
}
const onUpdate = (row, type) => {
formType.value = type
rowId.value = row.id
formState.title = row.title
formState.content = row.content
}
function updateRow() {
messageUpdate({
title: formState.title,
content: formState.content,
id:rowId.value
}).then(res => {
if (res.code === 200) {
getList()
formType.value = 'add'
}
})
}
getList()
function getList() {
messageList().then(res => {
if (res.code === 200) {
dataSource.value = res.data
}
}).catch(err => {
console.log('----', err);
})
}
return {
formState,
onSubmit,
onDel,
onUpdate,
formType,
columns,
dataSource
}
}
}
</script>
<style scoped>
</style>
\ No newline at end of file
<template>
<div class="fancy-btn">
<slot></slot> <!-- 插槽出口 -->
<slot name="header" :text="greetingMessage" :count="1"></slot>
<slot name="footer"></slot>
</div>
</template>
<script>
export default {
name: "FancyButton"
}
</script>
<style scoped>
</style>
\ No newline at end of file
<template>
<a-tree :tree-data="treeData" show-icon default-expand-all v-model:selectedKeys="selectedKeys">
<template #switcherIcon>
<down-outlined/>
</template>
<template #smile>
<smile-outlined/>
</template>
<template #meh>
<smile-outlined/>
</template>
<template #custom="{ selected }">
<frown-filled v-if="selected"/>
<frown-outlined v-else/>
</template>
</a-tree>
</template>
<script lang="ts">
import {DownOutlined, SmileOutlined, FrownOutlined, FrownFilled} from '@ant-design/icons-vue';
import {defineComponent, ref} from 'vue';
import {TreeDataItem} from 'ant-design-vue/es/tree/Tree';
const treeData: TreeDataItem[] = [
{
title: 'parent 1',
key: '0-0',
slots: {
icon: 'smile',
},
children: [
{title: 'leaf', key: '0-0-0', slots: {icon: 'meh'}},
{title: 'leaf', key: '0-0-1', slots: {icon: 'custom'}},
],
},
];
export default defineComponent({
components: {
DownOutlined,
SmileOutlined,
FrownOutlined,
FrownFilled,
},
setup() {
return {
selectedKeys: ref(['0-0-0']),
treeData,
};
},
});
</script>
<template>
</template>
<script>
export default {
};
</script>
<template>
<a-tree
v-model="checkedKeys"
checkable
:expanded-keys="expandedKeys"
:auto-expand-parent="autoExpandParent"
:selected-keys="selectedKeys"
:tree-data="treeData"
@expand="onExpand"
@select="onSelect"
/>
</template>
<script>
const treeData = [
{
title: '0-0',
key: '0-0',
children: [
{
title: '0-0-0',
key: '0-0-0',
children: [
{ title: '0-0-0-0', key: '0-0-0-0' },
{ title: '0-0-0-1', key: '0-0-0-1' },
{ title: '0-0-0-2', key: '0-0-0-2' },
],
},
{
title: '0-0-1',
key: '0-0-1',
children: [
{ title: '0-0-1-0', key: '0-0-1-0' },
{ title: '0-0-1-1', key: '0-0-1-1' },
{ title: '0-0-1-2', key: '0-0-1-2' },
],
},
{
title: '0-0-2',
key: '0-0-2',
},
],
},
{
title: '0-1',
key: '0-1',
children: [
{ title: '0-1-0-0', key: '0-1-0-0' },
{ title: '0-1-0-1', key: '0-1-0-1' },
{ title: '0-1-0-2', key: '0-1-0-2' },
],
},
{
title: '0-2',
key: '0-2',
},
];
export default {
data() {
return {
expandedKeys: ['0-0-0'], // 展开指定树节点
autoExpandParent: false, // 是否自动展开父节点
checkedKeys: ['0-0-1'], // 选中的父节点
selectedKeys: ['0-0'],
treeData,
};
},
watch: {
checkedKeys(val) {
console.log('onCheck', val);
},
},
methods: {
onExpand(expandedKeys) {
console.log('onExpand', expandedKeys);
// if not set autoExpandParent to false, if children expanded, parent can not collapse.
// or, you can remove all expanded children keys.
this.expandedKeys = expandedKeys;
this.autoExpandParent = false;
},
onCheck(checkedKeys) {
console.log('onCheck', checkedKeys);
this.checkedKeys = checkedKeys;
},
onSelect(selectedKeys, info) {
console.log('onSelect', info);
this.selectedKeys = selectedKeys;
},
},
};
</script>
<template>
<a-tabs v-model:activeKey="activeKey" type="card">
<a-tab-pane key="1" tab="jsx的使用和插槽传参">
<jsx></jsx>
<a-tabs v-model:activeKey="activeKey" type="card">
<a-tab-pane key="1" tab="jsx的使用和插槽传参">
<jsx></jsx>
</a-tab-pane>
<a-tab-pane key="2" tab="vue中的attrs" force-render>
<a-tabs tab-position="left">
<a-tab-pane key="1" tab="Tab 1">
<attrsVue3></attrsVue3>
</a-tab-pane>
<a-tab-pane key="2" tab="vue中的attrs" force-render>
<a-tabs tab-position="left">
<a-tab-pane key="1" tab="Tab 1">
<attrsVue3></attrsVue3>
</a-tab-pane>
<a-tab-pane key="2" tab="$attrs">
<attrs/>
</a-tab-pane>
</a-tabs>
</a-tab-pane>
<a-tab-pane key="3" tab="compositionApi">
<compositionAPI/>
<a-tab-pane key="2" tab="$attrs">
<attrs/>
</a-tab-pane>
</a-tabs>
</a-tab-pane>
<a-tab-pane key="3" tab="compositionApi">
<compositionAPI/>
</a-tab-pane>
<a-tab-pane key="4" tab="插槽">
<slots></slots>
<FancyButton>
2444
<span style="color:red">Click me!</span>
<template #header="{count}">
<div>
作用域插槽 -
<p>{{ count }}</p>
</div>
<tree></tree>
</template>
</FancyButton>
</a-tab-pane>
</a-tabs>
</a-tabs>
</template>
<script>
import {ref} from 'vue'
// jsx
import jsx from '../components/jsx/index.vue'
import attrsVue3 from "../components/attrs/vue3-attrs/index.vue";
// 通过attrs传递参数
import attrs from '../components/attrs/index.vue'
import compositionAPI from "../components/compositionAPI.vue";
export default {
name: "createVNode",
components: {
jsx,
attrsVue3,
attrs,
compositionAPI
},
setup(props, {emit}) {
function edit(val) {
console.log('edit', 0);
// 对返回的值做一个包装
emit('edit', `${val}time`)
}
import {ref} from 'vue'
// jsx
import jsx from '../components/jsx/index.vue'
import attrsVue3 from "../components/attrs/vue3-attrs/index.vue";
// 通过attrs传递参数
import attrs from '../components/attrs/index.vue'
import compositionAPI from "../components/compositionAPI.vue";
// 插槽
import slots from '../components/slots/index2.vue'
import FancyButton from '../components/slots/FancyButton.vue'
import tree from '../components/slots/tree.vue'
export default {
name: "createVNode",
components: {
jsx,
attrsVue3,
attrs,
compositionAPI,
slots,
FancyButton,
tree
},
setup(props, {emit}) {
function edit(val) {
console.log('edit', 0);
// 对返回的值做一个包装
emit('edit', `${val}time`)
}
return {
edit,
activeKey: ref('1'),
}
}
return {
edit,
activeKey: ref('4'),
}
}
}
</script>
<!--https://blog.csdn.net/jason_renyu/article/details/122042249-->
<style scoped>
......
<template>
</template>
<script>
import createSeedSecret from './index'
export default {
name: "index",
setup(){
let { secret, qrcodeUrl} = createSeedSecret('uuai','vite-demo')
console.log(' secret, qrcodeUrl', secret, qrcodeUrl)
return {
}
}
}
</script>
<style scoped>
</style>
\ No newline at end of file
......@@ -11,6 +11,25 @@ export default defineConfig({
mockPath: 'mock'
})
],
server: {
port: 3000,
open: true,
proxy: {
// 代理配置
'/api': {
target: 'http://localhost:3000',
changeOrigin: true,//允许跨域
secure:false,//解决自签名证书错误
rewrite: (path) => path.replace(/^\/api/, ''),
},
'/Api': {
target: 'http://localhost:8080',
changeOrigin: true,//允许跨域
secure:false,//解决自签名证书错误
rewrite: (path) => path.replace(/^\/Api/, ''),
},
},
},
resolve: {
alias: {
'@': resolve(__dirname, 'src'), // 配置组件
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册