change vue2 to vue3

This commit is contained in:
veypi
2021-10-28 17:22:10 +08:00
parent 82b64a4bb2
commit c74c332e6a
53 changed files with 2253 additions and 9836 deletions
+84 -35
View File
@@ -1,39 +1,88 @@
<template>
<v-app>
<v-app-bar
app
color="primary"
dark
>
<div class="d-flex align-center">
<one-icon style="color: aqua;font-size: 56px">glassdoor</one-icon>
<span class="font-italic font-weight-bold" style="font-size: 20px">统一认证</span>
</div>
<v-spacer></v-spacer>
</v-app-bar>
<script setup lang="ts">
// This starter template is using Vue 3 <script setup> SFCs
import { onBeforeMount, ref} from 'vue'
import util from './libs/util'
import {store} from "./store";
import {useOsTheme} from 'naive-ui'
<v-main>
<router-view></router-view>
</v-main>
</v-app>
</template>
const osThemeRef = useOsTheme()
<script lang="ts">
import Vue from 'vue'
import util from '@/libs/util'
export default Vue.extend({
name: 'App',
components: {},
data: () => ({
//
}),
beforeCreate() {
util.title('统一认证')
this.$store.dispatch('fetchSelf')
}
onBeforeMount(() => {
util.title("统一认证")
store.dispatch('fetchSelf')
store.commit('setTheme', osThemeRef.value)
})
</script>
<template>
<n-config-provider :theme="store.getters.GetTheme" class="h-full w-full">
<n-layout class="h-full w-full font-sans select-none">
<n-layout has-sider style="height: calc(100% - 24px)">
<n-layout-sider
class="h-full"
collapse-mode="transform"
:collapsed-width="0"
:width="120"
show-trigger="bar"
content-style="padding: 24px;"
bordered
default-collapsed
>
-
</n-layout-sider>
<n-layout>
<n-layout-header bordered style="height: 64px;line-height: 64px;">
{{ osThemeRef }}
<one-icon @click="store.dispatch('changeTheme')" class="float-right" style="font-size: 36px; margin: 14px">
{{ store.getters.IsDark ? 'Daytimemode' : 'nightmode-fill' }}
</one-icon>
</n-layout-header>
<n-layout style="height: calc(100% - 64px)">
<router-view class="h-full w-full"></router-view>
</n-layout>
</n-layout>
</n-layout>
<n-layout-footer style="height: 24px;line-height: 24px" class="flex justify-around px-3 text-gray-500 text-xs">
<span class="hover:text-black cursor-pointer">关于OA</span>
<span class="hover:text-black cursor-pointer">使用须知</span>
<span class="hover:text-black cursor-pointer">
©2021 veypi
</span>
</n-layout-footer>
</n-layout>
</n-config-provider>
</template>
<style>
html,
body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
/* 周围滑动留白 */
html {
overflow: hidden;
height: 100%;
}
body {
overflow: auto;
height: 100%;
}
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: #2c3e50;
width: 100%;
height: 100%;
}
::-webkit-scrollbar {
display: none; /* Chrome Safari */
}
</style>
+57 -56
View File
@@ -1,65 +1,66 @@
// @ts-ignore
import axios from 'axios'
import store from '@/store'
import {store} from '../store'
function baseRequests(url: string, method: any = 'GET', query: any, data: any, success: any, fail?: Function) {
return axios({
url: url,
params: query,
data: data,
method: method,
headers: {
auth_token: localStorage.auth_token
}
})
.then((res: any) => {
if ('auth_token' in res.headers) {
localStorage.auth_token = res.headers.auth_token
}
if (method === 'HEAD') {
success(res.headers)
} else {
success(res.data)
}
})
.catch((e: any) => {
if (e.response && e.response.status === 401) {
console.log(e)
store.dispatch('handleLogOut')
return
}
console.log(e)
if (e.response && e.response.status === 500) {
return
}
if (typeof fail === 'function') {
fail(e.response)
} else if (e.response && e.response.status === 400) {
console.log(400)
} else {
console.log(e.request)
}
})
return axios({
url: url,
params: query,
data: data,
method: method,
headers: {
auth_token: localStorage.auth_token
}
}).then((res: any) => {
if ('auth_token' in res.headers) {
localStorage.auth_token = res.headers.auth_token
}
if (method === 'HEAD') {
success(res.headers)
} else {
success(res.data)
}
})
.catch((e: any) => {
if (e.response && e.response.status === 401) {
console.log(e)
store.dispatch('handleLogout')
return
}
console.log(e)
if (e.response && e.response.status === 500) {
return
}
if (typeof fail === 'function') {
fail(e.response)
} else if (e.response && e.response.status === 400) {
console.log(400)
} else {
console.log(e.request)
}
})
}
const ajax = {
get(url: '', data = {}, success = {}, fail?: Function) {
return baseRequests(url, 'GET', data, {}, success, fail)
},
head(url: '', data = {}, success = {}, fail?: Function) {
return baseRequests(url, 'HEAD', data, {}, success, fail)
},
delete(url: '', data = {}, success = {}, fail?: Function) {
return baseRequests(url, 'DELETE', data, {}, success, fail)
},
post(url: '', data = {}, success = {}, fail?: Function) {
return baseRequests(url, 'POST', {}, data, success, fail)
},
put(url: '', data = {}, success = {}, fail?: Function) {
return baseRequests(url, 'PUT', {}, data, success, fail)
},
patch(url: '', data = {}, success = {}, fail?: Function) {
return baseRequests(url, 'PATCH', {}, data, success, fail)
}
get(url: '', data = {}, success = {}, fail?: Function) {
return baseRequests(url, 'GET', data, {}, success, fail)
},
head(url: '', data = {}, success = {}, fail?: Function) {
return baseRequests(url, 'HEAD', data, {}, success, fail)
},
delete(url: '', data = {}, success = {}, fail?: Function) {
return baseRequests(url, 'DELETE', data, {}, success, fail)
},
post(url: '', data = {}, success = {}, fail?: Function) {
return baseRequests(url, 'POST', {}, data, success, fail)
},
put(url: '', data = {}, success = {}, fail?: Function) {
return baseRequests(url, 'PUT', {}, data, success, fail)
},
patch(url: '', data = {}, success = {}, fail?: Function) {
return baseRequests(url, 'PATCH', {}, data, success, fail)
}
}
export default ajax
+74 -180
View File
@@ -4,213 +4,107 @@
* Distributed under terms of the MIT license.
*/
import Vue from 'vue'
import {Base64} from 'js-base64'
import {App} from 'vue'
import ajax from './ajax'
import store from '@/store'
import {store} from '../store'
import {Base64} from 'js-base64'
export type SuccessFunction<T> = (e: any) => void;
export type FailedFunction<T> = (e: any) => void;
const Code = {
42011: '无操作权限',
22031: '资源不存在 或 您无权操作该资源'
42011: '无操作权限',
22031: '资源不存在 或 您无权操作该资源'
}
class Interface {
private readonly method: Function
private readonly api: string
private readonly data: any
private readonly method: Function
private readonly api: string
private readonly data: any
constructor(method: Function, api: string, data?: any) {
this.method = method
this.api = api
this.data = data
}
Start(success: SuccessFunction<any>, fail?: FailedFunction<any>) {
const newFail = function (data: any) {
if (data && data.code === 40001) {
// no login
store.dispatch('handleLogout')
return
}
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
// @ts-ignore
if (data && data.code > 0 && Code[data.code]) {
}
if (fail) {
fail(data)
}
constructor(method: Function, api: string, data?: any) {
this.method = method
this.api = api
this.data = data
}
const newSuccess = function (data: any) {
if (Number(data.status) === 1) {
if (success) {
success(data.content)
Start(success: SuccessFunction<any>, fail?: FailedFunction<any>) {
const newFail = function (data: any) {
if (data && data.code === 40001) {
// no login
store.dispatch('handleLogout')
return
}
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
// @ts-ignore
if (data && data.code > 0 && Code[data.code]) {
}
if (fail) {
fail(data)
}
}
} else {
newFail(data)
if (data.code === 41001) {
store.dispatch('handleLogout')
// bus.$emit('log_out')
const newSuccess = function (data: any) {
if (Number(data.status) === 1) {
if (success) {
success(data.content)
}
} else {
newFail(data)
if (data.code === 41001) {
store.dispatch('handleLogout')
// bus.$emit('log_out')
}
}
}
}
this.method(this.api, this.data, newSuccess, newFail)
}
this.method(this.api, this.data, newSuccess, newFail)
}
}
const message = {
count() {
return new Interface(ajax.get, '/api/message/', {
count: true,
status: 'UnRead'
})
},
get_content(id: number) {
return new Interface(ajax.get, '/api/message/' + Number(id))
},
list(status: string) {
return new Interface(ajax.get, '/api/message/', {status})
},
update(id: number, status: string) {
return new Interface(ajax.patch, '/api/message/' + Number(id), {status})
}
}
const role = {
local: '/api/role/',
get(id: number) {
return new Interface(ajax.get, this.local + id)
},
list() {
return new Interface(ajax.get, this.local)
},
update(id: number, props: any) {
return new Interface(ajax.patch, this.local + id, props)
},
create(props: any) {
return new Interface(ajax.post, this.local, props)
},
del(id: number) {
return new Interface(ajax.delete, this.local + id)
},
bind(id: number, aid: number) {
return new Interface(ajax.get, this.local + id + '/bind/' + aid)
},
unbind(id: number, aid: number) {
return new Interface(ajax.get, this.local + id + '/unbind/' + aid)
}
}
const app = {
local: '/api/app/',
self() {
return new Interface(ajax.get, this.local, {is_self: true})
},
get(id: string) {
return new Interface(ajax.get, this.local + id)
},
list() {
return new Interface(ajax.get, this.local)
}
local: '/api/app/',
self() {
return new Interface(ajax.get, this.local, {is_self: true})
},
get(id: string) {
return new Interface(ajax.get, this.local + id)
},
list() {
return new Interface(ajax.get, this.local)
}
}
const user = {
local: '/api/user/',
register(username: string, password: string, uuid: string, prop?: any) {
const data = Object.assign({
username: username,
uuid: uuid,
password: Base64.encode(password)
}, prop)
return new Interface(ajax.post, this.local, data)
},
login(username: string, password: string, uuid: string) {
return new Interface(ajax.head, this.local + username, {
uid_type: 'username',
uuid: uuid,
password: Base64.encode(password)
})
}
local: '/api/user/',
register(username: string, password: string, uuid: string, prop?: any) {
const data = Object.assign({
username: username,
uuid: uuid,
password: Base64.encode(password)
}, prop)
return new Interface(ajax.post, this.local, data)
},
login(username: string, password: string, uuid: string) {
return new Interface(ajax.head, this.local + username, {
uid_type: 'username',
uuid: uuid,
password: Base64.encode(password)
})
}
}
const api = {
role: role,
app: app,
user: user,
admin: {
auths() {
return new Interface(ajax.get, '/api/auth/')
},
user: {
create(props: any) {
const p = Object.assign({}, props)
p.password = Base64.encode(props.password)
return new Interface(ajax.post, '/api/user/', p)
},
update(user_id: number, props: any) {
return new Interface(ajax.patch, '/api/user/' + user_id, props)
},
enable(user_id: number) {
return new Interface(ajax.patch, '/api/user/' + user_id, {
status: 'ok'
})
},
disable(user_id: number) {
return new Interface(ajax.patch, '/api/user/' + user_id, {
status: 'disabled'
})
},
attach_role(user_id: number, props: any) {
return new Interface(ajax.post, '/api/user/' + user_id + '/role/', props)
},
detach_role(user_id: number, id: any) {
return new Interface(ajax.delete, '/api/user/' + user_id + '/role/' + id)
},
reset_pass(user_id: number, password: string) {
return new Interface(ajax.patch, '/api/user/' + user_id, {password})
}
}
},
auth: {
event() {
return {
local: '/api/user/event/',
list() {
return new Interface(ajax.get, this.local)
},
create(title: string, tag: string, start_date: any, end_date: any) {
return new Interface(ajax.post, this.local, {title, tag, start_date, end_date})
},
del(id: number) {
return new Interface(ajax.delete, this.local + id)
}
}
},
favorite(name: string, tag: string, ok: boolean) {
if (ok) {
return new Interface(ajax.post, '/api/user/favorite', {name, tag})
}
return new Interface(ajax.delete, '/api/user/favorite', {name, tag})
},
get(id: number) {
return new Interface(ajax.get, '/api/user/' + id)
},
search(username: string) {
return new Interface(ajax.get, '/api/user/', {
username
})
}
},
message: message
user: user,
app: app
}
const Api = {
install(vue: typeof Vue): void {
vue.prototype.$api = api
}
install(vue: App): void {
vue.config.globalProperties.$api = api
}
}
export {Api}
export default api
-1
View File
@@ -1 +0,0 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 87.5 100"><defs><style>.cls-1{fill:#1697f6;}.cls-2{fill:#7bc6ff;}.cls-3{fill:#1867c0;}.cls-4{fill:#aeddff;}</style></defs><title>Artboard 46</title><polyline class="cls-1" points="43.75 0 23.31 0 43.75 48.32"/><polygon class="cls-2" points="43.75 62.5 43.75 100 0 14.58 22.92 14.58 43.75 62.5"/><polyline class="cls-3" points="43.75 0 64.19 0 43.75 48.32"/><polygon class="cls-4" points="64.58 14.58 87.5 14.58 43.75 100 43.75 62.5 64.58 14.58"/></svg>

Before

Width:  |  Height:  |  Size: 539 B

+52
View File
@@ -0,0 +1,52 @@
<script setup lang="ts">
import { ref } from 'vue'
defineProps<{ msg: string }>()
const count = ref(0)
</script>
<template>
<h1>{{ msg }}</h1>
<p>
Recommended IDE setup:
<a href="https://code.visualstudio.com/" target="_blank">VSCode</a>
+
<a href="https://github.com/johnsoncodehk/volar" target="_blank">Volar</a>
</p>
<p>See <code>README.md</code> for more information.</p>
<p>
<a href="https://vitejs.dev/guide/features.html" target="_blank">
Vite Docs
</a>
|
<a href="https://v3.vuejs.org/" target="_blank">Vue 3 Docs</a>
</p>
<button type="button" @click="count++">count is: {{ count }}</button>
<p>
Edit
<code>components/HelloWorld.vue</code> to test hot module replacement.
</p>
</template>
<style scoped>
a {
color: #42b983;
}
label {
margin: 0 0.5em;
font-weight: bold;
}
code {
background-color: #eee;
padding: 2px 4px;
border-radius: 4px;
color: #304455;
}
</style>
+24 -35
View File
@@ -1,43 +1,32 @@
<template>
<div id="wx_reg"></div>
</template>
<script lang='ts'>
import {Component, Vue, Prop} from 'vue-property-decorator'
import '@/libs/wwLogin.js'
<script setup lang='ts'>
import {onMounted} from 'vue'
@Component({
components: {}
})
export default class WxLogin extends Vue {
goto(id: string, app: string, url: string, state?: number, href?: string) {
// eslint-disable-next-line
// @ts-ignore
window.WwLogin({
id: 'wx_reg',
appid: id,
agentid: app,
redirect_uri: encodeURIComponent(url),
state: state,
href: href
})
}
@Prop({default: ''})
aid = ''
@Prop({default: ''})
app = ''
@Prop({default: ''})
url = ''
mounted() {
this.goto(this.aid, this.app, this.url, new Date().getTime())
}
created() {
}
function goto(id: string, app: string, url: string, state?: number, href?: string) {
// eslint-disable-next-line
// @ts-ignore
window.WwLogin({
id: 'wx_reg',
appid: id,
agentid: app,
redirect_uri: encodeURIComponent(url),
state: state,
href: href
})
}
let aid = ''
let app = ''
let url = ''
onMounted(() => {
goto(aid, app, url, new Date().getTime())
})
</script>
<style scoped>
-20
View File
@@ -1,20 +0,0 @@
<template>
<div></div>
</template>
<script lang='ts'>
import {Component, Vue} from 'vue-property-decorator'
@Component({
components: {}
})
export default class Demo extends Vue {
mounted() {
}
created() {
}
}
</script>
<style scoped>
</style>
-28
View File
@@ -1,28 +0,0 @@
<template>
<svg class="icon" aria-hidden="true">
<use :xlink:href="'#icon-'+icon"></use>
</svg>
</template>
<script lang='ts'>
import {Component, Vue} from 'vue-property-decorator'
@Component({
components: {}
})
export default class OneIcon extends Vue {
get icon() {
if (this.$slots.default) return this.$slots.default[0].text?.trim()
console.warn('blank icon name')
return ''
}
}
</script>
<style scoped>
.icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
</style>
-26
View File
@@ -1,26 +0,0 @@
import Vue from 'vue'
import OneIcon from './icon.vue'
function loadJS(url: string) {
const script = document.createElement('script')
script.type = 'text/javascript'
script.src = url
document.getElementsByTagName('head')[0].appendChild(script)
}
export default {
installed: false,
install(vue: typeof Vue, options?: { href: '' }): void {
if (this.installed) {
return
}
this.installed = true
if (options && options.href) {
console.log(options.href)
loadJS(options.href)
} else {
console.error('not set iconfont href')
}
vue.component('one-icon', OneIcon)
}
}
+8
View File
@@ -0,0 +1,8 @@
/// <reference types="vite/client" />
declare module '*.vue' {
import { DefineComponent } from 'vue'
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
const component: DefineComponent<{}, {}, any>
export default component
}
+6
View File
@@ -0,0 +1,6 @@
/* ./src/index.css */
/*! @import */
@tailwind base;
@tailwind components;
@tailwind utilities;
+12 -19
View File
@@ -1,24 +1,17 @@
import Vue from 'vue'
import {createApp} from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import vuetify from './plugins/vuetify'
import {Api} from '@/api'
import {store, key} from './store'
import OneIcon from '@veypi/one-icon'
import Message from 'vue-m-message'
import 'vue-m-message/dist/index.css'
import naive from 'naive-ui'
import './index.css'
import {Api} from './api'
Vue.use(Message) // will mount `Vue.prototype.$message`
const app = createApp(App)
// Vue.use(OneIcon, {href: 'https://at.alicdn.com/t/font_2872366_7aws02sx9bl.js'})
Vue.use(OneIcon, {href: './icon.js'})
Vue.use(Api)
Vue.config.productionTip = false
new Vue({
router,
store,
vuetify,
render: h => h(App)
}).$mount('#app')
app.use(Api)
app.use(naive)
app.use(OneIcon, {href: './icon.js'})
app.use(router)
app.use(store, key)
app.mount('#app')
-24
View File
@@ -1,24 +0,0 @@
import Vue from 'vue'
import Vuetify from 'vuetify/lib/framework'
Vue.use(Vuetify)
const light = {
primary: '#2196f3',
secondary: '#00bcd4',
accent: '#3f51b5',
error: '#f44336',
warning: '#ff5722',
info: '#ff9800',
success: '#4caf50',
reset: '#684bff'
}
export default new Vuetify({
theme: {
dark: false,
themes: {
light: light
}
}
})
+63 -50
View File
@@ -1,57 +1,70 @@
import Vue from 'vue'
import VueRouter, {RouteConfig} from 'vue-router'
import Home from '../views/Home.vue'
import Demo from '@/views/demo.vue'
import Login from '@/views/login.vue'
import Register from '@/views/register.vue'
import NotFound from '@/views/404.vue'
import {createRouter, createWebHistory} from 'vue-router'
import util from '../libs/util'
Vue.use(VueRouter)
// 避免push到相同路径报错
// 获取原型对象上的push函数
const originalPush = VueRouter.prototype.push
// 修改原型对象中的push方法
VueRouter.prototype.push = function push(location: any) {
// eslint-disable-next-line
// @ts-ignore
return originalPush.call(this, location).catch(err => err)
declare module 'vue-router' {
interface RouteMeta {
// 是可选的
isAdmin?: boolean
// 每个路由都必须声明
requiresAuth: boolean
}
}
const routes: Array<RouteConfig> = [
{
path: '/',
name: 'home',
component: Home
},
{
path: '/app',
name: 'app',
component: Demo
},
{
path: '/login/:uuid?',
name: 'login',
component: Login
},
{
path: '/register/:uuid?',
name: 'register',
component: Register
},
{
path: '/wx',
name: 'wx',
component: () => import('../views/wx.vue')
},
{
path: '*',
name: '404',
component: NotFound
}
]
const router = createRouter({
history: createWebHistory(),
routes: [
{
path: '/',
name: 'home',
meta: {
requiresAuth: true,
},
component: () => import('../view/home.vue')
},
{
path: '/app',
name: 'app',
meta: {
requiresAuth: true,
},
component: () => import('../view/demo.vue')
},
{
path: '/wx',
name: 'wx',
component: () => import('../view/wx.vue')
},
{
path: '/login/:uuid?',
name: 'login',
component: () => import('../view/login.vue')
},
{
path: '/register/:uuid?',
name: 'register',
component: () => import('../view/register.vue')
},
{
path: '/:path(.*)',
name: '404',
component: () => import('../view/404.vue')
}
//...
],
})
const router = new VueRouter({
routes
router.beforeEach((to, from) => {
// 而不是去检查每条路由记录
// to.matched.some(record => record.meta.requiresAuth)
if (to.meta.requiresAuth && !util.checkLogin()) {
// 此路由需要授权,请检查是否已登录
// 如果没有,则重定向到登录页面
return {
name: 'login',
// 保存我们所在的位置,以便以后再来
query: {redirect: to.fullPath},
}
}
})
export default router
-13
View File
@@ -1,13 +0,0 @@
import Vue, { VNode } from 'vue'
declare global {
namespace JSX {
// tslint:disable no-empty-interface
interface Element extends VNode {}
// tslint:disable no-empty-interface
interface ElementClass extends Vue {}
interface IntrinsicElements {
[elem: string]: any;
}
}
}
-5
View File
@@ -1,5 +0,0 @@
declare module '*.js'
declare module '*.vue' {
import Vue from 'vue'
export default Vue
}
-4
View File
@@ -1,4 +0,0 @@
declare module 'vuetify/lib/framework' {
import Vuetify from 'vuetify'
export default Vuetify
}
+57 -25
View File
@@ -1,30 +1,62 @@
import Vue from 'vue'
import Vuex from 'vuex'
import api from '@/api'
import router from '@/router'
import {InjectionKey} from 'vue'
import {createStore, useStore as baseUseStore, Store} from 'vuex'
import api from "../api";
import router from "../router";
import {darkTheme} from 'naive-ui'
Vue.use(Vuex)
export interface State {
oauuid: string
user: object
theme: string
export default new Vuex.Store({
state: {
oauuid: '',
user: null
},
mutations: {
setOA(state: any, data: any) {
state.oauuid = data.uuid
}
},
actions: {
fetchSelf({commit}) {
api.app.self().Start(d => {
commit('setOA', d)
})
}
export const key: InjectionKey<Store<State>> = Symbol()
export const store = createStore<State>({
state: {
theme: 'light',
oauuid: '',
user: {}
},
handleLogout() {
localStorage.removeItem('auth_token')
router.push({name: 'login'})
getters: {
IsDark(state: any) {
return state.theme === 'dark'
},
GetTheme(state: any, getters) {
return getters.IsDark ? darkTheme : null
}
},
mutations: {
setOA(state: any, data: any) {
state.oauuid = data.uuid
},
setTheme(state: any, t: string) {
state.theme = t
}
},
actions: {
changeTheme(context) {
if (context.getters.IsDark) {
context.commit('setTheme', 'light')
} else {
context.commit('setTheme', 'dark')
}
},
fetchSelf({commit}) {
api.app.self().Start(d => {
commit('setOA', d)
})
},
handleLogout() {
localStorage.removeItem('auth_token')
router.push({name: 'login'})
}
}
},
modules: {}
})
// 定义自己的 `useStore` 组合式函数
export function useStore() {
return baseUseStore(key)
}
-14
View File
@@ -1,14 +0,0 @@
// 1. 确保在声明补充的类型之前导入 'vue'
import Vue from 'vue'
import api from '@/api'
export type PluginFunction<T> = (Vue: typeof Vue, options?: T) => void;
// 2. 定制一个文件,设置你想要补充的类型
// 在 types/vue.d.ts 里 Vue 有构造函数类型
declare module 'vue/types/vue' {
// 3. 声明为 Vue 补充的东西
interface Vue {
$api: typeof api;
}
}
+32
View File
@@ -0,0 +1,32 @@
<template>
<div class="flex justify-center items-center">
<div class="text-center text-xl">
<one-icon style="font-size: 200px">404</one-icon>
<span>
路径失效啦! {{count}}
</span>
</div>
</div>
</template>
<script lang="ts" setup>
import {useRouter, useRoute} from 'vue-router'
import {onMounted, ref} from "vue";
const route = useRoute()
const router = useRouter()
let count = ref(5)
onMounted(() => {
console.log([route.path, route.params])
let timer = setInterval(()=> {
count.value--
if (count.value === 0) {
router.push('/')
clearInterval(timer)
}
}, 1000)
})
</script>
<style scoped>
</style>
+10
View File
@@ -0,0 +1,10 @@
<template>
<div></div>
</template>
<script lang="ts" setup>
</script>
<style scoped>
</style>
+10
View File
@@ -0,0 +1,10 @@
<template>
<div></div>
</template>
<script lang="ts" setup>
</script>
<style scoped>
</style>
+24
View File
@@ -0,0 +1,24 @@
<template>
<div>
</div>
</template>
<script lang="ts" setup>
import {ref} from "vue";
import api from "../api";
let apps = ref([])
function getApps() {
api.app.list().Start(e => {
apps.value = e
})
}
getApps()
</script>
<style scoped>
</style>
+61
View File
@@ -0,0 +1,61 @@
<template>
<div class="flex items-center justify-center">
<div class="p-3" style="">
<n-form ref="formRef" label-placement="left">
<n-form-item required label="username" :validation-status="rules.username[0]" :feedback="rules.username[1]">
<n-input v-model:value="data.username"></n-input>
</n-form-item>
<n-form-item required label="username" :validation-status="rules.username[0]" :feedback="rules.username[1]">
<n-input v-model:value="data.username"></n-input>
</n-form-item>
<n-button @click="login">登录</n-button>
</n-form>
</div>
</div>
</template>
<script lang="ts" setup>
import {computed, ref} from "vue";
let formRef = ref(null)
let data = ref({
username: null,
password: null
})
let ruleInline = {
username: [
(v: string) => !!v || 'required',
(v: string) => (v && v.length >= 3 && v.length <= 16) || '长度要求3~16'
],
password: [
(v: string) => !!v || 'required',
(v: string) => (v && v.length >= 6 && v.length <= 16) || '长度要求6~16'
]
}
function check(rs: [], v: any) {
for (let r of rs) {
let res = r(v)
if (res !== true) {
return ['error', res]
}
}
return ['', '']
}
let rules = ref({
username: computed(() => {
return check(ruleInline.username, data.value.username)
})
})
function login() {
formRef.value.validate(e => {
console.log(e)
})
}
</script>
<style scoped>
</style>
+10
View File
@@ -0,0 +1,10 @@
<template>
<div></div>
</template>
<script lang="ts" setup>
</script>
<style scoped>
</style>
+51
View File
@@ -0,0 +1,51 @@
<template>
<div class='home d-flex justify-center align-center'>
<wx-login v-if="enable" :aid="aid" :app="agentID" :url="url"></wx-login>
</div>
</template>
<script setup lang='ts'>
import WxLogin from '../components/WxLogin.vue'
import {computed, onMounted} from "vue";
import {useRoute} from 'vue-router'
import api from '../api'
let route = useRoute()
let aid = ''
let agentID = ''
let url = ''
let uuid = computed(() => {
return route.query.uuid
})
let enable = computed(() => {
return uuid && aid && agentID && url
})
let code = computed(() => {
return route.query.code
})
let state = computed(() => {
return route.query.state
})
let msg = computed(() => {
return route.query.msg
})
onMounted(() => {
if (msg) {
console.log(msg)
alert(msg)
}
})
if (uuid) {
api.app.get(uuid.value as string).Start(e => {
url = e.wx.url + '/api/wx/login/' + uuid
aid = e.wx.corp_id
agentID = e.wx.agent_id
})
}
</script>
<style scoped>
</style>
-24
View File
@@ -1,24 +0,0 @@
<style>
</style>
<template>
<div class='home d-flex justify-center align-center'>
<one-icon style="font-size: 100px">404</one-icon>
</div>
</template>
<script lang='ts'>
import {Component, Vue} from 'vue-property-decorator'
import util from '@/libs/util'
@Component({
components: {}
})
export default class NotFound extends Vue {
mounted() {
}
created() {
util.title('404')
}
}
</script>
-43
View File
@@ -1,43 +0,0 @@
<style>
.home {
height: 100%;
width: 100%;
}
</style>
<template>
<div class='home d-flex justify-center align-center'>
<one-icon style="color: aqua;font-size: 50px">glassdoor</one-icon>
</div>
</template>
<script lang='ts'>
import {Component, Vue} from 'vue-property-decorator'
import util from '@/libs/util'
@Component({
components: {}
})
export default class Home extends Vue {
apps = []
getApps() {
this.$api.app.list().Start(d => {
console.log(d)
this.apps = d
})
}
mounted() {
this.getApps()
}
created() {
}
beforeCreate() {
if (!util.checkLogin()) {
this.$router.push({name: 'login', query: this.$route.query, params: this.$route.params})
}
}
}
</script>
-21
View File
@@ -1,21 +0,0 @@
<style>
</style>
<template>
<div class='home d-flex justify-center align-center'>
</div>
</template>
<script lang='ts'>
import {Component, Vue} from 'vue-property-decorator'
@Component({
components: {}
})
export default class Demo extends Vue {
mounted() {
}
created() {
}
}
</script>
-123
View File
@@ -1,123 +0,0 @@
<style>
</style>
<template>
<v-row align="center" class="fill-height" justify="center" style="background: #ebebeb">
<v-col cols="12" sm="8" md="6" lg="4" xl="3">
<v-card class="elevation-12 mx-5" style="opacity: 0.8">
<v-row justify="center">
<v-col cols="10">
<v-card class="elevation-1 mt-n12 primary theme--dark">
<v-card-text class="text-center">
<h1 class="display-2 font-weight-bold mb-2">Login</h1>
<v-tooltip left>
<template v-slot:activator="{ on }">
<v-btn icon large v-on="on">
<v-icon>mdi-cellphone</v-icon>
</v-btn>
</template>
<span style="font-family:'Noto Sans Armenian'">手机登录</span>
</v-tooltip>
<v-tooltip right>
<template v-slot:activator="{ on }">
<v-btn icon large v-on="on">
<v-icon>mdi-barcode</v-icon>
</v-btn>
</template>
<span>授权码登录</span>
</v-tooltip>
</v-card-text>
</v-card>
</v-col>
</v-row>
<v-card-text>
<v-form ref="form">
<v-text-field
v-model="formInline.user"
:counter="16"
:rules="ruleInline.user"
label="账号"
required
prepend-inner-icon="mdi-account-circle"
></v-text-field>
<v-text-field
v-model="formInline.password"
type="password"
:counter="16"
:rules="ruleInline.password"
label="密码"
prepend-inner-icon="mdi-lock"
@keyup.enter="handleSubmit"
required
></v-text-field>
</v-form>
</v-card-text>
<v-card-actions>
<v-spacer/>
<v-btn type="primary" @click="handleSubmit">登录</v-btn>
<router-link :to="{name: 'register', query:$route.query, params: $route.params}"
style="text-decoration: none;">
<v-btn type="primary" style="margin-left:8px">注册</v-btn>
</router-link>
</v-card-actions>
</v-card>
</v-col>
</v-row>
</template>
<script lang='ts'>
import {Component, Vue} from 'vue-property-decorator'
import util from '@/libs/util'
@Component({
components: {}
})
export default class Login extends Vue {
formInline = {
user: '',
password: ''
}
ruleInline = {
user: [
(v: string) => !!v || 'required',
(v: string) => (v && v.length >= 3 && v.length <= 16) || '长度要求3~16'
],
password: [
(v: string) => !!v || 'required',
(v: string) => (v && v.length >= 6 && v.length <= 16) || '长度要求6~16'
]
}
get app_uuid() {
return this.$route.params.uuid || this.$store.state.oauuid
}
handleSubmit() {
// eslint-disable-next-line
// @ts-ignore
if (!this.$refs.form.validate()) {
return
}
this.$api.user.login(this.formInline.user, this.formInline.password, this.app_uuid).Start(
data => {
console.log(data)
if (util.checkLogin()) {
// this.$message.success('登录成功')
// EventBus.$emit('login', true)
this.$nextTick(() => {
if (this.$route.query.redirect) {
window.location.href = this.$route.query.redirect as string
}
this.$router.push({name: 'home'})
})
} else {
// this.$message.error('用户名或密码错误')
}
},
() => {
// this.$message.error('网络错误!')
}
)
}
}
</script>
-124
View File
@@ -1,124 +0,0 @@
<style>
</style>
<template>
<v-row class="fill-height" align="center" justify="center" style="background: #ebebeb">
<v-col cols="12" sm="8" md="6" lg="4" xl="3">
<v-card class="elevation-12 mx-5" style="opacity: 0.8">
<v-row justify="center">
<v-card class="elevation-1 mt-n7 primary" style="width: 80%">
<v-card-actions>
<v-row>
<v-icon
style="position: absolute;left: 10px;top:19px;z-index: 1"
@click="$router.back()"
size="36"
>mdi-arrow-left-circle
</v-icon>
<v-col cols="12" class="text-center">
<h1 class="display-2 ">注册</h1>
</v-col>
</v-row>
</v-card-actions>
</v-card>
</v-row>
<v-card-text class="text-center">
<v-form ref="form">
<v-text-field
type="text"
prepend-inner-icon="mdi-account-circle"
v-model="form.username"
label="账号"
:rules="ruleInline.user"
:counter="16"
>
</v-text-field>
<v-text-field
type="password"
v-model="form.passwd"
label="密码"
prepend-inner-icon="mdi-lock"
:rules="ruleInline.password"
:counter="16"
></v-text-field>
<v-text-field
type="password"
v-model="form.passwdCheck"
label="密码"
prepend-inner-icon="mdi-lock"
:rules="ruleInline.passwordCheck"
:counter="16"
@keyup.enter="handleSubmit"
></v-text-field>
</v-form>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn type="primary" @click="handleSubmit">提交</v-btn>
<v-btn @click="handleReset()">重置</v-btn>
</v-card-actions>
</v-card>
</v-col>
</v-row>
</template>
<script lang='ts'>
import {Component, Vue} from 'vue-property-decorator'
@Component({
components: {}
})
export default class Register extends Vue {
form = {
passwd: '',
passwdCheck: '',
email: '',
username: ''
}
ruleInline = {
user: [
(v: string) => !!v || 'required',
(v: string) => (v && v.length >= 3 && v.length <= 16) || '长度要求3~16'
],
password: [
(v: string) => !!v || 'required',
(v: string) => (v && v.length >= 6 && v.length <= 16) || '长度要求6~16'
],
passwordCheck: [
(v: string) => !!v || 'required',
(v: string) => (v && v === this.form.passwd) || '密码不一致'
]
}
get app_uuid() {
return this.$route.params.uuid || this.$store.state.oauuid
}
handleSubmit() {
// eslint-disable-next-line
// @ts-ignore
if (!this.$refs.form.validate()) {
return
}
this.$api.user.register(this.form.username, this.form.passwd, this.app_uuid).Start(
(data) => {
this.$message.success('注册成功!')
this.$router.push({name: 'login', params: this.$route.params, query: this.$route.query})
},
(data) => {
if (data && data.code === '31011') {
this.$message.error('用户名重复')
} else {
this.$message.error('注册失败')
}
}
)
}
handleReset() {
this.form.username = ''
this.form.passwd = ''
this.form.passwdCheck = ''
}
}
</script>
-66
View File
@@ -1,66 +0,0 @@
<template>
<div class='home d-flex justify-center align-center'>
<wx-login v-if="enable" :aid="aid" :app="agentID" :url="url"></wx-login>
<v-overlay :value="!enable">
<v-progress-circular
indeterminate
size="64"
></v-progress-circular>
</v-overlay>
</div>
</template>
<script lang='ts'>
import {Component, Vue} from 'vue-property-decorator'
import WxLogin from '@/components/WxLogin.vue'
@Component({
components: {
WxLogin
}
})
export default class Wx extends Vue {
aid = ''
agentID = ''
url = ''
get enable() {
return this.uuid && this.aid && this.agentID && this.url
}
get uuid() {
return this.$route.query.uuid
}
get code() {
return this.$route.query.code
}
get state() {
return this.$route.query.state
}
get msg() {
return this.$route.query.msg
}
mounted() {
if (this.msg) {
console.log(this.msg)
alert(this.msg)
}
}
created() {
if (this.uuid) {
this.$api.app.get(this.uuid as string).Start(e => {
this.url = e.wx.url + '/api/wx/login/' + this.uuid
this.aid = e.wx.corp_id
this.agentID = e.wx.agent_id
})
}
}
}
</script>
<style scoped>
</style>